Kraft102's picture
Update backend source
34367da verified
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { neuralCortex, CortexQuery } from '../../src/services/NeuralChat/NeuralCortex';
import { neo4jAdapter } from '../../src/adapters/Neo4jAdapter';
const mockVectorStore = vi.hoisted(() => ({
upsert: vi.fn(),
search: vi.fn(),
initialize: vi.fn(),
}));
// Mock dependencies
vi.mock('../../src/adapters/Neo4jAdapter', () => ({
neo4jAdapter: {
runQuery: vi.fn(),
},
}));
vi.mock('../../src/platform/vector/index', () => ({
getVectorStore: vi.fn(),
}));
// Setup the mock implementation result after hoisting
vi.mocked(await import('../../src/platform/vector/index')).getVectorStore.mockResolvedValue(mockVectorStore as any);
describe('NeuralCortex (Hybrid RAG)', () => {
beforeEach(() => {
vi.clearAllMocks();
// Reset vector store mock
mockVectorStore.search.mockReset();
mockVectorStore.upsert.mockReset();
mockVectorStore.initialize.mockReset();
});
afterEach(() => {
vi.clearAllMocks();
});
describe('processMessage', () => {
it('should store message in both Graph and Vector store', async () => {
const message = {
id: 'msg-123',
from: 'gemini' as any,
channel: 'core-dev',
body: 'We should use pgvector for semantic search and Neo4j for graphs.',
timestamp: new Date().toISOString(),
type: 'chat' as any,
priority: 'normal' as any,
};
// Mock Graph response
(neo4jAdapter.runQuery as any).mockResolvedValue([]);
const result = await neuralCortex.processMessage(message);
// Verify Graph interactions (called for message node + entities/concepts)
expect(neo4jAdapter.runQuery).toHaveBeenCalled();
expect(neo4jAdapter.runQuery).toHaveBeenCalledTimes(4);
// Verify Vector interaction
expect(mockVectorStore.upsert).toHaveBeenCalledWith(expect.objectContaining({
id: 'msg-123',
content: message.body,
namespace: 'neural_chat',
metadata: expect.objectContaining({
type: 'message',
from: 'gemini',
channel: 'core-dev',
concepts: expect.arrayContaining(['pgvector', 'neo4j'])
})
}));
expect(result.vectorStored).toBe(true);
// Verify concepts were extracted
expect(result.concepts).toContain('neo4j');
expect(result.concepts).toContain('pgvector');
expect(result.concepts.length).toBeGreaterThan(0);
});
});
describe('query (Hybrid Search)', () => {
it('should combine results from Vector and Graph search', async () => {
const query: CortexQuery = {
type: 'search',
query: 'database architecture',
};
// Mock Vector Results (Semantic)
mockVectorStore.search.mockResolvedValue([
{
id: 'doc-1',
content: 'PostgreSQL is a relational database.',
similarity: 0.9,
metadata: { title: 'Postgres Guide', type: 'Document' }
}
]);
// Mock Graph Results (Keyword/Structural)
(neo4jAdapter.runQuery as any).mockResolvedValue([
{
n: { properties: { name: 'Neo4j', id: 'node-2' } },
types: ['Technology'],
connections: []
}
]);
const results = await neuralCortex.query(query);
// Should have 2 results
expect(results).toHaveLength(2);
// Check sources
const vectorResult = results.find(r => r.source === 'semantic_search');
const graphResult = results.find(r => r.source === 'knowledge_graph');
expect(vectorResult).toBeDefined();
expect(vectorResult?.data.name).toBe('Postgres Guide');
expect(vectorResult?.relevance).toBe(0.9);
expect(graphResult).toBeDefined();
expect(graphResult?.data.name).toBe('Neo4j');
});
it('should fallback gracefully if vector store fails', async () => {
const query: CortexQuery = {
type: 'search',
query: 'resilient system',
};
// Mock Vector Failure
mockVectorStore.search.mockRejectedValue(new Error('Vector DB offline'));
// Mock Graph Success
(neo4jAdapter.runQuery as any).mockResolvedValue([
{
n: { properties: { name: 'SelfHealingAdapter', id: 'node-3' } },
types: ['Service'],
connections: []
}
]);
const results = await neuralCortex.query(query);
// Should still return graph results
expect(results).toHaveLength(1);
expect(results[0].data.name).toBe('SelfHealingAdapter');
expect(results[0].source).toBe('knowledge_graph');
});
});
});