## End-to-End Integration Tests ## ## This test suite validates the complete dependency resolution workflow ## from CLI input to final resolution result, testing all components ## working together. import unittest import tables import ../src/nip/resolver/orchestrator import ../src/nip/resolver/types import ../src/nip/cas/storage suite "End-to-End Resolution Workflow": test "Complete resolution workflow": # Setup let cas = newCASStorage("/tmp/test-e2e-1") let repos: seq[Repository] = @[] let config = defaultConfig() let orch = newResolutionOrchestrator(cas, repos, config) # Create variant demand let demand = VariantDemand( useFlags: @["ssl", "http2"], libc: "musl", allocator: "jemalloc", targetArch: "x86_64", buildFlags: @["-O2", "-march=native"] ) # Resolve dependencies let result = orch.resolve("nginx", ">=1.24.0", demand) # Verify success check result.isOk let resolution = result.get check resolution.resolutionTime >= 0.0 check resolution.cacheHit == false # First resolution # Verify metrics updated let metrics = orch.getMetrics() check metrics.totalResolutions == 1 check metrics.successfulResolutions == 1 check metrics.cacheMisses == 1 test "Cache hit on repeated resolution": # Setup let cas = newCASStorage("/tmp/test-e2e-2") let repos: seq[Repository] = @[] let config = defaultConfig() let orch = newResolutionOrchestrator(cas, repos, config) let demand = VariantDemand( useFlags: @[], libc: "musl", allocator: "jemalloc", targetArch: "x86_64", buildFlags: @[] ) # First resolution (cache miss) let result1 = orch.resolve("test-pkg", "*", demand) check result1.isOk check result1.get.cacheHit == false # Second resolution (cache hit) let result2 = orch.resolve("test-pkg", "*", demand) check result2.isOk check result2.get.cacheHit == true # Verify cache speedup check result2.get.resolutionTime < result1.get.resolutionTime # Verify metrics let metrics = orch.getMetrics() check metrics.totalResolutions == 2 check metrics.cacheHits == 1 check metrics.cacheMisses == 1 test "Different variants produce different resolutions": # Setup let cas = newCASStorage("/tmp/test-e2e-3") let repos: seq[Repository] = @[] let config = defaultConfig() let orch = newResolutionOrchestrator(cas, repos, config) # Resolve with first variant let demand1 = VariantDemand( useFlags: @["ssl"], libc: "musl", allocator: "jemalloc", targetArch: "x86_64", buildFlags: @[] ) let result1 = orch.resolve("nginx", "*", demand1) check result1.isOk # Resolve with second variant let demand2 = VariantDemand( useFlags: @["ssl", "http2"], # Different USE flags libc: "musl", allocator: "jemalloc", targetArch: "x86_64", buildFlags: @[] ) let result2 = orch.resolve("nginx", "*", demand2) check result2.isOk # Both should be cache misses (different variants) check result1.get.cacheHit == false check result2.get.cacheHit == false # Verify metrics let metrics = orch.getMetrics() check metrics.cacheMisses == 2 check metrics.cacheHits == 0 suite "Cache Invalidation Workflow": test "Repository update invalidates cache": # Setup let cas = newCASStorage("/tmp/test-e2e-4") let repos1: seq[Repository] = @[] let config = defaultConfig() let orch = newResolutionOrchestrator(cas, repos1, config) let demand = VariantDemand( useFlags: @[], libc: "musl", allocator: "jemalloc", targetArch: "x86_64", buildFlags: @[] ) # First resolution let result1 = orch.resolve("test-pkg", "*", demand) check result1.isOk check result1.get.cacheHit == false # Second resolution (cache hit) let result2 = orch.resolve("test-pkg", "*", demand) check result2.isOk check result2.get.cacheHit == true # Update repositories (simulates metadata change) let repos2 = @[ Repository( name: "main", packages: @[] ) ] orch.updateRepositories(repos2) # Third resolution (cache miss due to invalidation) let result3 = orch.resolve("test-pkg", "*", demand) check result3.isOk check result3.get.cacheHit == false # Verify metrics let metrics = orch.getMetrics() check metrics.totalResolutions == 3 check metrics.cacheHits == 1 check metrics.cacheMisses == 2 suite "Configuration Management Workflow": test "Disable cache affects behavior": # Setup with cache enabled let cas = newCASStorage("/tmp/test-e2e-5") let repos: seq[Repository] = @[] var config = defaultConfig() config.enableCache = true let orch = newResolutionOrchestrator(cas, repos, config) let demand = VariantDemand( useFlags: @[], libc: "musl", allocator: "jemalloc", targetArch: "x86_64", buildFlags: @[] ) # First resolution (cache miss) let result1 = orch.resolve("test-pkg", "*", demand) check result1.isOk check result1.get.cacheHit == false # Second resolution (cache hit) let result2 = orch.resolve("test-pkg", "*", demand) check result2.isOk check result2.get.cacheHit == true # Disable cache config.enableCache = false orch.updateConfig(config) # Third resolution (cache disabled, always miss) let result3 = orch.resolve("test-pkg", "*", demand) check result3.isOk check result3.get.cacheHit == false test "Clear cache resets state": # Setup let cas = newCASStorage("/tmp/test-e2e-6") let repos: seq[Repository] = @[] let config = defaultConfig() let orch = newResolutionOrchestrator(cas, repos, config) let demand = VariantDemand( useFlags: @[], libc: "musl", allocator: "jemalloc", targetArch: "x86_64", buildFlags: @[] ) # Populate cache let result1 = orch.resolve("test-pkg", "*", demand) check result1.isOk # Verify cache hit let result2 = orch.resolve("test-pkg", "*", demand) check result2.get.cacheHit == true # Clear cache orch.clearCache() # Verify cache miss let result3 = orch.resolve("test-pkg", "*", demand) check result3.get.cacheHit == false suite "Metrics Tracking Workflow": test "Metrics track complete workflow": # Setup let cas = newCASStorage("/tmp/test-e2e-7") let repos: seq[Repository] = @[] let config = defaultConfig() let orch = newResolutionOrchestrator(cas, repos, config) let demand = VariantDemand( useFlags: @[], libc: "musl", allocator: "jemalloc", targetArch: "x86_64", buildFlags: @[] ) # Initial metrics var metrics = orch.getMetrics() check metrics.totalResolutions == 0 check metrics.cacheHits == 0 check metrics.cacheMisses == 0 # First resolution discard orch.resolve("pkg1", "*", demand) metrics = orch.getMetrics() check metrics.totalResolutions == 1 check metrics.cacheMisses == 1 # Second resolution (same package, cache hit) discard orch.resolve("pkg1", "*", demand) metrics = orch.getMetrics() check metrics.totalResolutions == 2 check metrics.cacheHits == 1 # Third resolution (different package, cache miss) discard orch.resolve("pkg2", "*", demand) metrics = orch.getMetrics() check metrics.totalResolutions == 3 check metrics.cacheMisses == 2 # Verify final state check metrics.successfulResolutions == 3 check metrics.failedResolutions == 0 test "Reset metrics clears counters": # Setup let cas = newCASStorage("/tmp/test-e2e-8") let repos: seq[Repository] = @[] let config = defaultConfig() let orch = newResolutionOrchestrator(cas, repos, config) let demand = VariantDemand( useFlags: @[], libc: "musl", allocator: "jemalloc", targetArch: "x86_64", buildFlags: @[] ) # Do some resolutions for i in 0..<5: discard orch.resolve(fmt"pkg-{i}", "*", demand) # Verify metrics var metrics = orch.getMetrics() check metrics.totalResolutions == 5 # Reset metrics orch.resetMetrics() # Verify reset metrics = orch.getMetrics() check metrics.totalResolutions == 0 check metrics.cacheHits == 0 check metrics.cacheMisses == 0 suite "Performance Characteristics": test "Cache provides speedup": # Setup let cas = newCASStorage("/tmp/test-e2e-9") let repos: seq[Repository] = @[] let config = defaultConfig() let orch = newResolutionOrchestrator(cas, repos, config) let demand = VariantDemand( useFlags: @[], libc: "musl", allocator: "jemalloc", targetArch: "x86_64", buildFlags: @[] ) # First resolution (cold cache) let result1 = orch.resolve("test-pkg", "*", demand) check result1.isOk let coldTime = result1.get.resolutionTime # Second resolution (warm cache) let result2 = orch.resolve("test-pkg", "*", demand) check result2.isOk let warmTime = result2.get.resolutionTime # Verify speedup check warmTime < coldTime let speedup = coldTime / warmTime echo fmt" Cache speedup: {speedup:.2f}x" echo fmt" Cold: {coldTime * 1000:.2f}ms, Warm: {warmTime * 1000:.2f}ms" test "Multiple resolutions maintain performance": # Setup let cas = newCASStorage("/tmp/test-e2e-10") let repos: seq[Repository] = @[] let config = defaultConfig() let orch = newResolutionOrchestrator(cas, repos, config) let demand = VariantDemand( useFlags: @[], libc: "musl", allocator: "jemalloc", targetArch: "x86_64", buildFlags: @[] ) # Resolve multiple packages var totalTime = 0.0 for i in 0..<10: let result = orch.resolve(fmt"pkg-{i}", "*", demand) check result.isOk totalTime += result.get.resolutionTime let avgTime = totalTime / 10.0 echo fmt" Average resolution time: {avgTime * 1000:.2f}ms" # Verify reasonable performance check avgTime < 1.0 # Should be < 1 second per resolution suite "Integration with Components": test "Orchestrator integrates all components": # This test verifies that the orchestrator properly coordinates # all resolver components in the correct order let cas = newCASStorage("/tmp/test-e2e-11") let repos: seq[Repository] = @[] let config = defaultConfig() let orch = newResolutionOrchestrator(cas, repos, config) let demand = VariantDemand( useFlags: @["ssl", "http2"], libc: "musl", allocator: "jemalloc", targetArch: "x86_64", buildFlags: @["-O2"] ) # Resolve let result = orch.resolve("nginx", ">=1.24.0", demand) # Verify all components were invoked check result.isOk # Verify resolution result structure let resolution = result.get check resolution.graph.rootPackage.name == "nginx" check resolution.installOrder.len >= 0 check resolution.resolutionTime >= 0.0 # Verify cache was used let cacheMetrics = orch.getCacheMetrics() check cacheMetrics.l1Capacity == 100