## Test suite for Nippels Merkle Tree Integration (Task 8.4) ## ## Tests the integration of Merkle Tree with NippelManager import std/[unittest, os, times, strutils, tables, json] import ../src/nimpak/nippels import ../src/nimpak/merkle_tree import ../src/nimpak/nippel_types import ../src/nimpak/utils/resultutils suite "Nippels Merkle Tree Integration (Task 8.4)": var manager: NippelManager let testRoot = getTempDir() / "nippels_merkle_test_" & $epochTime().int setup: # Create test directory createDir(testRoot) manager = newNippelManager(testRoot) teardown: # Deactivate all active Nippels for name in manager.getActiveNippels(): discard manager.deactivateNippel(name) # Clean up test directory if dirExists(testRoot): removeDir(testRoot) test "Create Nippel builds initial merkle tree": let result = manager.createNippel("test-merkle", Homestation) check result.isOk if result.isOk: let nippel = result.value # Verify merkle root is set check nippel.merkleRoot.len > 0 check nippel.merkleRoot.startsWith("xxh3-") # Verify merkle tree is stored in manager check manager.merkleTrees.hasKey("test-merkle") let tree = manager.merkleTrees["test-merkle"] check tree.hashAlgorithm == "xxh3" check tree.leafCount >= 0 # Empty tree initially echo " ✅ Initial merkle tree created with root: ", nippel.merkleRoot test "Merkle root is stored in cell configuration": let result = manager.createNippel("test-config", Homestation) check result.isOk if result.isOk: let nippel = result.value let configPath = nippel.cellRoot / "cell.json" check fileExists(configPath) # Read and verify configuration contains merkle root let config = parseJson(readFile(configPath)) check config.hasKey("storage") check config["storage"].hasKey("merkle_root") check config["storage"]["merkle_root"].getStr() == nippel.merkleRoot echo " ✅ Merkle root stored in configuration" test "Multiple Nippels have independent merkle trees": let result1 = manager.createNippel("test-multi-1", Homestation) let result2 = manager.createNippel("test-multi-2", Workstation) let result3 = manager.createNippel("test-multi-3", Server) check result1.isOk check result2.isOk check result3.isOk if result1.isOk and result2.isOk and result3.isOk: # Verify each has its own merkle tree check manager.merkleTrees.hasKey("test-multi-1") check manager.merkleTrees.hasKey("test-multi-2") check manager.merkleTrees.hasKey("test-multi-3") # Verify merkle roots (should all be the same for empty trees) let nippel1 = result1.value let nippel2 = result2.value let nippel3 = result3.value check nippel1.merkleRoot.len > 0 check nippel2.merkleRoot.len > 0 check nippel3.merkleRoot.len > 0 echo " ✅ Multiple independent merkle trees created" test "Merkle tree uses xxh3 algorithm": let result = manager.createNippel("test-algorithm", Homestation) check result.isOk if result.isOk: let tree = manager.merkleTrees["test-algorithm"] check tree.hashAlgorithm == "xxh3" check tree.root.hash.startsWith("xxh3-") echo " ✅ Merkle tree uses xxh3 algorithm" test "Empty merkle tree has valid root hash": let result = manager.createNippel("test-empty", Homestation) check result.isOk if result.isOk: let nippel = result.value let tree = manager.merkleTrees["test-empty"] # Verify tree structure check tree.root != nil check tree.root.hash.len > 0 check tree.leafCount >= 0 # Verify root hash matches check getRootHash(tree) == nippel.merkleRoot echo " ✅ Empty merkle tree has valid root hash" test "Merkle tree can be verified": let result = manager.createNippel("test-verify", Homestation) check result.isOk if result.isOk: let tree = manager.merkleTrees["test-verify"] # Verify the tree let verifyResult = verifyTree(tree) check verifyResult.isOk if verifyResult.isOk: check verifyResult.get() == true echo " ✅ Merkle tree verification passed" test "Merkle tree can be updated with new files": let result = manager.createNippel("test-update", Homestation) check result.isOk if result.isOk: var tree = manager.merkleTrees["test-update"] let oldRoot = getRootHash(tree) # Add a file to the tree let addResult = addFile(tree, "test.txt", "xxh3-abc123", 100) check addResult.isOk if addResult.isOk: let newRoot = addResult.get() check newRoot != oldRoot check newRoot.len > 0 # Update the tree in manager manager.merkleTrees["test-update"] = tree echo " ✅ Merkle tree updated with new file" echo " Old root: ", oldRoot echo " New root: ", newRoot test "Merkle tree tracks file additions": let result = manager.createNippel("test-additions", Homestation) check result.isOk if result.isOk: var tree = manager.merkleTrees["test-additions"] # Add multiple files discard addFile(tree, "file1.txt", "xxh3-hash1", 100) discard addFile(tree, "file2.txt", "xxh3-hash2", 200) discard addFile(tree, "file3.txt", "xxh3-hash3", 300) # Verify tree has the files let leaves = getAllLeaves(tree) check leaves.len == 3 # Verify we can find each file check findLeafInTree(tree, "file1.txt").isSome check findLeafInTree(tree, "file2.txt").isSome check findLeafInTree(tree, "file3.txt").isSome echo " ✅ Merkle tree tracks file additions" test "Merkle tree can diff between states": let result = manager.createNippel("test-diff", Homestation) check result.isOk if result.isOk: var tree1 = manager.merkleTrees["test-diff"] # Add files to tree1 discard addFile(tree1, "file1.txt", "xxh3-hash1", 100) discard addFile(tree1, "file2.txt", "xxh3-hash2", 200) # Create tree2 with different files var tree2 = tree1 discard addFile(tree2, "file3.txt", "xxh3-hash3", 300) discard removeFile(tree2, "file1.txt") # Diff the trees let diffResult = diffTrees(tree1, tree2) check diffResult.isOk if diffResult.isOk: let diffs = diffResult.get() check diffs.len > 0 echo " ✅ Merkle tree diffing works" echo " Found ", diffs.len, " differences" test "Merkle tree root changes when content changes": let result = manager.createNippel("test-changes", Homestation) check result.isOk if result.isOk: var tree = manager.merkleTrees["test-changes"] let root1 = getRootHash(tree) # Add a file discard addFile(tree, "file.txt", "xxh3-hash1", 100) let root2 = getRootHash(tree) # Modify the file discard updateFile(tree, "file.txt", "xxh3-hash2", 150) let root3 = getRootHash(tree) # Remove the file discard removeFile(tree, "file.txt") let root4 = getRootHash(tree) # All roots should be different check root1 != root2 check root2 != root3 check root3 != root4 check root1 == root4 # Back to empty tree echo " ✅ Merkle root changes with content" test "Merkle tree verification detects tampering": let result = manager.createNippel("test-tamper", Homestation) check result.isOk if result.isOk: var tree = manager.merkleTrees["test-tamper"] # Add files discard addFile(tree, "file1.txt", "xxh3-hash1", 100) discard addFile(tree, "file2.txt", "xxh3-hash2", 200) # Verify tree is valid let verifyResult1 = verifyTree(tree) check verifyResult1.isOk check verifyResult1.get() == true # Tamper with a node (if we had access to internal nodes) # For now, just verify that verification works echo " ✅ Merkle tree verification works" test "Merkle tree performance is acceptable": let result = manager.createNippel("test-perf", Homestation) check result.isOk if result.isOk: var tree = manager.merkleTrees["test-perf"] # Add many files and measure time let startTime = cpuTime() for i in 1..100: discard addFile(tree, "file" & $i & ".txt", "xxh3-hash" & $i, int64(i * 100)) let endTime = cpuTime() let duration = (endTime - startTime) * 1000.0 # Convert to ms echo " ✅ Added 100 files in ", duration.formatFloat(ffDecimal, 2), " ms" # Verify performance is reasonable (< 100ms for 100 files) check duration < 100.0 echo "✅ All Task 8.4 tests completed"