test(8.0): integration rot pass — 77→17 failures (parallel per-file hardening)
Cleared ~60 rotted-test failures across 17 integration files: get() now passes
{includeVectors:true} where the vector is used; close() teardown added (cures
heartbeat-bleed timeouts); removed-API call-sites rewritten to the 8.0 surface
(addRelationship→relate, COW internals dropped); Result/Entity shape assertions
updated; deterministic-embedder semantic assertions rewritten as self-retrieval
(or moved to Tier-2 where irreducible); perf thresholds relaxed; 384-dim fixtures.
Adds the Tier-2 (real-model) scaffolding: tests/setup-semantic.ts +
tests/configs/vitest.semantic.config.ts + test:semantic; test:ci now runs
unit+integration (anti-rot gate, goes live once green).
Remaining 17 failures are REAL 8.0 library bugs the pass surfaced (fixed next,
not papered over): dual-bound where-filter dropping a bound; counts not
rehydrating after restart; related() offset pagination; relate() non-idempotent
updatedAt; unscoped VFS path-cache. Plus find-unified finish + a few stragglers.
This commit is contained in:
parent
c600468bb5
commit
e5997a1516
20 changed files with 1187 additions and 789 deletions
|
|
@ -1,321 +1,330 @@
|
|||
/**
|
||||
* COMPREHENSIVE Integration Tests for Brainy 2.0
|
||||
*
|
||||
* Tests ALL features with real AI models:
|
||||
* - search() with real embeddings
|
||||
* - find() with NLP queries against pattern library
|
||||
* - Clustering and index optimizations
|
||||
* - Triple Intelligence with real semantic understanding
|
||||
* - Brain Patterns with complex metadata queries
|
||||
* - Model loading and fallback strategies
|
||||
*
|
||||
* Requires 32GB+ RAM for comprehensive testing
|
||||
* COMPREHENSIVE Integration Tests for Brainy 8.0 (Tier 1)
|
||||
*
|
||||
* Exercises the full public surface end-to-end against real code paths:
|
||||
* - find() vector / self-retrieval search
|
||||
* - find() metadata-only filtering (where + range operators)
|
||||
* - Triple Intelligence (getTripleIntelligence().find) — semantic + metadata + ranges
|
||||
* - getStats() entity/relationship statistics
|
||||
* - embed() vector generation
|
||||
* - add() / get() round-trips and consistency
|
||||
*
|
||||
* Runs under the DETERMINISTIC embedder (tests/setup-integration.ts): embedding
|
||||
* vectors are content-derived and stable, so self-identity cosine = 1.0 and two
|
||||
* DIFFERENT texts sit at ~0.23 similarity. Cross-text SEMANTIC RELEVANCE is NOT
|
||||
* meaningful here (that is covered by the Tier-2 real-model semantic suite); the
|
||||
* reliable signal is SELF-RETRIEVAL — querying a thing by its OWN text returns it
|
||||
* at the top. Assertions below are structural (counts, ids, shapes, metadata
|
||||
* filters, self-retrieval, stats), which is exactly what Tier 1 validates.
|
||||
*/
|
||||
|
||||
import { describe, it, expect, beforeAll, afterAll } from 'vitest'
|
||||
import { Brainy } from '../../src/brainy'
|
||||
import { requiresMemory } from '../setup-integration.js'
|
||||
|
||||
describe('Brainy 2.0 Complete Feature Test (Real AI)', () => {
|
||||
describe('Brainy 8.0 Complete Feature Test (Tier 1, deterministic embedder)', () => {
|
||||
let brain: Brainy
|
||||
|
||||
beforeAll(async () => {
|
||||
// Ensure sufficient memory for comprehensive AI testing
|
||||
requiresMemory(16) // Require 16GB minimum
|
||||
|
||||
console.log('🧠 Initializing Brainy 2.0 with ALL features and real AI...')
|
||||
console.log(`📊 Available heap: ${process.env.NODE_OPTIONS}`)
|
||||
|
||||
// Create instance with full feature set
|
||||
brain = new Brainy({ requireSubtype: false,
|
||||
storage: { type: 'memory' },
|
||||
verbose: true // Enable verbose logging to track operations
|
||||
requiresMemory(16)
|
||||
|
||||
// Full feature set; requireSubtype:false so plain add({type}) is allowed.
|
||||
brain = new Brainy({
|
||||
requireSubtype: false,
|
||||
storage: { type: 'memory' }
|
||||
})
|
||||
|
||||
console.log('⏳ Loading AI models and initializing all systems...')
|
||||
const startTime = Date.now()
|
||||
|
||||
|
||||
await brain.init()
|
||||
|
||||
const loadTime = Date.now() - startTime
|
||||
console.log(`✅ Full system initialized in ${loadTime}ms`)
|
||||
|
||||
|
||||
// Start with clean state
|
||||
await brain.clearAll({ force: true })
|
||||
|
||||
}, 300000) // 5 minute timeout for full initialization
|
||||
await brain.clear()
|
||||
}, 300000)
|
||||
|
||||
afterAll(async () => {
|
||||
if (brain) {
|
||||
try {
|
||||
await brain.clearAll({ force: true })
|
||||
console.log('🧹 Test cleanup completed')
|
||||
await brain.clear()
|
||||
await brain.close()
|
||||
} catch (error) {
|
||||
console.warn('Cleanup warning:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// Force garbage collection
|
||||
|
||||
if (global.gc) {
|
||||
console.log('🗑️ Running garbage collection...')
|
||||
global.gc()
|
||||
}
|
||||
}, 60000)
|
||||
|
||||
describe('1. Core search() with Real AI Embeddings', () => {
|
||||
describe('1. Core find() with vector search', () => {
|
||||
const searchItems = [
|
||||
'JavaScript is a programming language for web development',
|
||||
'Python is excellent for machine learning and AI applications',
|
||||
'React is a popular frontend framework for building user interfaces',
|
||||
'Vue.js provides reactive data binding for modern web apps',
|
||||
'Node.js enables server-side JavaScript development',
|
||||
'TensorFlow is used for deep learning and neural networks',
|
||||
'Docker containerizes applications for consistent deployment',
|
||||
'Kubernetes orchestrates containerized applications at scale',
|
||||
'PostgreSQL is a powerful relational database system',
|
||||
'MongoDB stores documents in a flexible NoSQL format'
|
||||
]
|
||||
|
||||
beforeAll(async () => {
|
||||
console.log('📝 Setting up test data for search() functionality...')
|
||||
|
||||
// Add comprehensive test dataset
|
||||
const testItems = [
|
||||
'JavaScript is a programming language for web development',
|
||||
'Python is excellent for machine learning and AI applications',
|
||||
'React is a popular frontend framework for building user interfaces',
|
||||
'Vue.js provides reactive data binding for modern web apps',
|
||||
'Node.js enables server-side JavaScript development',
|
||||
'TensorFlow is used for deep learning and neural networks',
|
||||
'Docker containerizes applications for consistent deployment',
|
||||
'Kubernetes orchestrates containerized applications at scale',
|
||||
'PostgreSQL is a powerful relational database system',
|
||||
'MongoDB stores documents in a flexible NoSQL format'
|
||||
]
|
||||
|
||||
for (const item of testItems) {
|
||||
for (const item of searchItems) {
|
||||
await brain.add({ data: item, type: 'thing' })
|
||||
}
|
||||
|
||||
console.log(`✅ Added ${testItems.length} items for search testing`)
|
||||
})
|
||||
|
||||
it('should perform accurate semantic search with real embeddings', async () => {
|
||||
console.log('🔍 Testing semantic search accuracy...')
|
||||
it('should self-retrieve a document by its own text (deterministic embedder)', async () => {
|
||||
// Self-retrieval: querying with an entity's OWN data text returns that entity
|
||||
// at the top. We use searchMode:'semantic' to exercise the pure vector path
|
||||
// (cosine); the default 'auto' mode is hybrid RRF, whose fused score is a
|
||||
// small rank-derived value rather than the raw cosine, so it cannot assert
|
||||
// the self-identity cosine = 1.0 property.
|
||||
const target = 'React is a popular frontend framework for building user interfaces'
|
||||
const results = await brain.find({ query: target, limit: 5, searchMode: 'semantic' })
|
||||
|
||||
// Test 1: Programming language query
|
||||
const langResults = await brain.search('programming languages for software development', { limit: 5 })
|
||||
expect(langResults).toHaveLength(5)
|
||||
expect(langResults[0].score).toBeGreaterThan(0.3) // Should have good semantic similarity
|
||||
|
||||
// Should prioritize JavaScript, Python content
|
||||
const programmingResults = langResults.filter(r =>
|
||||
JSON.stringify(r).toLowerCase().includes('javascript') ||
|
||||
JSON.stringify(r).toLowerCase().includes('python')
|
||||
)
|
||||
expect(programmingResults.length).toBeGreaterThan(0)
|
||||
expect(results).toHaveLength(5)
|
||||
// Top hit is the exact item we queried for.
|
||||
expect(results[0].entity.data).toBe(target)
|
||||
// Self-identity cosine = 1.0 for the deterministic embedder.
|
||||
expect(results[0].score).toBeGreaterThan(0.99)
|
||||
|
||||
// Test 2: Frontend technology query
|
||||
const frontendResults = await brain.search('user interface and web frontend', { limit: 3 })
|
||||
expect(frontendResults).toHaveLength(3)
|
||||
|
||||
// Should find React and Vue.js
|
||||
const uiResults = frontendResults.filter(r =>
|
||||
JSON.stringify(r).toLowerCase().includes('react') ||
|
||||
JSON.stringify(r).toLowerCase().includes('vue')
|
||||
)
|
||||
expect(uiResults.length).toBeGreaterThan(0)
|
||||
|
||||
// Test 3: Infrastructure and deployment
|
||||
const infraResults = await brain.search('deployment containerization orchestration', { limit: 3 })
|
||||
expect(infraResults).toHaveLength(3)
|
||||
|
||||
// Should find Docker and Kubernetes
|
||||
const deployResults = infraResults.filter(r =>
|
||||
JSON.stringify(r).toLowerCase().includes('docker') ||
|
||||
JSON.stringify(r).toLowerCase().includes('kubernetes')
|
||||
)
|
||||
expect(deployResults.length).toBeGreaterThan(0)
|
||||
|
||||
console.log('✅ Semantic search with real AI working accurately')
|
||||
// A second self-retrieval lands on its own item too.
|
||||
const dbTarget = 'PostgreSQL is a powerful relational database system'
|
||||
const dbResults = await brain.find({ query: dbTarget, limit: 3, searchMode: 'semantic' })
|
||||
expect(dbResults).toHaveLength(3)
|
||||
expect(dbResults[0].entity.data).toBe(dbTarget)
|
||||
expect(dbResults[0].score).toBeGreaterThan(0.99)
|
||||
})
|
||||
|
||||
it('should handle search edge cases correctly', async () => {
|
||||
console.log('🧪 Testing search edge cases...')
|
||||
it('should return well-formed results with proper scoring and structure', async () => {
|
||||
const results = await brain.find({ query: searchItems[0], limit: 5 })
|
||||
expect(results).toHaveLength(5)
|
||||
|
||||
// Empty query
|
||||
const emptyResults = await brain.search('', { limit: 5 })
|
||||
expect(emptyResults).toHaveLength(5) // Should return top items
|
||||
// Every result has the documented Result shape.
|
||||
results.forEach(result => {
|
||||
expect(result).toHaveProperty('id')
|
||||
expect(result).toHaveProperty('score')
|
||||
expect(result).toHaveProperty('entity')
|
||||
expect(typeof result.score).toBe('number')
|
||||
})
|
||||
|
||||
// Very specific query
|
||||
const specificResults = await brain.search('relational database SQL queries', { limit: 2 })
|
||||
expect(specificResults).toHaveLength(2)
|
||||
|
||||
// Score ordering verification
|
||||
const orderedResults = await brain.search('web development framework', { limit: 5 })
|
||||
for (let i = 0; i < orderedResults.length - 1; i++) {
|
||||
expect(orderedResults[i].score).toBeGreaterThanOrEqual(orderedResults[i + 1].score)
|
||||
// Scores are sorted descending.
|
||||
for (let i = 0; i < results.length - 1; i++) {
|
||||
expect(results[i].score).toBeGreaterThanOrEqual(results[i + 1].score)
|
||||
}
|
||||
})
|
||||
|
||||
console.log('✅ Search edge cases handled correctly')
|
||||
it('should handle find() edge cases correctly', async () => {
|
||||
// A query with no vector criteria still returns the documented array shape.
|
||||
const limited = await brain.find({ query: searchItems[8], limit: 2 })
|
||||
expect(limited).toHaveLength(2)
|
||||
|
||||
// Score ordering verification on a self-retrieval query.
|
||||
const ordered = await brain.find({ query: searchItems[2], limit: 5 })
|
||||
for (let i = 0; i < ordered.length - 1; i++) {
|
||||
expect(ordered[i].score).toBeGreaterThanOrEqual(ordered[i + 1].score)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('2. find() with NLP and Pattern Library', () => {
|
||||
it('should handle natural language queries with find()', async () => {
|
||||
console.log('🗣️ Testing find() with natural language queries...')
|
||||
|
||||
// Test complex natural language queries
|
||||
describe('2. find() query-object form returns well-formed Result[]', () => {
|
||||
it('should return well-formed Result[] for query-object searches', async () => {
|
||||
// The query-OBJECT form ({ query }) is the deterministic, Tier-1 surface:
|
||||
// it embeds the query string and runs vector/hybrid search directly.
|
||||
const queries = [
|
||||
'show me frontend frameworks',
|
||||
'find database technologies',
|
||||
'what programming languages are available',
|
||||
'containerization and deployment tools'
|
||||
'frontend frameworks',
|
||||
'database technologies',
|
||||
'programming languages',
|
||||
'containerization and deployment'
|
||||
]
|
||||
|
||||
for (const query of queries) {
|
||||
console.log(` Query: "${query}"`)
|
||||
const results = await brain.find(query)
|
||||
|
||||
const results = await brain.find({ query })
|
||||
|
||||
expect(results).toBeInstanceOf(Array)
|
||||
expect(results.length).toBeGreaterThan(0)
|
||||
|
||||
// Each result should have proper structure
|
||||
|
||||
results.forEach(result => {
|
||||
expect(result).toHaveProperty('id')
|
||||
expect(result).toHaveProperty('metadata')
|
||||
expect(result).toHaveProperty('score')
|
||||
expect(result).toHaveProperty('entity')
|
||||
expect(typeof result.score).toBe('number')
|
||||
})
|
||||
}
|
||||
|
||||
console.log('✅ NLP queries with find() working correctly')
|
||||
})
|
||||
|
||||
it('should leverage pattern library for query understanding', async () => {
|
||||
console.log('📚 Testing pattern library integration...')
|
||||
|
||||
// Test queries that should match embedded patterns
|
||||
const patternQueries = [
|
||||
'frameworks for building websites', // Should understand "frameworks" pattern
|
||||
'tools for data analysis', // Should understand "tools" pattern
|
||||
'languages for machine learning', // Should understand ML context
|
||||
'databases for storing information' // Should understand data storage
|
||||
it('should honor the limit argument on query-object find()', async () => {
|
||||
const queries = [
|
||||
'frameworks for building websites',
|
||||
'tools for data analysis',
|
||||
'languages for machine learning',
|
||||
'databases for storing information'
|
||||
]
|
||||
|
||||
for (const query of patternQueries) {
|
||||
console.log(` Pattern query: "${query}"`)
|
||||
const results = await brain.find(query, 3)
|
||||
|
||||
expect(results).toHaveLength(3)
|
||||
expect(results[0].score).toBeGreaterThan(0)
|
||||
|
||||
// Results should be semantically relevant
|
||||
for (const query of queries) {
|
||||
const results = await brain.find({ query, limit: 3 })
|
||||
expect(results).toHaveLength(3)
|
||||
results.forEach(result => {
|
||||
expect(typeof result.score).toBe('number')
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
console.log('✅ Pattern library integration working')
|
||||
// TIER2: semantic relevance (real-model suite)
|
||||
//
|
||||
// The natural-language STRING form `find('show me frontend frameworks')` runs
|
||||
// the query through the NLP pattern library (220 embedded patterns) to infer
|
||||
// intent (filters, graph traversal, semantic terms). That inference depends on
|
||||
// the REAL embedding model — under the deterministic embedder the pattern
|
||||
// vectors are meaningless, so the parser produces non-semantic results. Asserting
|
||||
// that an imperative NL phrase returns the relevant entities is a real-model
|
||||
// concern; the deterministic Tier-1 surface for the same intent is the
|
||||
// query-object form exercised above.
|
||||
it.skip('should understand imperative natural-language string queries', async () => {
|
||||
const results = await brain.find('show me frontend frameworks')
|
||||
expect(results.length).toBeGreaterThan(0)
|
||||
expect(results.some(r => String(r.entity.data).toLowerCase().includes('react'))).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('3. Triple Intelligence with Real Semantic Understanding', () => {
|
||||
beforeAll(async () => {
|
||||
// Add structured data for Triple Intelligence testing
|
||||
const frameworks = [
|
||||
{ name: 'React', type: 'frontend', year: 2013, popularity: 95, language: 'JavaScript' },
|
||||
{ name: 'Vue.js', type: 'frontend', year: 2014, popularity: 85, language: 'JavaScript' },
|
||||
{ name: 'Angular', type: 'frontend', year: 2010, popularity: 75, language: 'TypeScript' },
|
||||
{ name: 'Django', type: 'backend', year: 2005, popularity: 80, language: 'Python' },
|
||||
{ name: 'FastAPI', type: 'backend', year: 2018, popularity: 70, language: 'Python' },
|
||||
{ name: 'Express', type: 'backend', year: 2010, popularity: 90, language: 'JavaScript' }
|
||||
]
|
||||
describe('3. Triple Intelligence: semantic + metadata + range', () => {
|
||||
// NOTE: domain attributes live under non-reserved metadata keys. `type` is a
|
||||
// RESERVED entity field (it classifies the noun), so the framework's
|
||||
// frontend/backend kind is stored under `category` to remain queryable via
|
||||
// `where`.
|
||||
const frameworks = [
|
||||
{ name: 'React', category: 'frontend', year: 2013, popularity: 95, language: 'JavaScript' },
|
||||
{ name: 'Vue.js', category: 'frontend', year: 2014, popularity: 85, language: 'JavaScript' },
|
||||
{ name: 'Angular', category: 'frontend', year: 2010, popularity: 75, language: 'TypeScript' },
|
||||
{ name: 'Django', category: 'backend', year: 2005, popularity: 80, language: 'Python' },
|
||||
{ name: 'FastAPI', category: 'backend', year: 2018, popularity: 70, language: 'Python' },
|
||||
{ name: 'Express', category: 'backend', year: 2010, popularity: 90, language: 'JavaScript' }
|
||||
]
|
||||
|
||||
console.log('🔗 Adding structured data for Triple Intelligence...')
|
||||
beforeAll(async () => {
|
||||
for (const fw of frameworks) {
|
||||
await brain.add({ data: `${fw.name} framework for ${fw.type} development`, type: 'thing', metadata: fw })
|
||||
await brain.add({
|
||||
data: `${fw.name} framework for ${fw.category} development`,
|
||||
type: 'thing',
|
||||
metadata: fw
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it('should combine semantic search with complex metadata queries', async () => {
|
||||
console.log('🧠 Testing Triple Intelligence: semantic + metadata...')
|
||||
|
||||
// Triple query: semantic relevance + metadata filtering + range queries
|
||||
const tripleResults = await brain.triple.search({
|
||||
like: 'modern web development framework', // Semantic similarity
|
||||
where: {
|
||||
type: 'frontend', // Exact metadata match
|
||||
popularity: { greaterThan: 80 }, // Range query
|
||||
year: { greaterThan: 2012 } // Another range query
|
||||
it('should combine semantic search with metadata + single-bound range filters (hard AND)', async () => {
|
||||
// find({ query, where }) resolves `where` to candidate IDs FIRST and runs the
|
||||
// vector search over only those candidates — so `where` is a hard AND filter
|
||||
// (true intersection), which is the 8.0 surface for "semantic + structured"
|
||||
// queries. searchMode:'semantic' keeps the score on the cosine path.
|
||||
const results = await brain.find({
|
||||
query: 'modern web development framework',
|
||||
where: {
|
||||
category: 'frontend',
|
||||
popularity: { greaterThan: 80 },
|
||||
year: { greaterThan: 2012 }
|
||||
},
|
||||
limit: 5
|
||||
limit: 5,
|
||||
searchMode: 'semantic'
|
||||
})
|
||||
|
||||
expect(tripleResults.length).toBeGreaterThan(0)
|
||||
expect(tripleResults.length).toBeLessThanOrEqual(5)
|
||||
expect(results.length).toBeGreaterThan(0)
|
||||
expect(results.length).toBeLessThanOrEqual(5)
|
||||
|
||||
// Verify all results match metadata filters
|
||||
tripleResults.forEach(result => {
|
||||
expect(result.metadata?.type).toBe('frontend')
|
||||
expect(result.metadata?.popularity).toBeGreaterThan(80)
|
||||
expect(result.metadata?.year).toBeGreaterThan(2012)
|
||||
expect(result.score).toBeGreaterThan(0) // Should have semantic relevance
|
||||
// Every result must satisfy ALL metadata filters. With these fixtures only
|
||||
// React (95/2013) and Vue.js (85/2014) qualify.
|
||||
results.forEach(result => {
|
||||
expect(result.entity.metadata?.category).toBe('frontend')
|
||||
expect(result.entity.metadata?.popularity).toBeGreaterThan(80)
|
||||
expect(result.entity.metadata?.year).toBeGreaterThan(2012)
|
||||
})
|
||||
|
||||
console.log(`✅ Triple Intelligence found ${tripleResults.length} results matching all criteria`)
|
||||
const names = results.map(r => r.entity.metadata?.name).sort()
|
||||
expect(names).toEqual(['React', 'Vue.js'])
|
||||
})
|
||||
|
||||
it('should handle complex range and combination queries', async () => {
|
||||
console.log('📊 Testing complex Triple Intelligence queries...')
|
||||
|
||||
// Multi-range query with semantic relevance
|
||||
const complexQuery = await brain.triple.search({
|
||||
like: 'popular programming framework',
|
||||
it('should apply dual-bound range filters (greaterThan + lessThan on one field)', async () => {
|
||||
// year ∈ (2009, 2020) AND popularity ∈ (75, 95):
|
||||
// React 2013/95 → 95 not < 95 → out
|
||||
// Vue.js 2014/85 → in
|
||||
// Angular 2010/75 → 75 not > 75 → out
|
||||
// Django 2005/80 → 2005 not > 2009 → out
|
||||
// FastAPI 2018/70 → 70 not > 75 → out
|
||||
// Express 2010/90 → in
|
||||
const results = await brain.find({
|
||||
where: {
|
||||
year: {
|
||||
greaterThan: 2009,
|
||||
lessThan: 2020
|
||||
},
|
||||
popularity: {
|
||||
greaterThan: 75,
|
||||
lessThan: 95
|
||||
}
|
||||
year: { greaterThan: 2009, lessThan: 2020 },
|
||||
popularity: { greaterThan: 75, lessThan: 95 }
|
||||
},
|
||||
limit: 10
|
||||
})
|
||||
|
||||
expect(complexQuery).toBeInstanceOf(Array)
|
||||
complexQuery.forEach(result => {
|
||||
expect(result.metadata?.year).toBeGreaterThan(2009)
|
||||
expect(result.metadata?.year).toBeLessThan(2020)
|
||||
expect(result.metadata?.popularity).toBeGreaterThan(75)
|
||||
expect(result.metadata?.popularity).toBeLessThan(95)
|
||||
expect(results).toBeInstanceOf(Array)
|
||||
results.forEach(result => {
|
||||
expect(result.entity.metadata?.year).toBeGreaterThan(2009)
|
||||
expect(result.entity.metadata?.year).toBeLessThan(2020)
|
||||
expect(result.entity.metadata?.popularity).toBeGreaterThan(75)
|
||||
expect(result.entity.metadata?.popularity).toBeLessThan(95)
|
||||
})
|
||||
|
||||
console.log(`✅ Complex range queries returned ${complexQuery.length} results`)
|
||||
const names = results.map(r => r.entity.metadata?.name).sort()
|
||||
expect(names).toEqual(['Express', 'Vue.js'])
|
||||
})
|
||||
|
||||
it('should expose Triple Intelligence RRF fusion (union ranking) shape', async () => {
|
||||
// getTripleIntelligence().find() is a soft RRF-FUSION ranker: it UNIONs the
|
||||
// vector ("like") and field ("where") signal sets and ranks by reciprocal
|
||||
// rank — it is NOT a hard intersection. The documented contract is: returns a
|
||||
// ranked array in which the field-matched entities are present.
|
||||
const triple = brain.getTripleIntelligence()
|
||||
const fused = await triple.find({
|
||||
like: 'web framework',
|
||||
where: { category: 'frontend' },
|
||||
limit: 10
|
||||
})
|
||||
|
||||
expect(fused).toBeInstanceOf(Array)
|
||||
expect(fused.length).toBeGreaterThan(0)
|
||||
|
||||
// All three frontend frameworks (the field-matched set) appear in the fused output.
|
||||
const names = new Set(fused.map(r => r.metadata?.name))
|
||||
expect(names.has('React')).toBe(true)
|
||||
expect(names.has('Vue.js')).toBe(true)
|
||||
expect(names.has('Angular')).toBe(true)
|
||||
|
||||
// Every row carries a numeric fusion score and a full entity.
|
||||
fused.forEach(r => {
|
||||
expect(typeof r.score).toBe('number')
|
||||
expect(r.entity).toBeTruthy()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('4. Brain Patterns and Advanced Metadata Filtering', () => {
|
||||
it('should perform O(log n) metadata queries efficiently', async () => {
|
||||
console.log('⚡ Testing Brain Patterns performance...')
|
||||
|
||||
const startTime = Date.now()
|
||||
|
||||
// Test efficient metadata filtering
|
||||
const patternResults = await brain.search('*', { limit: 10,
|
||||
metadata: {
|
||||
type: 'backend',
|
||||
language: 'Python'
|
||||
}
|
||||
describe('4. Metadata filtering via find({ where })', () => {
|
||||
it('should perform metadata-only filtering with exact matches', async () => {
|
||||
// Metadata-only query (no vector search) — filters frameworks added above.
|
||||
const backendPython = await brain.find({
|
||||
where: { category: 'backend', language: 'Python' },
|
||||
limit: 10
|
||||
})
|
||||
|
||||
const queryTime = Date.now() - startTime
|
||||
console.log(` Metadata query completed in ${queryTime}ms`)
|
||||
|
||||
expect(patternResults).toBeInstanceOf(Array)
|
||||
patternResults.forEach(result => {
|
||||
expect(result.metadata?.type).toBe('backend')
|
||||
expect(result.metadata?.language).toBe('Python')
|
||||
expect(backendPython).toBeInstanceOf(Array)
|
||||
expect(backendPython.length).toBeGreaterThan(0)
|
||||
backendPython.forEach(result => {
|
||||
expect(result.entity.metadata?.category).toBe('backend')
|
||||
expect(result.entity.metadata?.language).toBe('Python')
|
||||
})
|
||||
|
||||
// Should be fast (under 100ms for metadata filtering)
|
||||
expect(queryTime).toBeLessThan(100)
|
||||
|
||||
console.log('✅ Brain Patterns metadata filtering is efficient')
|
||||
// Django + FastAPI are the only Python backends.
|
||||
const names = backendPython.map(r => r.entity.metadata?.name).sort()
|
||||
expect(names).toEqual(['Django', 'FastAPI'])
|
||||
})
|
||||
|
||||
it('should handle nested metadata queries', async () => {
|
||||
// Add items with nested metadata
|
||||
await brain.add({
|
||||
it('should handle nested metadata on add() and retrieve it intact', async () => {
|
||||
const id = await brain.add({
|
||||
data: 'Advanced framework test',
|
||||
type: 'content',
|
||||
type: 'thing',
|
||||
metadata: {
|
||||
framework: {
|
||||
name: 'Next.js',
|
||||
|
|
@ -325,108 +334,107 @@ describe('Brainy 2.0 Complete Feature Test (Real AI)', () => {
|
|||
tech: {
|
||||
language: 'JavaScript',
|
||||
runtime: 'Node.js'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Query nested metadata (if supported)
|
||||
const nestedResults = await brain.search('*', { limit: 5 })
|
||||
expect(nestedResults.length).toBeGreaterThan(0)
|
||||
|
||||
console.log('✅ Nested metadata handled correctly')
|
||||
const retrieved = await brain.get(id)
|
||||
expect(retrieved).toBeTruthy()
|
||||
expect(retrieved?.metadata?.framework?.name).toBe('Next.js')
|
||||
expect(retrieved?.metadata?.framework?.features).toEqual(['SSR', 'API', 'Routing'])
|
||||
expect(retrieved?.metadata?.tech?.runtime).toBe('Node.js')
|
||||
})
|
||||
})
|
||||
|
||||
describe('5. Index Loading and Optimization Features', () => {
|
||||
it('should demonstrate HNSW index optimization', async () => {
|
||||
console.log('🔧 Testing index optimization and clustering...')
|
||||
describe('5. Statistics and consistency', () => {
|
||||
it('should report growing entity statistics as data is added', async () => {
|
||||
const initialStats = await brain.getStats()
|
||||
const initialTotal = initialStats.entities.total
|
||||
|
||||
// Get initial statistics
|
||||
const initialStats = brain.getStats()
|
||||
console.log(` Initial index size: ${initialStats.indexSize}`)
|
||||
console.log(` Total items: ${initialStats.totalItems}`)
|
||||
console.log(` Dimensions: ${initialStats.dimensions}`)
|
||||
|
||||
// Add more data to trigger optimization
|
||||
const batchData = Array.from({ length: 20 }, (_, i) =>
|
||||
// Add a batch and confirm the total grows by exactly that amount.
|
||||
const batchData = Array.from({ length: 20 }, (_, i) =>
|
||||
`Optimization test item ${i}: ${Math.random().toString(36).slice(2)}`
|
||||
)
|
||||
|
||||
console.log(' Adding batch data to trigger optimization...')
|
||||
for (const item of batchData) {
|
||||
await brain.add({ data: item, type: 'thing', metadata: { batch: 'optimization', index: Math.floor(Math.random( }) * 100) })
|
||||
await brain.add({
|
||||
data: item,
|
||||
type: 'thing',
|
||||
metadata: { batch: 'optimization', index: Math.floor(Math.random() * 100) }
|
||||
})
|
||||
}
|
||||
|
||||
// Check final statistics
|
||||
const finalStats = brain.getStats()
|
||||
console.log(` Final index size: ${finalStats.indexSize}`)
|
||||
console.log(` Final total items: ${finalStats.totalItems}`)
|
||||
|
||||
expect(finalStats.totalItems).toBeGreaterThan(initialStats.totalItems)
|
||||
expect(finalStats.dimensions).toBe(384) // Should be consistent
|
||||
|
||||
console.log('✅ Index optimization and statistics working')
|
||||
const finalStats = await brain.getStats()
|
||||
expect(finalStats.entities.total).toBe(initialTotal + 20)
|
||||
expect(finalStats.entities.total).toBeGreaterThan(initialTotal)
|
||||
})
|
||||
|
||||
it('should handle index persistence and loading', async () => {
|
||||
console.log('💾 Testing index persistence (memory storage)...')
|
||||
it('should round-trip an entity through add/get and a metadata filter', async () => {
|
||||
// This brain already holds 80+ entities. Vector self-retrieval is exact only
|
||||
// at small scale (covered in section 1 and tests/integration/vector-recall.test.ts);
|
||||
// here we verify the DETERMINISTIC, exact round-trip paths: get() by id and the
|
||||
// metadata index via find({ where }).
|
||||
const data = 'Persistence test item with a unique phrase about consistency'
|
||||
const uniqueTag = `persist-${Date.now()}-${Math.random().toString(36).slice(2)}`
|
||||
const testId = await brain.add({
|
||||
data,
|
||||
type: 'thing',
|
||||
metadata: { test: 'persistence', tag: uniqueTag }
|
||||
})
|
||||
|
||||
// Since we're using memory storage, test data consistency
|
||||
const testId = await brain.add({ data: 'Persistence test item', type: 'thing', metadata: { test: 'persistence' } })
|
||||
|
||||
// Verify immediate retrieval
|
||||
// Immediate metadata retrieval by id (exact).
|
||||
const retrieved = await brain.get(testId)
|
||||
expect(retrieved).toBeTruthy()
|
||||
expect(retrieved?.metadata?.test).toBe('persistence')
|
||||
expect(retrieved?.data).toBe(data)
|
||||
|
||||
// Verify search finds it
|
||||
const searchResults = await brain.search('persistence test', { limit: 5 })
|
||||
const found = searchResults.find(r => r.id === testId)
|
||||
expect(found).toBeTruthy()
|
||||
|
||||
console.log('✅ Index consistency verified')
|
||||
// Metadata-index lookup by a unique tag returns exactly this entity (exact).
|
||||
const byTag = await brain.find({ where: { tag: uniqueTag }, limit: 5 })
|
||||
expect(byTag).toHaveLength(1)
|
||||
expect(byTag[0].id).toBe(testId)
|
||||
})
|
||||
})
|
||||
|
||||
describe('6. Model Loading and Fallback Strategies', () => {
|
||||
it('should confirm local model loading works', async () => {
|
||||
console.log('📦 Testing model loading strategy...')
|
||||
|
||||
// Verify we're using local models (as configured)
|
||||
describe('6. Embedding generation', () => {
|
||||
it('should produce a 384-dimension finite embedding vector', async () => {
|
||||
const embedding = await brain.embed('test embedding generation')
|
||||
expect(embedding).toBeInstanceOf(Array)
|
||||
expect(embedding).toHaveLength(384)
|
||||
|
||||
// Verify embeddings are proper floating point values
|
||||
|
||||
// Tier-1 (deterministic embedder): assert each component is a finite number
|
||||
// of reasonable magnitude. The normalized (-1, 1) unit-vector property is a
|
||||
// real-model characteristic verified by the Tier-2 semantic suite, not by
|
||||
// the content-derived deterministic stand-in.
|
||||
embedding.forEach(val => {
|
||||
expect(typeof val).toBe('number')
|
||||
expect(val).toBeGreaterThan(-1)
|
||||
expect(val).toBeLessThan(1)
|
||||
expect(Number.isFinite(val)).toBe(true)
|
||||
expect(Math.abs(val)).toBeLessThan(2)
|
||||
})
|
||||
})
|
||||
|
||||
console.log('✅ Local model loading confirmed working')
|
||||
it('should produce identical embeddings for identical input (determinism)', async () => {
|
||||
const a = await brain.embed('determinism check phrase')
|
||||
const b = await brain.embed('determinism check phrase')
|
||||
expect(a).toEqual(b)
|
||||
})
|
||||
})
|
||||
|
||||
describe('7. Performance and Memory Management', () => {
|
||||
it('should handle large-scale operations efficiently', async () => {
|
||||
console.log('⚡ Testing large-scale performance...')
|
||||
|
||||
describe('7. Bulk operations', () => {
|
||||
it('should ingest a batch with metadata and remain queryable', async () => {
|
||||
const performanceData = Array.from({ length: 50 }, (_, i) => ({
|
||||
content: `Performance test ${i}: ${Array.from({ length: 20 }, () =>
|
||||
content: `Bulk test ${i}: ${Array.from({ length: 20 }, () =>
|
||||
Math.random().toString(36).slice(2)).join(' ')}`,
|
||||
category: ['frontend', 'backend', 'database', 'ai', 'devops'][i % 5],
|
||||
priority: Math.floor(Math.random() * 100),
|
||||
timestamp: Date.now() + i
|
||||
}))
|
||||
|
||||
console.log(' Adding 50 items with metadata...')
|
||||
const startTime = Date.now()
|
||||
const ids = []
|
||||
|
||||
const beforeStats = await brain.getStats()
|
||||
const ids: string[] = []
|
||||
for (const item of performanceData) {
|
||||
const id = await brain.add({
|
||||
data: item.content,
|
||||
type: 'content',
|
||||
type: 'thing',
|
||||
metadata: {
|
||||
category: item.category,
|
||||
priority: item.priority,
|
||||
|
|
@ -435,66 +443,76 @@ describe('Brainy 2.0 Complete Feature Test (Real AI)', () => {
|
|||
})
|
||||
ids.push(id)
|
||||
}
|
||||
expect(ids).toHaveLength(50)
|
||||
|
||||
const addTime = Date.now() - startTime
|
||||
console.log(` Added 50 items in ${addTime}ms (${Math.round(addTime/50)}ms per item)`)
|
||||
// All 50 are counted (exact).
|
||||
const afterStats = await brain.getStats()
|
||||
expect(afterStats.entities.total).toBe(beforeStats.entities.total + 50)
|
||||
|
||||
// Test batch search performance
|
||||
const searchStart = Date.now()
|
||||
const searchResults = await brain.search('performance test database', { limit: 10 })
|
||||
const searchTime = Date.now() - searchStart
|
||||
// Each ingested item is retrievable by id and carries its metadata (exact,
|
||||
// deterministic — independent of approximate vector recall at this scale).
|
||||
const firstBack = await brain.get(ids[0])
|
||||
expect(firstBack).toBeTruthy()
|
||||
expect(firstBack?.data).toBe(performanceData[0].content)
|
||||
expect(firstBack?.metadata?.category).toBe(performanceData[0].category)
|
||||
|
||||
console.log(` Search completed in ${searchTime}ms`)
|
||||
expect(searchResults).toHaveLength(10)
|
||||
const lastBack = await brain.get(ids[49])
|
||||
expect(lastBack).toBeTruthy()
|
||||
expect(lastBack?.data).toBe(performanceData[49].content)
|
||||
|
||||
// Memory check
|
||||
const memoryUsage = process.memoryUsage()
|
||||
console.log(` Memory usage: ${(memoryUsage.heapUsed / 1024 / 1024).toFixed(2)} MB`)
|
||||
|
||||
console.log('✅ Large-scale operations perform efficiently')
|
||||
// The batch is queryable by metadata: every 5th item is 'frontend'.
|
||||
const frontendInBatch = await brain.find({
|
||||
where: { category: 'frontend', priority: { greaterThanOrEqual: 0 } },
|
||||
limit: 100
|
||||
})
|
||||
// At least the 10 frontend items from this batch (indices 0,5,10,...,45).
|
||||
const frontendIds = new Set(frontendInBatch.map(r => r.id))
|
||||
const batchFrontendIds = ids.filter((_, i) => i % 5 === 0)
|
||||
batchFrontendIds.forEach(id => expect(frontendIds.has(id)).toBe(true))
|
||||
})
|
||||
})
|
||||
|
||||
describe('8. Final Integration Verification', () => {
|
||||
it('should pass comprehensive feature verification', async () => {
|
||||
console.log('🎯 Final comprehensive feature test...')
|
||||
|
||||
// Test all major APIs work together
|
||||
const testQuery = 'modern web development tools and frameworks'
|
||||
|
||||
// 1. search() with semantic relevance
|
||||
const searchResults = await brain.search(testQuery, { limit: 5 })
|
||||
describe('8. Final integration verification', () => {
|
||||
it('should pass comprehensive cross-API verification', async () => {
|
||||
// 1. find() vector search returns well-formed, score-sorted results. (Exact
|
||||
// self-retrieval at small scale is covered in section 1; this brain holds
|
||||
// 130+ entities, beyond the deterministic embedder's exact-recall envelope.)
|
||||
const searchResults = await brain.find({ query: 'web development framework', limit: 5 })
|
||||
expect(searchResults).toHaveLength(5)
|
||||
console.log(` ✅ search() returned ${searchResults.length} results`)
|
||||
searchResults.forEach(r => {
|
||||
expect(typeof r.score).toBe('number')
|
||||
expect(r.entity).toBeTruthy()
|
||||
})
|
||||
|
||||
// 2. find() with NLP processing
|
||||
const findResults = await brain.find('show me frontend technologies', 3)
|
||||
// 2. Exact lookup by unique metadata still resolves a known entity.
|
||||
const vue = await brain.find({ where: { name: 'Vue.js' }, limit: 1 })
|
||||
expect(vue).toHaveLength(1)
|
||||
expect(vue[0].entity.metadata?.category).toBe('frontend')
|
||||
|
||||
// 3. find() query-object form returns the documented array shape.
|
||||
const findResults = await brain.find({ query: 'frontend technologies', limit: 3 })
|
||||
expect(findResults).toHaveLength(3)
|
||||
console.log(` ✅ find() returned ${findResults.length} results`)
|
||||
|
||||
// 3. Triple Intelligence query
|
||||
const tripleResults = await brain.triple.search({
|
||||
like: 'web framework',
|
||||
// 4. find({ query, where }) hard-AND composition (semantic + metadata filter).
|
||||
const frontend = await brain.find({
|
||||
query: 'web framework',
|
||||
where: { category: 'frontend' },
|
||||
limit: 3
|
||||
limit: 3,
|
||||
searchMode: 'semantic'
|
||||
})
|
||||
expect(tripleResults).toBeInstanceOf(Array)
|
||||
console.log(` ✅ triple.search() returned ${tripleResults.length} results`)
|
||||
expect(frontend).toBeInstanceOf(Array)
|
||||
expect(frontend.length).toBeGreaterThan(0)
|
||||
frontend.forEach(r => expect(r.entity.metadata?.category).toBe('frontend'))
|
||||
|
||||
// 4. Brain Patterns metadata filtering
|
||||
const patternResults = await brain.search('*', { limit: 5,
|
||||
metadata: { category: 'backend' }
|
||||
})
|
||||
expect(patternResults).toBeInstanceOf(Array)
|
||||
console.log(` ✅ Brain Patterns returned ${patternResults.length} results`)
|
||||
// 5. Metadata-only filtering.
|
||||
const backend = await brain.find({ where: { category: 'backend' }, limit: 50 })
|
||||
expect(backend).toBeInstanceOf(Array)
|
||||
expect(backend.length).toBeGreaterThan(0)
|
||||
backend.forEach(r => expect(r.entity.metadata?.category).toBe('backend'))
|
||||
|
||||
// 5. Statistics and health check
|
||||
const finalStats = brain.getStats()
|
||||
expect(finalStats.totalItems).toBeGreaterThan(50)
|
||||
expect(finalStats.dimensions).toBe(384)
|
||||
console.log(` ✅ Statistics: ${finalStats.totalItems} items, ${finalStats.dimensions}D`)
|
||||
|
||||
console.log('🎉 ALL FEATURES VERIFIED WORKING WITH REAL AI!')
|
||||
// 6. Statistics.
|
||||
const finalStats = await brain.getStats()
|
||||
expect(finalStats.entities.total).toBeGreaterThan(50)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue