test(8.0): re-home orphaned test files into the gate + guard against recurrence

27 test files matched no vitest config, so they never ran in CI and gave false
coverage confidence (the drift the audit flagged).

- Re-homed 10 functional suites into the gate (renamed to *.unit.test.ts /
  *.integration.test.ts): Transaction + TransactionManager, type-utils,
  integrations/core + odata, comprehensive/public-api-complete, regression
  (metadata-index-cleanup + v5.7.0-deadlock), vfs/tree-operations +
  vfs-bulkwrite-race. ~192 previously-dark tests now run and pass.
- Deleted 8 bit-rotted/redundant files that fail against 8.0 and never ran:
  one had a literal syntax error; one used filesystem writer-locks that polluted
  parallel runs; the rest assert old "Brainy 3.0/v3.0" APIs already covered by
  the live suites (api/batch-operations + crud-operations-enhanced, brainy-3,
  comprehensive/core-api + find-triple-intelligence, streaming-pipeline,
  vfs/vfs-relationships, transaction/integration/typeaware-transactions).
- Added a coverage guard (tests/unit/test-suite-coverage-guard.test.ts) that
  FAILS CI if any *.test.ts ever again falls outside every config, with an
  explicit, conscious MANUAL_ONLY allowlist for the 9 genuine benchmark / perf /
  model-load files that are run by hand.

Gate green: unit 1712, integration 607.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
David Snelling 2026-06-29 11:47:18 -07:00
parent 5f974abc8a
commit 3f9f140c8c
19 changed files with 69 additions and 3658 deletions

View file

@ -1,660 +0,0 @@
/**
* Batch Operations Test Suite for Brainy v3.0
*
* Comprehensive testing of batch operations including:
* - addMany: Bulk entity creation
* - removeMany: Bulk deletion
* - Performance validation at scale
* - Memory efficiency testing
* - Error recovery scenarios
*/
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
import { Brainy } from '../../src/brainy'
import { performance } from 'perf_hooks'
interface BatchMetrics {
operation: string
totalItems: number
successCount: number
failureCount: number
duration: number
throughput: number
memoryUsed: number
errors: string[]
}
class BatchMetricsCollector {
private metrics: BatchMetrics[] = []
recordBatch(
operation: string,
totalItems: number,
results: any[],
duration: number,
memoryUsed: number
): BatchMetrics {
const successCount = results.filter(r =>
r?.status === 'fulfilled' || r === true || (r && !r.error)
).length
const failureCount = totalItems - successCount
const errors = results
.filter(r => r?.status === 'rejected' || r?.error)
.map(r => r?.reason?.message || r?.error || 'Unknown error')
.slice(0, 5) // Limit to first 5 errors
const metric: BatchMetrics = {
operation,
totalItems,
successCount,
failureCount,
duration,
throughput: (totalItems / duration) * 1000,
memoryUsed,
errors
}
this.metrics.push(metric)
return metric
}
getMetrics(): BatchMetrics[] {
return this.metrics
}
generateReport(): void {
console.log('\n=== Batch Operations Performance Report ===\n')
console.table(this.metrics.map(m => ({
Operation: m.operation,
'Total Items': m.totalItems,
'Success': `${m.successCount}/${m.totalItems} (${((m.successCount/m.totalItems)*100).toFixed(1)}%)`,
'Duration (ms)': m.duration.toFixed(2),
'Throughput (items/s)': m.throughput.toFixed(0),
'Memory (MB)': (m.memoryUsed / 1024 / 1024).toFixed(2),
'Errors': m.errors.length > 0 ? m.errors[0] : 'None'
})))
// Summary statistics
const totalOps = this.metrics.reduce((sum, m) => sum + m.totalItems, 0)
const totalSuccess = this.metrics.reduce((sum, m) => sum + m.successCount, 0)
const avgThroughput = this.metrics.reduce((sum, m) => sum + m.throughput, 0) / this.metrics.length
console.log('\nSummary:')
console.log(`Total Operations: ${totalOps}`)
console.log(`Success Rate: ${((totalSuccess/totalOps)*100).toFixed(2)}%`)
console.log(`Average Throughput: ${avgThroughput.toFixed(0)} items/sec`)
}
}
describe('Batch Operations - Public API Testing', () => {
let brainy: Brainy
let metricsCollector: BatchMetricsCollector
beforeEach(async () => {
brainy = new Brainy({ requireSubtype: false,
storage: { type: 'memory' }
})
await brainy.init()
metricsCollector = new BatchMetricsCollector()
})
afterEach(async () => {
await brainy.close()
if (global.gc) global.gc()
})
describe('addMany - Bulk Entity Creation', () => {
it('should add 100 entities efficiently', async () => {
const entities = Array(100).fill(null).map((_, i) => ({
data: `Batch entity ${i}: Test content for bulk operations`,
type: 'document' as const,
metadata: {
batchIndex: i,
batchId: 'batch-100',
timestamp: Date.now()
}
}))
const startMemory = process.memoryUsage().heapUsed
const startTime = performance.now()
const result = await brainy.addMany({ items: entities })
const duration = performance.now() - startTime
const memoryUsed = process.memoryUsage().heapUsed - startMemory
const metric = metricsCollector.recordBatch(
'addMany-100',
entities.length,
result.successful,
duration,
memoryUsed
)
expect(result.successful).toHaveLength(100)
expect(result.failed).toHaveLength(0)
expect(metric.throughput).toBeGreaterThan(100) // > 100 items/sec
})
it('should handle 1,000 entities with proper batching', async () => {
const entities = Array(1000).fill(null).map((_, i) => ({
data: `Entity ${i}: ${' '.repeat(100)}`, // ~100 bytes each
type: 'document' as const,
metadata: {
index: i,
category: `cat-${i % 10}`,
tags: [`tag-${i % 5}`, `tag-${i % 7}`]
}
}))
const startMemory = process.memoryUsage().heapUsed
const startTime = performance.now()
const result = await brainy.addMany({
items: entities,
chunkSize: 100, // Process in batches
parallel: true
})
const duration = performance.now() - startTime
const memoryUsed = process.memoryUsage().heapUsed - startMemory
metricsCollector.recordBatch(
'addMany-1k',
entities.length,
result.successful,
duration,
memoryUsed
)
expect(result.successful.length).toBe(1000)
expect(result.failed.length).toBe(0)
expect(duration).toBeLessThan(10000) // < 10 seconds
// Verify data integrity
const sampleIds = result.successful.slice(0, 10)
for (const id of sampleIds) {
const entity = await brainy.get(id)
expect(entity).toBeDefined()
}
})
it('should handle 10,000 entities with memory efficiency', async () => {
const chunkSize = 1000
const totalEntities = 10000
let allSuccessful: string[] = []
let allFailed: any[] = []
const startMemory = process.memoryUsage().heapUsed
const startTime = performance.now()
// Process in chunks to avoid memory issues
for (let chunk = 0; chunk < totalEntities; chunk += chunkSize) {
const entities = Array(Math.min(chunkSize, totalEntities - chunk))
.fill(null)
.map((_, i) => ({
data: `Chunk entity ${chunk + i}`,
type: 'document' as const,
metadata: { globalIndex: chunk + i }
}))
const result = await brainy.addMany({ items: entities })
allSuccessful.push(...result.successful)
allFailed.push(...result.failed)
// Check memory usage
const currentMemory = process.memoryUsage().heapUsed
const memoryGrowth = currentMemory - startMemory
expect(memoryGrowth).toBeLessThan(500 * 1024 * 1024) // < 500MB total
}
const duration = performance.now() - startTime
const finalMemory = process.memoryUsage().heapUsed - startMemory
metricsCollector.recordBatch(
'addMany-10k',
totalEntities,
allSuccessful,
duration,
finalMemory
)
expect(allSuccessful.length).toBe(10000)
expect(allFailed.length).toBe(0)
})
it('should handle partial failures gracefully', async () => {
const entities = [
{ data: 'Valid entity 1', type: 'document' as const },
{ data: '', type: 'document' as const }, // Invalid: empty data
{ data: 'Valid entity 2', type: 'document' as const },
{ data: null as any, type: 'document' as const }, // Invalid: null data
{ data: 'Valid entity 3', type: 'document' as const },
]
const result = await brainy.addMany({
items: entities,
continueOnError: true
})
// Should process valid entities even if some fail
expect(result.successful.length).toBeGreaterThanOrEqual(3)
expect(result.failed.length).toBeGreaterThanOrEqual(0) // May or may not validate
// Verify valid entities were added
for (const id of result.successful) {
const entity = await brainy.get(id)
expect(entity).toBeDefined()
}
})
it('should support concurrent batch operations', async () => {
const batches = Array(5).fill(null).map((_, batchIdx) =>
Array(100).fill(null).map((_, i) => ({
data: `Batch ${batchIdx} Entity ${i}`,
type: 'document' as const,
metadata: { batchId: batchIdx, index: i }
}))
)
const startTime = performance.now()
// Execute batches concurrently
const results = await Promise.all(
batches.map(entities => brainy.addMany({ items: entities }))
)
const duration = performance.now() - startTime
expect(results).toHaveLength(5)
const totalSuccess = results.reduce((sum, r) => sum + r.successful.length, 0)
expect(totalSuccess).toBe(500)
expect(duration).toBeLessThan(5000) // Concurrent should be faster
})
})
let testIds: string[] = []
beforeEach(async () => {
// Create test entities
const entities = Array(100).fill(null).map((_, i) => ({
data: `Original content ${i}`,
type: 'document' as const,
metadata: { version: 1, index: i }
}))
const result = await brainy.addMany({ items: entities })
testIds = result.successful
})
it('should update multiple entities by IDs', async () => {
const updates = testIds.slice(0, 50).map(id => ({
id,
updates: {
metadata: {
version: 2,
updatedAt: Date.now()
}
}
}))
const startTime = performance.now()
const results = await Promise.all(
updates.map(u => brainy.update({ id: u.id, ...u.updates }))
)
const duration = performance.now() - startTime
metricsCollector.recordBatch(
updates.length,
results,
duration,
0
)
// Verify updates
const sample = await brainy.get(testIds[0])
expect(sample?.metadata?.version).toBe(2)
})
it('should update entities matching criteria', async () => {
// Update all entities with index < 20
const targetIds = testIds.slice(0, 20)
const startTime = performance.now()
const results = await Promise.all(
targetIds.map(id =>
brainy.update({
id,
metadata: {
status: 'updated',
processedAt: Date.now()
}
})
)
)
const duration = performance.now() - startTime
metricsCollector.recordBatch(
targetIds.length,
results,
duration,
0
)
// Verify updates
for (const id of targetIds.slice(0, 5)) {
const entity = await brainy.get(id)
expect(entity?.metadata?.status).toBe('updated')
}
})
})
describe('removeMany - Bulk Deletion', () => {
let testIds: string[] = []
beforeEach(async () => {
// Create test entities
const entities = Array(200).fill(null).map((_, i) => ({
data: `Delete test ${i}`,
type: 'document' as const,
metadata: { deleteGroup: i % 4 }
}))
const result = await brainy.addMany({ items: entities })
testIds = result.successful
})
it('should delete multiple entities by IDs', async () => {
const toDelete = testIds.slice(0, 100)
const startMemory = process.memoryUsage().heapUsed
const startTime = performance.now()
// Use removeMany if available, otherwise individual deletes
let results: any[]
if ('removeMany' in brainy && typeof brainy.removeMany === 'function') {
const result = await brainy.removeMany({ ids: toDelete })
results = result.successful
} else {
results = await Promise.all(
toDelete.map(id => brainy.remove(id))
)
}
const duration = performance.now() - startTime
const memoryUsed = process.memoryUsage().heapUsed - startMemory
metricsCollector.recordBatch(
'removeMany-100',
toDelete.length,
results,
duration,
memoryUsed
)
// Verify deletion
for (const id of toDelete.slice(0, 10)) {
const entity = await brainy.get(id)
expect(entity).toBeNull()
}
// Remaining entities should still exist
const remaining = testIds.slice(100, 110)
for (const id of remaining) {
const entity = await brainy.get(id)
expect(entity).toBeDefined()
}
})
it('should handle large-scale deletion efficiently', async () => {
// Create a large dataset
const largeDataset = Array(1000).fill(null).map((_, i) => ({
data: `Large scale delete test ${i}`,
type: 'document' as const
}))
const addResult = await brainy.addMany({ items: largeDataset })
const idsToDelete = addResult.successful
const startTime = performance.now()
// Delete in batches
const batchSize = 100
for (let i = 0; i < idsToDelete.length; i += batchSize) {
const batch = idsToDelete.slice(i, i + batchSize)
await Promise.all(batch.map(id => brainy.remove(id)))
}
const duration = performance.now() - startTime
metricsCollector.recordBatch(
'removeMany-1k',
idsToDelete.length,
idsToDelete.map(() => true),
duration,
0
)
expect(duration).toBeLessThan(10000) // < 10 seconds
})
})
let nodeIds: string[] = []
beforeEach(async () => {
// Create nodes for relationships
const nodes = Array(50).fill(null).map((_, i) => ({
data: `Node ${i}`,
type: 'thing' as const,
metadata: { nodeIndex: i }
}))
const result = await brainy.addMany({ items: nodes })
nodeIds = result.successful
})
it('should create multiple relationships efficiently', async () => {
const relationships: Array<{from: string, to: string, type: string}> = []
// Create a connected graph
for (let i = 0; i < nodeIds.length - 1; i++) {
relationships.push({
from: nodeIds[i],
to: nodeIds[i + 1],
type: 'connected_to'
})
}
const startTime = performance.now()
const results = await Promise.all(
relationships.map(r =>
brainy.relate({ from: r.from, to: r.to, type: r.type as any })
)
)
const duration = performance.now() - startTime
metricsCollector.recordBatch(
relationships.length,
results,
duration,
0
)
expect(results.every(r => typeof r === 'string')).toBe(true) // relate returns ID
expect(duration).toBeLessThan(5000)
})
it('should create complex graph structures', async () => {
// Create a fully connected subgraph (first 10 nodes)
const subgraph = nodeIds.slice(0, 10)
const relationships: Array<{from: string, to: string}> = []
for (let i = 0; i < subgraph.length; i++) {
for (let j = i + 1; j < subgraph.length; j++) {
relationships.push({
from: subgraph[i],
to: subgraph[j]
})
}
}
const startTime = performance.now()
const results = await Promise.all(
relationships.map(r =>
brainy.relate({ from: r.from, to: r.to, type: 'relatedTo' })
)
)
const duration = performance.now() - startTime
metricsCollector.recordBatch(
relationships.length,
results,
duration,
0
)
expect(relationships.length).toBe(45) // 10 choose 2
expect(results.every(r => typeof r === 'string')).toBe(true) // relate returns ID
})
})
describe('Mixed Batch Operations', () => {
it('should handle mixed operation types concurrently', async () => {
// Prepare different operation types
const addOps = Array(100).fill(null).map((_, i) => ({
data: `Mixed add ${i}`,
type: 'document' as const
}))
// Add initial entities for update/delete
const setupResult = await brainy.addMany({
items: Array(100).fill(null).map((_, i) => ({
data: `Setup ${i}`,
type: 'document' as const
}))
})
const updateIds = setupResult.successful.slice(0, 50)
const deleteIds = setupResult.successful.slice(50, 100)
const startTime = performance.now()
// Execute all operations concurrently
const [addResults, updateResults, deleteResults] = await Promise.all([
brainy.addMany({ items: addOps }),
Promise.all(updateIds.map(id =>
brainy.update({ id, metadata: { updated: true } })
)),
Promise.all(deleteIds.map(id => brainy.remove(id)))
])
const duration = performance.now() - startTime
console.log(`Mixed operations completed in ${duration.toFixed(2)}ms`)
expect(addResults.successful.length).toBe(100)
expect(updateResults.length).toBe(50)
// Delete returns void, so just check length
expect(deleteResults).toHaveLength(50)
})
})
describe('Error Recovery', () => {
it('should recover from transient failures', async () => {
let attemptCount = 0
const entities = Array(10).fill(null).map((_, i) => ({
data: `Retry test ${i}`,
type: 'document' as const
}))
// Simulate transient failures
const originalAdd = brainy.add.bind(brainy)
brainy.add = async function(params: any) {
attemptCount++
if (attemptCount % 3 === 0) {
throw new Error('Transient failure')
}
return originalAdd(params)
}
const results: any[] = []
for (const entity of entities) {
let retries = 0
while (retries < 3) {
try {
const id = await brainy.add(entity)
results.push({ status: 'fulfilled', value: id })
break
} catch (error) {
retries++
if (retries === 3) {
results.push({ status: 'rejected', reason: error })
}
}
}
}
const successful = results.filter(r => r.status === 'fulfilled')
expect(successful.length).toBeGreaterThanOrEqual(6) // Most should succeed with retry
})
it('should handle memory pressure gracefully', async () => {
const largeEntities = Array(100).fill(null).map((_, i) => ({
data: 'x'.repeat(100000), // 100KB each = 10MB total
type: 'document' as const,
metadata: { index: i }
}))
const startMemory = process.memoryUsage().heapUsed
// Process with memory monitoring
const batchSize = 10
const results: any[] = []
for (let i = 0; i < largeEntities.length; i += batchSize) {
const batch = largeEntities.slice(i, i + batchSize)
// Check memory before processing
const currentMemory = process.memoryUsage().heapUsed
const memoryUsed = currentMemory - startMemory
if (memoryUsed > 100 * 1024 * 1024) { // If > 100MB
if (global.gc) global.gc() // Force GC if available
}
const batchResult = await brainy.addMany({ items: batch })
results.push(...batchResult.successful)
}
expect(results.length).toBe(100)
const finalMemory = process.memoryUsage().heapUsed - startMemory
expect(finalMemory).toBeLessThan(200 * 1024 * 1024) // Should stay under 200MB
})
})
describe('Performance Report', () => {
it('should generate comprehensive batch operations report', async () => {
metricsCollector.generateReport()
const metrics = metricsCollector.getMetrics()
expect(metrics.length).toBeGreaterThan(0)
// Validate performance targets
for (const metric of metrics) {
expect(metric.successCount).toBeGreaterThan(0)
if (metric.operation.includes('100')) {
expect(metric.throughput).toBeGreaterThan(50) // At least 50 items/sec
}
}
})
})
})

View file

@ -1,764 +0,0 @@
/**
* Enhanced CRUD Operations Test Suite for Brainy v3.0
*
* Comprehensive validation of all public API CRUD operations with:
* - Exhaustive edge case testing
* - Performance benchmarking
* - Memory leak detection
* - Concurrent operation validation
* - Large-scale data handling
*/
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
import { Brainy } from '../../src/brainy'
import { performance } from 'perf_hooks'
interface PerformanceMetrics {
operation: string
itemCount: number
duration: number
memoryUsed: number
itemsPerSecond: number
percentiles?: {
p50: number
p95: number
p99: number
}
}
class TestMetricsCollector {
private metrics: PerformanceMetrics[] = []
private initialMemory: number = 0
private latencies: Map<string, number[]> = new Map()
startOperation(operation: string, itemCount: number = 1): number {
this.initialMemory = process.memoryUsage().heapUsed
return performance.now()
}
endOperation(operation: string, itemCount: number, startTime: number): PerformanceMetrics {
const duration = performance.now() - startTime
const memoryUsed = process.memoryUsage().heapUsed - this.initialMemory
const itemsPerSecond = (itemCount / duration) * 1000
// Track latencies for percentile calculations
if (!this.latencies.has(operation)) {
this.latencies.set(operation, [])
}
this.latencies.get(operation)!.push(duration / itemCount)
const metric: PerformanceMetrics = {
operation,
itemCount,
duration,
memoryUsed,
itemsPerSecond
}
this.metrics.push(metric)
return metric
}
calculatePercentiles(operation: string): { p50: number; p95: number; p99: number } | undefined {
const latencies = this.latencies.get(operation)
if (!latencies || latencies.length === 0) return undefined
const sorted = [...latencies].sort((a, b) => a - b)
return {
p50: sorted[Math.floor(sorted.length * 0.5)],
p95: sorted[Math.floor(sorted.length * 0.95)],
p99: sorted[Math.floor(sorted.length * 0.99)]
}
}
getMetrics(): PerformanceMetrics[] {
return this.metrics
}
async reportMetrics(): Promise<void> {
console.log('\n=== Performance Metrics Report ===\n')
// Add percentiles to metrics
for (const metric of this.metrics) {
metric.percentiles = this.calculatePercentiles(metric.operation)
}
console.table(this.metrics.map(m => ({
Operation: m.operation,
'Items': m.itemCount,
'Duration (ms)': m.duration.toFixed(2),
'Items/sec': m.itemsPerSecond.toFixed(0),
'Memory (MB)': (m.memoryUsed / 1024 / 1024).toFixed(2),
'P50 (ms)': m.percentiles?.p50.toFixed(2) || 'N/A',
'P95 (ms)': m.percentiles?.p95.toFixed(2) || 'N/A',
'P99 (ms)': m.percentiles?.p99.toFixed(2) || 'N/A'
})))
}
}
describe('Enhanced CRUD Operations - Public API Validation', () => {
let brainy: Brainy
let metricsCollector: TestMetricsCollector
beforeEach(async () => {
brainy = new Brainy({ requireSubtype: false,
storage: { type: 'memory' }
})
await brainy.init()
metricsCollector = new TestMetricsCollector()
})
afterEach(async () => {
await brainy.close()
// Force garbage collection if available
if (global.gc) {
global.gc()
}
})
describe('ADD Operations - Comprehensive Testing', () => {
describe('Basic Add Functionality', () => {
it('should add entity with all supported data types', async () => {
const testData = {
text: 'This is a comprehensive test document about AI and machine learning',
metadata: {
title: 'Test Document',
author: 'Test Suite',
version: '1.0.0',
tags: ['test', 'validation', 'comprehensive'],
stats: {
words: 10,
characters: 68,
readingTime: 2
},
nullField: null,
booleanField: true,
numberField: 42.5,
dateField: new Date().toISOString()
}
}
const startTime = metricsCollector.startOperation('add-single')
const id = await brainy.add({
data: testData.text,
type: 'document' as const,
metadata: testData.metadata
})
const metric = metricsCollector.endOperation('add-single', 1, startTime)
expect(id).toBeDefined()
expect(typeof id).toBe('string')
expect(id.length).toBeGreaterThan(0)
expect(metric.duration).toBeLessThan(50) // 50ms SLA for single add
// Verify stored data
const retrieved = await brainy.get(id)
expect(retrieved).toBeDefined()
expect(retrieved?.metadata?.title).toBe('Test Document')
expect(retrieved?.type).toBe('document')
expect(retrieved?.metadata?.title).toBe('Test Document')
})
it('should handle Unicode and special characters correctly', async () => {
const specialCases = [
{ data: '😀🎉🚀 Emoji test document', desc: 'Emoji support' },
{ data: '中文测试文档 Chinese text', desc: 'Chinese characters' },
{ data: 'العربية اختبار Arabic text', desc: 'Arabic script' },
{ data: 'Русский текст тестирование', desc: 'Cyrillic script' },
{ data: '日本語のテストドキュメント', desc: 'Japanese characters' },
{ data: 'Line\nBreak\rReturn\tTab test', desc: 'Control characters' },
{ data: '<script>alert("XSS")</script>', desc: 'HTML injection attempt' },
{ data: '../../etc/passwd traversal', desc: 'Path traversal attempt' },
{ data: 'NULL\x00byte test', desc: 'Null byte injection' },
{ data: '𝓣𝓱𝓮 𝓺𝓾𝓲𝓬𝓴 𝓫𝓻𝓸𝔀𝓷 𝓯𝓸𝔁', desc: 'Mathematical alphanumeric symbols' }
]
for (const testCase of specialCases) {
const id = await brainy.add({
data: testCase.data,
type: 'document' as const,
metadata: { description: testCase.desc }
})
const retrieved = await brainy.get(id)
expect(retrieved?.data).toBe(testCase.data)
expect(retrieved?.metadata?.description).toBe(testCase.desc)
}
})
it('should auto-generate unique IDs when not provided', async () => {
const ids = new Set<string>()
const count = 100
for (let i = 0; i < count; i++) {
const id = await brainy.add({
data: `Auto-generated ID test ${i}`,
type: 'test'
})
ids.add(id)
}
expect(ids.size).toBe(count) // All IDs must be unique
// Verify ID format
for (const id of ids) {
expect(id).toMatch(/^[a-zA-Z0-9_-]+$/) // Valid ID characters
expect(id.length).toBeGreaterThanOrEqual(8) // Reasonable length
expect(id.length).toBeLessThanOrEqual(64) // Not too long
}
})
})
describe('Bulk Add Operations', () => {
it('should efficiently handle 1,000 entities', async () => {
const entities = Array(1000).fill(null).map((_, i) => ({
data: `Test document ${i}: This is content for testing bulk operations at scale`,
type: 'document',
metadata: {
index: i,
category: `category-${i % 10}`,
score: Math.random() * 100,
tags: [`tag-${i % 5}`, `tag-${i % 7}`]
}
}))
const startTime = metricsCollector.startOperation('add-bulk-1k', 1000)
const ids: string[] = []
// Add in batches for better performance
const batchSize = 100
for (let i = 0; i < entities.length; i += batchSize) {
const batch = entities.slice(i, i + batchSize)
const batchIds = await Promise.all(
batch.map(e => brainy.add(e))
)
ids.push(...batchIds)
}
const metric = metricsCollector.endOperation('add-bulk-1k', 1000, startTime)
expect(ids).toHaveLength(1000)
expect(new Set(ids).size).toBe(1000) // All unique
expect(metric.itemsPerSecond).toBeGreaterThan(100) // At least 100 items/sec
expect(metric.memoryUsed).toBeLessThan(100 * 1024 * 1024) // Less than 100MB
// Verify data integrity with random sampling
for (let i = 0; i < 10; i++) {
const randomIdx = Math.floor(Math.random() * 1000)
const entity = await brainy.get(ids[randomIdx])
expect(entity?.metadata?.index).toBe(randomIdx)
}
})
it('should handle 10,000 entities with memory efficiency', async () => {
const startMemory = process.memoryUsage().heapUsed
const count = 10000
const dataSize = 500 // bytes per entity
const startTime = metricsCollector.startOperation('add-bulk-10k', count)
const ids: string[] = []
// Stream-like processing
const batchSize = 500
for (let i = 0; i < count; i += batchSize) {
const batch = Array(Math.min(batchSize, count - i)).fill(null).map((_, j) => ({
data: 'x'.repeat(dataSize) + ` Entity ${i + j}`,
type: 'bulk-test',
metadata: { index: i + j }
}))
const batchIds = await Promise.all(
batch.map(e => brainy.add(e))
)
ids.push(...batchIds)
// Check memory periodically
if (i % 2000 === 0 && i > 0) {
const currentMemory = process.memoryUsage().heapUsed
const memoryGrowth = currentMemory - startMemory
expect(memoryGrowth).toBeLessThan(200 * 1024 * 1024) // Less than 200MB
}
}
const metric = metricsCollector.endOperation('add-bulk-10k', count, startTime)
expect(ids).toHaveLength(count)
expect(metric.duration).toBeLessThan(60000) // Complete within 60 seconds
expect(metric.itemsPerSecond).toBeGreaterThan(150) // At least 150 items/sec
})
it('should detect and prevent memory leaks', async () => {
const iterations = 5
const memoryDeltas: number[] = []
for (let iter = 0; iter < iterations; iter++) {
if (global.gc) global.gc() // Force GC if available
const beforeMemory = process.memoryUsage().heapUsed
// Add and delete 500 entities
const ids: string[] = []
for (let i = 0; i < 500; i++) {
const id = await brainy.add({
data: 'x'.repeat(1000), // 1KB per entity
type: 'leak-test',
metadata: { iteration: iter, index: i }
})
ids.push(id)
}
// Delete all entities
for (const id of ids) {
await brainy.remove(id)
}
if (global.gc) global.gc()
const afterMemory = process.memoryUsage().heapUsed
memoryDeltas.push(afterMemory - beforeMemory)
}
// Memory should stabilize, not continuously grow
const avgFirstTwo = (memoryDeltas[0] + memoryDeltas[1]) / 2
const avgLastTwo = (memoryDeltas[3] + memoryDeltas[4]) / 2
const growth = avgLastTwo - avgFirstTwo
expect(growth).toBeLessThan(10 * 1024 * 1024) // Less than 10MB growth
})
})
describe('Concurrent Operations', () => {
it('should handle 100 concurrent adds without race conditions', async () => {
const concurrentCount = 100
const operations = Array(concurrentCount).fill(null).map((_, i) => ({
data: `Concurrent test document ${i}`,
type: 'concurrent-test',
metadata: {
index: i,
timestamp: Date.now(),
random: Math.random()
}
}))
const startTime = performance.now()
const ids = await Promise.all(
operations.map(op => brainy.add(op))
)
const duration = performance.now() - startTime
expect(ids).toHaveLength(concurrentCount)
expect(new Set(ids).size).toBe(concurrentCount) // All unique
expect(duration).toBeLessThan(2000) // Complete within 2 seconds
// Verify data integrity
for (let i = 0; i < 10; i++) {
const randomIdx = Math.floor(Math.random() * concurrentCount)
const entity = await brainy.get(ids[randomIdx])
expect(entity?.metadata?.index).toBe(randomIdx)
}
})
it('should handle write conflicts gracefully', async () => {
// Test optimistic concurrency control
const id = await brainy.add({
data: 'Original content',
type: 'conflict-test',
metadata: { version: 1 }
})
// Simulate concurrent updates
const updates = Array(10).fill(null).map((_, i) =>
brainy.update(id, {
metadata: { version: i + 2, updatedBy: `process-${i}` }
})
)
const results = await Promise.allSettled(updates)
// At least one should succeed
const succeeded = results.filter(r => r.status === 'fulfilled')
expect(succeeded.length).toBeGreaterThanOrEqual(1)
// Final state should be consistent
const final = await brainy.get(id)
expect(final?.metadata?.version).toBeGreaterThanOrEqual(2)
})
})
describe('Input Validation', () => {
it('should reject invalid input types', async () => {
const invalidCases = [
{ data: null, desc: 'null data' },
{ data: undefined, desc: 'undefined data' },
{ data: '', desc: 'empty string' },
{ data: 42, desc: 'number instead of string' },
{ data: true, desc: 'boolean instead of string' },
{ data: [], desc: 'array instead of string' },
{ data: {}, desc: 'object instead of string' }
]
for (const testCase of invalidCases) {
await expect(
brainy.add({
data: testCase.data as any,
type: 'test'
})
).rejects.toThrow()
}
})
it('should handle extremely large entities', async () => {
const largeData = 'x'.repeat(5 * 1024 * 1024) // 5MB
const startTime = performance.now()
const id = await brainy.add({
data: largeData,
type: 'large-entity',
metadata: { size: largeData.length }
})
const duration = performance.now() - startTime
expect(id).toBeDefined()
expect(duration).toBeLessThan(5000) // Handle within 5 seconds
const retrieved = await brainy.get(id)
expect(retrieved?.data.length).toBe(largeData.length)
})
it('should sanitize and validate metadata fields', async () => {
const metadata = {
'normal-field': 'value1',
'$special.field': 'value2',
'__proto__': 'attempt-pollution',
'constructor': 'attempt-override',
'../../../etc/passwd': 'path-traversal',
'<script>alert("xss")</script>': 'xss-attempt'
}
const id = await brainy.add({
data: 'Test document with suspicious metadata',
type: 'security-test',
metadata
})
const retrieved = await brainy.get(id)
expect(retrieved).toBeDefined()
// Verify prototype pollution prevention
expect(Object.prototype).not.toHaveProperty('attempt-pollution')
expect(Object.constructor).not.toBe('attempt-override')
})
it('should handle circular references gracefully', async () => {
const metadata: any = {
name: 'Circular test',
level: 1
}
metadata.self = metadata // Create circular reference
// Should either serialize correctly or throw meaningful error
try {
const id = await brainy.add({
data: 'Document with circular metadata',
type: 'circular-test',
metadata
})
const retrieved = await brainy.get(id)
expect(retrieved).toBeDefined()
// Circular reference should be handled (removed or converted)
expect(retrieved?.metadata?.self).not.toBe(retrieved?.metadata)
} catch (error: any) {
expect(error.message).toMatch(/circular|cyclic/i)
}
})
})
describe('Performance SLAs', () => {
it('should meet latency SLAs for single operations', async () => {
const operations = 100
const latencies: number[] = []
for (let i = 0; i < operations; i++) {
const start = performance.now()
await brainy.add({
data: `Performance test document ${i}`,
type: 'perf-test',
metadata: { index: i }
})
latencies.push(performance.now() - start)
}
// Calculate percentiles
latencies.sort((a, b) => a - b)
const p50 = latencies[Math.floor(latencies.length * 0.5)]
const p95 = latencies[Math.floor(latencies.length * 0.95)]
const p99 = latencies[Math.floor(latencies.length * 0.99)]
console.log(`Add Latencies - P50: ${p50.toFixed(2)}ms, P95: ${p95.toFixed(2)}ms, P99: ${p99.toFixed(2)}ms`)
expect(p50).toBeLessThan(10) // P50 < 10ms
expect(p95).toBeLessThan(50) // P95 < 50ms
expect(p99).toBeLessThan(100) // P99 < 100ms
})
it('should maintain throughput under sustained load', async () => {
const duration = 5000 // 5 seconds
const startTime = performance.now()
let operationCount = 0
while (performance.now() - startTime < duration) {
await brainy.add({
data: `Sustained load test ${operationCount}`,
type: 'load-test',
metadata: { timestamp: Date.now() }
})
operationCount++
}
const actualDuration = performance.now() - startTime
const throughput = (operationCount / actualDuration) * 1000
console.log(`Sustained Load - Ops: ${operationCount}, Throughput: ${throughput.toFixed(2)} ops/sec`)
expect(throughput).toBeGreaterThan(50) // At least 50 ops/sec sustained
})
})
})
describe('GET Operations - Comprehensive Testing', () => {
let testIds: string[] = []
beforeEach(async () => {
// Seed test data
testIds = []
for (let i = 0; i < 10; i++) {
const id = await brainy.add({
data: `Test document ${i}`,
type: 'test',
metadata: { index: i, category: `cat-${i % 3}` }
})
testIds.push(id)
}
})
it('should retrieve existing entities', async () => {
const startTime = metricsCollector.startOperation('get-single')
const entity = await brainy.get(testIds[0])
metricsCollector.endOperation('get-single', 1, startTime)
expect(entity).toBeDefined()
expect(entity?.data).toBe('Test document 0')
expect(entity?.metadata?.index).toBe(0)
})
it('should return null for non-existent IDs', async () => {
const result = await brainy.get('non-existent-id-12345')
expect(result).toBeNull()
})
it('should handle batch retrieval efficiently', async () => {
const startTime = metricsCollector.startOperation('get-batch', testIds.length)
const entities = await Promise.all(
testIds.map(id => brainy.get(id))
)
const metric = metricsCollector.endOperation('get-batch', testIds.length, startTime)
expect(entities.every(e => e !== null)).toBe(true)
expect(metric.itemsPerSecond).toBeGreaterThan(100)
})
})
describe('UPDATE Operations - Comprehensive Testing', () => {
let testId: string
beforeEach(async () => {
testId = await brainy.add({
data: 'Original content',
type: 'update-test',
metadata: { version: 1, status: 'draft' }
})
})
it('should update entity metadata', async () => {
const startTime = metricsCollector.startOperation('update-single')
await brainy.update(testId, {
metadata: { version: 2, status: 'published' }
})
metricsCollector.endOperation('update-single', 1, startTime)
const updated = await brainy.get(testId)
expect(updated?.metadata?.version).toBe(2)
expect(updated?.metadata?.status).toBe('published')
})
it('should handle concurrent updates', async () => {
const updates = Array(10).fill(null).map((_, i) =>
brainy.update(testId, {
metadata: { lastUpdate: i }
})
)
const results = await Promise.allSettled(updates)
const succeeded = results.filter(r => r.status === 'fulfilled')
expect(succeeded.length).toBeGreaterThanOrEqual(1)
})
})
describe('DELETE Operations - Comprehensive Testing', () => {
it('should delete existing entities', async () => {
const id = await brainy.add({
data: 'To be deleted',
type: 'delete-test'
})
const startTime = metricsCollector.startOperation('delete-single')
const result = await brainy.remove(id)
metricsCollector.endOperation('delete-single', 1, startTime)
expect(result).toBe(true)
const retrieved = await brainy.get(id)
expect(retrieved).toBeNull()
})
it('should handle bulk deletions', async () => {
const ids: string[] = []
for (let i = 0; i < 100; i++) {
const id = await brainy.add({
data: `Bulk delete test ${i}`,
type: 'bulk-delete'
})
ids.push(id)
}
const startTime = metricsCollector.startOperation('delete-bulk', ids.length)
const results = await Promise.all(
ids.map(id => brainy.remove(id))
)
metricsCollector.endOperation('delete-bulk', ids.length, startTime)
expect(results.every(r => r === true)).toBe(true)
})
})
describe('RELATE Operations - Comprehensive Testing', () => {
it('should create relationships between entities', async () => {
const id1 = await brainy.add({
data: 'Entity 1',
type: 'node'
})
const id2 = await brainy.add({
data: 'Entity 2',
type: 'node'
})
const startTime = metricsCollector.startOperation('relate-single')
const result = await brainy.relate(id1, id2, 'connects_to')
metricsCollector.endOperation('relate-single', 1, startTime)
expect(result).toBe(true)
})
it('should handle complex graph structures', async () => {
const nodeIds: string[] = []
// Create nodes
for (let i = 0; i < 20; i++) {
const id = await brainy.add({
data: `Node ${i}`,
type: 'graph-node',
metadata: { index: i }
})
nodeIds.push(id)
}
// Create relationships (each node connects to next 3)
const startTime = metricsCollector.startOperation('relate-graph', 60)
for (let i = 0; i < nodeIds.length; i++) {
for (let j = 1; j <= 3; j++) {
const targetIdx = (i + j) % nodeIds.length
await brainy.relate(nodeIds[i], nodeIds[targetIdx], 'links_to')
}
}
metricsCollector.endOperation('relate-graph', 60, startTime)
// Graph should be created successfully
expect(nodeIds).toHaveLength(20)
})
})
describe('FIND Operations - Comprehensive Testing', () => {
beforeEach(async () => {
// Create diverse test dataset
for (let i = 0; i < 50; i++) {
await brainy.add({
data: `Search test document ${i}: Lorem ipsum dolor sit amet`,
type: 'searchable',
metadata: {
index: i,
category: `cat-${i % 5}`,
score: Math.random() * 100,
active: i % 2 === 0
}
})
}
})
it('should find entities by metadata criteria', async () => {
const startTime = metricsCollector.startOperation('find-simple')
const results = await brainy.find({
where: {
'metadata.category': 'cat-0'
}
})
metricsCollector.endOperation('find-simple', 1, startTime)
expect(results.length).toBe(10) // 50 / 5 = 10
})
it('should support pagination', async () => {
const page1 = await brainy.find({
limit: 10,
offset: 0
})
const page2 = await brainy.find({
limit: 10,
offset: 10
})
expect(page1).toHaveLength(10)
expect(page2).toHaveLength(10)
expect(page1[0].id).not.toBe(page2[0].id)
})
it('should handle complex queries', async () => {
const results = await brainy.find({
where: {
'metadata.active': true,
'metadata.score': { $gte: 50 }
},
limit: 100
})
expect(results.every(r => r.metadata?.active === true)).toBe(true)
expect(results.every(r => (r.metadata?.score ?? 0) >= 50)).toBe(true)
})
})
describe('Performance Summary', () => {
it('should generate comprehensive performance report', async () => {
await metricsCollector.reportMetrics()
const metrics = metricsCollector.getMetrics()
expect(metrics.length).toBeGreaterThan(0)
// Validate all operations met SLAs
for (const metric of metrics) {
if (metric.operation.includes('single')) {
expect(metric.duration).toBeLessThan(100) // Single ops < 100ms
}
}
})
})
})