668 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			668 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| //go:build slurp_full
 | |
| // +build slurp_full
 | |
| 
 | |
| package temporal
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"fmt"
 | |
| 	"testing"
 | |
| 	"time"
 | |
| 
 | |
| 	slurpContext "chorus/pkg/slurp/context"
 | |
| 	"chorus/pkg/ucxl"
 | |
| )
 | |
| 
 | |
| // Core temporal graph tests
 | |
| 
 | |
| func TestTemporalGraph_CreateInitialContext(t *testing.T) {
 | |
| 	storage := newMockStorage()
 | |
| 	graph := NewTemporalGraph(storage).(*temporalGraphImpl)
 | |
| 	ctx := context.Background()
 | |
| 
 | |
| 	address := createTestAddress("test/component")
 | |
| 	contextData := createTestContext("test/component", []string{"go", "test"})
 | |
| 
 | |
| 	node, err := graph.CreateInitialContext(ctx, address, contextData, "test_creator")
 | |
| 
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("Failed to create initial context: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	if node == nil {
 | |
| 		t.Fatal("Expected node to be created")
 | |
| 	}
 | |
| 
 | |
| 	if node.Version != 1 {
 | |
| 		t.Errorf("Expected version 1, got %d", node.Version)
 | |
| 	}
 | |
| 
 | |
| 	if node.ChangeReason != ReasonInitialCreation {
 | |
| 		t.Errorf("Expected initial creation reason, got %s", node.ChangeReason)
 | |
| 	}
 | |
| 
 | |
| 	if node.ParentNode != nil {
 | |
| 		t.Error("Expected no parent node for initial context")
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestTemporalGraph_EvolveContext(t *testing.T) {
 | |
| 	storage := newMockStorage()
 | |
| 	graph := NewTemporalGraph(storage)
 | |
| 	ctx := context.Background()
 | |
| 
 | |
| 	address := createTestAddress("test/component")
 | |
| 	initialContext := createTestContext("test/component", []string{"go", "test"})
 | |
| 
 | |
| 	// Create initial context
 | |
| 	_, err := graph.CreateInitialContext(ctx, address, initialContext, "test_creator")
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("Failed to create initial context: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	// Evolve context
 | |
| 	updatedContext := createTestContext("test/component", []string{"go", "test", "updated"})
 | |
| 	decision := createTestDecision("dec-001", "test_maker", "Adding new technology", ImpactModule)
 | |
| 
 | |
| 	evolvedNode, err := graph.EvolveContext(ctx, address, updatedContext, ReasonCodeChange, decision)
 | |
| 
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("Failed to evolve context: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	if evolvedNode.Version != 2 {
 | |
| 		t.Errorf("Expected version 2, got %d", evolvedNode.Version)
 | |
| 	}
 | |
| 
 | |
| 	if evolvedNode.ChangeReason != ReasonCodeChange {
 | |
| 		t.Errorf("Expected code change reason, got %s", evolvedNode.ChangeReason)
 | |
| 	}
 | |
| 
 | |
| 	if evolvedNode.ParentNode == nil {
 | |
| 		t.Error("Expected parent node reference")
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestTemporalGraph_GetLatestVersion(t *testing.T) {
 | |
| 	storage := newMockStorage()
 | |
| 	graph := NewTemporalGraph(storage)
 | |
| 	ctx := context.Background()
 | |
| 
 | |
| 	address := createTestAddress("test/component")
 | |
| 	initialContext := createTestContext("test/component", []string{"go"})
 | |
| 
 | |
| 	// Create initial version
 | |
| 	_, err := graph.CreateInitialContext(ctx, address, initialContext, "test_creator")
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("Failed to create initial context: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	// Evolve multiple times
 | |
| 	for i := 2; i <= 5; i++ {
 | |
| 		updatedContext := createTestContext("test/component", []string{"go", fmt.Sprintf("tech%d", i)})
 | |
| 		decision := createTestDecision(fmt.Sprintf("dec-%03d", i), "test_maker", "Update", ImpactLocal)
 | |
| 
 | |
| 		_, err := graph.EvolveContext(ctx, address, updatedContext, ReasonCodeChange, decision)
 | |
| 		if err != nil {
 | |
| 			t.Fatalf("Failed to evolve context to version %d: %v", i, err)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Get latest version
 | |
| 	latest, err := graph.GetLatestVersion(ctx, address)
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("Failed to get latest version: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	if latest.Version != 5 {
 | |
| 		t.Errorf("Expected latest version 5, got %d", latest.Version)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestTemporalGraph_GetEvolutionHistory(t *testing.T) {
 | |
| 	storage := newMockStorage()
 | |
| 	graph := NewTemporalGraph(storage)
 | |
| 	ctx := context.Background()
 | |
| 
 | |
| 	address := createTestAddress("test/component")
 | |
| 	initialContext := createTestContext("test/component", []string{"go"})
 | |
| 
 | |
| 	// Create initial version
 | |
| 	_, err := graph.CreateInitialContext(ctx, address, initialContext, "test_creator")
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("Failed to create initial context: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	// Evolve multiple times
 | |
| 	for i := 2; i <= 3; i++ {
 | |
| 		updatedContext := createTestContext("test/component", []string{"go", fmt.Sprintf("tech%d", i)})
 | |
| 		decision := createTestDecision(fmt.Sprintf("dec-%03d", i), "test_maker", "Update", ImpactLocal)
 | |
| 
 | |
| 		_, err := graph.EvolveContext(ctx, address, updatedContext, ReasonCodeChange, decision)
 | |
| 		if err != nil {
 | |
| 			t.Fatalf("Failed to evolve context to version %d: %v", i, err)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Get evolution history
 | |
| 	history, err := graph.GetEvolutionHistory(ctx, address)
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("Failed to get evolution history: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	if len(history) != 3 {
 | |
| 		t.Errorf("Expected 3 versions in history, got %d", len(history))
 | |
| 	}
 | |
| 
 | |
| 	// Verify ordering
 | |
| 	for i, node := range history {
 | |
| 		expectedVersion := i + 1
 | |
| 		if node.Version != expectedVersion {
 | |
| 			t.Errorf("Expected version %d at index %d, got %d", expectedVersion, i, node.Version)
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestTemporalGraph_InfluenceRelationships(t *testing.T) {
 | |
| 	storage := newMockStorage()
 | |
| 	graph := NewTemporalGraph(storage)
 | |
| 	ctx := context.Background()
 | |
| 
 | |
| 	// Create two contexts
 | |
| 	addr1 := createTestAddress("test/component1")
 | |
| 	addr2 := createTestAddress("test/component2")
 | |
| 
 | |
| 	context1 := createTestContext("test/component1", []string{"go"})
 | |
| 	context2 := createTestContext("test/component2", []string{"go"})
 | |
| 
 | |
| 	_, err := graph.CreateInitialContext(ctx, addr1, context1, "test_creator")
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("Failed to create context 1: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	_, err = graph.CreateInitialContext(ctx, addr2, context2, "test_creator")
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("Failed to create context 2: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	// Add influence relationship
 | |
| 	err = graph.AddInfluenceRelationship(ctx, addr1, addr2)
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("Failed to add influence relationship: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	// Get influence relationships
 | |
| 	influences, influencedBy, err := graph.GetInfluenceRelationships(ctx, addr1)
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("Failed to get influence relationships: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	if len(influences) != 1 {
 | |
| 		t.Errorf("Expected 1 influence, got %d", len(influences))
 | |
| 	}
 | |
| 
 | |
| 	if influences[0].String() != addr2.String() {
 | |
| 		t.Errorf("Expected influence to addr2, got %s", influences[0].String())
 | |
| 	}
 | |
| 
 | |
| 	if len(influencedBy) != 0 {
 | |
| 		t.Errorf("Expected 0 influenced by, got %d", len(influencedBy))
 | |
| 	}
 | |
| 
 | |
| 	// Check reverse relationship
 | |
| 	influences2, influencedBy2, err := graph.GetInfluenceRelationships(ctx, addr2)
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("Failed to get influence relationships for addr2: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	if len(influences2) != 0 {
 | |
| 		t.Errorf("Expected 0 influences for addr2, got %d", len(influences2))
 | |
| 	}
 | |
| 
 | |
| 	if len(influencedBy2) != 1 {
 | |
| 		t.Errorf("Expected 1 influenced by for addr2, got %d", len(influencedBy2))
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestTemporalGraph_FindRelatedDecisions(t *testing.T) {
 | |
| 	storage := newMockStorage()
 | |
| 	graph := NewTemporalGraph(storage)
 | |
| 	ctx := context.Background()
 | |
| 
 | |
| 	// Create a network of contexts
 | |
| 	addresses := make([]ucxl.Address, 5)
 | |
| 	for i := 0; i < 5; i++ {
 | |
| 		addresses[i] = createTestAddress(fmt.Sprintf("test/component%d", i))
 | |
| 		context := createTestContext(fmt.Sprintf("test/component%d", i), []string{"go"})
 | |
| 
 | |
| 		_, err := graph.CreateInitialContext(ctx, addresses[i], context, "test_creator")
 | |
| 		if err != nil {
 | |
| 			t.Fatalf("Failed to create context %d: %v", i, err)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Create influence chain: 0 -> 1 -> 2 -> 3 -> 4
 | |
| 	for i := 0; i < 4; i++ {
 | |
| 		err := graph.AddInfluenceRelationship(ctx, addresses[i], addresses[i+1])
 | |
| 		if err != nil {
 | |
| 			t.Fatalf("Failed to add influence relationship %d->%d: %v", i, i+1, err)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Find related decisions within 3 hops from address 0
 | |
| 	relatedPaths, err := graph.FindRelatedDecisions(ctx, addresses[0], 3)
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("Failed to find related decisions: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	// Should find addresses 1, 2, 3 (within 3 hops)
 | |
| 	if len(relatedPaths) < 3 {
 | |
| 		t.Errorf("Expected at least 3 related decisions, got %d", len(relatedPaths))
 | |
| 	}
 | |
| 
 | |
| 	// Verify hop distances
 | |
| 	foundAddresses := make(map[string]int)
 | |
| 	for _, path := range relatedPaths {
 | |
| 		foundAddresses[path.To.String()] = path.TotalHops
 | |
| 	}
 | |
| 
 | |
| 	for i := 1; i <= 3; i++ {
 | |
| 		expectedAddr := addresses[i].String()
 | |
| 		if hops, found := foundAddresses[expectedAddr]; found {
 | |
| 			if hops != i {
 | |
| 				t.Errorf("Expected %d hops to address %d, got %d", i, i, hops)
 | |
| 			}
 | |
| 		} else {
 | |
| 			t.Errorf("Expected to find address %d in related decisions", i)
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestTemporalGraph_FindDecisionPath(t *testing.T) {
 | |
| 	storage := newMockStorage()
 | |
| 	graph := NewTemporalGraph(storage)
 | |
| 	ctx := context.Background()
 | |
| 
 | |
| 	// Create contexts
 | |
| 	addr1 := createTestAddress("test/start")
 | |
| 	addr2 := createTestAddress("test/middle")
 | |
| 	addr3 := createTestAddress("test/end")
 | |
| 
 | |
| 	contexts := []*slurpContext.ContextNode{
 | |
| 		createTestContext("test/start", []string{"go"}),
 | |
| 		createTestContext("test/middle", []string{"go"}),
 | |
| 		createTestContext("test/end", []string{"go"}),
 | |
| 	}
 | |
| 
 | |
| 	addresses := []ucxl.Address{addr1, addr2, addr3}
 | |
| 
 | |
| 	for i, context := range contexts {
 | |
| 		_, err := graph.CreateInitialContext(ctx, addresses[i], context, "test_creator")
 | |
| 		if err != nil {
 | |
| 			t.Fatalf("Failed to create context %d: %v", i, err)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Create path: start -> middle -> end
 | |
| 	err := graph.AddInfluenceRelationship(ctx, addr1, addr2)
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("Failed to add relationship start->middle: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	err = graph.AddInfluenceRelationship(ctx, addr2, addr3)
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("Failed to add relationship middle->end: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	// Find path from start to end
 | |
| 	path, err := graph.FindDecisionPath(ctx, addr1, addr3)
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("Failed to find decision path: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	if len(path) != 2 {
 | |
| 		t.Errorf("Expected path length 2, got %d", len(path))
 | |
| 	}
 | |
| 
 | |
| 	// Verify path steps
 | |
| 	if path[0].Address.String() != addr1.String() {
 | |
| 		t.Errorf("Expected first step to be start address, got %s", path[0].Address.String())
 | |
| 	}
 | |
| 
 | |
| 	if path[1].Address.String() != addr2.String() {
 | |
| 		t.Errorf("Expected second step to be middle address, got %s", path[1].Address.String())
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestTemporalGraph_ValidateIntegrity(t *testing.T) {
 | |
| 	storage := newMockStorage()
 | |
| 	graph := NewTemporalGraph(storage)
 | |
| 	ctx := context.Background()
 | |
| 
 | |
| 	// Create valid contexts with proper relationships
 | |
| 	addr1 := createTestAddress("test/component1")
 | |
| 	addr2 := createTestAddress("test/component2")
 | |
| 
 | |
| 	context1 := createTestContext("test/component1", []string{"go"})
 | |
| 	context2 := createTestContext("test/component2", []string{"go"})
 | |
| 
 | |
| 	_, err := graph.CreateInitialContext(ctx, addr1, context1, "test_creator")
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("Failed to create context 1: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	_, err = graph.CreateInitialContext(ctx, addr2, context2, "test_creator")
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("Failed to create context 2: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	err = graph.AddInfluenceRelationship(ctx, addr1, addr2)
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("Failed to add influence relationship: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	// Validate integrity - should pass
 | |
| 	err = graph.ValidateTemporalIntegrity(ctx)
 | |
| 	if err != nil {
 | |
| 		t.Errorf("Expected integrity validation to pass, got error: %v", err)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestTemporalGraph_CompactHistory(t *testing.T) {
 | |
| 	storage := newMockStorage()
 | |
| 	graphBase := NewTemporalGraph(storage)
 | |
| 	graph := graphBase.(*temporalGraphImpl)
 | |
| 	ctx := context.Background()
 | |
| 
 | |
| 	address := createTestAddress("test/component")
 | |
| 	initialContext := createTestContext("test/component", []string{"go"})
 | |
| 
 | |
| 	// Create initial version (old)
 | |
| 	_, err := graph.CreateInitialContext(ctx, address, initialContext, "test_creator")
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("Failed to create initial context: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	// Create several more versions
 | |
| 	for i := 2; i <= 10; i++ {
 | |
| 		updatedContext := createTestContext("test/component", []string{"go", fmt.Sprintf("tech%d", i)})
 | |
| 
 | |
| 		var reason ChangeReason
 | |
| 		if i%3 == 0 {
 | |
| 			reason = ReasonArchitectureChange // Major change - should be kept
 | |
| 		} else {
 | |
| 			reason = ReasonCodeChange // Minor change - may be compacted
 | |
| 		}
 | |
| 
 | |
| 		decision := createTestDecision(fmt.Sprintf("dec-%03d", i), "test_maker", "Update", ImpactLocal)
 | |
| 
 | |
| 		_, err := graph.EvolveContext(ctx, address, updatedContext, reason, decision)
 | |
| 		if err != nil {
 | |
| 			t.Fatalf("Failed to evolve context to version %d: %v", i, err)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Mark older versions beyond the retention window
 | |
| 	for _, node := range graph.addressToNodes[address.String()] {
 | |
| 		if node.Version <= 6 {
 | |
| 			node.Timestamp = time.Now().Add(-60 * 24 * time.Hour)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Get history before compaction
 | |
| 	historyBefore, err := graph.GetEvolutionHistory(ctx, address)
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("Failed to get history before compaction: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	// Compact history (keep recent changes within 30 days)
 | |
| 	cutoffTime := time.Now().Add(-30 * 24 * time.Hour)
 | |
| 	err = graph.CompactHistory(ctx, cutoffTime)
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("Failed to compact history: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	// Get history after compaction
 | |
| 	historyAfter, err := graph.GetEvolutionHistory(ctx, address)
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("Failed to get history after compaction: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	// History should be smaller but still contain recent changes
 | |
| 	if len(historyAfter) >= len(historyBefore) {
 | |
| 		t.Errorf("Expected history to be compacted, before: %d, after: %d", len(historyBefore), len(historyAfter))
 | |
| 	}
 | |
| 
 | |
| 	// Latest version should still exist
 | |
| 	latest, err := graph.GetLatestVersion(ctx, address)
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("Failed to get latest version after compaction: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	if latest.Version != 10 {
 | |
| 		t.Errorf("Expected latest version 10 after compaction, got %d", latest.Version)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Performance tests
 | |
| 
 | |
| func BenchmarkTemporalGraph_CreateInitialContext(b *testing.B) {
 | |
| 	storage := newMockStorage()
 | |
| 	graph := NewTemporalGraph(storage)
 | |
| 	ctx := context.Background()
 | |
| 
 | |
| 	b.ResetTimer()
 | |
| 
 | |
| 	for i := 0; i < b.N; i++ {
 | |
| 		address := createTestAddress(fmt.Sprintf("test/component%d", i))
 | |
| 		contextData := createTestContext(fmt.Sprintf("test/component%d", i), []string{"go", "test"})
 | |
| 
 | |
| 		_, err := graph.CreateInitialContext(ctx, address, contextData, "test_creator")
 | |
| 		if err != nil {
 | |
| 			b.Fatalf("Failed to create initial context: %v", err)
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func BenchmarkTemporalGraph_EvolveContext(b *testing.B) {
 | |
| 	storage := newMockStorage()
 | |
| 	graph := NewTemporalGraph(storage)
 | |
| 	ctx := context.Background()
 | |
| 
 | |
| 	// Setup: create initial context
 | |
| 	address := createTestAddress("test/component")
 | |
| 	initialContext := createTestContext("test/component", []string{"go"})
 | |
| 
 | |
| 	_, err := graph.CreateInitialContext(ctx, address, initialContext, "test_creator")
 | |
| 	if err != nil {
 | |
| 		b.Fatalf("Failed to create initial context: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	b.ResetTimer()
 | |
| 
 | |
| 	for i := 0; i < b.N; i++ {
 | |
| 		updatedContext := createTestContext("test/component", []string{"go", fmt.Sprintf("tech%d", i)})
 | |
| 		decision := createTestDecision(fmt.Sprintf("dec-%03d", i), "test_maker", "Update", ImpactLocal)
 | |
| 
 | |
| 		_, err := graph.EvolveContext(ctx, address, updatedContext, ReasonCodeChange, decision)
 | |
| 		if err != nil {
 | |
| 			b.Fatalf("Failed to evolve context: %v", err)
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func BenchmarkTemporalGraph_FindRelatedDecisions(b *testing.B) {
 | |
| 	storage := newMockStorage()
 | |
| 	graph := NewTemporalGraph(storage)
 | |
| 	ctx := context.Background()
 | |
| 
 | |
| 	// Setup: create network of 100 contexts
 | |
| 	addresses := make([]ucxl.Address, 100)
 | |
| 	for i := 0; i < 100; i++ {
 | |
| 		addresses[i] = createTestAddress(fmt.Sprintf("test/component%d", i))
 | |
| 		context := createTestContext(fmt.Sprintf("test/component%d", i), []string{"go"})
 | |
| 
 | |
| 		_, err := graph.CreateInitialContext(ctx, addresses[i], context, "test_creator")
 | |
| 		if err != nil {
 | |
| 			b.Fatalf("Failed to create context %d: %v", i, err)
 | |
| 		}
 | |
| 
 | |
| 		// Add some influence relationships
 | |
| 		if i > 0 {
 | |
| 			err = graph.AddInfluenceRelationship(ctx, addresses[i-1], addresses[i])
 | |
| 			if err != nil {
 | |
| 				b.Fatalf("Failed to add influence relationship: %v", err)
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		// Add some random relationships
 | |
| 		if i > 10 && i%10 == 0 {
 | |
| 			err = graph.AddInfluenceRelationship(ctx, addresses[i-10], addresses[i])
 | |
| 			if err != nil {
 | |
| 				b.Fatalf("Failed to add random influence relationship: %v", err)
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	b.ResetTimer()
 | |
| 
 | |
| 	for i := 0; i < b.N; i++ {
 | |
| 		startIdx := i % 50 // Use first 50 as starting points
 | |
| 		_, err := graph.FindRelatedDecisions(ctx, addresses[startIdx], 5)
 | |
| 		if err != nil {
 | |
| 			b.Fatalf("Failed to find related decisions: %v", err)
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Integration tests
 | |
| 
 | |
| func TestTemporalGraphIntegration_ComplexScenario(t *testing.T) {
 | |
| 	storage := newMockStorage()
 | |
| 	graph := NewTemporalGraph(storage)
 | |
| 	ctx := context.Background()
 | |
| 
 | |
| 	// Scenario: Microservices architecture evolution
 | |
| 	services := []string{"user-service", "order-service", "payment-service", "notification-service"}
 | |
| 	addresses := make([]ucxl.Address, len(services))
 | |
| 
 | |
| 	// Create initial services
 | |
| 	for i, service := range services {
 | |
| 		addresses[i] = createTestAddress(fmt.Sprintf("microservices/%s", service))
 | |
| 		context := createTestContext(fmt.Sprintf("microservices/%s", service), []string{"go", "microservice"})
 | |
| 
 | |
| 		_, err := graph.CreateInitialContext(ctx, addresses[i], context, "architect")
 | |
| 		if err != nil {
 | |
| 			t.Fatalf("Failed to create %s: %v", service, err)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Establish service dependencies
 | |
| 	// user-service -> order-service -> payment-service
 | |
| 	// order-service -> notification-service
 | |
| 	dependencies := [][]int{
 | |
| 		{0, 1}, // user -> order
 | |
| 		{1, 2}, // order -> payment
 | |
| 		{1, 3}, // order -> notification
 | |
| 	}
 | |
| 
 | |
| 	for _, dep := range dependencies {
 | |
| 		err := graph.AddInfluenceRelationship(ctx, addresses[dep[0]], addresses[dep[1]])
 | |
| 		if err != nil {
 | |
| 			t.Fatalf("Failed to add dependency: %v", err)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Evolve payment service (add security features)
 | |
| 	paymentContext := createTestContext("microservices/payment-service", []string{"go", "microservice", "security", "encryption"})
 | |
| 	decision := createTestDecision("sec-001", "security-team", "Add encryption for PCI compliance", ImpactProject)
 | |
| 
 | |
| 	_, err := graph.EvolveContext(ctx, addresses[2], paymentContext, ReasonSecurityReview, decision)
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("Failed to evolve payment service: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	// Evolve order service (performance improvements)
 | |
| 	orderContext := createTestContext("microservices/order-service", []string{"go", "microservice", "caching", "performance"})
 | |
| 	decision2 := createTestDecision("perf-001", "performance-team", "Add Redis caching", ImpactModule)
 | |
| 
 | |
| 	_, err = graph.EvolveContext(ctx, addresses[1], orderContext, ReasonPerformanceInsight, decision2)
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("Failed to evolve order service: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	// Test: Find impact of payment service changes
 | |
| 	relatedPaths, err := graph.FindRelatedDecisions(ctx, addresses[2], 3)
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("Failed to find related decisions: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	// Should find order-service as it depends on payment-service
 | |
| 	foundOrderService := false
 | |
| 	for _, path := range relatedPaths {
 | |
| 		if path.To.String() == addresses[1].String() {
 | |
| 			foundOrderService = true
 | |
| 			break
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if !foundOrderService {
 | |
| 		t.Error("Expected to find order-service in related decisions")
 | |
| 	}
 | |
| 
 | |
| 	// Test: Get evolution history for order service
 | |
| 	history, err := graph.GetEvolutionHistory(ctx, addresses[1])
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("Failed to get order service history: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	if len(history) != 2 {
 | |
| 		t.Errorf("Expected 2 versions in order service history, got %d", len(history))
 | |
| 	}
 | |
| 
 | |
| 	// Test: Validate overall integrity
 | |
| 	err = graph.ValidateTemporalIntegrity(ctx)
 | |
| 	if err != nil {
 | |
| 		t.Errorf("Integrity validation failed: %v", err)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Error handling tests
 | |
| 
 | |
| func TestTemporalGraph_ErrorHandling(t *testing.T) {
 | |
| 	storage := newMockStorage()
 | |
| 	graph := NewTemporalGraph(storage)
 | |
| 	ctx := context.Background()
 | |
| 
 | |
| 	// Test: Get latest version for non-existent address
 | |
| 	nonExistentAddr := createTestAddress("non/existent")
 | |
| 	_, err := graph.GetLatestVersion(ctx, nonExistentAddr)
 | |
| 	if err == nil {
 | |
| 		t.Error("Expected error when getting latest version for non-existent address")
 | |
| 	}
 | |
| 
 | |
| 	// Test: Evolve non-existent context
 | |
| 	context := createTestContext("non/existent", []string{"go"})
 | |
| 	decision := createTestDecision("dec-001", "test", "Test", ImpactLocal)
 | |
| 
 | |
| 	_, err = graph.EvolveContext(ctx, nonExistentAddr, context, ReasonCodeChange, decision)
 | |
| 	if err == nil {
 | |
| 		t.Error("Expected error when evolving non-existent context")
 | |
| 	}
 | |
| 
 | |
| 	// Test: Add influence relationship with non-existent addresses
 | |
| 	addr1 := createTestAddress("test/addr1")
 | |
| 	addr2 := createTestAddress("test/addr2")
 | |
| 
 | |
| 	err = graph.AddInfluenceRelationship(ctx, addr1, addr2)
 | |
| 	if err == nil {
 | |
| 		t.Error("Expected error when adding influence relationship with non-existent addresses")
 | |
| 	}
 | |
| 
 | |
| 	// Test: Find decision path between non-existent addresses
 | |
| 	_, err = graph.FindDecisionPath(ctx, addr1, addr2)
 | |
| 	if err == nil {
 | |
| 		t.Error("Expected error when finding path between non-existent addresses")
 | |
| 	}
 | |
| }
 | 
