## NEXTER Container Startup Tests ## ## Tests for container startup and lifecycle management. ## Verifies configuration validation, process setup, and execution. import std/[unittest, os, tempfiles, options, strutils, times, tables] import nip/container_startup import nip/nexter_manifest import nip/manifest_parser # Helper to create a test manifest proc createTestManifest(name: string, version: string): NEXTERManifest = let buildDate = parse("2025-11-28T12:00:00Z", "yyyy-MM-dd'T'HH:mm:ss'Z'") return NEXTERManifest( name: name, version: parseSemanticVersion(version), buildDate: buildDate, metadata: ContainerInfo( description: "Test container", license: "MIT" ), provenance: ProvenanceInfo( source: "https://example.com/source.tar.gz", sourceHash: "xxh3-source-hash", buildTimestamp: buildDate ), buildConfig: BuildConfiguration( configureFlags: @[], compilerFlags: @[], compilerVersion: "gcc-13", targetArchitecture: "x86_64", libc: "musl", allocator: "jemalloc", buildSystem: "custom" ), base: BaseConfig( baseImage: some("alpine"), baseVersion: some("3.18") ), environment: initTable[string, string](), casChunks: @[], namespace: ContainerNamespace( isolationType: "full", capabilities: @[], mounts: @[], devices: @[] ), startup: StartupConfig( command: @["/bin/sh"], workingDir: "/", user: none(string), entrypoint: none(string) ), buildHash: "xxh3-build-hash", signature: SignatureInfo( algorithm: "ed25519", keyId: "test-key", signature: "test-sig" ) ) suite "Container Startup Configuration Tests": test "Create startup config from manifest": ## Verify startup config can be created from manifest let manifest = createTestManifest("startup-test", "1.0.0") let config = createStartupConfig(manifest) check config.command.len > 0 check config.workingDir == "/" check config.user.isNone test "Startup config with custom command": ## Verify custom command is preserved let manifest = createTestManifest("cmd-test", "1.0.0") var cmdManifest = manifest cmdManifest.startup.command = @["/bin/bash", "-c", "echo hello"] let config = createStartupConfig(cmdManifest) check config.command.len == 3 check config.command[0] == "/bin/bash" check config.command[1] == "-c" check config.command[2] == "echo hello" test "Startup config with working directory": ## Verify working directory is preserved let manifest = createTestManifest("workdir-test", "1.0.0") var workdirManifest = manifest workdirManifest.startup.workingDir = "/app" let config = createStartupConfig(workdirManifest) check config.workingDir == "/app" test "Startup config with user": ## Verify user is preserved let manifest = createTestManifest("user-test", "1.0.0") var userManifest = manifest userManifest.startup.user = some("appuser") let config = createStartupConfig(userManifest) check config.user.isSome check config.user.get() == "appuser" test "Startup config with entrypoint": ## Verify entrypoint is preserved let manifest = createTestManifest("entry-test", "1.0.0") var entryManifest = manifest entryManifest.startup.entrypoint = some("/app/entrypoint.sh") let config = createStartupConfig(entryManifest) check config.entrypoint.isSome check config.entrypoint.get() == "/app/entrypoint.sh" test "Startup config with environment": ## Verify environment variables are preserved let manifest = createTestManifest("env-test", "1.0.0") var envManifest = manifest envManifest.environment["APP_ENV"] = "production" envManifest.environment["DEBUG"] = "false" let config = createStartupConfig(envManifest) check config.environment["APP_ENV"] == "production" check config.environment["DEBUG"] == "false" suite "Container Startup Validation Tests": test "Validate valid startup config": ## Verify valid config passes validation let config = ContainerStartupConfig( command: @["/bin/sh"], workingDir: "/", user: none(string), entrypoint: none(string), environment: initTable[string, string]() ) check validateStartupConfig(config) test "Validate fails for empty command": ## Verify validation fails for empty command let config = ContainerStartupConfig( command: @[], workingDir: "/", user: none(string), entrypoint: none(string), environment: initTable[string, string]() ) check not validateStartupConfig(config) test "Validate fails for empty user": ## Verify validation fails for empty user let config = ContainerStartupConfig( command: @["/bin/sh"], workingDir: "/", user: some(""), entrypoint: none(string), environment: initTable[string, string]() ) check not validateStartupConfig(config) test "Validate fails for empty entrypoint": ## Verify validation fails for empty entrypoint let config = ContainerStartupConfig( command: @["/bin/sh"], workingDir: "/", user: none(string), entrypoint: some(""), environment: initTable[string, string]() ) check not validateStartupConfig(config) suite "Container Process Tests": test "Start container with valid config": ## Verify container can be started let config = ContainerStartupConfig( command: @["/bin/echo", "hello"], workingDir: "/", user: none(string), entrypoint: none(string), environment: initTable[string, string]() ) let process = startContainer(config) # Process should be created (or fail gracefully) check process.startTime <= now() test "Start container with invalid config": ## Verify container startup fails gracefully for invalid config let config = ContainerStartupConfig( command: @[], workingDir: "/", user: none(string), entrypoint: none(string), environment: initTable[string, string]() ) let process = startContainer(config) check process.status == Failed check process.pid == -1 test "Get container logs": ## Verify logs can be retrieved let process = ContainerProcess( pid: 1234, startTime: now(), status: Running, exitCode: none[int](), output: "stdout output", error: "stderr output" ) let logs = getContainerLogs(process) check "stdout output" in logs check "stderr output" in logs test "Get container status": ## Verify status can be retrieved let process = ContainerProcess( pid: 1234, startTime: now(), status: Running, exitCode: none[int](), output: "", error: "" ) let status = getContainerStatus(process) check status == Running test "Format startup config": ## Verify startup config formatting let config = ContainerStartupConfig( command: @["/bin/sh"], workingDir: "/app", user: some("appuser"), entrypoint: some("/app/start.sh"), environment: initTable[string, string]() ) let formatted = $config check "Container Startup Config" in formatted check "/bin/sh" in formatted check "/app" in formatted check "appuser" in formatted test "Format container process": ## Verify container process formatting let process = ContainerProcess( pid: 1234, startTime: now(), status: Running, exitCode: none[int](), output: "", error: "" ) let formatted = $process check "Container Process" in formatted check "1234" in formatted check "Running" in formatted suite "Container Startup Property Tests": test "Property: Config preserves all manifest startup settings": ## Verify all startup settings are preserved let manifest = createTestManifest("prop-startup", "1.0.0") var testManifest = manifest testManifest.startup.command = @["/bin/bash", "-c", "test"] testManifest.startup.workingDir = "/test" testManifest.startup.user = some("testuser") testManifest.startup.entrypoint = some("/test/entry.sh") let config = createStartupConfig(testManifest) check config.command == @["/bin/bash", "-c", "test"] check config.workingDir == "/test" check config.user.get() == "testuser" check config.entrypoint.get() == "/test/entry.sh" test "Property: Process has valid start time": ## Verify process start time is set correctly let beforeStart = now() let config = ContainerStartupConfig( command: @["/bin/echo"], workingDir: "/", user: none(string), entrypoint: none(string), environment: initTable[string, string]() ) let process = startContainer(config) let afterStart = now() check process.startTime >= beforeStart check process.startTime <= afterStart test "Property: Failed process has negative PID": ## Verify failed processes have negative PID let config = ContainerStartupConfig( command: @[], workingDir: "/", user: none(string), entrypoint: none(string), environment: initTable[string, string]() ) let process = startContainer(config) if process.status == Failed: check process.pid < 0 test "Property: Valid config always validates": ## Verify valid configs always pass validation for i in 1..10: let config = ContainerStartupConfig( command: @["/bin/sh", "-c", "echo test-" & $i], workingDir: "/", user: none(string), entrypoint: none(string), environment: initTable[string, string]() ) check validateStartupConfig(config)