nip/tests/test_unified_storage.nim

217 lines
6.4 KiB
Nim

## Property-Based Tests for Unified Storage
##
## Feature: 01-nip-unified-storage-and-formats
## Property 2: Chunk Integrity
## Validates: Requirements 2.2
##
## This test verifies that xxh3 hash integrity is maintained for all chunks:
## For any CAS chunk, the xxh3 hash SHALL match the chunk content after decompression
import std/[unittest, os, random, strutils]
import ../src/nip/unified_storage
import ../src/nip/xxhash
# Simple property-based testing framework
type
TestCase = object
data: string
description: string
proc generateRandomData(size: int): string =
## Generate random data for testing
result = newString(size)
for i in 0..<size:
result[i] = char(rand(255))
proc generateTestCases(count: int): seq[TestCase] =
## Generate test cases with various data patterns
result = @[]
# Edge cases
result.add(TestCase(data: "", description: "empty string"))
result.add(TestCase(data: "a", description: "single character"))
result.add(TestCase(data: "Hello, World!", description: "simple text"))
# Random data of various sizes
for i in 0..<count:
let size = rand(1..10000)
result.add(TestCase(
data: generateRandomData(size),
description: "random data size=" & $size
))
# Repeated patterns
result.add(TestCase(data: "a".repeat(1000), description: "repeated character"))
result.add(TestCase(data: "ab".repeat(500), description: "repeated pattern"))
# Binary data
var binaryData = ""
for i in 0..255:
binaryData.add(char(i))
result.add(TestCase(data: binaryData, description: "all byte values"))
suite "Unified Storage - Property Tests":
setup:
# Create temporary test directory
let testRoot = getTempDir() / "nip_test_" & $rand(100000)
let storageRoot = initStorageRoot(testRoot)
discard createStorageStructure(storageRoot)
teardown:
# Clean up test directory
try:
removeDir(testRoot)
except:
discard
test "Property 2: Chunk Integrity - Hash matches content after storage":
## **Feature: 01-nip-unified-storage-and-formats, Property 2: Chunk Integrity**
## **Validates: Requirements 2.2**
##
## For any chunk data, calculating the hash and then verifying it
## should always succeed. This ensures hash integrity is maintained.
let testCases = generateTestCases(100)
var passCount = 0
var failCount = 0
for tc in testCases:
# Calculate hash
let hash = calculateXXH3(tc.data)
# Verify hash matches original data
let verified = verifyXXH3(tc.data, hash)
if verified:
passCount.inc
else:
failCount.inc
echo "FAILED: ", tc.description
echo " Data length: ", tc.data.len
echo " Hash: ", $hash
echo "\nProperty Test Results:"
echo " Total cases: ", testCases.len
echo " Passed: ", passCount
echo " Failed: ", failCount
check failCount == 0
check passCount == testCases.len
test "Property 2: Chunk Integrity - Hash is deterministic":
## Hashing the same data multiple times should produce the same hash
let testData = "NexusOS unified storage test data"
var hashes: seq[XXH3Hash] = @[]
# Calculate hash 100 times
for i in 0..<100:
hashes.add(calculateXXH3(testData))
# All hashes should be identical
let firstHash = hashes[0]
for h in hashes:
check h == firstHash
test "Property 2: Chunk Integrity - Different data produces different hashes":
## Different data should produce different hashes (collision resistance)
var hashes: seq[XXH3Hash] = @[]
var dataSet: seq[string] = @[]
# Generate 1000 different data samples
for i in 0..<1000:
let data = generateRandomData(rand(10..1000))
dataSet.add(data)
hashes.add(calculateXXH3(data))
# Check for collisions
var collisions = 0
for i in 0..<hashes.len:
for j in (i+1)..<hashes.len:
if hashes[i] == hashes[j] and dataSet[i] != dataSet[j]:
collisions.inc
echo "COLLISION DETECTED:"
echo " Data 1 length: ", dataSet[i].len
echo " Data 2 length: ", dataSet[j].len
echo " Hash: ", $hashes[i]
echo "\nCollision Test Results:"
echo " Total comparisons: ", (hashes.len * (hashes.len - 1)) div 2
echo " Collisions found: ", collisions
check collisions == 0
test "Property 2: Chunk Integrity - Byte sequence hashing":
## Hashing byte sequences should work correctly
let testCases = generateTestCases(50)
for tc in testCases:
# Convert string to byte sequence
var bytes: seq[byte] = @[]
for c in tc.data:
bytes.add(byte(c))
# Hash both string and bytes
let stringHash = calculateXXH3(tc.data)
let bytesHash = calculateXXH3(bytes)
# They should produce the same hash
check stringHash == bytesHash
test "Storage Structure Creation":
## Verify that storage structure is created correctly
let root = initStorageRoot()
check createStorageStructure(root)
check verifyStorageStructure(root)
# Verify all directories exist
check dirExists(root.basePath)
check dirExists(root.casPath)
check dirExists(root.casPath / "chunks")
check dirExists(root.casPath / "refs")
check dirExists(root.casPath / "refs" / "npks")
check dirExists(root.casPath / "refs" / "nips")
check dirExists(root.casPath / "refs" / "nexters")
check dirExists(root.npksPath)
check dirExists(root.nipsPath)
check dirExists(root.nextersPath)
check fileExists(root.auditLogPath)
test "CAS Store Initialization":
## Verify CAS store can be initialized
let root = initStorageRoot()
discard createStorageStructure(root)
let store = initCASStore(root.casPath)
check store.rootPath == root.casPath
check store.chunksPath == root.casPath / "chunks"
check store.refsPath == root.casPath / "refs"
check store.auditLog == root.auditLogPath
test "Audit Log Writing":
## Verify audit log entries can be written
let root = initStorageRoot()
discard createStorageStructure(root)
let store = initCASStore(root.casPath)
store.logAuditEntry("TEST", "Test audit entry")
# Verify log file was updated
check fileExists(store.auditLog)
let logContent = readFile(store.auditLog)
check "TEST" in logContent
check "Test audit entry" in logContent
when isMainModule:
# Run tests with random seed for reproducibility
randomize(12345)
echo "Running Unified Storage Property Tests..."
echo "Random seed: 12345"
echo ""