469 lines
14 KiB
Nim
469 lines
14 KiB
Nim
# tests/test_install_manager.nim
|
|
# Unit tests for install_manager module
|
|
|
|
import unittest, os, times, json, tables, strutils, sequtils
|
|
import ../src/nimpak/install_manager
|
|
import ../src/nimpak/cas
|
|
|
|
suite "InstallManager Tests":
|
|
var testRoot: string
|
|
var manager: InstallManager
|
|
var config: InstallConfig
|
|
|
|
setup:
|
|
# Create temporary test directory
|
|
testRoot = getTempDir() / "nip_test_" & $epochTime().int
|
|
createDir(testRoot)
|
|
|
|
# Configure test environment
|
|
config = InstallConfig(
|
|
programsDir: testRoot / "Programs",
|
|
linksDir: testRoot / "System" / "Links",
|
|
cacheDir: testRoot / "cache",
|
|
dbFile: testRoot / "db" / "packages.json",
|
|
autoSymlink: true,
|
|
checkConflicts: true,
|
|
verbose: false
|
|
)
|
|
|
|
# Create manager
|
|
manager = newInstallManager(config)
|
|
|
|
teardown:
|
|
# Clean up test directory
|
|
if dirExists(testRoot):
|
|
removeDir(testRoot)
|
|
|
|
test "Create install manager with default config":
|
|
let defaultMgr = newInstallManager(defaultConfig())
|
|
check defaultMgr != nil
|
|
check defaultMgr.config.programsDir == "/Programs"
|
|
check defaultMgr.config.linksDir == "/System/Links"
|
|
check defaultMgr.config.autoSymlink == true
|
|
check defaultMgr.config.checkConflicts == true
|
|
|
|
test "Install package to temporary directory":
|
|
# Create a mock package source directory
|
|
let sourcePath = testRoot / "source" / "testpkg"
|
|
createDir(sourcePath / "bin")
|
|
createDir(sourcePath / "lib")
|
|
|
|
# Create test files
|
|
writeFile(sourcePath / "bin" / "testcmd", "#!/bin/sh\necho test")
|
|
writeFile(sourcePath / "lib" / "libtest.so.1", "mock library")
|
|
|
|
# Install the package
|
|
let metadata = %*{"description": "Test package"}
|
|
let result = manager.installPackage(
|
|
packageName = "testpkg",
|
|
version = "1.0.0",
|
|
source = "test",
|
|
sourcePath = sourcePath,
|
|
graftHash = "blake2b-abc123",
|
|
metadata = metadata
|
|
)
|
|
|
|
# Verify installation succeeded
|
|
check result.success == true
|
|
check result.packageName == "testpkg"
|
|
check result.version == "1.0.0"
|
|
check result.errors.len == 0
|
|
|
|
# Verify package directory was created
|
|
check dirExists(result.installPath)
|
|
check fileExists(result.installPath / "bin" / "testcmd")
|
|
check fileExists(result.installPath / "lib" / "libtest.so.1")
|
|
|
|
# Verify package is in database
|
|
check manager.isInstalled("testpkg")
|
|
let pkg = manager.getInstalledPackage("testpkg")
|
|
check pkg.name == "testpkg"
|
|
check pkg.version == "1.0.0"
|
|
check pkg.source == "test"
|
|
|
|
test "Install package with variant descriptor":
|
|
let sourcePath = testRoot / "source" / "varpkg"
|
|
createDir(sourcePath / "bin")
|
|
writeFile(sourcePath / "bin" / "varcmd", "#!/bin/sh\necho variant")
|
|
|
|
# Install with custom variant
|
|
let result = manager.installPackage(
|
|
packageName = "varpkg",
|
|
version = "2.0.0",
|
|
source = "test",
|
|
sourcePath = sourcePath,
|
|
graftHash = "blake2b-def456",
|
|
metadata = newJObject(),
|
|
variantDescriptor = "optimized"
|
|
)
|
|
|
|
check result.success == true
|
|
check "optimized" in result.installPath
|
|
|
|
test "Symlink creation for executables":
|
|
let sourcePath = testRoot / "source" / "binpkg"
|
|
createDir(sourcePath / "bin")
|
|
writeFile(sourcePath / "bin" / "cmd1", "#!/bin/sh\necho cmd1")
|
|
writeFile(sourcePath / "bin" / "cmd2", "#!/bin/sh\necho cmd2")
|
|
|
|
let result = manager.installPackage(
|
|
packageName = "binpkg",
|
|
version = "1.0.0",
|
|
source = "test",
|
|
sourcePath = sourcePath,
|
|
graftHash = "blake2b-bin123"
|
|
)
|
|
|
|
check result.success == true
|
|
check result.symlinksCreated.len == 2
|
|
|
|
# Verify symlinks were created
|
|
let execDir = config.linksDir / "Executables"
|
|
check symlinkExists(execDir / "cmd1")
|
|
check symlinkExists(execDir / "cmd2")
|
|
|
|
test "Symlink creation for libraries":
|
|
let sourcePath = testRoot / "source" / "libpkg"
|
|
createDir(sourcePath / "lib")
|
|
writeFile(sourcePath / "lib" / "libfoo.so.1", "library")
|
|
writeFile(sourcePath / "lib" / "libbar.so.2.0", "library")
|
|
|
|
let result = manager.installPackage(
|
|
packageName = "libpkg",
|
|
version = "1.0.0",
|
|
source = "test",
|
|
sourcePath = sourcePath,
|
|
graftHash = "blake2b-lib123"
|
|
)
|
|
|
|
check result.success == true
|
|
check result.symlinksCreated.len == 2
|
|
|
|
# Verify library symlinks
|
|
let libDir = config.linksDir / "Libraries"
|
|
check symlinkExists(libDir / "libfoo.so.1")
|
|
check symlinkExists(libDir / "libbar.so.2.0")
|
|
|
|
test "Package removal and cleanup":
|
|
# First install a package
|
|
let sourcePath = testRoot / "source" / "rmpkg"
|
|
createDir(sourcePath / "bin")
|
|
writeFile(sourcePath / "bin" / "rmcmd", "#!/bin/sh\necho remove")
|
|
|
|
let installResult = manager.installPackage(
|
|
packageName = "rmpkg",
|
|
version = "1.0.0",
|
|
source = "test",
|
|
sourcePath = sourcePath,
|
|
graftHash = "blake2b-rm123"
|
|
)
|
|
|
|
check installResult.success == true
|
|
check manager.isInstalled("rmpkg")
|
|
|
|
# Now remove it
|
|
let removeResult = manager.removePackage("rmpkg")
|
|
|
|
check removeResult.success == true
|
|
check removeResult.packageName == "rmpkg"
|
|
check removeResult.errors.len == 0
|
|
|
|
# Verify package was removed
|
|
check not manager.isInstalled("rmpkg")
|
|
check not dirExists(installResult.installPath)
|
|
|
|
# Verify symlinks were removed
|
|
let execDir = config.linksDir / "Executables"
|
|
check not symlinkExists(execDir / "rmcmd")
|
|
|
|
test "Remove non-existent package":
|
|
let result = manager.removePackage("nonexistent")
|
|
|
|
check result.success == false
|
|
check result.errors.len > 0
|
|
check "not installed" in result.errors[0]
|
|
|
|
test "Conflict detection - executable":
|
|
# Install first package
|
|
let source1 = testRoot / "source" / "pkg1"
|
|
createDir(source1 / "bin")
|
|
writeFile(source1 / "bin" / "conflict", "#!/bin/sh\necho pkg1")
|
|
|
|
let result1 = manager.installPackage(
|
|
packageName = "pkg1",
|
|
version = "1.0.0",
|
|
source = "test",
|
|
sourcePath = source1,
|
|
graftHash = "blake2b-pkg1"
|
|
)
|
|
|
|
check result1.success == true
|
|
|
|
# Try to install second package with same executable
|
|
let source2 = testRoot / "source" / "pkg2"
|
|
createDir(source2 / "bin")
|
|
writeFile(source2 / "bin" / "conflict", "#!/bin/sh\necho pkg2")
|
|
|
|
let result2 = manager.installPackage(
|
|
packageName = "pkg2",
|
|
version = "1.0.0",
|
|
source = "test",
|
|
sourcePath = source2,
|
|
graftHash = "blake2b-pkg2"
|
|
)
|
|
|
|
# Installation should succeed but with warnings
|
|
check result2.success == true
|
|
check result2.warnings.len > 0
|
|
check "conflict" in result2.warnings[0].toLowerAscii()
|
|
|
|
test "Conflict detection - library":
|
|
# Install first package with library
|
|
let source1 = testRoot / "source" / "libpkg1"
|
|
createDir(source1 / "lib")
|
|
writeFile(source1 / "lib" / "libconflict.so.1", "lib1")
|
|
|
|
let result1 = manager.installPackage(
|
|
packageName = "libpkg1",
|
|
version = "1.0.0",
|
|
source = "test",
|
|
sourcePath = source1,
|
|
graftHash = "blake2b-libpkg1"
|
|
)
|
|
|
|
check result1.success == true
|
|
|
|
# Try to install second package with same library
|
|
let source2 = testRoot / "source" / "libpkg2"
|
|
createDir(source2 / "lib")
|
|
writeFile(source2 / "lib" / "libconflict.so.1", "lib2")
|
|
|
|
let result2 = manager.installPackage(
|
|
packageName = "libpkg2",
|
|
version = "1.0.0",
|
|
source = "test",
|
|
sourcePath = source2,
|
|
graftHash = "blake2b-libpkg2"
|
|
)
|
|
|
|
check result2.success == true
|
|
check result2.warnings.len > 0
|
|
|
|
test "List installed packages":
|
|
# Install multiple packages
|
|
for i in 1..3:
|
|
let sourcePath = testRoot / "source" / "pkg" & $i
|
|
createDir(sourcePath / "bin")
|
|
writeFile(sourcePath / "bin" / "cmd" & $i, "test")
|
|
|
|
let result = manager.installPackage(
|
|
packageName = "pkg" & $i,
|
|
version = "1.0.0",
|
|
source = "test",
|
|
sourcePath = sourcePath,
|
|
graftHash = "blake2b-pkg" & $i
|
|
)
|
|
check result.success == true
|
|
|
|
# List packages
|
|
let installed = manager.listInstalled()
|
|
check installed.len == 3
|
|
|
|
# Verify package names
|
|
let names = installed.mapIt(it.name)
|
|
check "pkg1" in names
|
|
check "pkg2" in names
|
|
check "pkg3" in names
|
|
|
|
test "Get system status":
|
|
# Install a package
|
|
let sourcePath = testRoot / "source" / "statuspkg"
|
|
createDir(sourcePath / "bin")
|
|
writeFile(sourcePath / "bin" / "statuscmd", "test")
|
|
|
|
discard manager.installPackage(
|
|
packageName = "statuspkg",
|
|
version = "1.0.0",
|
|
source = "test",
|
|
sourcePath = sourcePath,
|
|
graftHash = "blake2b-status"
|
|
)
|
|
|
|
# Get status
|
|
let status = manager.getStatus()
|
|
|
|
check status.hasKey("total_packages")
|
|
check status["total_packages"].getInt() == 1
|
|
check status.hasKey("by_source")
|
|
check status.hasKey("total_size_mb")
|
|
check status.hasKey("programs_dir")
|
|
check status.hasKey("links_dir")
|
|
|
|
test "Database persistence":
|
|
# Install a package
|
|
let sourcePath = testRoot / "source" / "dbpkg"
|
|
createDir(sourcePath / "bin")
|
|
writeFile(sourcePath / "bin" / "dbcmd", "test")
|
|
|
|
let result = manager.installPackage(
|
|
packageName = "dbpkg",
|
|
version = "1.0.0",
|
|
source = "test",
|
|
sourcePath = sourcePath,
|
|
graftHash = "blake2b-db123"
|
|
)
|
|
|
|
check result.success == true
|
|
|
|
# Create new manager to test database loading
|
|
let manager2 = newInstallManager(config)
|
|
|
|
# Verify package was loaded from database
|
|
check manager2.isInstalled("dbpkg")
|
|
let pkg = manager2.getInstalledPackage("dbpkg")
|
|
check pkg.name == "dbpkg"
|
|
check pkg.version == "1.0.0"
|
|
|
|
test "Database backup creation":
|
|
# Install first package
|
|
let source1 = testRoot / "source" / "backup1"
|
|
createDir(source1 / "bin")
|
|
writeFile(source1 / "bin" / "cmd1", "test")
|
|
|
|
discard manager.installPackage(
|
|
packageName = "backup1",
|
|
version = "1.0.0",
|
|
source = "test",
|
|
sourcePath = source1,
|
|
graftHash = "blake2b-backup1"
|
|
)
|
|
|
|
# Install second package (should create backup)
|
|
let source2 = testRoot / "source" / "backup2"
|
|
createDir(source2 / "bin")
|
|
writeFile(source2 / "bin" / "cmd2", "test")
|
|
|
|
discard manager.installPackage(
|
|
packageName = "backup2",
|
|
version = "1.0.0",
|
|
source = "test",
|
|
sourcePath = source2,
|
|
graftHash = "blake2b-backup2"
|
|
)
|
|
|
|
# Check for backup files
|
|
let dbDir = parentDir(config.dbFile)
|
|
var backupFound = false
|
|
for file in walkDir(dbDir):
|
|
if ".backup." in extractFilename(file.path):
|
|
backupFound = true
|
|
break
|
|
|
|
check backupFound == true
|
|
|
|
test "Install with missing source directory":
|
|
let result = manager.installPackage(
|
|
packageName = "missing",
|
|
version = "1.0.0",
|
|
source = "test",
|
|
sourcePath = testRoot / "nonexistent",
|
|
graftHash = "blake2b-missing"
|
|
)
|
|
|
|
check result.success == false
|
|
check result.errors.len > 0
|
|
check "does not exist" in result.errors[0]
|
|
|
|
test "Install duplicate package":
|
|
# Install package first time
|
|
let sourcePath = testRoot / "source" / "duppkg"
|
|
createDir(sourcePath / "bin")
|
|
writeFile(sourcePath / "bin" / "dupcmd", "test")
|
|
|
|
let result1 = manager.installPackage(
|
|
packageName = "duppkg",
|
|
version = "1.0.0",
|
|
source = "test",
|
|
sourcePath = sourcePath,
|
|
graftHash = "blake2b-dup123"
|
|
)
|
|
|
|
check result1.success == true
|
|
|
|
# Try to install again
|
|
let result2 = manager.installPackage(
|
|
packageName = "duppkg",
|
|
version = "1.0.0",
|
|
source = "test",
|
|
sourcePath = sourcePath,
|
|
graftHash = "blake2b-dup123"
|
|
)
|
|
|
|
check result2.success == false
|
|
check result2.errors.len > 0
|
|
check "already installed" in result2.errors[0]
|
|
|
|
test "Symlink creation with auto-symlink disabled":
|
|
# Create manager with auto-symlink disabled
|
|
var noSymlinkConfig = config
|
|
noSymlinkConfig.autoSymlink = false
|
|
let noSymlinkMgr = newInstallManager(noSymlinkConfig)
|
|
|
|
let sourcePath = testRoot / "source" / "nosympkg"
|
|
createDir(sourcePath / "bin")
|
|
writeFile(sourcePath / "bin" / "nosymcmd", "test")
|
|
|
|
let result = noSymlinkMgr.installPackage(
|
|
packageName = "nosympkg",
|
|
version = "1.0.0",
|
|
source = "test",
|
|
sourcePath = sourcePath,
|
|
graftHash = "blake2b-nosym"
|
|
)
|
|
|
|
check result.success == true
|
|
check result.symlinksCreated.len == 0
|
|
|
|
test "Current symlink creation and switching":
|
|
# Install first variant
|
|
let source1 = testRoot / "source" / "varpkg1"
|
|
createDir(source1 / "bin")
|
|
writeFile(source1 / "bin" / "varcmd", "variant1")
|
|
|
|
let result1 = manager.installPackage(
|
|
packageName = "varpkg",
|
|
version = "1.0.0",
|
|
source = "test",
|
|
sourcePath = source1,
|
|
graftHash = "blake2b-var1",
|
|
variantDescriptor = "default"
|
|
)
|
|
|
|
check result1.success == true
|
|
|
|
# Verify Current symlink exists
|
|
let versionDir = config.programsDir / "varpkg" / "1.0.0"
|
|
let currentLink = versionDir / "Current"
|
|
check symlinkExists(currentLink)
|
|
|
|
# Install second variant (should switch Current)
|
|
let source2 = testRoot / "source" / "varpkg2"
|
|
createDir(source2 / "bin")
|
|
writeFile(source2 / "bin" / "varcmd", "variant2")
|
|
|
|
let result2 = manager.installPackage(
|
|
packageName = "varpkg",
|
|
version = "1.0.0",
|
|
source = "test",
|
|
sourcePath = source2,
|
|
graftHash = "blake2b-var2",
|
|
variantDescriptor = "optimized"
|
|
)
|
|
|
|
check result2.success == true
|
|
check symlinkExists(currentLink)
|
|
|
|
# Current should now point to optimized variant
|
|
let target = expandSymlink(currentLink)
|
|
check "optimized" in target
|