@simonecoelhosfo/optimizely-mcp-server
Version:
Optimizely MCP Server for AI assistants with integrated CLI tools
173 lines (170 loc) • 7.69 kB
JavaScript
/**
* 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