@@ -1351,6 +1351,224 @@ func TestLFUPolicyTiebreaker(t *testing.T) {
13511351 }
13521352}
13531353
1354+ // TestFIFOPolicyOptimized tests the O(1) FIFO policy operations
1355+ func TestFIFOPolicyOptimized (t * testing.T ) {
1356+ policy := NewFIFOPolicy ()
1357+ entries := []CacheEntry {
1358+ {RequestID : "req-0" },
1359+ {RequestID : "req-1" },
1360+ {RequestID : "req-2" },
1361+ }
1362+
1363+ // Test OnInsert and SelectVictim
1364+ for i , e := range entries {
1365+ policy .OnInsert (i , e .RequestID )
1366+ }
1367+
1368+ victim := policy .SelectVictim (entries )
1369+ if victim != 0 {
1370+ t .Errorf ("Expected victim 0 (oldest), got %d" , victim )
1371+ }
1372+
1373+ // Test Evict
1374+ evicted := policy .Evict ()
1375+ if evicted != 0 {
1376+ t .Errorf ("Expected evicted index 0, got %d" , evicted )
1377+ }
1378+
1379+ // Test UpdateIndex (simulating swap after eviction)
1380+ policy .UpdateIndex ("req-2" , 2 , 0 )
1381+ victim = policy .SelectVictim (entries )
1382+ if victim != 1 {
1383+ t .Errorf ("Expected victim 1 after swap, got %d" , victim )
1384+ }
1385+
1386+ // Test OnRemove
1387+ policy .OnRemove (1 , "req-1" )
1388+ victim = policy .SelectVictim (entries )
1389+ if victim != 0 {
1390+ t .Errorf ("Expected victim 0 (req-2 moved), got %d" , victim )
1391+ }
1392+ }
1393+
1394+ // TestLRUPolicyOptimized tests the O(1) LRU policy operations
1395+ func TestLRUPolicyOptimized (t * testing.T ) {
1396+ policy := NewLRUPolicy ()
1397+ entries := []CacheEntry {
1398+ {RequestID : "req-0" },
1399+ {RequestID : "req-1" },
1400+ {RequestID : "req-2" },
1401+ }
1402+
1403+ // Insert all entries
1404+ for i , e := range entries {
1405+ policy .OnInsert (i , e .RequestID )
1406+ }
1407+
1408+ // LRU order: req-2 (MRU) -> req-1 -> req-0 (LRU)
1409+ victim := policy .SelectVictim (entries )
1410+ if victim != 0 {
1411+ t .Errorf ("Expected victim 0 (LRU), got %d" , victim )
1412+ }
1413+
1414+ // Access req-0 to make it MRU
1415+ policy .OnAccess (0 , "req-0" )
1416+ victim = policy .SelectVictim (entries )
1417+ if victim != 1 {
1418+ t .Errorf ("Expected victim 1 after accessing req-0, got %d" , victim )
1419+ }
1420+
1421+ // Test Evict
1422+ evicted := policy .Evict ()
1423+ if evicted != 1 {
1424+ t .Errorf ("Expected evicted index 1, got %d" , evicted )
1425+ }
1426+
1427+ // Test UpdateIndex
1428+ policy .UpdateIndex ("req-2" , 2 , 1 )
1429+
1430+ // Test OnRemove
1431+ policy .OnRemove (1 , "req-2" )
1432+
1433+ // Only req-0 should remain
1434+ victim = policy .SelectVictim (entries )
1435+ if victim != 0 {
1436+ t .Errorf ("Expected victim 0, got %d" , victim )
1437+ }
1438+ }
1439+
1440+ // TestLFUPolicyOptimized tests the O(1) LFU policy operations
1441+ func TestLFUPolicyOptimized (t * testing.T ) {
1442+ policy := NewLFUPolicy ()
1443+ entries := []CacheEntry {
1444+ {RequestID : "req-0" },
1445+ {RequestID : "req-1" },
1446+ {RequestID : "req-2" },
1447+ }
1448+
1449+ // Insert all entries (all start with freq=1)
1450+ for i , e := range entries {
1451+ policy .OnInsert (i , e .RequestID )
1452+ }
1453+
1454+ // Access req-2 multiple times to increase frequency
1455+ for i := 0 ; i < 5 ; i ++ {
1456+ policy .OnAccess (2 , "req-2" )
1457+ }
1458+
1459+ // req-0 and req-1 have freq=1, req-2 has freq=6
1460+ victim := policy .SelectVictim (entries )
1461+ if victim != 0 && victim != 1 {
1462+ t .Errorf ("Expected victim 0 or 1 (lowest freq), got %d" , victim )
1463+ }
1464+
1465+ // Test Evict
1466+ evicted := policy .Evict ()
1467+ if evicted != 0 && evicted != 1 {
1468+ t .Errorf ("Expected evicted 0 or 1, got %d" , evicted )
1469+ }
1470+
1471+ // Test UpdateIndex
1472+ policy .UpdateIndex ("req-2" , 2 , 0 )
1473+
1474+ // Test OnRemove
1475+ policy .OnRemove (1 , "req-1" )
1476+ }
1477+
1478+ // TestExpirationHeapOperations tests all ExpirationHeap operations
1479+ func TestExpirationHeapOperations (t * testing.T ) {
1480+ now := time .Now ()
1481+ heap := NewExpirationHeap ()
1482+
1483+ // Test Add
1484+ heap .Add ("req-0" , 0 , now .Add (1 * time .Hour ))
1485+ heap .Add ("req-1" , 1 , now .Add (30 * time .Minute ))
1486+ heap .Add ("req-2" , 2 , now .Add (2 * time .Hour ))
1487+
1488+ // Test Size
1489+ if heap .Size () != 3 {
1490+ t .Errorf ("Expected size 3, got %d" , heap .Size ())
1491+ }
1492+
1493+ // Test PeekNext (should be req-1, earliest expiration)
1494+ reqID , idx , expiresAt , ok := heap .PeekNext ()
1495+ if ! ok || reqID != "req-1" || idx != 1 {
1496+ t .Errorf ("Expected PeekNext to return req-1, got %s (idx=%d, ok=%v)" , reqID , idx , ok )
1497+ }
1498+ _ = expiresAt
1499+
1500+ // Test UpdateExpiration (move req-1 to later)
1501+ heap .UpdateExpiration ("req-1" , now .Add (3 * time .Hour ))
1502+
1503+ // Now req-0 should be earliest
1504+ reqID , _ , _ , ok = heap .PeekNext ()
1505+ if ! ok || reqID != "req-0" {
1506+ t .Errorf ("Expected PeekNext to return req-0 after update, got %s" , reqID )
1507+ }
1508+
1509+ // Test UpdateIndex
1510+ heap .UpdateIndex ("req-0" , 5 )
1511+
1512+ // Test Remove
1513+ heap .Remove ("req-0" )
1514+ if heap .Size () != 2 {
1515+ t .Errorf ("Expected size 2 after remove, got %d" , heap .Size ())
1516+ }
1517+
1518+ // Test PopExpired
1519+ heap .Add ("req-expired" , 10 , now .Add (- 1 * time .Hour )) // Already expired
1520+ expired := heap .PopExpired (now )
1521+ if len (expired ) != 1 || expired [0 ] != "req-expired" {
1522+ t .Errorf ("Expected 1 expired entry, got %v" , expired )
1523+ }
1524+ }
1525+
1526+ // TestInMemoryCacheEviction tests cache eviction with O(1) policies
1527+ func TestInMemoryCacheEviction (t * testing.T ) {
1528+ cache := NewInMemoryCache (InMemoryCacheOptions {
1529+ Enabled : true ,
1530+ MaxEntries : 3 ,
1531+ TTLSeconds : 3600 ,
1532+ SimilarityThreshold : 0.9 ,
1533+ EvictionPolicy : LRUEvictionPolicyType ,
1534+ })
1535+
1536+ // Add entries up to max
1537+ for i := 0 ; i < 3 ; i ++ {
1538+ embedding := make ([]float32 , 384 )
1539+ embedding [i ] = 1.0
1540+ cache .mu .Lock ()
1541+ cache .entries = append (cache .entries , CacheEntry {
1542+ RequestID : fmt .Sprintf ("req-%d" , i ),
1543+ Query : fmt .Sprintf ("query %d" , i ),
1544+ Embedding : embedding ,
1545+ })
1546+ idx := len (cache .entries ) - 1
1547+ cache .entryMap [fmt .Sprintf ("req-%d" , i )] = idx
1548+ cache .registerEntryWithEvictionPolicy (idx , fmt .Sprintf ("req-%d" , i ))
1549+ cache .mu .Unlock ()
1550+ }
1551+
1552+ // Verify we have 3 entries
1553+ stats := cache .GetStats ()
1554+ if stats .TotalEntries != 3 {
1555+ t .Errorf ("Expected 3 entries, got %d" , stats .TotalEntries )
1556+ }
1557+
1558+ // Add one more to trigger eviction
1559+ cache .mu .Lock ()
1560+ cache .evictOne ()
1561+ cache .mu .Unlock ()
1562+
1563+ // Should have 2 entries now
1564+ cache .mu .RLock ()
1565+ count := len (cache .entries )
1566+ cache .mu .RUnlock ()
1567+ if count != 2 {
1568+ t .Errorf ("Expected 2 entries after eviction, got %d" , count )
1569+ }
1570+ }
1571+
13541572// TestHybridCacheDisabled tests that disabled hybrid cache returns immediately
13551573func TestHybridCacheDisabled (t * testing.T ) {
13561574 cache , err := NewHybridCache (HybridCacheOptions {
0 commit comments