279 lines
8.6 KiB
Nim
279 lines
8.6 KiB
Nim
## 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"
|