UNPKG

universal-ai-brain

Version:

🧠 UNIVERSAL AI BRAIN 3.3 - The world's most advanced cognitive architecture with 24 specialized systems, MongoDB 8.1 $rankFusion hybrid search, latest Voyage 3.5 embeddings, and framework-agnostic design. Works with Mastra, Vercel AI, LangChain, OpenAI A

533 lines (449 loc) • 17.1 kB
/** * @file ContextCollection Tests * Comprehensive tests for the ContextCollection component */ import { ContextCollection, ContextItem, ContextFilter, ContextUpdateData } from '../../collections/ContextCollection'; import { Db, Collection } from 'mongodb'; // Mock MongoDB jest.mock('mongodb'); describe('ContextCollection', () => { let contextCollection: ContextCollection; let mockDb: jest.Mocked<Db>; let mockCollection: jest.Mocked<Collection>; beforeEach(() => { mockCollection = { createIndex: jest.fn().mockResolvedValue('index_created'), insertOne: jest.fn().mockResolvedValue({ insertedId: 'context_123' }), find: jest.fn().mockReturnValue({ sort: jest.fn().mockReturnThis(), skip: jest.fn().mockReturnThis(), limit: jest.fn().mockReturnThis(), toArray: jest.fn().mockResolvedValue([]) }), findOneAndUpdate: jest.fn().mockResolvedValue({ value: null }), aggregate: jest.fn().mockReturnValue({ toArray: jest.fn().mockResolvedValue([]) }), deleteMany: jest.fn().mockResolvedValue({ deletedCount: 0 }) } as any; mockDb = { collection: jest.fn().mockReturnValue(mockCollection) } as any; contextCollection = new ContextCollection(mockDb); }); describe('Index Creation', () => { it('should create all required indexes', async () => { await contextCollection.createIndexes(); expect(mockCollection.createIndex).toHaveBeenCalledWith( { contextId: 1 }, { unique: true } ); expect(mockCollection.createIndex).toHaveBeenCalledWith({ source: 1 }); expect(mockCollection.createIndex).toHaveBeenCalledWith({ 'metadata.type': 1 }); expect(mockCollection.createIndex).toHaveBeenCalledWith({ 'metadata.framework': 1 }); expect(mockCollection.createIndex).toHaveBeenCalledWith({ 'metadata.sessionId': 1 }); expect(mockCollection.createIndex).toHaveBeenCalledWith({ 'metadata.userId': 1 }); expect(mockCollection.createIndex).toHaveBeenCalledWith({ 'metadata.tags': 1 }); expect(mockCollection.createIndex).toHaveBeenCalledWith({ relevanceScore: -1 }); expect(mockCollection.createIndex).toHaveBeenCalledWith({ 'metadata.importance': -1 }); expect(mockCollection.createIndex).toHaveBeenCalledWith({ 'metadata.confidence': -1 }); expect(mockCollection.createIndex).toHaveBeenCalledWith({ 'metadata.lastUsed': -1 }); expect(mockCollection.createIndex).toHaveBeenCalledWith({ 'metadata.usageCount': -1 }); }); it('should create compound indexes for performance', async () => { await contextCollection.createIndexes(); expect(mockCollection.createIndex).toHaveBeenCalledWith({ 'metadata.framework': 1, 'metadata.type': 1, relevanceScore: -1 }); expect(mockCollection.createIndex).toHaveBeenCalledWith({ 'metadata.sessionId': 1, 'metadata.lastUsed': -1 }); expect(mockCollection.createIndex).toHaveBeenCalledWith({ 'metadata.userId': 1, 'metadata.framework': 1, 'metadata.lastUsed': -1 }); }); it('should create TTL index for automatic cleanup', async () => { await contextCollection.createIndexes(); expect(mockCollection.createIndex).toHaveBeenCalledWith( { ttl: 1 }, { expireAfterSeconds: 0 } ); }); it('should create vector and text search indexes', async () => { await contextCollection.createIndexes(); expect(mockCollection.createIndex).toHaveBeenCalledWith({ 'embedding.values': '2dsphere' }); expect(mockCollection.createIndex).toHaveBeenCalledWith( { content: 'text', source: 'text', 'metadata.tags': 'text' }, { name: 'context_text_index' } ); }); }); describe('Context Storage', () => { it('should store context item successfully', async () => { const contextData = { contextId: 'context_123', content: 'User prefers morning meetings', source: 'user_input', relevanceScore: 0.8, metadata: { type: 'preference' as const, framework: 'vercel-ai', sessionId: 'session_123', userId: 'user_456', tags: ['preference', 'scheduling'], importance: 0.8, confidence: 0.9, lastUsed: new Date(), usageCount: 0 }, embedding: { values: [0.1, 0.2, 0.3], model: 'text-embedding-3-small', dimensions: 1536 } }; const result = await contextCollection.storeContext(contextData); expect(mockCollection.insertOne).toHaveBeenCalled(); expect(result.contextId).toBe('context_123'); expect(result.content).toBe('User prefers morning meetings'); expect(result.createdAt).toBeInstanceOf(Date); expect(result.updatedAt).toBeInstanceOf(Date); }); it('should store context without embedding', async () => { const contextData = { contextId: 'context_456', content: 'Simple context item', source: 'system', relevanceScore: 0.7, metadata: { type: 'knowledge' as const, framework: 'mastra', tags: [], importance: 0.7, confidence: 0.8, lastUsed: new Date(), usageCount: 0 } }; const result = await contextCollection.storeContext(contextData); expect(mockCollection.insertOne).toHaveBeenCalled(); expect(result.contextId).toBe('context_456'); expect(result.embedding).toBeUndefined(); }); it('should store context with TTL', async () => { const ttlDate = new Date(Date.now() + 24 * 60 * 60 * 1000); // 24 hours from now const contextData = { contextId: 'context_ttl', content: 'Temporary context', source: 'temp', relevanceScore: 0.6, metadata: { type: 'conversation' as const, framework: 'universal', tags: [], importance: 0.5, confidence: 0.7, lastUsed: new Date(), usageCount: 0 }, ttl: ttlDate }; const result = await contextCollection.storeContext(contextData); expect(result.ttl).toEqual(ttlDate); }); }); describe('Context Retrieval', () => { it('should find context items with basic filter', async () => { const mockContexts = [ { _id: 'doc1', contextId: 'context_1', content: 'Test context', source: 'test', relevanceScore: 0.8, metadata: { type: 'preference', framework: 'vercel-ai', tags: ['test'] }, createdAt: new Date(), updatedAt: new Date() } ]; (mockCollection.find().toArray as jest.Mock).mockResolvedValue(mockContexts); const filter: ContextFilter = { type: 'preference', framework: 'vercel-ai' }; const results = await contextCollection.findContext(filter); expect(mockCollection.find).toHaveBeenCalledWith( expect.objectContaining({ 'metadata.type': 'preference', 'metadata.framework': 'vercel-ai' }), expect.any(Object) ); expect(results).toHaveLength(1); expect(results[0].contextId).toBe('context_1'); }); it('should apply search options correctly', async () => { const filter: ContextFilter = { framework: 'mastra' }; const options = { limit: 20, skip: 10, sort: { relevanceScore: -1 }, minRelevanceScore: 0.7 }; await contextCollection.findContext(filter, options); expect(mockCollection.find).toHaveBeenCalledWith( expect.objectContaining({ 'metadata.framework': 'mastra', relevanceScore: { $gte: 0.7 } }), expect.any(Object) ); expect(mockCollection.find().sort).toHaveBeenCalledWith({ relevanceScore: -1 }); expect(mockCollection.find().skip).toHaveBeenCalledWith(10); expect(mockCollection.find().limit).toHaveBeenCalledWith(20); }); it('should exclude embeddings when not requested', async () => { const filter: ContextFilter = { framework: 'langchain' }; const options = { includeEmbeddings: false }; await contextCollection.findContext(filter, options); expect(mockCollection.find).toHaveBeenCalledWith( expect.any(Object), expect.objectContaining({ projection: { 'embedding.values': 0 } }) ); }); it('should include embeddings when requested', async () => { const filter: ContextFilter = { framework: 'openai-agents' }; const options = { includeEmbeddings: true }; await contextCollection.findContext(filter, options); expect(mockCollection.find).toHaveBeenCalledWith( expect.any(Object), expect.objectContaining({ projection: {} }) ); }); it('should filter by date ranges', async () => { const startDate = new Date('2024-01-01'); const endDate = new Date('2024-01-31'); const filter: ContextFilter = { createdAfter: startDate, createdBefore: endDate, lastUsedAfter: startDate, lastUsedBefore: endDate }; await contextCollection.findContext(filter); expect(mockCollection.find).toHaveBeenCalledWith( expect.objectContaining({ createdAt: { $gte: startDate, $lte: endDate }, 'metadata.lastUsed': { $gte: startDate, $lte: endDate } }), expect.any(Object) ); }); it('should filter by tags using $in operator', async () => { const filter: ContextFilter = { tags: ['preference', 'scheduling', 'important'] }; await contextCollection.findContext(filter); expect(mockCollection.find).toHaveBeenCalledWith( expect.objectContaining({ 'metadata.tags': { $in: ['preference', 'scheduling', 'important'] } }), expect.any(Object) ); }); }); describe('Context Updates', () => { it('should update context item successfully', async () => { const updatedContext = { _id: 'context_123', contextId: 'context_123', content: 'Updated content', updatedAt: new Date() }; mockCollection.findOneAndUpdate.mockResolvedValue({ value: updatedContext }); const updateData: ContextUpdateData = { content: 'Updated content', relevanceScore: 0.9 }; const result = await contextCollection.updateContext('context_123', updateData); expect(mockCollection.findOneAndUpdate).toHaveBeenCalledWith( { contextId: 'context_123' }, { $set: expect.objectContaining({ content: 'Updated content', relevanceScore: 0.9, updatedAt: expect.any(Date) }) }, { returnDocument: 'after' } ); expect(result?.contextId).toBe('context_123'); }); it('should return null for non-existent context', async () => { mockCollection.findOneAndUpdate.mockResolvedValue({ value: null }); const result = await contextCollection.updateContext('non_existent', { content: 'New content' }); expect(result).toBeNull(); }); }); describe('Usage Tracking', () => { it('should record context usage correctly', async () => { const updatedContext = { _id: 'context_123', contextId: 'context_123', metadata: { usageCount: 6, lastUsed: new Date() } }; mockCollection.findOneAndUpdate.mockResolvedValue({ value: updatedContext }); const result = await contextCollection.recordContextUsage('context_123'); expect(mockCollection.findOneAndUpdate).toHaveBeenCalledWith( { contextId: 'context_123' }, { $inc: { 'metadata.usageCount': 1 }, $set: { 'metadata.lastUsed': expect.any(Date), updatedAt: expect.any(Date) } }, { returnDocument: 'after' } ); expect(result?.metadata.usageCount).toBe(6); }); }); describe('Context Statistics', () => { it('should generate comprehensive context statistics', async () => { const mockStatsResult = [{ totalCount: [{ total: 150 }], byType: [ { _id: 'preference', count: 50 }, { _id: 'knowledge', count: 60 }, { _id: 'conversation', count: 40 } ], byFramework: [ { _id: 'vercel-ai', count: 70 }, { _id: 'mastra', count: 50 }, { _id: 'langchain', count: 30 } ], averageRelevance: [{ avg: 0.78 }], averageUsage: [{ avg: 3.2 }], recentlyUsed: [{ recent: 25 }] }]; (mockCollection.aggregate().toArray as jest.Mock).mockResolvedValue(mockStatsResult); const stats = await contextCollection.getContextStats(); expect(stats.totalContexts).toBe(150); expect(stats.contextsByType).toEqual({ 'preference': 50, 'knowledge': 60, 'conversation': 40 }); expect(stats.contextsByFramework).toEqual({ 'vercel-ai': 70, 'mastra': 50, 'langchain': 30 }); expect(stats.averageRelevanceScore).toBe(0.78); expect(stats.averageUsageCount).toBe(3.2); expect(stats.recentlyUsed).toBe(25); }); it('should handle empty statistics gracefully', async () => { const emptyStatsResult = [{ totalCount: [], byType: [], byFramework: [], averageRelevance: [], averageUsage: [], recentlyUsed: [] }]; (mockCollection.aggregate().toArray as jest.Mock).mockResolvedValue(emptyStatsResult); const stats = await contextCollection.getContextStats(); expect(stats.totalContexts).toBe(0); expect(stats.averageRelevanceScore).toBe(0); expect(stats.averageUsageCount).toBe(0); expect(stats.recentlyUsed).toBe(0); }); }); describe('Context Cleanup', () => { it('should clean up expired context items', async () => { mockCollection.deleteMany.mockResolvedValue({ deletedCount: 5 }); const deletedCount = await contextCollection.cleanupExpiredContext(); expect(mockCollection.deleteMany).toHaveBeenCalledWith({ ttl: { $lte: expect.any(Date) } }); expect(deletedCount).toBe(5); }); it('should clean up old unused context items', async () => { mockCollection.deleteMany.mockResolvedValue({ deletedCount: 12 }); const deletedCount = await contextCollection.cleanupUnusedContext(30); const cutoffDate = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000); expect(mockCollection.deleteMany).toHaveBeenCalledWith({ $and: [ { 'metadata.lastUsed': { $lt: expect.any(Date) } }, { 'metadata.usageCount': { $lte: 1 } }, { 'metadata.importance': { $lt: 0.3 } } ] }); expect(deletedCount).toBe(12); }); it('should use default cleanup period', async () => { mockCollection.deleteMany.mockResolvedValue({ deletedCount: 8 }); await contextCollection.cleanupUnusedContext(); // Should use default 30 days expect(mockCollection.deleteMany).toHaveBeenCalled(); }); }); describe('Collection Initialization', () => { it('should initialize collection with indexes', async () => { const consoleSpy = jest.spyOn(console, 'log').mockImplementation(); await contextCollection.initialize(); expect(mockCollection.createIndex).toHaveBeenCalled(); expect(consoleSpy).toHaveBeenCalledWith( expect.stringContaining('ContextCollection (context_items) initialized') ); consoleSpy.mockRestore(); }); it('should use custom collection name', async () => { const customContextCollection = new ContextCollection(mockDb, 'custom_context'); expect(mockDb.collection).toHaveBeenCalledWith('custom_context'); }); }); describe('Error Handling', () => { it('should handle database errors gracefully', async () => { mockCollection.insertOne.mockRejectedValue(new Error('Database error')); await expect(contextCollection.storeContext({ contextId: 'test', content: 'test', source: 'test', relevanceScore: 0.5, metadata: { type: 'conversation', framework: 'test', tags: [], importance: 0.5, confidence: 0.5, lastUsed: new Date(), usageCount: 0 } })).rejects.toThrow('Database error'); }); it('should handle aggregation errors in statistics', async () => { (mockCollection.aggregate().toArray as jest.Mock).mockRejectedValue(new Error('Aggregation failed')); await expect(contextCollection.getContextStats()).rejects.toThrow('Aggregation failed'); }); }); });