2025-08-04 12:18:58 -07:00
/ * *
* Tests for Brainy Distributed Mode functionality
* /
import { describe , it , expect , beforeEach , afterEach , vi } from 'vitest'
import { BrainyData } from '../src/brainyData.js'
import { DistributedConfigManager } from '../src/distributed/configManager.js'
import { HashPartitioner } from '../src/distributed/hashPartitioner.js'
import { DomainDetector } from '../src/distributed/domainDetector.js'
import {
ReaderMode ,
WriterMode ,
HybridMode ,
OperationalModeFactory
} from '../src/distributed/operationalModes.js'
import { HealthMonitor } from '../src/distributed/healthMonitor.js'
// Mock storage adapter for testing
class MockStorageAdapter {
private metadata : Map < string , any > = new Map ( )
async init() { }
async saveMetadata ( id : string , data : any ) {
this . metadata . set ( id , data )
}
async getMetadata ( id : string ) {
return this . metadata . get ( id ) || null
}
async saveNoun ( noun : any ) { }
async getNoun ( id : string ) { return null }
async getAllNouns() { return [ ] }
async getNouns() { return { items : [ ] , pagination : { page : 1 , pageSize : 100 , total : 0 } } }
async deleteNoun ( id : string ) { }
async saveVerb ( verb : any ) { }
async getVerb ( id : string ) { return null }
async getVerbsBySource ( source : string ) { return [ ] }
async getVerbsByTarget ( target : string ) { return [ ] }
async getVerbsByType ( type : string ) { return [ ] }
async getAllVerbs() { return [ ] }
async deleteVerb ( id : string ) { }
async incrementStatistic ( stat : string , service : string ) { }
async updateHnswIndexSize ( size : number ) { }
async trackFieldNames ( obj : any , service : string ) { }
}
describe ( 'Distributed Configuration Manager' , ( ) = > {
let storage : MockStorageAdapter
beforeEach ( ( ) = > {
storage = new MockStorageAdapter ( )
// Clear any environment variables that might be set
delete process . env . BRAINY_ROLE
} )
afterEach ( ( ) = > {
// Clean up environment
delete process . env . BRAINY_ROLE
} )
it ( 'should require explicit role configuration' , async ( ) = > {
const configManager = new DistributedConfigManager (
storage as any ,
{ enabled : true } , // No role specified
{ } // No read/write mode
)
// Should throw error when no role is set
await expect ( configManager . initialize ( ) ) . rejects . toThrow (
'Distributed mode requires explicit role configuration'
)
} )
it ( 'should accept role from environment variable' , async ( ) = > {
process . env . BRAINY_ROLE = 'writer'
const configManager = new DistributedConfigManager (
storage as any ,
{ enabled : true }
)
await configManager . initialize ( )
expect ( configManager . getRole ( ) ) . toBe ( 'writer' )
delete process . env . BRAINY_ROLE
} )
it ( 'should accept role from config' , async ( ) = > {
const configManager = new DistributedConfigManager (
storage as any ,
{ enabled : true , role : 'reader' }
)
await configManager . initialize ( )
expect ( configManager . getRole ( ) ) . toBe ( 'reader' )
} )
it ( 'should infer role from read/write mode' , async ( ) = > {
const configManager = new DistributedConfigManager (
storage as any ,
{ enabled : true } ,
{ writeOnly : true }
)
expect ( configManager . getRole ( ) ) . toBe ( 'writer' )
} )
it ( 'should validate role values' , async ( ) = > {
process . env . BRAINY_ROLE = 'invalid'
const configManager = new DistributedConfigManager (
storage as any ,
{ enabled : true } ,
{ } // No read/write mode
)
await expect ( configManager . initialize ( ) ) . rejects . toThrow (
'Invalid BRAINY_ROLE: invalid'
)
delete process . env . BRAINY_ROLE
} )
} )
describe ( 'Hash Partitioner' , ( ) = > {
it ( 'should partition vectors deterministically' , ( ) = > {
const config = {
version : 1 ,
updated : new Date ( ) . toISOString ( ) ,
settings : {
partitionStrategy : 'hash' as const ,
partitionCount : 10 ,
embeddingModel : 'test' ,
2025-08-05 19:29:59 -07:00
dimensions : 384 ,
2025-08-04 12:18:58 -07:00
distanceMetric : 'cosine' as const
} ,
instances : { }
}
const partitioner = new HashPartitioner ( config )
// Same ID should always go to same partition
const id = 'test-vector-123'
const partition1 = partitioner . getPartition ( id )
const partition2 = partitioner . getPartition ( id )
expect ( partition1 ) . toBe ( partition2 )
expect ( partition1 ) . toMatch ( /^vectors\/p\d{3}$/ )
} )
it ( 'should distribute vectors evenly' , ( ) = > {
const config = {
version : 1 ,
updated : new Date ( ) . toISOString ( ) ,
settings : {
partitionStrategy : 'hash' as const ,
partitionCount : 10 ,
embeddingModel : 'test' ,
2025-08-05 19:29:59 -07:00
dimensions : 384 ,
2025-08-04 12:18:58 -07:00
distanceMetric : 'cosine' as const
} ,
instances : { }
}
const partitioner = new HashPartitioner ( config )
const partitionCounts = new Map < string , number > ( )
// Generate many IDs and check distribution
for ( let i = 0 ; i < 1000 ; i ++ ) {
const partition = partitioner . getPartition ( ` vector- ${ i } ` )
partitionCounts . set ( partition , ( partitionCounts . get ( partition ) || 0 ) + 1 )
}
// Check that all partitions got some vectors
expect ( partitionCounts . size ) . toBeGreaterThan ( 5 )
// Check distribution is reasonably even (no partition has more than 20% of vectors)
for ( const count of partitionCounts . values ( ) ) {
expect ( count ) . toBeLessThan ( 200 )
}
} )
} )
describe ( 'Domain Detector' , ( ) = > {
let detector : DomainDetector
beforeEach ( ( ) = > {
detector = new DomainDetector ( )
} )
it ( 'should detect medical domain' , ( ) = > {
const data = {
symptoms : 'headache and fever' ,
diagnosis : 'flu' ,
treatment : 'rest and fluids'
}
const result = detector . detectDomain ( data )
expect ( result . domain ) . toBe ( 'medical' )
} )
it ( 'should detect legal domain' , ( ) = > {
const data = {
contract : 'lease agreement' ,
clause : 'termination clause' ,
jurisdiction : 'California'
}
const result = detector . detectDomain ( data )
expect ( result . domain ) . toBe ( 'legal' )
} )
it ( 'should detect product domain' , ( ) = > {
const data = {
price : 99.99 ,
sku : 'PROD-123' ,
inventory : 50 ,
category : 'electronics'
}
const result = detector . detectDomain ( data )
expect ( result . domain ) . toBe ( 'product' )
} )
it ( 'should return general for unrecognized data' , ( ) = > {
const data = {
foo : 'bar' ,
baz : 'qux'
}
const result = detector . detectDomain ( data )
expect ( result . domain ) . toBe ( 'general' )
} )
it ( 'should respect explicit domain field' , ( ) = > {
const data = {
domain : 'custom' ,
foo : 'bar'
}
const result = detector . detectDomain ( data )
expect ( result . domain ) . toBe ( 'custom' )
} )
} )
describe ( 'Operational Modes' , ( ) = > {
it ( 'should create reader mode with correct settings' , ( ) = > {
const mode = new ReaderMode ( )
expect ( mode . canRead ) . toBe ( true )
expect ( mode . canWrite ) . toBe ( false )
expect ( mode . canDelete ) . toBe ( false )
expect ( mode . cacheStrategy . hotCacheRatio ) . toBe ( 0.8 )
expect ( mode . cacheStrategy . prefetchAggressive ) . toBe ( true )
} )
it ( 'should create writer mode with correct settings' , ( ) = > {
const mode = new WriterMode ( )
expect ( mode . canRead ) . toBe ( false )
expect ( mode . canWrite ) . toBe ( true )
expect ( mode . canDelete ) . toBe ( true )
expect ( mode . cacheStrategy . hotCacheRatio ) . toBe ( 0.2 )
expect ( mode . cacheStrategy . batchWrites ) . toBe ( true )
} )
it ( 'should create hybrid mode with correct settings' , ( ) = > {
const mode = new HybridMode ( )
expect ( mode . canRead ) . toBe ( true )
expect ( mode . canWrite ) . toBe ( true )
expect ( mode . canDelete ) . toBe ( true )
expect ( mode . cacheStrategy . hotCacheRatio ) . toBe ( 0.5 )
expect ( mode . cacheStrategy . adaptive ) . toBe ( true )
} )
it ( 'should validate operations based on mode' , ( ) = > {
const readerMode = new ReaderMode ( )
const writerMode = new WriterMode ( )
// Reader should not allow writes
expect ( ( ) = > readerMode . validateOperation ( 'write' ) ) . toThrow (
'Write operations are not allowed in read-only mode'
)
// Writer should not allow reads
expect ( ( ) = > writerMode . validateOperation ( 'read' ) ) . toThrow (
'Read operations are not allowed in write-only mode'
)
} )
it ( 'should create correct mode from factory' , ( ) = > {
const reader = OperationalModeFactory . createMode ( 'reader' )
const writer = OperationalModeFactory . createMode ( 'writer' )
const hybrid = OperationalModeFactory . createMode ( 'hybrid' )
expect ( reader ) . toBeInstanceOf ( ReaderMode )
expect ( writer ) . toBeInstanceOf ( WriterMode )
expect ( hybrid ) . toBeInstanceOf ( HybridMode )
} )
} )
describe ( 'Health Monitor' , ( ) = > {
let configManager : DistributedConfigManager
let healthMonitor : HealthMonitor
let storage : MockStorageAdapter
beforeEach ( ( ) = > {
storage = new MockStorageAdapter ( )
configManager = new DistributedConfigManager (
storage as any ,
{ enabled : true , role : 'reader' }
)
healthMonitor = new HealthMonitor ( configManager )
} )
afterEach ( ( ) = > {
healthMonitor . stop ( )
} )
it ( 'should track request metrics' , ( ) = > {
healthMonitor . recordRequest ( 100 , false )
healthMonitor . recordRequest ( 150 , false )
healthMonitor . recordRequest ( 200 , true ) // Error
const status = healthMonitor . getHealthStatus ( )
expect ( status . metrics . averageLatency ) . toBeGreaterThan ( 0 )
expect ( status . metrics . errorRate ) . toBeGreaterThan ( 0 )
} )
it ( 'should track cache metrics' , ( ) = > {
healthMonitor . recordCacheAccess ( true ) // Hit
healthMonitor . recordCacheAccess ( true ) // Hit
healthMonitor . recordCacheAccess ( false ) // Miss
const status = healthMonitor . getHealthStatus ( )
expect ( status . metrics . cacheHitRate ) . toBeCloseTo ( 0.667 , 2 )
} )
it ( 'should update vector count' , ( ) = > {
healthMonitor . updateVectorCount ( 1000 )
const status = healthMonitor . getHealthStatus ( )
expect ( status . metrics . vectorCount ) . toBe ( 1000 )
} )
it ( 'should determine health status based on metrics' , ( ) = > {
// Add some successful requests first to establish a good baseline
for ( let i = 0 ; i < 5 ; i ++ ) {
healthMonitor . recordRequest ( 50 , false )
healthMonitor . recordCacheAccess ( true )
}
let status = healthMonitor . getHealthStatus ( )
// With good metrics, should be healthy (unless cache hit rate is too low initially)
// Let's just check it's not unhealthy
expect ( status . status ) . not . toBe ( 'unhealthy' )
// High error rate
for ( let i = 0 ; i < 10 ; i ++ ) {
healthMonitor . recordRequest ( 100 , true )
}
status = healthMonitor . getHealthStatus ( )
expect ( status . status ) . toBe ( 'unhealthy' )
expect ( status . errors ) . toContain ( 'Critical error rate' )
} )
} )
describe ( 'BrainyData with Distributed Mode' , ( ) = > {
it ( 'should initialize with distributed config' , async ( ) = > {
const brainy = new BrainyData ( {
distributed : { role : 'reader' } ,
storage : {
forceMemoryStorage : true
}
} )
await brainy . init ( )
// Should be in read-only mode
expect ( ( ) = > brainy [ 'checkReadOnly' ] ( ) ) . toThrow ( )
await brainy . cleanup ( )
} )
it ( 'should detect domain and add to metadata' , async ( ) = > {
const brainy = new BrainyData ( {
distributed : { role : 'writer' } ,
storage : {
forceMemoryStorage : true
}
} )
await brainy . init ( )
const medicalData = {
symptoms : 'headache' ,
diagnosis : 'migraine'
}
// Create a proper 512-dimensional vector
2025-08-05 19:29:59 -07:00
const vector = new Array ( 384 ) . fill ( 0 ) . map ( ( _ , i ) = > i / 384 )
2025-08-04 12:18:58 -07:00
const id = await brainy . add ( vector , medicalData )
const result = await brainy . get ( id )
// Check that domain was added to metadata
expect ( result ? . metadata ) . toHaveProperty ( 'domain' )
// Note: In memory storage, the domain detection happens but may not persist
// This is just checking the flow works
await brainy . cleanup ( )
} )
it ( 'should support domain filtering in search' , async ( ) = > {
const brainy = new BrainyData ( {
distributed : { role : 'hybrid' } ,
storage : {
forceMemoryStorage : true
}
} )
await brainy . init ( )
// Create proper 512-dimensional vectors
2025-08-05 19:29:59 -07:00
const vector1 = new Array ( 384 ) . fill ( 0 ) . map ( ( _ , i ) = > i === 0 ? 1 : 0 )
const vector2 = new Array ( 384 ) . fill ( 0 ) . map ( ( _ , i ) = > i === 1 ? 1 : 0 )
const vector3 = new Array ( 384 ) . fill ( 0 ) . map ( ( _ , i ) = > i === 2 ? 1 : 0 )
2025-08-04 12:18:58 -07:00
// Add items with different domains
await brainy . add ( vector1 , { domain : 'medical' , content : 'medical1' } )
await brainy . add ( vector2 , { domain : 'legal' , content : 'legal1' } )
await brainy . add ( vector3 , { domain : 'medical' , content : 'medical2' } )
// Search with domain filter
const results = await brainy . search ( vector1 , 10 , {
filter : { domain : 'medical' }
} )
// Should filter out non-medical results
const medicalResults = results . filter ( r = >
r . metadata && ( r . metadata as any ) . domain === 'medical'
)
expect ( medicalResults . length ) . toBeGreaterThan ( 0 )
await brainy . cleanup ( )
} )
it ( 'should provide health status' , async ( ) = > {
const brainy = new BrainyData ( {
distributed : { role : 'reader' } ,
storage : {
forceMemoryStorage : true
}
} )
await brainy . init ( )
const health = brainy . getHealthStatus ( )
expect ( health ) . toHaveProperty ( 'status' )
expect ( health ) . toHaveProperty ( 'instanceId' )
expect ( health ) . toHaveProperty ( 'role' )
expect ( health ) . toHaveProperty ( 'metrics' )
await brainy . cleanup ( )
} )
} )