nip/tests/test_end_to_end.nim

402 lines
11 KiB
Nim

## 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