2025-08-25 09:52:32 -07:00
import { describe , it , expect , beforeEach , afterEach } from 'vitest'
import { BrainyData } from '../src/index.js'
import { RequestDeduplicatorAugmentation } from '../src/augmentations/requestDeduplicatorAugmentation.js'
describe ( 'Request Deduplicator Augmentation' , ( ) = > {
let db : BrainyData | null = null
// Helper to create test vectors
const createTestVector = ( seed : number = 0 ) = > {
return new Array ( 384 ) . fill ( 0 ) . map ( ( _ , i ) = > Math . sin ( i + seed ) * 0.5 )
}
afterEach ( async ( ) = > {
if ( db ) {
await db . cleanup ? . ( )
db = null
}
// Force garbage collection if available
if ( global . gc ) {
global . gc ( )
}
} )
describe ( 'Configuration and Initialization' , ( ) = > {
it ( 'should be enabled by default' , async ( ) = > {
db = new BrainyData ( )
await db . init ( )
// Request deduplicator should be active
// Test by making duplicate searches
const vector = createTestVector ( 1 )
2025-08-26 12:03:45 -07:00
const promise1 = db . search ( vector , { limit : 5 } )
const promise2 = db . search ( vector , { limit : 5 } )
2025-08-25 09:52:32 -07:00
const [ results1 , results2 ] = await Promise . all ( [ promise1 , promise2 ] )
// Both should return same results
expect ( results1 . length ) . toBe ( results2 . length )
} )
it ( 'should accept custom TTL configuration' , async ( ) = > {
db = new BrainyData ( {
requestDeduplicator : {
enabled : true ,
ttl : 1000 , // 1 second TTL
maxSize : 100
}
} )
await db . init ( )
// Add test data
await db . add ( createTestVector ( 1 ) , { id : 'test1' } )
// Should work with custom config
2025-08-26 12:03:45 -07:00
const results = await db . search ( createTestVector ( 1 ) , { limit : 1 } )
2025-08-25 09:52:32 -07:00
expect ( results . length ) . toBeGreaterThan ( 0 )
} )
} )
describe ( 'Deduplication Behavior' , ( ) = > {
beforeEach ( async ( ) = > {
db = new BrainyData ( {
requestDeduplicator : {
enabled : true ,
ttl : 500 , // 500ms TTL for testing
maxSize : 10
}
} )
await db . init ( )
// Add test data
for ( let i = 0 ; i < 10 ; i ++ ) {
await db . add ( createTestVector ( i ) , {
id : ` item ${ i } ` ,
data : ` Test item ${ i } `
} )
}
} )
it ( 'should deduplicate identical concurrent searches' , async ( ) = > {
const searchVector = createTestVector ( 5 )
// Track if searches are actually executed
let searchCount = 0
const originalSearch = db ! . search . bind ( db )
db ! . search = async function ( . . . args : any [ ] ) {
searchCount ++
return originalSearch . apply ( this , args )
}
// Make multiple identical searches concurrently
const promises = [ ]
for ( let i = 0 ; i < 5 ; i ++ ) {
2025-08-26 12:03:45 -07:00
promises . push ( db ! . search ( searchVector , { limit : 3 } ) )
2025-08-25 09:52:32 -07:00
}
const results = await Promise . all ( promises )
// All should return same results
for ( let i = 1 ; i < results . length ; i ++ ) {
expect ( results [ i ] . length ) . toBe ( results [ 0 ] . length )
expect ( results [ i ] [ 0 ] ? . id ) . toBe ( results [ 0 ] [ 0 ] ? . id )
}
// Should have only executed once (or very few times)
expect ( searchCount ) . toBeLessThanOrEqual ( 2 )
} )
it ( 'should not deduplicate different searches' , async ( ) = > {
// Make different searches
const promises = [ ]
for ( let i = 0 ; i < 5 ; i ++ ) {
const uniqueVector = createTestVector ( i * 10 )
2025-08-26 12:03:45 -07:00
promises . push ( db ! . search ( uniqueVector , { limit : 2 } ) )
2025-08-25 09:52:32 -07:00
}
const results = await Promise . all ( promises )
// Results might be different
const uniqueResults = new Set ( results . map ( r = > JSON . stringify ( r . map ( x = > x . id ) ) ) )
expect ( uniqueResults . size ) . toBeGreaterThan ( 1 )
} )
it ( 'should respect TTL for cache expiration' , async ( ) = > {
const searchVector = createTestVector ( 1 )
// First search
2025-08-26 12:03:45 -07:00
const result1 = await db ! . search ( searchVector , { limit : 3 } )
2025-08-25 09:52:32 -07:00
// Immediate second search (should be cached)
2025-08-26 12:03:45 -07:00
const result2 = await db ! . search ( searchVector , { limit : 3 } )
2025-08-25 09:52:32 -07:00
expect ( result2 ) . toEqual ( result1 )
// Wait for TTL to expire
await new Promise ( resolve = > setTimeout ( resolve , 600 ) )
// Third search (cache expired, should re-execute)
2025-08-26 12:03:45 -07:00
const result3 = await db ! . search ( searchVector , { limit : 3 } )
2025-08-25 09:52:32 -07:00
// Results should be same content but might be new objects
expect ( result3 . length ) . toBe ( result1 . length )
} )
} )
describe ( 'Performance Impact' , ( ) = > {
beforeEach ( async ( ) = > {
db = new BrainyData ( {
requestDeduplicator : {
enabled : true ,
ttl : 5000
}
} )
await db . init ( )
// Add substantial test data
for ( let i = 0 ; i < 100 ; i ++ ) {
await db . add ( createTestVector ( i ) , { id : ` perf ${ i } ` } )
}
} )
it ( 'should improve performance for duplicate requests' , async ( ) = > {
const searchVector = createTestVector ( 50 )
// First search (cold)
const start1 = performance . now ( )
2025-08-26 12:03:45 -07:00
await db ! . search ( searchVector , { limit : 10 } )
2025-08-25 09:52:32 -07:00
const time1 = performance . now ( ) - start1
// Second search (cached)
const start2 = performance . now ( )
2025-08-26 12:03:45 -07:00
await db ! . search ( searchVector , { limit : 10 } )
2025-08-25 09:52:32 -07:00
const time2 = performance . now ( ) - start2
// Cached should be much faster
expect ( time2 ) . toBeLessThan ( time1 * 0.5 )
} )
it ( 'should handle high concurrency efficiently' , async ( ) = > {
const searchVector = createTestVector ( 25 )
// Make many concurrent identical requests
const startTime = performance . now ( )
const promises = [ ]
for ( let i = 0 ; i < 100 ; i ++ ) {
2025-08-26 12:03:45 -07:00
promises . push ( db ! . search ( searchVector , { limit : 5 } ) )
2025-08-25 09:52:32 -07:00
}
await Promise . all ( promises )
const elapsed = performance . now ( ) - startTime
// Should complete quickly due to deduplication
expect ( elapsed ) . toBeLessThan ( 1000 ) // Under 1 second for 100 requests
} )
} )
describe ( 'Cache Management' , ( ) = > {
it ( 'should respect maximum cache size' , async ( ) = > {
const dedup = new RequestDeduplicatorAugmentation ( {
ttl : 10000 , // Long TTL
maxSize : 5 // Small cache
} )
await dedup . initialize ( {
brain : { } ,
storage : { } ,
config : { } ,
log : ( ) = > { }
} as any )
// Add more than max size
for ( let i = 0 ; i < 10 ; i ++ ) {
const key = ` search- ${ i } `
// Simulate caching (implementation specific)
}
const stats = dedup . getStats ( )
expect ( stats . cacheSize ) . toBeLessThanOrEqual ( 5 )
} )
it ( 'should use LRU eviction strategy' , async ( ) = > {
db = new BrainyData ( {
requestDeduplicator : {
enabled : true ,
ttl : 10000 ,
maxSize : 3
}
} )
await db . init ( )
// Add test data
for ( let i = 0 ; i < 5 ; i ++ ) {
await db . add ( createTestVector ( i ) , { id : ` lru ${ i } ` } )
}
// Make searches to fill cache
2025-08-26 12:03:45 -07:00
await db . search ( createTestVector ( 1 ) , { limit : 1 } ) // Cache entry 1
await db . search ( createTestVector ( 2 ) , { limit : 1 } ) // Cache entry 2
await db . search ( createTestVector ( 3 ) , { limit : 1 } ) // Cache entry 3
2025-08-25 09:52:32 -07:00
// Access entry 1 again (makes it recently used)
2025-08-26 12:03:45 -07:00
await db . search ( createTestVector ( 1 ) , { limit : 1 } )
2025-08-25 09:52:32 -07:00
// Add new entry (should evict entry 2, not 1)
2025-08-26 12:03:45 -07:00
await db . search ( createTestVector ( 4 ) , { limit : 1 } )
2025-08-25 09:52:32 -07:00
// Entry 1 should still be cached (was recently used)
const start = performance . now ( )
2025-08-26 12:03:45 -07:00
await db . search ( createTestVector ( 1 ) , { limit : 1 } )
2025-08-25 09:52:32 -07:00
const time = performance . now ( ) - start
expect ( time ) . toBeLessThan ( 5 ) // Should be very fast (cached)
} )
} )
describe ( 'Operation Types' , ( ) = > {
beforeEach ( async ( ) = > {
db = new BrainyData ( {
requestDeduplicator : {
enabled : true ,
ttl : 1000
}
} )
await db . init ( )
// Add test data
for ( let i = 0 ; i < 20 ; i ++ ) {
await db . add ( createTestVector ( i ) , {
id : ` op ${ i } ` ,
type : i < 10 ? 'typeA' : 'typeB'
} )
}
} )
it ( 'should deduplicate search operations' , async ( ) = > {
const vector = createTestVector ( 5 )
const promises = [
2025-08-26 12:03:45 -07:00
db ! . search ( vector , { limit : 5 } ) ,
db ! . search ( vector , { limit : 5 } ) ,
db ! . search ( vector , { limit : 5 } )
2025-08-25 09:52:32 -07:00
]
const results = await Promise . all ( promises )
// All should get same results
expect ( results [ 0 ] ) . toEqual ( results [ 1 ] )
expect ( results [ 1 ] ) . toEqual ( results [ 2 ] )
} )
it ( 'should deduplicate searchText operations' , async ( ) = > {
const promises = [
db ! . searchText ( 'test query' , 3 ) ,
db ! . searchText ( 'test query' , 3 ) ,
db ! . searchText ( 'test query' , 3 )
]
const results = await Promise . all ( promises )
// All should get same results
expect ( results [ 0 ] ) . toEqual ( results [ 1 ] )
expect ( results [ 1 ] ) . toEqual ( results [ 2 ] )
} )
it ( 'should deduplicate findSimilar operations' , async ( ) = > {
const promises = [
db ! . findSimilar ( 'op5' , { limit : 3 } ) ,
db ! . findSimilar ( 'op5' , { limit : 3 } ) ,
db ! . findSimilar ( 'op5' , { limit : 3 } )
]
const results = await Promise . all ( promises )
// All should get same results
expect ( results [ 0 ] . length ) . toBe ( results [ 1 ] . length )
expect ( results [ 1 ] . length ) . toBe ( results [ 2 ] . length )
} )
} )
describe ( 'Statistics and Monitoring' , ( ) = > {
it ( 'should track deduplication statistics' , async ( ) = > {
const dedup = new RequestDeduplicatorAugmentation ( {
ttl : 5000 ,
maxSize : 100
} )
await dedup . initialize ( {
brain : { } ,
storage : { } ,
config : { } ,
log : ( ) = > { }
} as any )
const stats = dedup . getStats ( )
expect ( stats ) . toBeDefined ( )
expect ( stats ) . toHaveProperty ( 'hits' )
expect ( stats ) . toHaveProperty ( 'misses' )
expect ( stats ) . toHaveProperty ( 'totalRequests' )
expect ( stats ) . toHaveProperty ( 'cacheSize' )
expect ( stats ) . toHaveProperty ( 'evictions' )
} )
it ( 'should calculate hit rate' , async ( ) = > {
db = new BrainyData ( {
requestDeduplicator : {
enabled : true ,
ttl : 5000
}
} )
await db . init ( )
// Add test data
await db . add ( createTestVector ( 1 ) , { id : 'stat1' } )
const vector = createTestVector ( 1 )
// First search (miss)
2025-08-26 12:03:45 -07:00
await db . search ( vector , { limit : 1 } )
2025-08-25 09:52:32 -07:00
// Duplicate searches (hits)
2025-08-26 12:03:45 -07:00
await db . search ( vector , { limit : 1 } )
await db . search ( vector , { limit : 1 } )
await db . search ( vector , { limit : 1 } )
2025-08-25 09:52:32 -07:00
// Hit rate should be 75% (3 hits out of 4 total)
// Note: Actual implementation may vary
} )
} )
describe ( 'Error Handling' , ( ) = > {
beforeEach ( async ( ) = > {
db = new BrainyData ( {
requestDeduplicator : {
enabled : true ,
ttl : 1000
}
} )
await db . init ( )
} )
it ( 'should handle search errors gracefully' , async ( ) = > {
// Search with invalid parameters
try {
await db ! . search ( null as any , - 1 )
} catch ( error ) {
// Should handle error without breaking deduplicator
expect ( error ) . toBeDefined ( )
}
// Subsequent valid search should work
await db ! . add ( createTestVector ( 1 ) , { id : 'error1' } )
2025-08-26 12:03:45 -07:00
const results = await db ! . search ( createTestVector ( 1 ) , { limit : 1 } )
2025-08-25 09:52:32 -07:00
expect ( results . length ) . toBeGreaterThan ( 0 )
} )
it ( 'should not cache failed requests' , async ( ) = > {
// Make a search that will fail
const badVector = new Array ( 100 ) . fill ( 0 ) // Wrong dimensions
let error1 , error2
try {
2025-08-26 12:03:45 -07:00
await db ! . search ( badVector , { limit : 1 } )
2025-08-25 09:52:32 -07:00
} catch ( e ) {
error1 = e
}
try {
2025-08-26 12:03:45 -07:00
await db ! . search ( badVector , { limit : 1 } )
2025-08-25 09:52:32 -07:00
} catch ( e ) {
error2 = e
}
// Both should fail (not cached)
expect ( error1 ) . toBeDefined ( )
expect ( error2 ) . toBeDefined ( )
} )
} )
describe ( 'Standalone Usage' , ( ) = > {
it ( 'should work as standalone augmentation' , ( ) = > {
const dedup = new RequestDeduplicatorAugmentation ( {
ttl : 5000 ,
maxSize : 1000
} )
expect ( dedup . name ) . toBe ( 'RequestDeduplicator' )
expect ( dedup . timing ) . toBe ( 'around' )
expect ( dedup . priority ) . toBe ( 50 ) // Medium priority
expect ( dedup . operations ) . toContain ( 'search' )
expect ( dedup . operations ) . toContain ( 'searchText' )
expect ( dedup . operations ) . toContain ( 'findSimilar' )
} )
it ( 'should provide 3x performance boost claim' , async ( ) = > {
const dedup = new RequestDeduplicatorAugmentation ( {
ttl : 5000
} )
await dedup . initialize ( {
brain : { } ,
storage : { } ,
config : { } ,
log : ( msg : string ) = > {
expect ( msg ) . toContain ( '3x performance boost' )
}
} as any )
} )
} )
} )