UNPKG

@simonecoelhosfo/optimizely-mcp-server

Version:

Optimizely MCP Server for AI assistants with integrated CLI tools

147 lines (146 loc) • 7.42 kB
/** * Test cache invalidation on data updates * Verifies that cache is properly cleared when data changes */ import { IntelligentQueryEngine } from './IntelligentQueryEngine.js'; import { OptimizelyAdapter } from './adapters/OptimizelyAdapter.js'; import Database from 'better-sqlite3'; console.log('Testing Cache Invalidation on Data Updates...\n'); async function setupDatabase(db) { // Create tables db.exec(` CREATE TABLE IF NOT EXISTS flags ( id TEXT PRIMARY KEY, key TEXT NOT NULL, name TEXT, enabled INTEGER DEFAULT 1, project_id TEXT ); CREATE TABLE IF NOT EXISTS experiments ( id TEXT PRIMARY KEY, key TEXT NOT NULL, name TEXT, status TEXT, project_id TEXT ); `); // Insert initial data const insertFlag = db.prepare('INSERT INTO flags (id, key, name, enabled, project_id) VALUES (?, ?, ?, ?, ?)'); insertFlag.run('flag1', 'feature_a', 'Feature A', 1, 'proj1'); insertFlag.run('flag2', 'feature_b', 'Feature B', 0, 'proj1'); insertFlag.run('flag3', 'feature_c', 'Feature C', 1, 'proj1'); const insertExp = db.prepare('INSERT INTO experiments (id, key, name, status, project_id) VALUES (?, ?, ?, ?, ?)'); insertExp.run('exp1', 'test_a', 'Test A', 'running', 'proj1'); insertExp.run('exp2', 'test_b', 'Test B', 'paused', 'proj1'); } async function testCacheInvalidation() { try { // Initialize database const db = new Database(':memory:'); await setupDatabase(db); // Create engine with cache const engine = new IntelligentQueryEngine({ cache: { enabled: true, defaultTTL: 300000, // 5 minutes } }); // Register adapter const adapter = new OptimizelyAdapter({ database: db }); engine.registerAdapter(adapter); // Test queries const flagQuery = { find: 'flags', select: ['key', 'name', 'enabled'], where: [{ field: 'enabled', operator: '=', value: 1 }], }; const experimentQuery = { find: 'experiments', select: ['key', 'status'], groupBy: ['status'], aggregations: [{ field: 'id', function: 'COUNT', alias: 'count' }], }; console.log('=== Test 1: Initial Query & Cache ==='); console.log('1.1 First query (should NOT be cached)'); let result = await engine.query(flagQuery); console.log(` Cached: ${result.metadata.cached} | Enabled flags: ${result.data.length}`); console.log(` Flags:`, result.data.map(f => f.key).join(', ')); console.log('\n1.2 Second query (should BE cached)'); result = await engine.query(flagQuery); console.log(` Cached: ${result.metadata.cached} | Enabled flags: ${result.data.length}`); console.log('\n=== Test 2: Update Data Without Invalidation ==='); console.log('2.1 Updating feature_b to enabled=1'); db.prepare('UPDATE flags SET enabled = 1 WHERE key = ?').run('feature_b'); console.log('\n2.2 Query again (still cached - WRONG data!)'); result = await engine.query(flagQuery); console.log(` Cached: ${result.metadata.cached} | Enabled flags: ${result.data.length}`); console.log(` Flags:`, result.data.map(f => f.key).join(', ')); console.log(' NOTE: Still showing 2 flags, but should be 3!'); console.log('\n=== Test 3: Manual Cache Invalidation ==='); console.log('3.1 Invalidating flag cache'); const invalidated = await engine.invalidateCache('flags'); console.log(` Invalidated ${invalidated} entries`); console.log('\n3.2 Query after invalidation (NOT cached - correct data)'); result = await engine.query(flagQuery); console.log(` Cached: ${result.metadata.cached} | Enabled flags: ${result.data.length}`); console.log(` Flags:`, result.data.map(f => f.key).join(', ')); console.log(' NOW showing correct 3 flags!'); console.log('\n=== Test 4: Cross-Entity Cache Test ==='); console.log('4.1 Query experiments (NOT cached)'); let expResult = await engine.query(experimentQuery); console.log(` Cached: ${expResult.metadata.cached}`); console.log(` Results:`, expResult.data); console.log('\n4.2 Query experiments again (cached)'); expResult = await engine.query(experimentQuery); console.log(` Cached: ${expResult.metadata.cached}`); console.log('\n4.3 Invalidate only flags (not experiments)'); await engine.invalidateCache('flags'); console.log('\n4.4 Query experiments (should still be cached)'); expResult = await engine.query(experimentQuery); console.log(` Cached: ${expResult.metadata.cached} Experiments cache unaffected`); console.log('\n=== Test 5: Full Cache Clear ==='); console.log('5.1 Clear all caches'); engine.clearCaches(); console.log('\n5.2 Query flags (NOT cached)'); result = await engine.query(flagQuery); console.log(` Cached: ${result.metadata.cached}`); console.log('\n5.3 Query experiments (NOT cached)'); expResult = await engine.query(experimentQuery); console.log(` Cached: ${expResult.metadata.cached}`); console.log('\n=== Test 6: Simulating Sync Process ==='); console.log('6.1 Cache some queries'); await engine.query(flagQuery); await engine.query(experimentQuery); console.log('\n6.2 Simulate sync detecting changes to flags'); console.log(' - Adding new flag'); db.prepare('INSERT INTO flags (id, key, name, enabled, project_id) VALUES (?, ?, ?, ?, ?)').run('flag4', 'feature_d', 'Feature D', 1, 'proj1'); console.log(' - Invalidating flag cache'); await engine.invalidateCache('flags'); console.log('\n6.3 Query flags (NOT cached - includes new flag)'); result = await engine.query(flagQuery); console.log(` Cached: ${result.metadata.cached} | Enabled flags: ${result.data.length}`); console.log(` Flags:`, result.data.map(f => f.key).join(', ')); console.log('\n=== Test 7: Cache Statistics ==='); const stats = engine.getCacheMetrics(); console.log(`Cache metrics:`); console.log(` Hit rate: ${(stats.hitRate * 100).toFixed(1)}%`); console.log(` Entries: ${stats.entries}`); console.log(` Size: ${(stats.sizeBytes / 1024).toFixed(1)} KB`); // Shutdown await engine.shutdown(); console.log('\nCache invalidation tests completed!'); console.log('\nšŸ“ Summary:'); console.log(' - Cache correctly stores query results'); console.log(' - Data updates are NOT automatically detected (by design)'); console.log(' - Manual invalidation correctly clears affected caches'); console.log(' - Entity-specific invalidation works (flags vs experiments)'); console.log(' - Full cache clear works for all entities'); console.log('\n IMPORTANT: Sync process MUST call invalidateCache() when data changes!'); } catch (error) { console.error('Test failed:', error); process.exit(1); } } testCacheInvalidation(); //# sourceMappingURL=test-cache-invalidation.js.map