## Tests for Resolution Orchestrator ## ## This test suite verifies the orchestrator's ability to coordinate ## all resolver components and provide a unified resolution interface. import unittest import tables import ../src/nip/resolver/orchestrator import ../src/nip/resolver/types import ../src/nip/cas/storage suite "Orchestrator Construction": test "Create with default config": let cas = newCASStorage("/tmp/test-orch-1") let repos: seq[Repository] = @[] let config = defaultConfig() let orch = newResolutionOrchestrator(cas, repos, config) check orch.getConfig().enableCache == true check orch.getConfig().enableParallel == false check orch.getConfig().maxRetries == 3 check orch.getConfig().l1CacheCapacity == 100 test "Create with custom config": let cas = newCASStorage("/tmp/test-orch-2") let repos: seq[Repository] = @[] let config = ResolverConfig( enableCache: false, enableParallel: true, maxRetries: 5, timeout: initDuration(seconds = 600), l1CacheCapacity: 200 ) let orch = newResolutionOrchestrator(cas, repos, config) check orch.getConfig().enableCache == false check orch.getConfig().enableParallel == true check orch.getConfig().maxRetries == 5 check orch.getConfig().l1CacheCapacity == 200 suite "Basic Resolution": test "Resolve simple package": let cas = newCASStorage("/tmp/test-orch-3") let repos: seq[Repository] = @[] let config = defaultConfig() let orch = newResolutionOrchestrator(cas, repos, config) let result = orch.resolve( "test-pkg", "*", VariantDemand( useFlags: @[], libc: "musl", allocator: "jemalloc", targetArch: "x86_64", buildFlags: @[] ) ) check result.isOk check result.get.cacheHit == false check result.get.resolutionTime >= 0.0 test "Resolve with version constraint": let cas = newCASStorage("/tmp/test-orch-4") let repos: seq[Repository] = @[] let config = defaultConfig() let orch = newResolutionOrchestrator(cas, repos, config) let result = orch.resolve( "nginx", ">=1.24.0", VariantDemand( useFlags: @["ssl", "http2"], libc: "musl", allocator: "jemalloc", targetArch: "x86_64", buildFlags: @[] ) ) check result.isOk test "Resolve with USE flags": let cas = newCASStorage("/tmp/test-orch-5") let repos: seq[Repository] = @[] let config = defaultConfig() let orch = newResolutionOrchestrator(cas, repos, config) let result = orch.resolve( "firefox", "*", VariantDemand( useFlags: @["wayland", "pulseaudio", "alsa"], libc: "glibc", allocator: "default", targetArch: "x86_64", buildFlags: @["-O3", "-march=native"] ) ) check result.isOk suite "Caching Behavior": test "Cache miss on first resolution": let cas = newCASStorage("/tmp/test-orch-6") let repos: seq[Repository] = @[] let config = defaultConfig() let orch = newResolutionOrchestrator(cas, repos, config) let result = orch.resolve( "test-pkg", "*", VariantDemand( useFlags: @[], libc: "musl", allocator: "jemalloc", targetArch: "x86_64", buildFlags: @[] ) ) check result.isOk check result.get.cacheHit == false let metrics = orch.getMetrics() check metrics.cacheMisses == 1 check metrics.cacheHits == 0 test "Cache hit on second resolution": let cas = newCASStorage("/tmp/test-orch-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: @[] ) # First resolution let result1 = orch.resolve("test-pkg", "*", demand) check result1.isOk check result1.get.cacheHit == false # Second resolution (should hit cache) let result2 = orch.resolve("test-pkg", "*", demand) check result2.isOk check result2.get.cacheHit == true let metrics = orch.getMetrics() check metrics.cacheHits == 1 check metrics.cacheMisses == 1 test "Different variants produce different cache keys": let cas = newCASStorage("/tmp/test-orch-8") let repos: seq[Repository] = @[] let config = defaultConfig() let orch = newResolutionOrchestrator(cas, repos, config) let demand1 = VariantDemand( useFlags: @["ssl"], libc: "musl", allocator: "jemalloc", targetArch: "x86_64", buildFlags: @[] ) let demand2 = VariantDemand( useFlags: @["ssl", "http2"], # Different USE flags libc: "musl", allocator: "jemalloc", targetArch: "x86_64", buildFlags: @[] ) # Resolve with first variant let result1 = orch.resolve("nginx", "*", demand1) check result1.isOk check result1.get.cacheHit == false # Resolve with second variant (different cache key) let result2 = orch.resolve("nginx", "*", demand2) check result2.isOk check result2.get.cacheHit == false let metrics = orch.getMetrics() check metrics.cacheMisses == 2 check metrics.cacheHits == 0 test "Disabled cache always misses": let cas = newCASStorage("/tmp/test-orch-9") let repos: seq[Repository] = @[] let config = ResolverConfig( enableCache: false, enableParallel: false, maxRetries: 3, timeout: initDuration(seconds = 300), l1CacheCapacity: 100 ) let orch = newResolutionOrchestrator(cas, repos, 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 disabled, should still miss) let result2 = orch.resolve("test-pkg", "*", demand) check result2.isOk check result2.get.cacheHit == false suite "Metrics Tracking": test "Track total resolutions": let cas = newCASStorage("/tmp/test-orch-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: @[] ) for i in 0..<5: discard orch.resolve(fmt"pkg-{i}", "*", demand) let metrics = orch.getMetrics() check metrics.totalResolutions == 5 check metrics.successfulResolutions == 5 test "Track cache hit rate": let cas = newCASStorage("/tmp/test-orch-11") 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 (miss) discard orch.resolve("test-pkg", "*", demand) # Three more resolutions (hits) for i in 0..<3: discard orch.resolve("test-pkg", "*", demand) let metrics = orch.getMetrics() check metrics.totalResolutions == 4 check metrics.cacheHits == 3 check metrics.cacheMisses == 1 test "Reset metrics": let cas = newCASStorage("/tmp/test-orch-12") 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..<3: discard orch.resolve(fmt"pkg-{i}", "*", demand) check orch.getMetrics().totalResolutions == 3 # Reset metrics orch.resetMetrics() check orch.getMetrics().totalResolutions == 0 check orch.getMetrics().cacheHits == 0 check orch.getMetrics().cacheMisses == 0 suite "Configuration Management": test "Update configuration": let cas = newCASStorage("/tmp/test-orch-13") let repos: seq[Repository] = @[] let config = defaultConfig() let orch = newResolutionOrchestrator(cas, repos, config) check orch.getConfig().enableCache == true var newConfig = config newConfig.enableCache = false orch.updateConfig(newConfig) check orch.getConfig().enableCache == false test "Configuration affects behavior": let cas = newCASStorage("/tmp/test-orch-14") 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 with cache enabled let result1 = orch.resolve("test-pkg", "*", demand) check result1.isOk let result2 = orch.resolve("test-pkg", "*", demand) check result2.get.cacheHit == true # Disable cache var newConfig = orch.getConfig() newConfig.enableCache = false orch.updateConfig(newConfig) # Resolve with cache disabled let result3 = orch.resolve("test-pkg", "*", demand) check result3.get.cacheHit == false suite "Cache Management": test "Clear cache": let cas = newCASStorage("/tmp/test-orch-15") 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 discard orch.resolve("test-pkg", "*", demand) # Verify cache hit let result1 = orch.resolve("test-pkg", "*", demand) check result1.get.cacheHit == true # Clear cache orch.clearCache() # Verify cache miss let result2 = orch.resolve("test-pkg", "*", demand) check result2.get.cacheHit == false test "Get cache metrics": let cas = newCASStorage("/tmp/test-orch-16") let repos: seq[Repository] = @[] let config = defaultConfig() let orch = newResolutionOrchestrator(cas, repos, config) let cacheMetrics = orch.getCacheMetrics() check cacheMetrics.l1Size == 0 check cacheMetrics.l1Capacity == 100 suite "Repository Management": test "Update repositories": let cas = newCASStorage("/tmp/test-orch-17") let repos: seq[Repository] = @[] let config = defaultConfig() let orch = newResolutionOrchestrator(cas, repos, config) check orch.getRepositories().len == 0 let newRepos = @[ Repository( name: "main", packages: @[] ) ] orch.updateRepositories(newRepos) check orch.getRepositories().len == 1 check orch.getRepositories()[0].name == "main" test "Repository update invalidates cache": let cas = newCASStorage("/tmp/test-orch-18") 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 discard orch.resolve("test-pkg", "*", demand) # Verify cache hit let result1 = orch.resolve("test-pkg", "*", demand) check result1.get.cacheHit == true # Update repositories (should invalidate cache) let newRepos = @[ Repository( name: "main", packages: @[] ) ] orch.updateRepositories(newRepos) # Verify cache miss (invalidated) let result2 = orch.resolve("test-pkg", "*", demand) check result2.get.cacheHit == false