import unittest, os, strutils, tables, options, json import ../src/nimpak/cas import ../src/nip/types suite "CAS Performance Optimizations Tests": var cas: CasManager testRoot = getTempDir() / "nip_optim_test_" & $getCurrentProcessId() testFile = testRoot / "large_file.dat" setup: createDir(testRoot) cas = initCasManager(testRoot) # Create a dummy large file (larger than 1MB to trigger chunking) var f = open(testFile, fmWrite) # Write 1.5MB let chunk = newString(1024 * 64) # 64KB for i in 0..<24: f.write(chunk) f.close() teardown: removeDir(testRoot) test "Index Caching": # Initial state check cas.indexCache.isNone # Load index (should create empty one) discard cas.loadIndex() check cas.indexCache.isSome let idx = cas.indexCache.get() check idx.totalChunks == 0 # Update index cas.updateIndex(100, 1) check cas.indexCache.get().totalChunks == 1 check cas.indexCache.get().totalSize == 100 # Save and reload discard cas.saveIndex() # Reset manager to clear cache var newCas = initCasManager(testRoot) discard newCas.loadIndex() check newCas.indexCache.get().totalChunks == 1 check newCas.indexCache.get().totalSize == 100 test "Existence Caching": let data = "test data" let res = cas.storeObject(data.toOpenArrayByte(0, data.len-1)) let hash = res.get().hash # Cache should be empty initially (or populated by storeObject? storeObject doesn't update existenceCache currently) # Wait, storeObject calls objectExists. # But objectExists updates cache ONLY if found. # When we store a NEW object, objectExists returns false. # Then we write file. # So cache is NOT updated for the new object yet. check not cas.existenceCache.hasKey(hash) # First check - should hit disk and populate cache check cas.objectExists(hash) check cas.existenceCache.hasKey(hash) check cas.existenceCache[hash].endsWith(hash.split('-')[1]) # Second check - should hit cache # Since our cache verifies file existence, deleting the file invalidates the cache. # So we just verify the cache is populated. check cas.existenceCache.hasKey(hash) check cas.existenceCache[hash].endsWith(hash.split('-')[1]) # Invalidate cache manually cas.existenceCache.del(hash) check not cas.existenceCache.hasKey(hash) test "Parallel Store Correctness": # We test storeFileParallel for correctness let res = cas.storeFileParallel(testFile) if not res.isOk: echo "Store failed: ", res.getError().msg check res.isOk let obj = res.get() check obj.chunks.len > 0 # Verify we can retrieve it let outFile = testRoot / "retrieved.dat" let retRes = cas.retrieveFile(obj.hash, outFile) if not retRes.isOk: echo "Retrieve failed: ", retRes.errValue.msg check retRes.isOk if retRes.isOk: check getFileInfo(outFile).size == getFileInfo(testFile).size else: # Debug: check if it wrote a manifest file if fileExists(outFile): echo "Output file size: ", getFileInfo(outFile).size echo "Output content preview: ", readFile(outFile)[0..100] test "Manifest Caching": # Store a file (creates manifest) let res = cas.storeFile(testFile) let hash = res.get().hash check not cas.manifestCache.hasKey(hash) # Retrieve file - should populate manifest cache let outFile = testRoot / "retrieved_manifest.dat" discard cas.retrieveFile(hash, outFile) check cas.manifestCache.hasKey(hash) check cas.manifestCache[hash].kind == JObject check cas.manifestCache[hash].hasKey("chunks")