knowledgegraph-mcp
Version:
MCP server for enabling persistent knowledge storage for Claude through a knowledge graph with multiple storage backends
176 lines • 6.43 kB
JavaScript
/**
* Backend-Specific Test Helpers
*
* Provides utilities for handling backend-specific behavior in tests,
* such as different search capabilities and configuration requirements.
*/
import { StorageType } from '../../storage/types.js';
import { KnowledgeGraphManager } from '../../core.js';
/**
* Get capabilities for a specific backend
*/
export function getBackendCapabilities(storageType) {
switch (storageType) {
case StorageType.SQLITE:
return {
supportsDatabaseSearch: false, // SQLite uses client-side fuzzy search
supportsTransactions: true,
supportsFullTextSearch: true, // SQLite FTS
isInMemory: true, // For tests
requiresExternalServer: false
};
case StorageType.POSTGRESQL:
return {
supportsDatabaseSearch: true, // PostgreSQL has similarity functions
supportsTransactions: true,
supportsFullTextSearch: true, // PostgreSQL full-text search
isInMemory: false,
requiresExternalServer: true
};
default:
throw new Error(`Unknown storage type: ${storageType}`);
}
}
/**
* Create appropriate search configuration for a backend
*/
export function createSearchConfig(storageType) {
const capabilities = getBackendCapabilities(storageType);
return {
useDatabaseSearch: capabilities.supportsDatabaseSearch,
threshold: 0.3,
clientSideFallback: true,
fuseOptions: {
threshold: 0.3,
distance: 100,
includeScore: true,
keys: ['name', 'entityType', 'observations', 'tags']
}
};
}
/**
* Create a KnowledgeGraphManager instance for testing with appropriate configuration
*/
export async function createTestManager(config, backendName, options = {}) {
const searchConfig = createSearchConfig(config.type);
// Apply custom search configuration if provided
if (options.customSearchConfig) {
Object.assign(searchConfig, options.customSearchConfig);
}
const manager = new KnowledgeGraphManager({
...config,
fuzzySearch: searchConfig
});
// Wait for initialization with backend-specific timeout
const timeout = options.timeout || (backendName === 'PostgreSQL' ? 2000 : 500);
await new Promise(resolve => setTimeout(resolve, timeout));
return manager;
}
/**
* Cleanup test manager and handle backend-specific cleanup
*/
export async function cleanupTestManager(manager, backendName) {
try {
await manager.close();
}
catch (error) {
console.warn(`Error closing ${backendName} manager:`, error);
}
}
/**
* Skip test if backend doesn't support required capability
*/
export function skipIfNotSupported(storageType, capability, testContext) {
const capabilities = getBackendCapabilities(storageType);
const isSupported = capabilities[capability];
if (!isSupported && testContext) {
testContext.skip();
}
return isSupported;
}
/**
* Create backend-specific test expectations
*/
export function createBackendExpectations(storageType) {
const capabilities = getBackendCapabilities(storageType);
return {
/**
* Expect search to use database-level search if supported
*/
expectDatabaseSearch: (searchResults) => {
if (capabilities.supportsDatabaseSearch) {
// For PostgreSQL, we expect database-level search to be used
// This would be verified by checking that the search was performed at DB level
expect(searchResults).toBeDefined();
}
else {
// For SQLite, we expect client-side search
expect(searchResults).toBeDefined();
}
},
/**
* Expect appropriate search performance characteristics
*/
expectSearchPerformance: (duration) => {
if (capabilities.supportsDatabaseSearch) {
// Database search might be slower due to network overhead
expect(duration).toBeLessThan(5000); // 5 seconds max
}
else {
// Client-side search should be faster
expect(duration).toBeLessThan(1000); // 1 second max
}
},
/**
* Expect backend-specific error handling
*/
expectErrorHandling: (error) => {
if (capabilities.requiresExternalServer) {
// PostgreSQL might have connection errors
expect(error.message).toMatch(/connection|timeout|server/i);
}
else {
// SQLite errors are usually file/memory related
expect(error.message).toMatch(/database|file|memory/i);
}
}
};
}
/**
* Generate backend-specific test data
*/
export function generateTestData(storageType, size = 10) {
const capabilities = getBackendCapabilities(storageType);
const prefix = storageType.toLowerCase();
return Array.from({ length: size }, (_, i) => ({
name: `${prefix}_entity_${i}`,
entityType: `${prefix}_type`,
observations: [
`Test observation ${i} for ${storageType}`,
capabilities.isInMemory ? 'In-memory test data' : 'Persistent test data'
],
tags: [`${prefix}`, 'test', `item_${i}`]
}));
}
/**
* Wait for backend-specific operations to complete
*/
export async function waitForBackendOperation(storageType, operation) {
const capabilities = getBackendCapabilities(storageType);
const timeout = capabilities.requiresExternalServer ? 10000 : 5000;
return Promise.race([
operation(),
new Promise((_, reject) => setTimeout(() => reject(new Error(`${storageType} operation timed out after ${timeout}ms`)), timeout))
]);
}
/**
* Create a test project name that's unique per backend
*/
export function createBackendTestProject(storageType, testName, suffix) {
const timestamp = Date.now();
const backendPrefix = storageType.toLowerCase();
const sanitizedTestName = testName.replace(/[^a-zA-Z0-9]/g, '_');
const suffixPart = suffix ? `_${suffix}` : '';
return `${backendPrefix}_${sanitizedTestName}_${timestamp}${suffixPart}`;
}
//# sourceMappingURL=backend-test-helpers.js.map