Skip to main content
Glama
graph-traversal-processor.test.ts7.41 kB
/** * Graph Traversal Processor Tests * Coverage for graph traversal functionality */ import { describe, it, expect, vi, beforeEach } from 'vitest'; import { GraphTraversalProcessor } from '../../../../src/application/unified-handlers/services/graph-traversal-processor'; // Mock config vi.mock('../../../../src/config'); import { getLimitsConfig } from '../../../../src/config'; describe('GraphTraversalProcessor - Production Coverage', () => { let processor: GraphTraversalProcessor; beforeEach(() => { vi.clearAllMocks(); // Mock limits config vi.mocked(getLimitsConfig).mockReturnValue({ maxMemoriesPerOperation: 50, maxRelationsPerOperation: 200, maxTraversalDepth: 5 }); processor = new GraphTraversalProcessor(); }); describe('Traversal Query Construction', () => { it('should build outbound traversal query', () => { // Arrange const options = { traverseFrom: 'test-memory-id', maxDepth: 2, traverseDirection: 'outbound' as const }; // Act const result = processor.processTraversal(options); // Assert expect(result.cypher).toContain('(start)-[r:RELATES_TO*1..2]->(end:Memory)'); expect(result.cypher).toContain('start:Memory {id: $startId}'); expect(result.params.startId).toBe('test-memory-id'); expect(result.params.maxDepth).toBe(2); }); it('should build inbound traversal query', () => { // Arrange const options = { traverseFrom: 'test-memory-id', maxDepth: 3, traverseDirection: 'inbound' as const }; // Act const result = processor.processTraversal(options); // Assert expect(result.cypher).toContain('(start:Memory)-[r:RELATES_TO*1..3]->(target)'); expect(result.cypher).toContain('target:Memory {id: $startId}'); expect(result.params.startId).toBe('test-memory-id'); expect(result.params.maxDepth).toBe(3); }); it('should build bidirectional traversal query', () => { // Arrange const options = { traverseFrom: 'test-memory-id', maxDepth: 1, traverseDirection: 'both' as const }; // Act const result = processor.processTraversal(options); // Assert expect(result.cypher).toContain('(center)-[r:RELATES_TO*1..1]-(connected:Memory)'); expect(result.cypher).toContain('center:Memory {id: $startId}'); expect(result.params.startId).toBe('test-memory-id'); expect(result.params.maxDepth).toBe(1); }); it('should default to bidirectional when no direction specified', () => { // Arrange const options = { traverseFrom: 'test-memory-id' }; // Act const result = processor.processTraversal(options); // Assert expect(result.cypher).toContain('(center)-[r:RELATES_TO*1..2]-(connected:Memory)'); expect(result.params.maxDepth).toBe(2); // Default depth }); it('should include relation type filtering when specified', () => { // Arrange const options = { traverseFrom: 'test-memory-id', traverseRelations: ['INFLUENCES', 'DEPENDS_ON'], traverseDirection: 'outbound' as const }; // Act const result = processor.processTraversal(options); // Assert expect(result.cypher).toContain('ALL(rel IN relationships(path) WHERE rel.relationType IN $relationTypes)'); expect(result.params.relationTypes).toEqual(['INFLUENCES', 'DEPENDS_ON']); }); it('should enforce maximum depth limits', () => { // Arrange const options = { traverseFrom: 'test-memory-id', maxDepth: 10 // Exceeds limit }; // Act & Assert expect(() => processor.processTraversal(options)) .toThrow('maxDepth must be between 1 and 5'); }); }); describe('Result Processing', () => { it('should process traversal results with Neo4j integer conversion', () => { // Arrange const mockResults = [ { id: 'memory-1', name: 'Test Memory 1', type: 'concept', distance: { toNumber: () => 2 }, // Mock Neo4j Integer relation: 'INFLUENCES', strength: 0.8, source: 'agent', createdAt: '2025-01-01T00:00:00Z' }, { id: 'memory-2', name: 'Test Memory 2', type: 'implementation', distance: 1, // Regular number relation: 'DEPENDS_ON', strength: 0.6, source: 'user' } ]; // Act const results = processor.processTraversalResults(mockResults); // Assert expect(results).toHaveLength(2); expect(results[0]).toEqual({ id: 'memory-1', name: 'Test Memory 1', type: 'concept', distance: 2, // Converted from Neo4j Integer relation: 'INFLUENCES', strength: 0.8, source: 'agent', createdAt: '2025-01-01T00:00:00Z' }); expect(results[1].distance).toBe(1); // Regular number preserved }); it('should handle missing or null values gracefully', () => { // Arrange const mockResults = [ { id: 'memory-1', name: 'Test Memory', type: 'concept', distance: null, relation: 'RELATES_TO' } ]; // Act const results = processor.processTraversalResults(mockResults); // Assert expect(results[0].distance).toBe(0); // Default for null/invalid }); }); describe('Validation', () => { it('should validate required traverseFrom parameter', () => { // Arrange const invalidOptions = { maxDepth: 2 // Missing traverseFrom } as any; // Act & Assert expect(() => processor.processTraversal(invalidOptions)) .toThrow('traverseFrom memory ID is required for graph traversal'); }); it('should validate maxDepth range', () => { // Arrange const invalidOptions = { traverseFrom: 'test-id', maxDepth: 0 // Below minimum }; // Act & Assert expect(() => processor.processTraversal(invalidOptions)) .toThrow('maxDepth must be between 1 and 5'); }); it('should validate traverseDirection options', () => { // Arrange const invalidOptions = { traverseFrom: 'test-id', traverseDirection: 'invalid' as any }; // Act & Assert expect(() => processor.processTraversal(invalidOptions)) .toThrow('Invalid traversal direction: invalid'); }); it('should validate empty traverseRelations array', () => { // Arrange const invalidOptions = { traverseFrom: 'test-id', traverseRelations: [] // Empty array }; // Act & Assert expect(() => processor.processTraversal(invalidOptions)) .toThrow('traverseRelations array cannot be empty if provided'); }); }); describe('Helper Methods', () => { it('should provide supported directions documentation', () => { // Act const directions = processor.getSupportedDirections(); // Assert expect(directions).toEqual([ 'outbound: What this memory influences', 'inbound: What influences this memory', 'both: All connected memories (default)' ]); }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/sylweriusz/mcp-neo4j-memory-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server