## NEXTER Container Namespace Tests ## ## Tests for container namespace isolation and configuration. ## Verifies namespace creation, mount setup, and environment configuration. import std/[unittest, os, tempfiles, options, strutils, times, tables] import nip/container 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 Namespace Configuration Tests": test "Create container config from manifest": ## Verify container config can be created from manifest let manifest = createTestManifest("config-test", "1.0.0") let casRoot = "/tmp/cas" let config = createContainerConfig(manifest, casRoot) check config.isolationType == "full" check config.mounts.len >= 3 # CAS mount + tmpfs mounts check config.environment.len >= 0 test "Container config includes CAS mount": ## Verify CAS mount is configured correctly let manifest = createTestManifest("cas-mount-test", "1.0.0") let casRoot = "/var/lib/nexus/cas" let config = createContainerConfig(manifest, casRoot) # Find CAS mount var casMountFound = false for mount in config.mounts: if mount.target == "/cas": casMountFound = true check mount.source == casRoot / "chunks" check mount.mountType == "bind" check mount.readOnly == true break check casMountFound test "Container config includes tmpfs mounts": ## Verify tmpfs mounts are configured let manifest = createTestManifest("tmpfs-test", "1.0.0") let casRoot = "/tmp/cas" let config = createContainerConfig(manifest, casRoot) # Find tmpfs mounts var tmpMountFound = false var runMountFound = false for mount in config.mounts: if mount.target == "/tmp" and mount.mountType == "tmpfs": tmpMountFound = true if mount.target == "/run" and mount.mountType == "tmpfs": runMountFound = true check tmpMountFound check runMountFound test "Container config with custom environment": ## Verify custom environment variables are preserved let manifest = createTestManifest("env-test", "1.0.0") var envManifest = manifest envManifest.environment["PATH"] = "/usr/bin:/bin" envManifest.environment["HOME"] = "/root" let config = createContainerConfig(envManifest, "/tmp/cas") check config.environment["PATH"] == "/usr/bin:/bin" check config.environment["HOME"] == "/root" test "Container config with capabilities": ## Verify capabilities are preserved let manifest = createTestManifest("cap-test", "1.0.0") var capManifest = manifest capManifest.namespace.capabilities = @["net_bind_service", "sys_admin"] let config = createContainerConfig(capManifest, "/tmp/cas") check config.capabilities.len == 2 check "net_bind_service" in config.capabilities check "sys_admin" in config.capabilities test "Container config with different isolation types": ## Verify different isolation types are supported for isolationType in ["full", "network", "pid", "ipc", "uts"]: let manifest = createTestManifest("iso-" & isolationType, "1.0.0") var isoManifest = manifest isoManifest.namespace.isolationType = isolationType let config = createContainerConfig(isoManifest, "/tmp/cas") check config.isolationType == isolationType suite "Container Runtime Tests": test "Create container runtime": ## Verify container runtime can be created let manifest = createTestManifest("runtime-test", "1.0.0") let config = createContainerConfig(manifest, "/tmp/cas") let runtime = createContainerRuntime("test-container", manifest, config) check runtime.name == "test-container" check runtime.manifest.name == "runtime-test" check runtime.status == Created check runtime.pid == 0 test "Container runtime has unique ID": ## Verify each runtime gets unique ID let manifest = createTestManifest("id-test", "1.0.0") let config = createContainerConfig(manifest, "/tmp/cas") let runtime1 = createContainerRuntime("container1", manifest, config) let runtime2 = createContainerRuntime("container2", manifest, config) check runtime1.id != runtime2.id test "Get container status - created": ## Verify status for created container let manifest = createTestManifest("status-test", "1.0.0") let config = createContainerConfig(manifest, "/tmp/cas") let runtime = createContainerRuntime("test", manifest, config) check runtime.status == Created test "Format container config": ## Verify container config formatting let manifest = createTestManifest("format-test", "1.0.0") let config = createContainerConfig(manifest, "/tmp/cas") let formatted = $config check "Container Config" in formatted check "Isolation" in formatted check "Mounts" in formatted test "Format container runtime": ## Verify container runtime formatting let manifest = createTestManifest("format-runtime", "1.0.0") let config = createContainerConfig(manifest, "/tmp/cas") let runtime = createContainerRuntime("test", manifest, config) let formatted = $runtime check "Container" in formatted check "test" in formatted check "Created" in formatted suite "Container Namespace Property Tests": test "Property: Config preserves manifest isolation type": ## Verify isolation type is preserved through config creation for isolationType in ["full", "network", "pid"]: let manifest = createTestManifest("prop-iso", "1.0.0") var isoManifest = manifest isoManifest.namespace.isolationType = isolationType let config = createContainerConfig(isoManifest, "/tmp/cas") check config.isolationType == isolationType test "Property: Config preserves all environment variables": ## Verify all environment variables are preserved let manifest = createTestManifest("prop-env", "1.0.0") var envManifest = manifest # Add multiple environment variables for i in 1..10: envManifest.environment["VAR_" & $i] = "value_" & $i let config = createContainerConfig(envManifest, "/tmp/cas") check config.environment.len == 10 for i in 1..10: check config.environment["VAR_" & $i] == "value_" & $i test "Property: Config always includes CAS mount": ## Verify CAS mount is always present for i in 1..5: let manifest = createTestManifest("prop-cas-" & $i, "1.0.0") let config = createContainerConfig(manifest, "/tmp/cas-" & $i) var casMountFound = false for mount in config.mounts: if mount.target == "/cas": casMountFound = true break check casMountFound test "Property: Runtime ID format is consistent": ## Verify runtime IDs follow consistent format let manifest = createTestManifest("prop-id", "1.0.0") let config = createContainerConfig(manifest, "/tmp/cas") for i in 1..10: let runtime = createContainerRuntime("container-" & $i, manifest, config) check runtime.id.startsWith("container-") check runtime.id.len > 10 # Should have timestamp test "Property: Config mounts are read-only for CAS": ## Verify CAS mounts are always read-only let manifest = createTestManifest("prop-ro", "1.0.0") let config = createContainerConfig(manifest, "/tmp/cas") for mount in config.mounts: if mount.target == "/cas": check mount.readOnly == true break