Skip to main content
Glama
n-r-w

KnowledgeGraph MCP Server

by n-r-w
search-multi-backend.test.ts9.24 kB
import { Entity } from '../core.js'; import { SearchManager } from '../search/search-manager.js'; import { PostgreSQLFuzzyStrategy } from '../search/strategies/postgresql-strategy.js'; import { SQLiteFuzzyStrategy } from '../search/strategies/sqlite-strategy.js'; import { runTestsForAvailableBackends } from './utils/multi-backend-runner.js'; import { createTestManager, cleanupTestManager, getBackendCapabilities, createSearchConfig, createBackendTestProject, generateTestData } from './utils/backend-test-helpers.js'; import { StorageConfig, StorageType } from '../storage/types.js'; describe('Search Functionality - Multi-Backend Tests', () => { const testEntities: Entity[] = [ { name: 'JavaScript', entityType: 'Language', observations: ['Popular programming language'], tags: ['programming', 'web'] }, { name: 'TypeScript', entityType: 'Language', observations: ['Typed superset of JavaScript'], tags: ['programming', 'web', 'types'] }, { name: 'Python', entityType: 'Language', observations: ['Versatile programming language'], tags: ['programming', 'data-science'] }, { name: 'React', entityType: 'Framework', observations: ['JavaScript library for building UIs'], tags: ['frontend', 'web', 'javascript'] }, { name: 'Node.js', entityType: 'Runtime', observations: ['JavaScript runtime built on Chrome V8'], tags: ['backend', 'javascript'] } ]; // Test search functionality across all backends runTestsForAvailableBackends((config: StorageConfig, backendName: string) => { describe(`Search Tests`, () => { let manager: any; let testProject: string; beforeEach(async () => { manager = await createTestManager(config, backendName); testProject = createBackendTestProject(config.type, 'search_test'); // Create test entities await manager.createEntities(testEntities, testProject); }); afterEach(async () => { await cleanupTestManager(manager, backendName); }); test('should perform fuzzy search', async () => { // Test with a less strict typo that should still match const results = await manager.searchNodes('Javascrip', testProject); // Missing 't' at end expect(results.entities.length).toBeGreaterThan(0); expect(results.entities.map((r: Entity) => r.name)).toContain('JavaScript'); }, 10000); test('should perform exact search', async () => { const results = await manager.searchNodes('JavaScript', testProject); expect(results.entities.length).toBeGreaterThan(0); expect(results.entities[0].name).toBe('JavaScript'); }, 10000); test('should search by entity type', async () => { const results = await manager.searchNodes('Language', testProject); expect(results.entities.length).toBeGreaterThanOrEqual(3); // JavaScript, TypeScript, Python const languageNames = results.entities.map((r: Entity) => r.name); expect(languageNames).toContain('JavaScript'); expect(languageNames).toContain('TypeScript'); expect(languageNames).toContain('Python'); }, 10000); test('should search by observations', async () => { const results = await manager.searchNodes('programming', testProject); expect(results.entities.length).toBeGreaterThan(0); const foundEntity = results.entities.find((r: Entity) => r.name === 'JavaScript'); expect(foundEntity).toBeDefined(); }, 10000); test('should search by tags', async () => { const results = await manager.searchNodes('web', testProject); expect(results.entities.length).toBeGreaterThan(0); const webEntities = results.entities.filter((r: Entity) => r.tags?.includes('web')); expect(webEntities.length).toBeGreaterThan(0); }, 10000); test('should handle empty search results', async () => { const results = await manager.searchNodes('nonexistent', testProject); expect(results.entities).toEqual([]); }, 10000); test('should handle backend-specific search behavior', async () => { const capabilities = getBackendCapabilities(config.type); if (capabilities.supportsDatabaseSearch) { // PostgreSQL should use database-level search const results = await manager.searchNodes('script', testProject); expect(results.entities.length).toBeGreaterThan(0); // Verify that database search was used (this would be implementation-specific) // For now, just verify that search works expect(results.entities.map((r: Entity) => r.name)).toContain('JavaScript'); } else { // SQLite should use client-side search const results = await manager.searchNodes('script', testProject); expect(results.entities.length).toBeGreaterThan(0); // Verify that client-side search was used expect(results.entities.map((r: Entity) => r.name)).toContain('JavaScript'); } }, 10000); test('should handle case-insensitive search', async () => { const lowerResults = await manager.searchNodes('javascript', testProject); const upperResults = await manager.searchNodes('JAVASCRIPT', testProject); const mixedResults = await manager.searchNodes('JavaScript', testProject); expect(lowerResults.entities.length).toBeGreaterThan(0); expect(upperResults.entities.length).toBeGreaterThan(0); expect(mixedResults.entities.length).toBeGreaterThan(0); // All should find the JavaScript entity expect(lowerResults.entities.map((r: Entity) => r.name)).toContain('JavaScript'); expect(upperResults.entities.map((r: Entity) => r.name)).toContain('JavaScript'); expect(mixedResults.entities.map((r: Entity) => r.name)).toContain('JavaScript'); }, 10000); test('should handle partial matches', async () => { const results = await manager.searchNodes('Type', testProject); expect(results.entities.length).toBeGreaterThan(0); expect(results.entities.map((r: Entity) => r.name)).toContain('TypeScript'); }, 10000); test('should handle search with special characters', async () => { // Create entity with special characters const specialEntity = { name: 'C++', entityType: 'Language', observations: ['Systems programming language'], tags: ['programming', 'systems'] }; await manager.createEntities([specialEntity], testProject); const results = await manager.searchNodes('C++', testProject); expect(results.entities.length).toBeGreaterThan(0); expect(results.entities.map((r: Entity) => r.name)).toContain('C++'); }, 10000); }); }); // Test search strategy creation (backend-specific) describe('Search Strategy Creation', () => { test('should create appropriate search strategy for each backend', () => { // Test PostgreSQL strategy const pgConfig = createSearchConfig(StorageType.POSTGRESQL); expect(pgConfig.useDatabaseSearch).toBe(true); expect(pgConfig.clientSideFallback).toBe(true); // Test SQLite strategy const sqliteConfig = createSearchConfig(StorageType.SQLITE); expect(sqliteConfig.useDatabaseSearch).toBe(false); expect(sqliteConfig.clientSideFallback).toBe(true); }); test('should handle backend capabilities correctly', () => { const pgCapabilities = getBackendCapabilities(StorageType.POSTGRESQL); expect(pgCapabilities.supportsDatabaseSearch).toBe(true); expect(pgCapabilities.requiresExternalServer).toBe(true); const sqliteCapabilities = getBackendCapabilities(StorageType.SQLITE); expect(sqliteCapabilities.supportsDatabaseSearch).toBe(false); expect(sqliteCapabilities.requiresExternalServer).toBe(false); }); }); // Test search performance characteristics describe('Search Performance', () => { runTestsForAvailableBackends((config: StorageConfig, backendName: string) => { test(`should perform search within reasonable time limits`, async () => { const manager = await createTestManager(config, backendName); const testProject = createBackendTestProject(config.type, 'perf_test'); try { // Create larger dataset for performance testing const largeDataset = generateTestData(config.type, 100); await manager.createEntities(largeDataset, testProject); const startTime = Date.now(); const results = await manager.searchNodes('entity', testProject); const duration = Date.now() - startTime; expect(results.entities.length).toBeGreaterThan(0); // Backend-specific performance expectations const capabilities = getBackendCapabilities(config.type); if (capabilities.requiresExternalServer) { expect(duration).toBeLessThan(5000); // 5 seconds for PostgreSQL } else { expect(duration).toBeLessThan(2000); // 2 seconds for SQLite } } finally { await cleanupTestManager(manager, backendName); } }, 15000); }); }); });

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/n-r-w/knowledgegraph-mcp'

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