nip/tests/test_system_integration.nim

178 lines
5.5 KiB
Nim

import std/[unittest, os, tempfiles, options, strutils]
import nip/system_integration
import nip/manifest_parser
import nip/cas
suite "System Integration Tests":
setup:
let tempDir = createTempDir("nip_test_", "")
let casRoot = tempDir / "cas"
let programsRoot = tempDir / "Programs"
let systemIndexRoot = tempDir / "System/Index"
createDir(casRoot)
createDir(programsRoot)
createDir(systemIndexRoot)
# Initialize CAS
discard initCasManager(casRoot, casRoot)
let si = newSystemIntegrator(casRoot, programsRoot, systemIndexRoot)
teardown:
removeDir(tempDir)
test "Install package with file reconstruction":
# 1. Prepare CAS content
let fileContent = "echo 'Hello World'"
let casObj = storeObject(fileContent, casRoot)
let fileHash = string(casObj.hash)
# 2. Create Manifest
var manifest = PackageManifest(
name: "hello-world",
version: parseSemanticVersion("1.0.0"),
license: "MIT",
artifactHash: "hash123"
)
manifest.files.add(FileSpec(
path: "bin/hello",
hash: fileHash,
size: fileContent.len,
permissions: "755"
))
# 3. Install
si.installPackage(manifest)
# 4. Verify
let installPath = programsRoot / "hello-world/1.0.0/hash123"
let binPath = installPath / "bin/hello"
check fileExists(binPath)
check readFile(binPath) == fileContent
# Verify permissions (basic check)
let perms = getFilePermissions(binPath)
check fpUserExec in perms
test "Create symlinks":
# 1. Prepare installed state (simulate previous step)
let installPath = programsRoot / "hello-world/1.0.0/hash123"
createDir(installPath / "bin")
writeFile(installPath / "bin/hello", "binary")
var manifest = PackageManifest(
name: "hello-world",
version: parseSemanticVersion("1.0.0"),
license: "MIT",
artifactHash: "hash123"
)
# 2. Run symlink creation (via installPackage or directly)
# We'll run installPackage which calls createSymlinks
# But we need files in manifest to avoid error in reconstructFiles?
# No, reconstructFiles iterates manifest.files. If empty, it does nothing.
# But we want to test symlinks, so we need the file to exist in installPath.
# We already created it manually.
# But reconstructFiles might overwrite it or fail if hash not in CAS.
# So we should add file to manifest AND CAS.
let fileContent = "binary"
let casObj = storeObject(fileContent, casRoot)
manifest.files.add(FileSpec(
path: "bin/hello",
hash: string(casObj.hash),
size: fileContent.len,
permissions: "755"
))
si.installPackage(manifest)
# 3. Verify Symlinks
let currentLink = programsRoot / "hello-world/Current"
check symlinkExists(currentLink)
check expandSymlink(currentLink) == installPath
let binLink = systemIndexRoot / "bin/hello"
check symlinkExists(binLink)
# The link should point to .../Current/bin/hello
check expandSymlink(binLink).contains("Current")
test "Service creation":
var manifest = PackageManifest(
name: "myservice",
version: parseSemanticVersion("1.0.0"),
license: "MIT",
artifactHash: "hash123"
)
manifest.services.add(ServiceSpec(
name: "myservice",
content: "[Unit]\nDescription=My Service",
enabled: true
))
# We need to run as root for systemctl, so this part might fail or need mocking.
# But writeFile should work if we have permissions on tempDir.
# execCmd("systemctl") will fail.
# We should probably mock execCmd or check for root/systemd.
# For this test, we just check file creation.
# But `manageServices` calls `execCmd`.
# We can't easily mock `execCmd` in Nim without dependency injection or mixins.
# However, `execCmd` failure just logs error in our implementation?
# No, `discard execCmd` ignores result.
si.installPackage(manifest)
let serviceFile = systemIndexRoot / "lib/systemd/system/myservice.service"
check fileExists(serviceFile)
check readFile(serviceFile) == "[Unit]\nDescription=My Service"
test "Remove package":
# 1. Setup: Install a package
let fileContent = "binary"
let casObj = storeObject(fileContent, casRoot)
var manifest = PackageManifest(
name: "removable-pkg",
version: parseSemanticVersion("1.0.0"),
license: "MIT",
artifactHash: "hash123"
)
manifest.files.add(FileSpec(
path: "bin/removable",
hash: string(casObj.hash),
size: fileContent.len,
permissions: "755"
))
si.installPackage(manifest)
# Verify installation
let installPath = programsRoot / "removable-pkg/1.0.0/hash123"
check fileExists(installPath / "bin/removable")
check symlinkExists(programsRoot / "removable-pkg/Current")
check symlinkExists(systemIndexRoot / "bin/removable")
# Verify CAS reference
check hasReferences(casRoot, casObj.hash)
# 2. Remove package
si.removePackage(manifest)
# 3. Verify removal
check not fileExists(installPath / "bin/removable")
check not dirExists(installPath)
check not symlinkExists(programsRoot / "removable-pkg/Current")
check not symlinkExists(systemIndexRoot / "bin/removable")
# Verify CAS reference removal
check not hasReferences(casRoot, casObj.hash)
# Verify package dir removal (since it was empty)
check not dirExists(programsRoot / "removable-pkg")