nip/tests/test_sync_engine.nim

201 lines
6.4 KiB
Nim

## Test suite for the synchronization engine
##
## This module tests the bloom filter handshake, delta object creation,
## and incremental synchronization functionality.
import std/[unittest, times, json, tables, sequtils, asyncdispatch]
import ../src/nimpak/remote/sync_engine
import ../src/nimpak/cas
import ../src/nimpak/security/event_logger
suite "Synchronization Engine Tests":
setup:
# Initialize test environment
let testCasPath = "/tmp/test_cas"
let testLogPath = "/tmp/test_security.log"
# Create test CAS manager
let casManager = newCasManager(testCasPath, testCasPath)
# Create test event logger
let eventLogger = newSecurityEventLogger(testLogPath, testCasPath)
# Create sync engine with test configuration
var config = getDefaultSyncEngineConfig()
config.bloomFilterSize = 1000 # Smaller for testing
config.syncIntervalSeconds = 10 # Faster for testing
var syncEngine = newSyncEngine(casManager, eventLogger, config)
test "Bloom Filter Creation and Operations":
var filter = newBloomFilter(100, 0.01)
# Test adding items
filter.add("test-hash-1")
filter.add("test-hash-2")
filter.add("test-hash-3")
# Test contains (should return true for added items)
check filter.contains("test-hash-1") == true
check filter.contains("test-hash-2") == true
check filter.contains("test-hash-3") == true
# Test false negatives (should not occur)
check filter.contains("non-existent-hash") == false or true # May be false positive
# Test serialization
let serialized = filter.serialize()
check serialized.len > 0
# Test deserialization
let deserialized = deserializeBloomFilter(serialized)
check deserialized.size == filter.size
check deserialized.hashFunctions == filter.hashFunctions
test "Bandwidth Limiter":
var limiter = newBandwidthLimiter(1000) # 1KB/s limit
# Test bandwidth checking
check limiter.checkBandwidth(500) == true # Should allow 500 bytes
check limiter.checkBandwidth(600) == false # Should deny 600 more bytes (total 1100)
# Test bandwidth reset after time window
limiter.windowStart = now() - initDuration(seconds = 2) # Simulate time passage
check limiter.checkBandwidth(500) == true # Should allow after reset
test "Mirror Management":
var engine = syncEngine
# Test adding mirrors
let result1 = engine.addMirror("test-mirror-1", "https://test1.example.com", 100)
check result1.success == true
let result2 = engine.addMirror("test-mirror-2", "https://test2.example.com", 50)
check result2.success == true
# Test duplicate mirror
let result3 = engine.addMirror("test-mirror-1", "https://duplicate.example.com", 75)
check result3.success == false
check result3.errorCode == 409
# Test mirror selection
let bestMirror = engine.selectBestMirror()
check bestMirror.isSome()
check bestMirror.get().id == "test-mirror-1" # Higher priority
# Test removing mirror
let removeResult = engine.removeMirror("test-mirror-2")
check removeResult.success == true
test "Delta Object Creation":
let engine = syncEngine
let testData = "This is test data for delta object creation"
# Store test data in CAS
let storeResult = engine.localCasManager.storeObject(testData.toOpenArrayByte(0, testData.len - 1))
check storeResult.isOk == true
let casObject = storeResult.get()
# Create delta object
let deltaResult = engine.createDeltaObject(casObject.hash)
check deltaResult.success == true
let delta = deltaResult.value
check delta.objectHash == casObject.hash
check delta.deltaType == "add"
check delta.originalSize == testData.len.int64
test "Sync Event Extraction":
let engine = syncEngine
# Create some test security events
var testEvent = createSecurityEvent(
EventPackageVerification,
SeverityInfo,
"test-source",
"Test package verification",
%*{"package_hash": "blake2b-test123"}
)
engine.eventLogger.logSecurityEvent(testEvent)
# Extract sync events
let syncEvents = engine.extractSyncEventsFromSecurityLog(now() - initDuration(hours = 1))
# Should find at least one sync event
check syncEvents.len >= 1
# Check event properties
if syncEvents.len > 0:
let syncEvent = syncEvents[0]
check syncEvent.eventType == SyncPackageUpdated
check syncEvent.objectHash == "blake2b-test123"
test "Bloom Filter Update from Events":
var engine = syncEngine
# Create test sync events
let events = @[
SyncEvent(
id: "test-1",
timestamp: now(),
eventType: SyncPackageAdded,
objectHash: "blake2b-hash1",
metadata: newJObject(),
sequenceNumber: 1
),
SyncEvent(
id: "test-2",
timestamp: now(),
eventType: SyncPackageUpdated,
objectHash: "blake2b-hash2",
metadata: newJObject(),
sequenceNumber: 2
)
]
# Update bloom filter
engine.updateBloomFilterFromEvents(events)
# Check that objects were added to bloom filter and known objects
check engine.syncState.bloomFilter.contains("blake2b-hash1") == true
check engine.syncState.bloomFilter.contains("blake2b-hash2") == true
check "blake2b-hash1" in engine.syncState.knownObjects
check "blake2b-hash2" in engine.syncState.knownObjects
test "Mirror Health Updates":
var engine = syncEngine
# Add test mirror
discard engine.addMirror("health-test", "https://health.example.com", 50)
# Update health with good metrics
engine.updateMirrorHealth("health-test", 100.0, true) # 100ms latency, success
let mirror1 = engine.mirrors["health-test"]
check mirror1.status == MirrorActive
check mirror1.latency == 100.0
check mirror1.reliability > 0.5
# Update health with bad metrics
engine.updateMirrorHealth("health-test", 6000.0, false) # 6s latency, failure
let mirror2 = engine.mirrors["health-test"]
check mirror2.status == MirrorSlow or mirror2.status == MirrorUnreachable
check mirror2.reliability < 0.9 # Should decrease
teardown:
# Clean up test files
try:
removeDir("/tmp/test_cas")
removeFile("/tmp/test_security.log")
except:
discard # Ignore cleanup errors
# Run async tests
when isMainModule:
# Note: Async tests would need special handling in a real test suite
# For now, we just run the synchronous tests
discard