nip/tests/test_container_namespace.nim

283 lines
8.9 KiB
Nim

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