## Tests for NPK Installation Workflow ## ## **Feature:** 01-nip-unified-storage-and-formats ## **Task:** 13. Implement NPK installation workflow ## **Requirements:** 3.5, 11.1, 11.2 ## ## **Test Strategy:** ## - Test atomic installation workflow ## - Test chunk extraction to CAS with deduplication ## - Test manifest creation ## - Test reference tracking ## - Test rollback on failure ## - Test installation verification import std/[unittest, os, times, json, options, strutils] import nip/[npk, npk_manifest, npk_installer, manifest_parser, cas] # ============================================================================ # Test Fixtures # ============================================================================ proc createTestPackage(name: string, version: string, testDir: string): string = ## Create a test NPK package and return its path let manifest = NPKManifest( name: name, version: parseSemanticVersion(version), buildDate: now(), metadata: PackageInfo( description: "Test package for installation", license: "MIT" ), provenance: ProvenanceInfo( source: "https://example.com/test.tar.gz", sourceHash: "xxh3-test123", buildTimestamp: now() ), buildConfig: BuildConfiguration( compilerVersion: "gcc-13.2.0", targetArchitecture: "x86_64", libc: "musl", allocator: "default", buildSystem: "cmake" ), casChunks: @[ ChunkReference( hash: "xxh3-chunk1", size: 1024, chunkType: Binary, path: "bin/test" ), ChunkReference( hash: "xxh3-chunk2", size: 2048, chunkType: Library, path: "lib/libtest.so" ) ], install: InstallPaths( programsPath: "/Programs/" & name & "/" & version, binPath: "/Programs/" & name & "/" & version & "/bin", libPath: "/Programs/" & name & "/" & version & "/lib", sharePath: "/Programs/" & name & "/" & version & "/share", etcPath: "/Programs/" & name & "/" & version & "/etc" ), system: SystemIntegration(), buildHash: "xxh3-build123", signature: SignatureInfo( algorithm: "ed25519", keyId: "test-key", signature: "test-signature" ) ) let chunks = @[ ChunkData( hash: "xxh3-chunk1", data: "test chunk data 1", size: 17, chunkType: Binary ), ChunkData( hash: "xxh3-chunk2", data: "test chunk data 2 - larger content", size: 35, chunkType: Library ) ] let metadata = %* { "package": name, "version": version, "created": "2025-11-20T14:00:00Z" } let signature = "test-signature-data" let pkgPath = testDir / (name & ".npk") discard createNPK(manifest, chunks, metadata, signature, pkgPath) return pkgPath # ============================================================================ # Installation Tests # ============================================================================ suite "NPK Installation Workflow (Task 13)": setup: let testDir = getTempDir() / "npk-install-test-" & $getTime().toUnix() let storageRoot = testDir / "storage" createDir(testDir) createDir(storageRoot) teardown: if dirExists(testDir): removeDir(testDir) test "Install NPK package successfully": ## **Requirement 3.5:** Extract chunks to CAS and create manifest ## **Requirement 11.1:** Atomic installation let pkgPath = createTestPackage("test-pkg", "1.0.0", testDir) let result = installNPK(pkgPath, storageRoot) # Verify installation succeeded check result.success check result.packageName == "test-pkg" check result.version == "1.0.0" check result.chunksInstalled == 2 check result.error == "" # Verify manifest was created let manifestPath = storageRoot / "npks" / "test-pkg.kdl" check fileExists(manifestPath) # Verify references were created let refsPath = storageRoot / "cas" / "refs" / "npks" / "test-pkg.refs" check fileExists(refsPath) # Verify chunks were extracted to CAS let casDir = storageRoot / "cas" / "chunks" check dirExists(casDir) test "Install creates correct directory structure": ## Verify all required directories are created let pkgPath = createTestPackage("test-pkg", "1.0.0", testDir) discard installNPK(pkgPath, storageRoot) # Check directory structure check dirExists(storageRoot / "npks") check dirExists(storageRoot / "cas") check dirExists(storageRoot / "cas" / "chunks") check dirExists(storageRoot / "cas" / "refs") check dirExists(storageRoot / "cas" / "refs" / "npks") test "Install fails for already installed package": ## Verify duplicate installation is prevented let pkgPath = createTestPackage("test-pkg", "1.0.0", testDir) # First installation should succeed let result1 = installNPK(pkgPath, storageRoot) check result1.success # Second installation should fail let result2 = installNPK(pkgPath, storageRoot) check not result2.success check "already installed" in result2.error.toLowerAscii() test "Install creates valid manifest file": ## Verify manifest can be parsed after installation let pkgPath = createTestPackage("test-pkg", "1.0.0", testDir) discard installNPK(pkgPath, storageRoot) let manifestPath = storageRoot / "npks" / "test-pkg.kdl" let manifestKdl = readFile(manifestPath) # Parse manifest to verify it's valid let manifest = parseNPKManifest(manifestKdl) check manifest.name == "test-pkg" check manifest.version.major == 1 check manifest.version.minor == 0 check manifest.version.patch == 0 test "Install creates valid references file": ## Verify references file contains correct information let pkgPath = createTestPackage("test-pkg", "1.0.0", testDir) discard installNPK(pkgPath, storageRoot) let refsPath = storageRoot / "cas" / "refs" / "npks" / "test-pkg.refs" let refsContent = readFile(refsPath) check "test-pkg" in refsContent check "1.0.0" in refsContent check "chunks:" in refsContent # ============================================================================ # Deduplication Tests # ============================================================================ suite "NPK Installation Deduplication (Task 13)": setup: let testDir = getTempDir() / "npk-dedup-test-" & $getTime().toUnix() let storageRoot = testDir / "storage" createDir(testDir) createDir(storageRoot) teardown: if dirExists(testDir): removeDir(testDir) test "Multiple packages share chunks via CAS": ## Verify CAS deduplication works across packages # Create two packages with overlapping chunks let pkg1Path = createTestPackage("pkg1", "1.0.0", testDir) let pkg2Path = createTestPackage("pkg2", "1.0.0", testDir) # Install both packages let result1 = installNPK(pkg1Path, storageRoot) let result2 = installNPK(pkg2Path, storageRoot) check result1.success check result2.success # Both packages should be installed check isInstalled("pkg1", storageRoot) check isInstalled("pkg2", storageRoot) # ============================================================================ # Query Function Tests # ============================================================================ suite "NPK Installation Queries (Task 13)": setup: let testDir = getTempDir() / "npk-query-test-" & $getTime().toUnix() let storageRoot = testDir / "storage" createDir(testDir) createDir(storageRoot) teardown: if dirExists(testDir): removeDir(testDir) test "Check if package is installed": ## Test isInstalled() function check not isInstalled("test-pkg", storageRoot) let pkgPath = createTestPackage("test-pkg", "1.0.0", testDir) discard installNPK(pkgPath, storageRoot) check isInstalled("test-pkg", storageRoot) test "Get installed package version": ## Test getInstalledVersion() function let version1 = getInstalledVersion("test-pkg", storageRoot) check version1.isNone let pkgPath = createTestPackage("test-pkg", "1.0.0", testDir) discard installNPK(pkgPath, storageRoot) let version2 = getInstalledVersion("test-pkg", storageRoot) check version2.isSome check version2.get() == "1.0.0" test "List installed packages": ## Test listInstalledPackages() function let list1 = listInstalledPackages(storageRoot) check list1.len == 0 let pkg1Path = createTestPackage("pkg1", "1.0.0", testDir) let pkg2Path = createTestPackage("pkg2", "2.0.0", testDir) discard installNPK(pkg1Path, storageRoot) discard installNPK(pkg2Path, storageRoot) let list2 = listInstalledPackages(storageRoot) check list2.len == 2 check "pkg1" in list2 check "pkg2" in list2 # ============================================================================ # Verification Tests # ============================================================================ suite "NPK Installation Verification (Task 13)": setup: let testDir = getTempDir() / "npk-verify-test-" & $getTime().toUnix() let storageRoot = testDir / "storage" createDir(testDir) createDir(storageRoot) teardown: if dirExists(testDir): removeDir(testDir) test "Verify valid installation": ## Test verifyInstallation() function let pkgPath = createTestPackage("test-pkg", "1.0.0", testDir) discard installNPK(pkgPath, storageRoot) let isValid = verifyInstallation("test-pkg", storageRoot) check isValid test "Verify fails for non-existent package": ## Verify detection of missing package let isValid = verifyInstallation("nonexistent", storageRoot) check not isValid test "Verify fails for corrupted installation": ## Verify detection of corrupted installation let pkgPath = createTestPackage("test-pkg", "1.0.0", testDir) discard installNPK(pkgPath, storageRoot) # Remove the references file to simulate corruption let refsPath = storageRoot / "cas" / "refs" / "npks" / "test-pkg.refs" removeFile(refsPath) # Verification should fail let isValid = verifyInstallation("test-pkg", storageRoot) check not isValid # ============================================================================ # Rollback Tests # ============================================================================ suite "NPK Installation Rollback (Task 13)": setup: let testDir = getTempDir() / "npk-rollback-test-" & $getTime().toUnix() let storageRoot = testDir / "storage" createDir(testDir) createDir(storageRoot) teardown: if dirExists(testDir): removeDir(testDir) test "Rollback on installation failure": ## **Requirement 11.2:** Rollback to previous state on failure # Create invalid package path let invalidPath = testDir / "nonexistent.npk" # Installation should fail let result = installNPK(invalidPath, storageRoot) check not result.success # Verify no artifacts left behind let manifestPath = storageRoot / "npks" / "test-pkg.kdl" check not fileExists(manifestPath) # ============================================================================ # Utility Function Tests # ============================================================================ suite "NPK Installation Utilities (Task 13)": test "Format install result - success": let result = InstallResult( success: true, packageName: "test-pkg", version: "1.0.0", installPath: "/path/to/manifest.kdl", chunksInstalled: 5, error: "" ) let str = $result check str.contains("Successfully installed") check str.contains("test-pkg") check str.contains("1.0.0") check str.contains("5") test "Format install result - failure": let result = InstallResult( success: false, packageName: "test-pkg", version: "", installPath: "", chunksInstalled: 0, error: "Package not found" ) let str = $result check str.contains("Failed") check str.contains("test-pkg") check str.contains("Package not found")