## 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