Fix temporal persistence wiring and restore slurp_full suite

This commit is contained in:
anthonyrawlins
2025-09-28 11:39:03 +10:00
parent 9c32755632
commit 2ff408729c
16 changed files with 1195 additions and 802 deletions

View File

@@ -1,13 +1,17 @@
//go:build slurp_full
// +build slurp_full
package temporal
import (
"context"
"fmt"
"testing"
"time"
"chorus/pkg/ucxl"
slurpContext "chorus/pkg/slurp/context"
"chorus/pkg/slurp/storage"
"chorus/pkg/ucxl"
)
// Integration tests for the complete temporal graph system
@@ -16,26 +20,26 @@ func TestTemporalGraphSystem_FullIntegration(t *testing.T) {
// Create a complete temporal graph system
system := createTestSystem(t)
ctx := context.Background()
// Test scenario: E-commerce platform evolution
// Services: user-service, product-service, order-service, payment-service, notification-service
services := []string{
"user-service",
"product-service",
"product-service",
"order-service",
"payment-service",
"notification-service",
}
addresses := make([]ucxl.Address, len(services))
// Phase 1: Initial architecture setup
t.Log("Phase 1: Creating initial microservices architecture")
for i, service := range services {
addresses[i] = createTestAddress(fmt.Sprintf("ecommerce/%s", service))
initialContext := &slurpContext.ContextNode{
Path: fmt.Sprintf("ecommerce/%s", service),
UCXLAddress: addresses[i],
@@ -47,51 +51,51 @@ func TestTemporalGraphSystem_FullIntegration(t *testing.T) {
GeneratedAt: time.Now(),
RAGConfidence: 0.8,
}
_, err := system.Graph.CreateInitialContext(ctx, addresses[i], initialContext, "architect")
if err != nil {
t.Fatalf("Failed to create %s: %v", service, err)
}
}
// Phase 2: Establish service dependencies
t.Log("Phase 2: Establishing service dependencies")
dependencies := []struct {
from, to int
reason string
}{
{2, 0, "Order service needs user validation"}, // order -> user
{2, 1, "Order service needs product information"}, // order -> product
{2, 3, "Order service needs payment processing"}, // order -> payment
{2, 4, "Order service triggers notifications"}, // order -> notification
{3, 4, "Payment service sends payment confirmations"}, // payment -> notification
{2, 0, "Order service needs user validation"}, // order -> user
{2, 1, "Order service needs product information"}, // order -> product
{2, 3, "Order service needs payment processing"}, // order -> payment
{2, 4, "Order service triggers notifications"}, // order -> notification
{3, 4, "Payment service sends payment confirmations"}, // payment -> notification
}
for _, dep := range dependencies {
err := system.Graph.AddInfluenceRelationship(ctx, addresses[dep.from], addresses[dep.to])
if err != nil {
t.Fatalf("Failed to add dependency %s -> %s: %v",
t.Fatalf("Failed to add dependency %s -> %s: %v",
services[dep.from], services[dep.to], err)
}
t.Logf("Added dependency: %s -> %s (%s)",
t.Logf("Added dependency: %s -> %s (%s)",
services[dep.from], services[dep.to], dep.reason)
}
// Phase 3: System evolution - Add caching layer
t.Log("Phase 3: Adding Redis caching to improve performance")
for i, service := range []string{"user-service", "product-service"} {
addr := addresses[i]
updatedContext := &slurpContext.ContextNode{
Path: fmt.Sprintf("ecommerce/%s", service),
UCXLAddress: addr,
Summary: fmt.Sprintf("%s with Redis caching layer", service),
Purpose: fmt.Sprintf("Manage %s with improved performance", service[:len(service)-8]),
Technologies: []string{"go", "grpc", "postgres", "redis"},
Tags: []string{"microservice", "ecommerce", "cached"},
Insights: []string{
Path: fmt.Sprintf("ecommerce/%s", service),
UCXLAddress: addr,
Summary: fmt.Sprintf("%s with Redis caching layer", service),
Purpose: fmt.Sprintf("Manage %s with improved performance", service[:len(service)-8]),
Technologies: []string{"go", "grpc", "postgres", "redis"},
Tags: []string{"microservice", "ecommerce", "cached"},
Insights: []string{
fmt.Sprintf("Core service for %s management", service[:len(service)-8]),
"Improved response times with Redis caching",
"Reduced database load",
@@ -99,7 +103,7 @@ func TestTemporalGraphSystem_FullIntegration(t *testing.T) {
GeneratedAt: time.Now(),
RAGConfidence: 0.85,
}
decision := &DecisionMetadata{
ID: fmt.Sprintf("perf-cache-%d", i+1),
Maker: "performance-team",
@@ -111,26 +115,26 @@ func TestTemporalGraphSystem_FullIntegration(t *testing.T) {
ImplementationStatus: "completed",
Metadata: map[string]interface{}{"performance_improvement": "40%"},
}
_, err := system.Graph.EvolveContext(ctx, addr, updatedContext, ReasonPerformanceInsight, decision)
if err != nil {
t.Fatalf("Failed to add caching to %s: %v", service, err)
}
t.Logf("Added Redis caching to %s", service)
}
// Phase 4: Security enhancement - Payment service PCI compliance
t.Log("Phase 4: Implementing PCI compliance for payment service")
paymentAddr := addresses[3] // payment-service
securePaymentContext := &slurpContext.ContextNode{
Path: "ecommerce/payment-service",
UCXLAddress: paymentAddr,
Summary: "PCI-compliant payment service with end-to-end encryption",
Purpose: "Securely process payments with PCI DSS compliance",
Technologies: []string{"go", "grpc", "postgres", "vault", "encryption"},
Tags: []string{"microservice", "ecommerce", "secure", "pci-compliant"},
Path: "ecommerce/payment-service",
UCXLAddress: paymentAddr,
Summary: "PCI-compliant payment service with end-to-end encryption",
Purpose: "Securely process payments with PCI DSS compliance",
Technologies: []string{"go", "grpc", "postgres", "vault", "encryption"},
Tags: []string{"microservice", "ecommerce", "secure", "pci-compliant"},
Insights: []string{
"Core service for payment management",
"PCI DSS Level 1 compliant",
@@ -140,7 +144,7 @@ func TestTemporalGraphSystem_FullIntegration(t *testing.T) {
GeneratedAt: time.Now(),
RAGConfidence: 0.95,
}
securityDecision := &DecisionMetadata{
ID: "sec-pci-001",
Maker: "security-team",
@@ -155,24 +159,24 @@ func TestTemporalGraphSystem_FullIntegration(t *testing.T) {
"audit_date": time.Now().Format("2006-01-02"),
},
}
_, err := system.Graph.EvolveContext(ctx, paymentAddr, securePaymentContext, ReasonSecurityReview, securityDecision)
if err != nil {
t.Fatalf("Failed to implement PCI compliance: %v", err)
}
// Phase 5: Analyze impact and relationships
t.Log("Phase 5: Analyzing system impact and relationships")
// Test influence analysis
analysis, err := system.InfluenceAnalyzer.AnalyzeInfluenceNetwork(ctx)
if err != nil {
t.Fatalf("Failed to analyze influence network: %v", err)
}
t.Logf("Network analysis: %d nodes, %d edges, density: %.3f",
t.Logf("Network analysis: %d nodes, %d edges, density: %.3f",
analysis.TotalNodes, analysis.TotalEdges, analysis.NetworkDensity)
// Order service should be central (influences most other services)
if len(analysis.CentralNodes) > 0 {
t.Logf("Most central nodes:")
@@ -183,37 +187,37 @@ func TestTemporalGraphSystem_FullIntegration(t *testing.T) {
t.Logf(" %s (influence score: %.3f)", node.Address.String(), node.InfluenceScore)
}
}
// Test decision impact analysis
paymentEvolution, err := system.Graph.GetEvolutionHistory(ctx, paymentAddr)
if err != nil {
t.Fatalf("Failed to get payment service evolution: %v", err)
}
if len(paymentEvolution) < 2 {
t.Fatalf("Expected at least 2 versions in payment service evolution, got %d", len(paymentEvolution))
}
latestVersion := paymentEvolution[len(paymentEvolution)-1]
impact, err := system.InfluenceAnalyzer.AnalyzeDecisionImpact(ctx, paymentAddr, latestVersion.Version)
if err != nil {
t.Fatalf("Failed to analyze payment service impact: %v", err)
}
t.Logf("Payment service security impact: %d direct impacts, strength: %.3f",
t.Logf("Payment service security impact: %d direct impacts, strength: %.3f",
len(impact.DirectImpact), impact.ImpactStrength)
// Test staleness detection
staleContexts, err := system.StalenessDetector.DetectStaleContexts(ctx, 0.3)
if err != nil {
t.Fatalf("Failed to detect stale contexts: %v", err)
}
t.Logf("Found %d potentially stale contexts", len(staleContexts))
// Phase 6: Query system testing
t.Log("Phase 6: Testing decision-hop queries")
// Find all services within 2 hops of order service
orderAddr := addresses[2] // order-service
hopQuery := &HopQuery{
@@ -230,78 +234,78 @@ func TestTemporalGraphSystem_FullIntegration(t *testing.T) {
Limit: 10,
IncludeMetadata: true,
}
queryResult, err := system.QuerySystem.ExecuteHopQuery(ctx, hopQuery)
if err != nil {
t.Fatalf("Failed to execute hop query: %v", err)
}
t.Logf("Hop query found %d related decisions in %v",
t.Logf("Hop query found %d related decisions in %v",
len(queryResult.Results), queryResult.ExecutionTime)
for _, result := range queryResult.Results {
t.Logf(" %s at %d hops (relevance: %.3f)",
t.Logf(" %s at %d hops (relevance: %.3f)",
result.Address.String(), result.HopDistance, result.RelevanceScore)
}
// Test decision genealogy
genealogy, err := system.QuerySystem.AnalyzeDecisionGenealogy(ctx, paymentAddr)
if err != nil {
t.Fatalf("Failed to analyze payment service genealogy: %v", err)
}
t.Logf("Payment service genealogy: %d ancestors, %d descendants, depth: %d",
t.Logf("Payment service genealogy: %d ancestors, %d descendants, depth: %d",
len(genealogy.AllAncestors), len(genealogy.AllDescendants), genealogy.GenealogyDepth)
// Phase 7: Persistence and synchronization testing
t.Log("Phase 7: Testing persistence and synchronization")
// Test backup
err = system.PersistenceManager.BackupGraph(ctx)
if err != nil {
t.Fatalf("Failed to backup graph: %v", err)
}
// Test synchronization
syncResult, err := system.PersistenceManager.SynchronizeGraph(ctx)
if err != nil {
t.Fatalf("Failed to synchronize graph: %v", err)
}
t.Logf("Synchronization completed: %d nodes processed, %d conflicts resolved",
t.Logf("Synchronization completed: %d nodes processed, %d conflicts resolved",
syncResult.NodesProcessed, syncResult.ConflictsResolved)
// Phase 8: System validation
t.Log("Phase 8: Validating system integrity")
// Validate temporal integrity
err = system.Graph.ValidateTemporalIntegrity(ctx)
if err != nil {
t.Fatalf("Temporal integrity validation failed: %v", err)
}
// Collect metrics
metrics, err := system.MetricsCollector.CollectTemporalMetrics(ctx)
if err != nil {
t.Fatalf("Failed to collect temporal metrics: %v", err)
}
t.Logf("System metrics: %d total nodes, %d decisions, %d active contexts",
t.Logf("System metrics: %d total nodes, %d decisions, %d active contexts",
metrics.TotalNodes, metrics.TotalDecisions, metrics.ActiveContexts)
// Final verification: Check that all expected relationships exist
expectedConnections := []struct {
from, to int
}{
{2, 0}, {2, 1}, {2, 3}, {2, 4}, {3, 4}, // Dependencies we created
}
for _, conn := range expectedConnections {
influences, _, err := system.Graph.GetInfluenceRelationships(ctx, addresses[conn.from])
if err != nil {
t.Fatalf("Failed to get influence relationships: %v", err)
}
found := false
for _, influenced := range influences {
if influenced.String() == addresses[conn.to].String() {
@@ -309,35 +313,35 @@ func TestTemporalGraphSystem_FullIntegration(t *testing.T) {
break
}
}
if !found {
t.Errorf("Expected influence relationship %s -> %s not found",
t.Errorf("Expected influence relationship %s -> %s not found",
services[conn.from], services[conn.to])
}
}
t.Log("Integration test completed successfully!")
}
func TestTemporalGraphSystem_PerformanceUnderLoad(t *testing.T) {
system := createTestSystem(t)
ctx := context.Background()
t.Log("Creating large-scale system for performance testing")
// Create 100 contexts representing a complex microservices architecture
numServices := 100
addresses := make([]ucxl.Address, numServices)
// Create services in batches to simulate realistic growth
batchSize := 10
for batch := 0; batch < numServices/batchSize; batch++ {
start := batch * batchSize
end := start + batchSize
for i := start; i < end; i++ {
addresses[i] = createTestAddress(fmt.Sprintf("services/service-%03d", i))
context := &slurpContext.ContextNode{
Path: fmt.Sprintf("services/service-%03d", i),
UCXLAddress: addresses[i],
@@ -349,19 +353,19 @@ func TestTemporalGraphSystem_PerformanceUnderLoad(t *testing.T) {
GeneratedAt: time.Now(),
RAGConfidence: 0.7 + float64(i%3)*0.1,
}
_, err := system.Graph.CreateInitialContext(ctx, addresses[i], context, "automation")
if err != nil {
t.Fatalf("Failed to create service %d: %v", i, err)
}
}
t.Logf("Created batch %d (%d-%d)", batch+1, start, end-1)
}
// Create realistic dependency patterns
t.Log("Creating dependency relationships")
dependencyCount := 0
for i := 0; i < numServices; i++ {
// Each service depends on 2-5 other services
@@ -376,18 +380,18 @@ func TestTemporalGraphSystem_PerformanceUnderLoad(t *testing.T) {
}
}
}
t.Logf("Created %d dependency relationships", dependencyCount)
// Performance test: Large-scale evolution
t.Log("Testing large-scale context evolution")
startTime := time.Now()
evolutionCount := 0
for i := 0; i < 50; i++ { // Evolve 50 services
service := i * 2 % numServices // Distribute evenly
updatedContext := &slurpContext.ContextNode{
Path: fmt.Sprintf("services/service-%03d", service),
UCXLAddress: addresses[service],
@@ -399,7 +403,7 @@ func TestTemporalGraphSystem_PerformanceUnderLoad(t *testing.T) {
GeneratedAt: time.Now(),
RAGConfidence: 0.8,
}
decision := &DecisionMetadata{
ID: fmt.Sprintf("auto-update-%03d", service),
Maker: "automation",
@@ -409,7 +413,7 @@ func TestTemporalGraphSystem_PerformanceUnderLoad(t *testing.T) {
CreatedAt: time.Now(),
ImplementationStatus: "completed",
}
_, err := system.Graph.EvolveContext(ctx, addresses[service], updatedContext, ReasonPerformanceInsight, decision)
if err != nil {
t.Errorf("Failed to evolve service %d: %v", service, err)
@@ -417,33 +421,33 @@ func TestTemporalGraphSystem_PerformanceUnderLoad(t *testing.T) {
evolutionCount++
}
}
evolutionTime := time.Since(startTime)
t.Logf("Evolved %d services in %v (%.2f ops/sec)",
t.Logf("Evolved %d services in %v (%.2f ops/sec)",
evolutionCount, evolutionTime, float64(evolutionCount)/evolutionTime.Seconds())
// Performance test: Large-scale analysis
t.Log("Testing large-scale influence analysis")
analysisStart := time.Now()
analysis, err := system.InfluenceAnalyzer.AnalyzeInfluenceNetwork(ctx)
if err != nil {
t.Fatalf("Failed to analyze large network: %v", err)
}
analysisTime := time.Since(analysisStart)
t.Logf("Analyzed network (%d nodes, %d edges) in %v",
t.Logf("Analyzed network (%d nodes, %d edges) in %v",
analysis.TotalNodes, analysis.TotalEdges, analysisTime)
// Performance test: Bulk queries
t.Log("Testing bulk decision-hop queries")
queryStart := time.Now()
queryCount := 0
for i := 0; i < 20; i++ { // Test 20 queries
startService := i * 5 % numServices
hopQuery := &HopQuery{
StartAddress: addresses[startService],
MaxHops: 3,
@@ -453,7 +457,7 @@ func TestTemporalGraphSystem_PerformanceUnderLoad(t *testing.T) {
},
Limit: 50,
}
_, err := system.QuerySystem.ExecuteHopQuery(ctx, hopQuery)
if err != nil {
t.Errorf("Failed to execute query %d: %v", i, err)
@@ -461,80 +465,80 @@ func TestTemporalGraphSystem_PerformanceUnderLoad(t *testing.T) {
queryCount++
}
}
queryTime := time.Since(queryStart)
t.Logf("Executed %d queries in %v (%.2f queries/sec)",
t.Logf("Executed %d queries in %v (%.2f queries/sec)",
queryCount, queryTime, float64(queryCount)/queryTime.Seconds())
// Memory usage check
metrics, err := system.MetricsCollector.CollectTemporalMetrics(ctx)
if err != nil {
t.Fatalf("Failed to collect final metrics: %v", err)
}
t.Logf("Final system state: %d nodes, %d decisions, %d connections",
t.Logf("Final system state: %d nodes, %d decisions, %d connections",
metrics.TotalNodes, metrics.TotalDecisions, metrics.InfluenceConnections)
// Verify system integrity under load
err = system.Graph.ValidateTemporalIntegrity(ctx)
if err != nil {
t.Fatalf("System integrity compromised under load: %v", err)
}
t.Log("Performance test completed successfully!")
}
func TestTemporalGraphSystem_ErrorRecovery(t *testing.T) {
system := createTestSystem(t)
ctx := context.Background()
t.Log("Testing error recovery and resilience")
// Create some contexts
addresses := make([]ucxl.Address, 5)
for i := 0; i < 5; i++ {
addresses[i] = createTestAddress(fmt.Sprintf("test/resilience-%d", i))
context := createTestContext(fmt.Sprintf("test/resilience-%d", i), []string{"go"})
_, err := system.Graph.CreateInitialContext(ctx, addresses[i], context, "test")
if err != nil {
t.Fatalf("Failed to create context %d: %v", i, err)
}
}
// Test recovery from invalid operations
t.Log("Testing recovery from invalid operations")
// Try to evolve non-existent context
invalidAddr := createTestAddress("test/non-existent")
invalidContext := createTestContext("test/non-existent", []string{"go"})
invalidDecision := createTestDecision("invalid-001", "test", "Invalid", ImpactLocal)
_, err := system.Graph.EvolveContext(ctx, invalidAddr, invalidContext, ReasonCodeChange, invalidDecision)
if err == nil {
t.Error("Expected error when evolving non-existent context")
}
// Try to add influence to non-existent context
err = system.Graph.AddInfluenceRelationship(ctx, addresses[0], invalidAddr)
if err == nil {
t.Error("Expected error when adding influence to non-existent context")
}
// System should still be functional after errors
_, err = system.Graph.GetLatestVersion(ctx, addresses[0])
if err != nil {
t.Fatalf("System became non-functional after errors: %v", err)
}
// Test integrity validation detects and reports issues
t.Log("Testing integrity validation")
err = system.Graph.ValidateTemporalIntegrity(ctx)
if err != nil {
t.Fatalf("Integrity validation failed: %v", err)
}
t.Log("Error recovery test completed successfully!")
}
@@ -546,14 +550,14 @@ func createTestSystem(t *testing.T) *TemporalGraphSystem {
distributedStorage := &mockDistributedStorage{}
encryptedStorage := &mockEncryptedStorage{}
backupManager := &mockBackupManager{}
// Create factory with test configuration
config := DefaultTemporalConfig()
config.EnableDebugLogging = true
config.EnableValidation = true
factory := NewTemporalGraphFactory(contextStore, config)
// Create complete system
system, err := factory.CreateTemporalGraphSystem(
localStorage,
@@ -564,7 +568,7 @@ func createTestSystem(t *testing.T) *TemporalGraphSystem {
if err != nil {
t.Fatalf("Failed to create temporal graph system: %v", err)
}
return system
}
@@ -720,10 +724,9 @@ type mockBackupManager struct{}
func (m *mockBackupManager) CreateBackup(ctx context.Context, config *storage.BackupConfig) (*storage.BackupInfo, error) {
return &storage.BackupInfo{
ID: "test-backup-1",
CreatedAt: time.Now(),
Size: 1024,
Description: "Test backup",
ID: "test-backup-1",
CreatedAt: time.Now(),
Size: 1024,
}, nil
}
@@ -751,4 +754,4 @@ func (m *mockBackupManager) ScheduleBackup(ctx context.Context, schedule *storag
func (m *mockBackupManager) GetBackupStats(ctx context.Context) (*storage.BackupStatistics, error) {
return &storage.BackupStatistics{}, nil
}
}