nip/tests/test_npk_packages.nim

437 lines
13 KiB
Nim

## Tests for NPK Package Format Handler
##
## This module tests the NPK package format creation, validation, and conversion
## capabilities with CAS integration and digital signature support.
import unittest, os, times, json, options
import ../src/nimpak/[types, packages, cas]
suite "NPK Package Format Handler":
setup:
let testDir = getTempDir() / "nimpak_test_npk"
let casDir = testDir / "cas"
let sourceDir = testDir / "source"
let outputDir = testDir / "output"
# Clean up and create test directories
if dirExists(testDir):
removeDir(testDir)
createDir(testDir)
createDir(casDir)
createDir(sourceDir)
createDir(outputDir)
# Initialize CAS manager
let cas = initCasManager(casDir, casDir)
# Create test files in source directory
writeFile(sourceDir / "test.txt", "Hello, NimPak!")
writeFile(sourceDir / "config.conf", "setting=value\nother=123")
createDir(sourceDir / "subdir")
writeFile(sourceDir / "subdir" / "nested.dat", "nested file content")
teardown:
let testDir = getTempDir() / "nimpak_test_npk"
if dirExists(testDir):
removeDir(testDir)
test "create NPK package from Fragment and source directory":
leagment = Fragment(
id: PackageId(name: "test-package", version: "1.0.0", stream: Stable),
source: Source(
url: "https://example.com/test-package-1.0.0.tar.gz",
hash: "blake2b-test123",
hashAlgorithm: "blake2b",
sourceMethod: Http,
timestamp: now()
),
dependencies: @[],
buildSystem: Custom,
metadata: PackageMetadata(
description: "Test package for NPK format",
license: "MIT",
maintainer: "test@example.com",
tags: @["test"],
runtime: RuntimeProfile(
libc: Musl,
allocator: Jemalloc,
systemdAware: false,
reproducible: true,
tags: @["cli"]
)
),
acul: AculCompliance(
required: false,
membership: "",
attribution: "",
buildLog: ""
)
)
let result = createNpkPackage(fragment, sourceDir, cas)
check result.isOk
let npk = result.get()
check npk.metadata.id.name == "test-package"
check npk.metadata.id.version == "1.0.0"
check npk.files.len == 3 # test.txt, config.conf, subdir/nested.dat
check npk.manifest.totalSize > 0
check npk.manifest.merkleRoot.len > 0
check npk.manifest.merkleRoot.startsWith("blake2b-")
test "validate NPK package metadata and structure":
let fragment = Fragment(
id: PackageId(name: "valid-package", version: "2.0.0", stream: Testing),
source: Source(
url: "https://example.com/valid-package.tar.gz",
hash: "blake2b-valid123",
hashAlgorithm: "blake2b",
sourceMethod: Git,
timestamp: now()
),
dependencies: @[PackageId(name: "dep1", version: "1.0", stream: Stable)],
buildSystem: CMake,
metadata: PackageMetadata(
description: "Valid test package",
license: "ACUL",
maintainer: "maintainer@example.com",
tags: @["valid", "test"],
runtime: RuntimeProfile(
libc: Glibc,
allocator: System,
systemdAware: true,
reproducible: true,
tags: @["system"]
)
),
acul: AculCompliance(
required: true,
membership: "NexusOS-Community",
attribution: "Original work",
buildLog: "Build completed successfully"
)
)
let createResult = createNpkPackage(fragment, sourceDir, cas)
check createResult.isOk
let npk = createResult.get()
let validation = validateNpkPackage(npk)
check validation.valid == true
check validation.errors.len == 0
# May have warnings about non-standard hash algorithms, but should be valid
test "serialize NPK package to KDL format":
let fragment = Fragment(
id: PackageId(name: "kdl-test", version: "1.5.0", stream: Stable),
source: Source(
url: "https://example.com/kdl-test.tar.gz",
hash: "blake2b-kdltest123",
hashAlgorithm: "blake2b",
sourceMethod: Http,
timestamp: now()
),
dependencies: @[],
buildSystem: Meson,
metadata: PackageMetadata(
description: "KDL serialization test",
license: "MIT",
maintainer: "test@kdl.com",
tags: @["kdl"],
runtime: RuntimeProfile(
libc: Musl,
allocator: Jemalloc,
systemdAware: false,
reproducible: true,
tags: @["serialization"]
)
),
acul: AculCompliance(
required: false,
membership: "",
attribution: "",
buildLog: ""
)
)
let createResult = createNpkPackage(fragment, sourceDir, cas)
check createResult.isOk
let npk = createResult.get()
let kdlContent = serializeToKdl(npk)
# Check that KDL content contains expected sections
check kdlContent.contains("package \"kdl-test\"")
check kdlContent.contains("version \"1.5.0\"")
check kdlContent.contains("stream \"Stable\"")
check kdlContent.contains("source {")
check kdlContent.contains("integrity {")
check kdlContent.contains("runtime {")
check kdlContent.contains("acul {")
check kdlContent.contains("manifest {")
check kdlContent.contains("files {")
check kdlContent.contains("algorithm \"BLAKE2b\"")
test "create and validate .npk.zst archive":
let fragment = Fragment(
id: PackageId(name: "archive-test", version: "3.0.0", stream: Dev),
source: Source(
url: "https://example.com/archive-test.tar.gz",
hash: "blake2b-archive123",
hashAlgorithm: "blake2b",
sourceMethod: Local,
timestamp: now()
),
dependencies: @[],
buildSystem: Autotools,
metadata: PackageMetadata(
description: "Archive format test",
license: "EUPL-1.2",
maintainer: "archive@test.com",
tags: @["archive"],
runtime: RuntimeProfile(
libc: Musl,
allocator: Internal,
systemdAware: false,
reproducible: true,
tags: @["compression"]
)
),
acul: AculCompliance(
required: true,
membership: "NexusOS",
attribution: "Test archive",
buildLog: "Archive test build"
)
)
let createResult = createNpkPackage(fragment, sourceDir, cas)
check createResult.isOk
let npk = createResult.get()
let archivePath = outputDir / "test-archive"
# Test .npk.zst format (default)
let archiveResult = createNpkArchive(npk, archivePath, NpkZst)
check archiveResult.isOk
let finalPath = archivePath & ".npk.zst"
check fileExists(finalPath)
# Verify archive is not empty
let archiveInfo = getFileInfo(finalPath)
check archiveInfo.size > 0
test "create uncompressed .npk.tar archive for debugging":
let fragment = Fragment(
id: PackageId(name: "debug-test", version: "1.0.0", stream: Dev),
source: Source(
url: "file:///tmp/debug-test",
hash: "blake2b-debug123",
hashAlgorithm: "blake2b",
sourceMethod: Local,
timestamp: now()
),
dependencies: @[],
buildSystem: Custom,
metadata: PackageMetadata(
description: "Debug archive test",
license: "MIT",
maintainer: "debug@test.com",
tags: @["debug"],
runtime: RuntimeProfile(
libc: None,
allocator: System,
systemdAware: false,
reproducible: true,
tags: @["debug"]
)
),
acul: AculCompliance(
required: false,
membership: "",
attribution: "",
buildLog: ""
)
)
let createResult = createNpkPackage(fragment, sourceDir, cas)
check createResult.isOk
let npk = createResult.get()
let archivePath = outputDir / "debug-archive"
# Test .npk.tar format (uncompressed)
let archiveResult = createNpkArchive(npk, archivePath, NpkTar)
check archiveResult.isOk
let finalPath = archivePath & ".npk.tar"
check fileExists(finalPath)
test "extract NPK package using CAS":
let fragment = Fragment(
id: PackageId(name: "extract-test", version: "2.5.0", stream: Stable),
source: Source(
url: "https://example.com/extract-test.tar.gz",
hash: "blake2b-extract123",
hashAlgorithm: "blake2b",
sourceMethod: Http,
timestamp: now()
),
dependencies: @[],
buildSystem: Nim,
metadata: PackageMetadata(
description: "Extraction test package",
license: "MIT",
maintainer: "extract@test.com",
tags: @["extract"],
runtime: RuntimeProfile(
libc: Musl,
allocator: Jemalloc,
systemdAware: false,
reproducible: true,
tags: @["extraction"]
)
),
acul: AculCompliance(
required: false,
membership: "",
attribution: "",
buildLog: ""
)
)
let createResult = createNpkPackage(fragment, sourceDir, cas)
check createResult.isOk
let npk = createResult.get()
let extractDir = outputDir / "extracted"
let extractResult = extractNpkPackage(npk, extractDir, cas)
check extractResult.isOk
# Verify extracted files exist
check fileExists(extractDir / "test.txt")
check fileExists(extractDir / "config.conf")
check fileExists(extractDir / "subdir" / "nested.dat")
# Verify file contents
check readFile(extractDir / "test.txt") == "Hello, NimPak!"
check readFile(extractDir / "config.conf") == "setting=value\nother=123"
check readFile(extractDir / "subdir" / "nested.dat") == "nested file content"
test "validate NPK package with missing required fields":
# Create an invalid fragment with missing required fields
let invalidFragment = Fragment(
id: PackageId(name: "", version: "", stream: Stable), # Empty name and version
source: Source(
url: "", # Empty URL
hash: "", # Empty hash
hashAlgorithm: "blake2b",
sourceMethod: Http,
timestamp: now()
),
dependencies: @[],
buildSystem: Custom,
metadata: PackageMetadata(
description: "Invalid test package",
license: "MIT",
maintainer: "invalid@test.com",
tags: @[],
runtime: RuntimeProfile(
libc: Musl,
allocator: System,
systemdAware: false,
reproducible: false,
tags: @[]
)
),
acul: AculCompliance(
required: false,
membership: "",
attribution: "",
buildLog: ""
)
)
let createResult = createNpkPackage(invalidFragment, sourceDir, cas)
check createResult.isOk # Creation should succeed even with invalid metadata
let npk = createResult.get()
let validation = validateNpkPackage(npk)
check validation.valid == false
check validation.errors.len > 0
# Check for specific validation errors
var hasNameError = false
var hasVersionError = false
var hasUrlError = false
var hasHashError = false
for error in validation.errors:
if error.field == "metadata.id.name":
hasNameError = true
elif error.field == "metadata.id.version":
hasVersionError = true
elif error.field == "metadata.source.url":
hasUrlError = true
elif error.field == "metadata.source.hash":
hasHashError = true
check hasNameError
check hasVersionError
check hasUrlError
check hasHashError
test "get human-readable NPK package information":
let fragment = Fragment(
id: PackageId(name: "info-test", version: "4.2.1", stream: LTS),
source: Source(
url: "https://example.com/info-test.tar.gz",
hash: "blake2b-info123",
hashAlgorithm: "blake2b",
sourceMethod: Git,
timestamp: now()
),
dependencies: @[],
buildSystem: Cargo,
metadata: PackageMetadata(
description: "Package info test",
license: "Apache-2.0",
maintainer: "info@test.com",
tags: @["info"],
runtime: RuntimeProfile(
libc: Glibc,
allocator: Jemalloc,
systemdAware: true,
reproducible: true,
tags: @["information"]
)
),
acul: AculCompliance(
required: true,
membership: "NexusOS-Pro",
attribution: "Info test package",
buildLog: "Info build completed"
)
)
let createResult = createNpkPackage(fragment, sourceDir, cas)
check createResult.isOk
let npk = createResult.get()
let info = getNpkInfo(npk)
check info.contains("NPK Package: info-test v4.2.1")
check info.contains("Stream: LTS")
check info.contains("Files: 3")
check info.contains("Total Size:")
check info.contains("Created:")
check info.contains("Merkle Root: blake2b-")
check info.contains("Signed: No")
when isMainModule:
# Run the tests
echo "Running NPK Package Format Handler tests..."