283 lines
8.9 KiB
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
|