288 lines
9.0 KiB
Nim
288 lines
9.0 KiB
Nim
## test_build_coordinator.nim
|
|
## Unit tests for BuildCoordinator
|
|
|
|
import std/[unittest, tables, times, os, options]
|
|
import ../src/nimpak/build/[types, coordinator, adapter]
|
|
import ../src/nimpak/graft_coordinator
|
|
import ../src/nimpak/install_manager
|
|
import ../src/nimpak/variants
|
|
|
|
# Mock adapter for testing
|
|
type
|
|
MockAdapter = ref object of BuildAdapter
|
|
shouldFail: bool
|
|
searchResult: bool
|
|
|
|
proc newMockAdapter(name: string, available: bool = true): MockAdapter =
|
|
result = MockAdapter(
|
|
name: name,
|
|
available: available,
|
|
packageCount: 100,
|
|
shouldFail: false,
|
|
searchResult: true
|
|
)
|
|
|
|
method isAvailable*(adapter: MockAdapter): bool =
|
|
adapter.available
|
|
|
|
method searchPackage*(
|
|
adapter: MockAdapter,
|
|
packageName: string
|
|
): Option[PackageInfo] =
|
|
if adapter.searchResult:
|
|
return some(PackageInfo(
|
|
name: packageName,
|
|
version: "1.0.0",
|
|
description: "Mock package",
|
|
source: adapter.name,
|
|
category: "",
|
|
available: true
|
|
))
|
|
return none(PackageInfo)
|
|
|
|
method buildPackage*(
|
|
adapter: MockAdapter,
|
|
request: BuildRequest
|
|
): BuildResult =
|
|
result = BuildResult(
|
|
success: not adapter.shouldFail,
|
|
source: adapter.name,
|
|
packageName: request.packageName,
|
|
version: "1.0.0",
|
|
artifactPath: if not adapter.shouldFail: "/mock/path" else: "",
|
|
buildLog: "Mock build log",
|
|
variantFingerprint: "mock-fingerprint",
|
|
variantDomains: request.variantFlags,
|
|
errors: if adapter.shouldFail: @["Mock build error"] else: @[],
|
|
warnings: @[],
|
|
buildTime: initDuration(seconds = 1)
|
|
)
|
|
|
|
suite "BuildCoordinator Tests":
|
|
|
|
setup:
|
|
let buildConfig = BuildConfig(
|
|
cacheDir: getTempDir() / "nip-test-cache",
|
|
buildLogsDir: getTempDir() / "nip-test-cache" / "logs",
|
|
keepWork: false,
|
|
rebuild: false,
|
|
noInstall: false,
|
|
timeout: initDuration(hours = 2),
|
|
jobs: 4,
|
|
verbose: false
|
|
)
|
|
|
|
# Create a minimal graft coordinator for testing
|
|
let installConfig = InstallConfig(
|
|
programsDir: getTempDir() / "Programs",
|
|
linksDir: getTempDir() / "System" / "Links",
|
|
cacheDir: getTempDir() / "nip-test-cache",
|
|
dbFile: getTempDir() / "nip-test.db",
|
|
autoSymlink: true,
|
|
checkConflicts: true,
|
|
verbose: false
|
|
)
|
|
let graftCoordinator = newGraftCoordinator(installConfig, false)
|
|
|
|
let coordinator = newBuildCoordinator(buildConfig, graftCoordinator)
|
|
|
|
test "BuildCoordinator initialization":
|
|
check coordinator != nil
|
|
check coordinator.config.cacheDir == getTempDir() / "nip-test-cache"
|
|
check coordinator.adapters.len == 0
|
|
check coordinator.verbose == false
|
|
|
|
test "Adapter registration":
|
|
let mockAdapter = newMockAdapter("mock")
|
|
coordinator.registerAdapter(mockAdapter)
|
|
|
|
check coordinator.adapters.len == 1
|
|
check coordinator.adapters.hasKey("mock")
|
|
|
|
test "Get adapter by name":
|
|
let mockAdapter = newMockAdapter("test-adapter")
|
|
coordinator.registerAdapter(mockAdapter)
|
|
|
|
let retrieved = coordinator.getAdapter("test-adapter")
|
|
check retrieved.isSome
|
|
check retrieved.get().name == "test-adapter"
|
|
|
|
test "Get non-existent adapter":
|
|
let retrieved = coordinator.getAdapter("non-existent")
|
|
check retrieved.isNone
|
|
|
|
test "Adapter name case insensitivity":
|
|
let mockAdapter = newMockAdapter("TestAdapter")
|
|
coordinator.registerAdapter(mockAdapter)
|
|
|
|
let retrieved1 = coordinator.getAdapter("testadapter")
|
|
let retrieved2 = coordinator.getAdapter("TESTADAPTER")
|
|
let retrieved3 = coordinator.getAdapter("TestAdapter")
|
|
|
|
check retrieved1.isSome
|
|
check retrieved2.isSome
|
|
check retrieved3.isSome
|
|
|
|
test "Source detection - Nix available":
|
|
if dirExists("/nix"):
|
|
let sources = coordinator.detectSources()
|
|
check "nix" in sources
|
|
|
|
test "Source detection - PKGSRC available":
|
|
if dirExists("/usr/pkgsrc"):
|
|
let sources = coordinator.detectSources()
|
|
check "pkgsrc" in sources
|
|
|
|
test "Source detection - Gentoo available":
|
|
if fileExists("/usr/bin/emerge"):
|
|
let sources = coordinator.detectSources()
|
|
check "gentoo" in sources
|
|
|
|
test "Source selection - auto with priority":
|
|
let nixAdapter = newMockAdapter("nix", available = true)
|
|
let pkgsrcAdapter = newMockAdapter("pkgsrc", available = true)
|
|
let gentooAdapter = newMockAdapter("gentoo", available = true)
|
|
|
|
coordinator.registerAdapter(nixAdapter)
|
|
coordinator.registerAdapter(pkgsrcAdapter)
|
|
coordinator.registerAdapter(gentooAdapter)
|
|
|
|
# Mock the detection to return all sources
|
|
if dirExists("/nix"):
|
|
let selected = coordinator.selectSource("auto")
|
|
check selected.isSome
|
|
check selected.get() == "nix" # Nix has highest priority
|
|
|
|
test "Source selection - specific source":
|
|
let mockAdapter = newMockAdapter("mock", available = true)
|
|
coordinator.registerAdapter(mockAdapter)
|
|
|
|
let selected = coordinator.selectSource("mock")
|
|
check selected.isSome
|
|
check selected.get() == "mock"
|
|
|
|
test "Source selection - unavailable source":
|
|
let mockAdapter = newMockAdapter("mock", available = false)
|
|
coordinator.registerAdapter(mockAdapter)
|
|
|
|
let selected = coordinator.selectSource("mock")
|
|
check selected.isNone
|
|
|
|
test "Source selection - no sources available":
|
|
# Don't register any adapters
|
|
let selected = coordinator.selectSource("auto")
|
|
# Result depends on actual system state
|
|
discard selected
|
|
|
|
test "Build package - successful build":
|
|
let mockAdapter = newMockAdapter("mock", available = true)
|
|
coordinator.registerAdapter(mockAdapter)
|
|
|
|
let variantFlags = @[
|
|
VariantFlag(domain: "graphics", value: "wayland"),
|
|
VariantFlag(domain: "optimization", value: "lto")
|
|
]
|
|
|
|
let result = coordinator.buildPackage("test-package", variantFlags, "mock")
|
|
|
|
check result.success == true
|
|
check result.packageName == "test-package"
|
|
check result.source == "mock"
|
|
check result.artifactPath == "/mock/path"
|
|
check result.errors.len == 0
|
|
|
|
test "Build package - failed build":
|
|
let mockAdapter = newMockAdapter("mock", available = true)
|
|
mockAdapter.shouldFail = true
|
|
coordinator.registerAdapter(mockAdapter)
|
|
|
|
let variantFlags: seq[VariantFlag] = @[]
|
|
let result = coordinator.buildPackage("test-package", variantFlags, "mock")
|
|
|
|
check result.success == false
|
|
check result.errors.len > 0
|
|
check "Mock build error" in result.errors
|
|
|
|
test "Build package - no suitable source":
|
|
let variantFlags: seq[VariantFlag] = @[]
|
|
let result = coordinator.buildPackage("test-package", variantFlags, "non-existent")
|
|
|
|
check result.success == false
|
|
check result.errors.len > 0
|
|
|
|
test "Build package - variant flags conversion":
|
|
let mockAdapter = newMockAdapter("mock", available = true)
|
|
coordinator.registerAdapter(mockAdapter)
|
|
|
|
let variantFlags = @[
|
|
VariantFlag(domain: "graphics", value: "wayland"),
|
|
VariantFlag(domain: "graphics", value: "vulkan"),
|
|
VariantFlag(domain: "audio", value: "pipewire")
|
|
]
|
|
|
|
let result = coordinator.buildPackage("test-package", variantFlags, "mock")
|
|
|
|
check result.success == true
|
|
check result.variantDomains.hasKey("graphics")
|
|
check result.variantDomains["graphics"].len == 2
|
|
check result.variantDomains.hasKey("audio")
|
|
check result.variantDomains["audio"].len == 1
|
|
|
|
test "Install build artifact - successful":
|
|
let mockResult = BuildResult(
|
|
success: true,
|
|
source: "mock",
|
|
packageName: "test-package",
|
|
version: "1.0.0",
|
|
artifactPath: "/mock/path",
|
|
buildLog: "",
|
|
variantFingerprint: "test-fingerprint",
|
|
variantDomains: initTable[string, seq[string]](),
|
|
errors: @[],
|
|
warnings: @[],
|
|
buildTime: initDuration(seconds = 1)
|
|
)
|
|
|
|
let installed = coordinator.installBuildArtifact(mockResult)
|
|
# Will fail because mock path doesn't exist, but that's expected
|
|
# The important thing is it returns a tuple with the right structure
|
|
check installed.errors.len >= 0 # Just check structure is correct
|
|
|
|
test "Install build artifact - failed build":
|
|
let mockResult = BuildResult(
|
|
success: false,
|
|
source: "mock",
|
|
packageName: "test-package",
|
|
version: "1.0.0",
|
|
artifactPath: "",
|
|
buildLog: "",
|
|
variantFingerprint: "",
|
|
variantDomains: initTable[string, seq[string]](),
|
|
errors: @["Build failed"],
|
|
warnings: @[],
|
|
buildTime: initDuration(seconds = 1)
|
|
)
|
|
|
|
let installed = coordinator.installBuildArtifact(mockResult)
|
|
check installed.success == false
|
|
|
|
test "Install build artifact - no install flag":
|
|
coordinator.config.noInstall = true
|
|
|
|
let mockResult = BuildResult(
|
|
success: true,
|
|
source: "mock",
|
|
packageName: "test-package",
|
|
version: "1.0.0",
|
|
artifactPath: "/mock/path",
|
|
buildLog: "",
|
|
variantFingerprint: "test-fingerprint",
|
|
variantDomains: initTable[string, seq[string]](),
|
|
errors: @[],
|
|
warnings: @[],
|
|
buildTime: initDuration(seconds = 1)
|
|
)
|
|
|
|
let installed = coordinator.installBuildArtifact(mockResult)
|
|
check installed.success == true # Returns true but skips installation
|