nip/tests/test_source_selection.nim

353 lines
11 KiB
Nim

## Unit Tests for Source Selection Strategy
##
## Tests for the source selection logic that chooses the best
## source adapter based on strategy (PreferBinary, PreferSource, Balanced).
import std/[unittest, options, strutils]
import ../src/nip/resolver/source_adapter
import ../src/nip/resolver/frozen_adapter
import ../src/nip/resolver/flexible_adapter
import ../src/nip/resolver/variant_types
suite "Source Selection Strategy Tests":
test "PreferBinary: Chooses frozen when available":
## Test that PreferBinary strategy prefers frozen sources
# Create frozen adapter with package
let frozenAdapter = newFrozenAdapter("nix", priority = 50)
var profile = newVariantProfile()
profile.addFlag("optimization", "lto")
profile.calculateHash()
let frozenMetadata = PackageMetadata(
name: "nginx",
version: "1.24.0",
availableVariants: @[profile],
sourceHash: "nix-store-hash",
buildTime: 0
)
frozenAdapter.addPackage(frozenMetadata)
# Create flexible adapter with same package
let flexibleAdapter = newFlexibleAdapter("gentoo", priority = 30)
let flexibleMetadata = PackageMetadata(
name: "nginx",
version: "1.24.0",
availableVariants: @[profile],
sourceHash: "https://nginx.org/nginx-1.24.0.tar.gz",
buildTime: 300
)
flexibleAdapter.addPackage(flexibleMetadata)
# Create demand
let demand = VariantDemand(
packageName: "nginx",
variantProfile: profile,
optional: false
)
# Select source with PreferBinary strategy
let adapters = @[SourceAdapter(frozenAdapter), SourceAdapter(flexibleAdapter)]
let selection = selectSource(adapters, demand, PreferBinary)
check selection.isSome
check selection.get.adapter.name == "nix"
check selection.get.adapter.class == Frozen
check selection.get.estimatedTime == 0
check "binary" in selection.get.reason.toLowerAscii()
test "PreferBinary: Falls back to flexible when no frozen available":
## Test that PreferBinary falls back to flexible sources
# Create only flexible adapter
let flexibleAdapter = newFlexibleAdapter("gentoo", priority = 30)
var profile = newVariantProfile()
profile.addFlag("optimization", "lto")
profile.calculateHash()
let metadata = PackageMetadata(
name: "nginx",
version: "1.24.0",
availableVariants: @[profile],
sourceHash: "https://nginx.org/nginx-1.24.0.tar.gz",
buildTime: 300
)
flexibleAdapter.addPackage(metadata)
let demand = VariantDemand(
packageName: "nginx",
variantProfile: profile,
optional: false
)
let adapters = @[SourceAdapter(flexibleAdapter)]
let selection = selectSource(adapters, demand, PreferBinary)
check selection.isSome
check selection.get.adapter.name == "gentoo"
check selection.get.adapter.class == Flexible
check selection.get.estimatedTime == 300
check "source" in selection.get.reason.toLowerAscii()
test "PreferSource: Always chooses flexible when available":
## Test that PreferSource strategy prefers flexible sources
# Create both frozen and flexible adapters
let frozenAdapter = newFrozenAdapter("nix", priority = 50)
var profile = newVariantProfile()
profile.addFlag("optimization", "lto")
profile.calculateHash()
let frozenMetadata = PackageMetadata(
name: "nginx",
version: "1.24.0",
availableVariants: @[profile],
sourceHash: "nix-store-hash",
buildTime: 0
)
frozenAdapter.addPackage(frozenMetadata)
let flexibleAdapter = newFlexibleAdapter("gentoo", priority = 30)
let flexibleMetadata = PackageMetadata(
name: "nginx",
version: "1.24.0",
availableVariants: @[profile],
sourceHash: "https://nginx.org/nginx-1.24.0.tar.gz",
buildTime: 300
)
flexibleAdapter.addPackage(flexibleMetadata)
let demand = VariantDemand(
packageName: "nginx",
variantProfile: profile,
optional: false
)
# Select with PreferSource strategy
let adapters = @[SourceAdapter(frozenAdapter), SourceAdapter(flexibleAdapter)]
let selection = selectSource(adapters, demand, PreferSource)
check selection.isSome
check selection.get.adapter.name == "gentoo"
check selection.get.adapter.class == Flexible
check selection.get.estimatedTime == 300
check "source" in selection.get.reason.toLowerAscii()
test "PreferSource: Falls back to frozen when no flexible available":
## Test that PreferSource falls back to frozen sources
# Create only frozen adapter
let frozenAdapter = newFrozenAdapter("nix", priority = 50)
var profile = newVariantProfile()
profile.addFlag("optimization", "lto")
profile.calculateHash()
let metadata = PackageMetadata(
name: "nginx",
version: "1.24.0",
availableVariants: @[profile],
sourceHash: "nix-store-hash",
buildTime: 0
)
frozenAdapter.addPackage(metadata)
let demand = VariantDemand(
packageName: "nginx",
variantProfile: profile,
optional: false
)
let adapters = @[SourceAdapter(frozenAdapter)]
let selection = selectSource(adapters, demand, PreferSource)
check selection.isSome
check selection.get.adapter.name == "nix"
check selection.get.adapter.class == Frozen
check selection.get.estimatedTime == 0
test "Balanced: Considers priority":
## Test that Balanced strategy respects adapter priority
# Create two frozen adapters with different priorities
let highPriorityAdapter = newFrozenAdapter("nix", priority = 100)
let lowPriorityAdapter = newFrozenAdapter("arch", priority = 50)
var profile = newVariantProfile()
profile.addFlag("optimization", "lto")
profile.calculateHash()
let metadata = PackageMetadata(
name: "nginx",
version: "1.24.0",
availableVariants: @[profile],
sourceHash: "hash",
buildTime: 0
)
highPriorityAdapter.addPackage(metadata)
lowPriorityAdapter.addPackage(metadata)
let demand = VariantDemand(
packageName: "nginx",
variantProfile: profile,
optional: false
)
# Select with Balanced strategy
let adapters = @[SourceAdapter(lowPriorityAdapter), SourceAdapter(highPriorityAdapter)]
let selection = selectSource(adapters, demand, Balanced)
check selection.isSome
check selection.get.adapter.name == "nix"
check selection.get.adapter.priority == 100
test "No source available returns None":
## Test that selectSource returns None when no source can satisfy
let frozenAdapter = newFrozenAdapter("nix", priority = 50)
var profile = newVariantProfile()
profile.addFlag("optimization", "lto")
profile.calculateHash()
# Don't add any packages to adapter
let demand = VariantDemand(
packageName: "nonexistent",
variantProfile: profile,
optional: false
)
let adapters = @[SourceAdapter(frozenAdapter)]
let selection = selectSource(adapters, demand, PreferBinary)
check selection.isNone
test "Empty adapter list returns None":
## Test that selectSource handles empty adapter list
var profile = newVariantProfile()
profile.addFlag("optimization", "lto")
profile.calculateHash()
let demand = VariantDemand(
packageName: "nginx",
variantProfile: profile,
optional: false
)
let adapters: seq[SourceAdapter] = @[]
let selection = selectSource(adapters, demand, PreferBinary)
check selection.isNone
test "Multiple adapters with same priority":
## Test behavior when multiple adapters have same priority
let adapter1 = newFrozenAdapter("nix", priority = 50)
let adapter2 = newFrozenAdapter("arch", priority = 50)
var profile = newVariantProfile()
profile.addFlag("optimization", "lto")
profile.calculateHash()
let metadata = PackageMetadata(
name: "nginx",
version: "1.24.0",
availableVariants: @[profile],
sourceHash: "hash",
buildTime: 0
)
adapter1.addPackage(metadata)
adapter2.addPackage(metadata)
let demand = VariantDemand(
packageName: "nginx",
variantProfile: profile,
optional: false
)
# With Balanced strategy, should pick one deterministically
let adapters = @[SourceAdapter(adapter1), SourceAdapter(adapter2)]
let selection = selectSource(adapters, demand, Balanced)
check selection.isSome
# Should pick one of them (deterministic based on order)
check selection.get.adapter.name in ["nix", "arch"]
test "Frozen adapter with wrong variant is skipped":
## Test that frozen adapters with wrong variants are not selected
let frozenAdapter = newFrozenAdapter("nix", priority = 50)
var availableProfile = newVariantProfile()
availableProfile.addFlag("optimization", "lto")
availableProfile.calculateHash()
let metadata = PackageMetadata(
name: "nginx",
version: "1.24.0",
availableVariants: @[availableProfile],
sourceHash: "hash",
buildTime: 0
)
frozenAdapter.addPackage(metadata)
# Request different variant
var demandProfile = newVariantProfile()
demandProfile.addFlag("optimization", "pgo")
demandProfile.calculateHash()
let demand = VariantDemand(
packageName: "nginx",
variantProfile: demandProfile,
optional: false
)
let adapters = @[SourceAdapter(frozenAdapter)]
let selection = selectSource(adapters, demand, PreferBinary)
# Frozen adapter can't satisfy wrong variant
check selection.isNone
test "Flexible adapter accepts any variant":
## Test that flexible adapters can satisfy any variant
let flexibleAdapter = newFlexibleAdapter("gentoo", priority = 30)
var availableProfile = newVariantProfile()
availableProfile.addFlag("optimization", "lto")
availableProfile.calculateHash()
let metadata = PackageMetadata(
name: "nginx",
version: "1.24.0",
availableVariants: @[availableProfile],
sourceHash: "https://nginx.org/nginx-1.24.0.tar.gz",
buildTime: 300
)
flexibleAdapter.addPackage(metadata)
# Request different variant
var demandProfile = newVariantProfile()
demandProfile.addFlag("optimization", "pgo")
demandProfile.addFlag("graphics", "wayland")
demandProfile.calculateHash()
let demand = VariantDemand(
packageName: "nginx",
variantProfile: demandProfile,
optional: false
)
let adapters = @[SourceAdapter(flexibleAdapter)]
let selection = selectSource(adapters, demand, PreferBinary)
# Flexible adapter can satisfy any variant
check selection.isSome
check selection.get.adapter.name == "gentoo"
check selection.get.estimatedTime == 300