UNPKG

@simonecoelhosfo/optimizely-mcp-server

Version:

Optimizely MCP Server for AI assistants with integrated CLI tools

173 lines (170 loc) 7.69 kB
/** * Phase 3 Validation Test * * Comprehensive test to validate that cache invalidation actually works * with the sync integration. */ import { IntelligentQueryEngine } from './IntelligentQueryEngine.js'; import { CacheInvalidationHelper } from '../../sync/CacheInvalidationHelper.js'; import Database from 'better-sqlite3'; console.log('Phase 3 Validation: Cache Invalidation with Sync Integration\n'); async function validatePhase3() { // Create in-memory database const db = new Database(':memory:'); // Setup schema db.exec(` CREATE TABLE flags ( id TEXT PRIMARY KEY, key TEXT NOT NULL, name TEXT, description TEXT, enabled INTEGER DEFAULT 1, project_id TEXT, environments TEXT ); CREATE TABLE experiments ( id TEXT PRIMARY KEY, key TEXT NOT NULL, name TEXT, status TEXT, project_id TEXT, flag_key TEXT ); -- Initial data INSERT INTO flags VALUES ('f1', 'feature_a', 'Feature A', 'First feature', 1, 'proj_123', '{}'), ('f2', 'feature_b', 'Feature B', 'Second feature', 0, 'proj_123', '{}'), ('f3', 'feature_c', 'Feature C', 'Third feature', 1, 'proj_456', '{}'); INSERT INTO experiments VALUES ('e1', 'exp_a', 'Experiment A', 'running', 'proj_123', 'feature_a'), ('e2', 'exp_b', 'Experiment B', 'paused', 'proj_123', 'feature_b'); `); // Initialize engine with cache enabled const engine = new IntelligentQueryEngine({ cache: { enabled: true, defaultTTL: 300000, maxSizeMB: 50 }, execution: { defaultStrategy: 'hybrid-sql-first', enableParallel: false, maxQueryTime: 30000, parallelThreshold: 1000 } }); // Register Optimizely adapter const { OptimizelyAdapter } = await import('./adapters/OptimizelyAdapter.js'); const adapter = new OptimizelyAdapter({ database: db }); engine.registerAdapter(adapter); // Get sync handler and create helper const syncHandler = engine.getSyncCacheHandler(); if (!syncHandler) { console.error('FAILED: getSyncCacheHandler() returned null'); return; } const cacheHelper = new CacheInvalidationHelper(syncHandler); console.log('Cache invalidation helper initialized\n'); // Test 1: Verify initial query is cached console.log('=== Test 1: Initial Query (Should NOT be cached) ==='); const query1 = { find: 'flags', where: [{ field: 'enabled', operator: '=', value: 1 }], select: ['key', 'name', 'description'] }; const result1 = await engine.query(query1); console.log(`Result: ${result1.data.length} flags found`); console.log(`Cached: ${result1.metadata.cached} (should be false)`); console.log(`Execution time: ${result1.metadata.executionTime}ms`); // Test 2: Same query should be cached console.log('\n=== Test 2: Repeat Query (Should BE cached) ==='); const result2 = await engine.query(query1); console.log(`Result: ${result2.data.length} flags found`); console.log(`Cached: ${result2.metadata.cached} (should be true)`); console.log(`Execution time: ${result2.metadata.executionTime}ms (should be much faster)`); if (!result2.metadata.cached) { console.error('FAILED: Query was not cached!'); // Debug cache state const cacheMetrics = engine.getCacheMetrics(); console.log('\nCache Metrics:', cacheMetrics); // Check engine statistics const stats = engine.getStatistics(); console.log('Engine Stats:', stats); return; } // Test 3: Update database and verify cache still returns old data console.log('\n=== Test 3: Update Database (Cache should still return old data) ==='); db.prepare('UPDATE flags SET enabled = 1 WHERE key = ?').run('feature_b'); console.log('Updated feature_b to enabled=1'); const result3 = await engine.query(query1); console.log(`Result: ${result3.data.length} flags found (should still be 1 - cached)`); console.log(`Cached: ${result3.metadata.cached}`); // Test 4: Simulate sync with cache invalidation console.log('\n=== Test 4: Simulate Sync with Cache Invalidation ==='); await cacheHelper.onProjectSyncStart('proj_123'); console.log('Sync started...'); // Notify about the flag update await cacheHelper.onEntitySynced('proj_123', 'flags', 'f2', 'feature_b', 'update'); console.log('Notified cache about feature_b update'); // Complete sync (triggers invalidation) await cacheHelper.onProjectSyncComplete('proj_123'); console.log('Sync completed - cache should be invalidated'); // Test 5: Query should now return fresh data console.log('\n=== Test 5: Query After Invalidation (Should NOT be cached) ==='); const result4 = await engine.query(query1); console.log(`Result: ${result4.data.length} flags found (should be 3 - fresh from DB)`); console.log(`Cached: ${result4.metadata.cached} (should be false)`); console.log('Flag keys:', result4.data.map(f => f.key).join(', ')); if (result4.data.length !== 3) { console.error('FAILED: Expected 3 flags but got', result4.data.length); return; } // Test 6: Cross-entity invalidation console.log('\n=== Test 6: Cross-Entity Invalidation ==='); const expQuery = { find: 'experiments', where: [{ field: 'flag_key', operator: '=', value: 'feature_a' }], select: ['key', 'name', 'status'] }; // First query experiments (not cached) const expResult1 = await engine.query(expQuery); console.log(`Experiments: ${expResult1.data.length} found, Cached: ${expResult1.metadata.cached}`); // Query again (should be cached) const expResult2 = await engine.query(expQuery); console.log(`Experiments: ${expResult2.data.length} found, Cached: ${expResult2.metadata.cached}`); // Invalidate flags - should also invalidate dependent experiments await cacheHelper.onProjectSyncStart('proj_123'); await cacheHelper.onEntitySynced('proj_123', 'flags', 'f1', 'feature_a', 'update'); await cacheHelper.onProjectSyncComplete('proj_123'); const expResult3 = await engine.query(expQuery); console.log(`After flag invalidation - Cached: ${expResult3.metadata.cached} (should be false due to dependency)`); // Final statistics console.log('\n=== Final Statistics ==='); const stats = engine.getStatistics(); console.log('Engine Stats:', stats); const cacheMetrics = engine.getCacheMetrics(); console.log('Cache Metrics:', cacheMetrics); const invalidationStats = engine.getInvalidationEngine().getStats(); console.log(' Invalidation Stats:', { totalInvalidations: invalidationStats.totalInvalidations, byEntity: invalidationStats.invalidationsByEntity, cascadeInvalidations: invalidationStats.cascadeInvalidations }); // Verify all tests passed if (result2.metadata.cached && result4.data.length === 3 && !result4.metadata.cached) { console.log('\nAll Phase 3 tests PASSED!'); console.log('- Cache stores query results correctly'); console.log('- Cache returns cached data on repeat queries'); console.log('- Sync integration invalidates cache properly'); console.log('- Fresh data is fetched after invalidation'); } else { console.log('\nSome tests FAILED'); } // Cleanup engine.shutdown(); db.close(); } // Run validation validatePhase3().catch(console.error); //# sourceMappingURL=test-phase3-validation.js.map