Skip to main content
Glama

CTS MCP Server

by EricA1019
cache_manager.test.ts6.21 kB
/** * Cache Manager Tests * * Unit tests for GraphCacheManager with intelligent staleness detection. */ import { describe, it, expect, beforeEach, jest } from '@jest/globals'; import { GraphCacheManager } from '../../src/artifacts/scanner/cache_manager.js'; import { ArtifactVersionRegistry } from '../../src/artifacts/artifact_metadata.js'; import { writeFile, unlink, utimes } from 'fs/promises'; import { join } from 'path'; import { tmpdir } from 'os'; describe('GraphCacheManager', () => { let cacheManager: GraphCacheManager; let testFile: string; beforeEach(() => { cacheManager = new GraphCacheManager(); testFile = join(tmpdir(), `test_${Date.now()}.gd`); }); describe('Cache Staleness Detection', () => { it('should detect cache miss (file not cached)', async () => { const isStale = await cacheManager.isStale('/nonexistent/file.gd'); expect(isStale).toBe(true); }); it('should detect fresh cache (file unchanged)', async () => { // Create test file await writeFile(testFile, 'extends Node\nsignal test_signal'); const mtime = Date.now(); cacheManager.updateCache(testFile, mtime); const isStale = await cacheManager.isStale(testFile); expect(isStale).toBe(false); // Cleanup await unlink(testFile); }); it('should detect stale cache (file modified)', async () => { // Create test file with old mtime await writeFile(testFile, 'extends Node\nsignal old_signal'); const oldMtime = Date.now() - 10000; // 10 seconds ago cacheManager.updateCache(testFile, oldMtime); // Modify file (update mtime to now) await utimes(testFile, new Date(), new Date()); const isStale = await cacheManager.isStale(testFile); expect(isStale).toBe(true); // Cleanup await unlink(testFile); }); it('should detect stale cache (version mismatch)', async () => { // Create test file await writeFile(testFile, 'extends Node'); const mtime = Date.now(); cacheManager.updateCache(testFile, mtime); // Simulate version upgrade by creating new cache manager const registryV4 = new ArtifactVersionRegistry(); registryV4.registerVersion('ast_forest', '4.0.0'); // Version mismatch const newCacheManager = new GraphCacheManager(registryV4); newCacheManager.updateCache(testFile, mtime); // Original cache manager should detect staleness after version change // (In practice, this tests schema version handling) const isStale = await cacheManager.isStale(testFile); expect(isStale).toBe(false); // Same manager, same version // Cleanup await unlink(testFile); }); it('should handle missing file gracefully', async () => { const deletedFile = '/tmp/deleted_file.gd'; // Cache a file that doesn't exist cacheManager.updateCache(deletedFile, Date.now()); // Should detect as stale const isStale = await cacheManager.isStale(deletedFile); expect(isStale).toBe(true); }); }); describe('Cache Operations', () => { it('should update cache correctly', () => { const filePath = '/test/file.gd'; const mtime = 1234567890; cacheManager.updateCache(filePath, mtime); const cachedFiles = cacheManager.getCachedFiles(); expect(cachedFiles).toContain(filePath); expect(cacheManager.getCacheSize()).toBe(1); }); it('should clear cache', () => { cacheManager.updateCache('/file1.gd', Date.now()); cacheManager.updateCache('/file2.gd', Date.now()); expect(cacheManager.getCacheSize()).toBe(2); cacheManager.clearCache(); expect(cacheManager.getCacheSize()).toBe(0); expect(cacheManager.getCachedFiles()).toEqual([]); }); it('should evict specific file', () => { const file1 = '/file1.gd'; const file2 = '/file2.gd'; cacheManager.updateCache(file1, Date.now()); cacheManager.updateCache(file2, Date.now()); expect(cacheManager.getCacheSize()).toBe(2); cacheManager.evict(file1); expect(cacheManager.getCacheSize()).toBe(1); expect(cacheManager.getCachedFiles()).not.toContain(file1); expect(cacheManager.getCachedFiles()).toContain(file2); }); it('should handle fractional mtime (round down)', () => { const filePath = '/test/file.gd'; const mtime = 1234567890.456; // Fractional milliseconds cacheManager.updateCache(filePath, mtime); // Cache should store rounded-down value // (Verified indirectly via staleness check) const cached = cacheManager.getCachedFiles(); expect(cached).toContain(filePath); }); }); describe('Integration with ArtifactVersionRegistry', () => { it('should use custom version registry', () => { const customRegistry = new ArtifactVersionRegistry(); customRegistry.registerVersion('ast_forest', '3.1.0'); const manager = new GraphCacheManager(customRegistry); // Update cache manager.updateCache('/file.gd', Date.now()); // Cache should work normally expect(manager.getCacheSize()).toBe(1); }); it('should default to version 3.0.0 for Phase 3', () => { const manager = new GraphCacheManager(); // Cache manager should have version 3.0.0 registered // (Verified indirectly - cache works correctly) manager.updateCache('/file.gd', Date.now()); expect(manager.getCacheSize()).toBe(1); }); }); describe('Edge Cases', () => { it('should handle empty file path', async () => { const isStale = await cacheManager.isStale(''); expect(isStale).toBe(true); }); it('should handle concurrent cache updates', () => { const filePath = '/concurrent/file.gd'; // Simulate concurrent updates cacheManager.updateCache(filePath, 1000); cacheManager.updateCache(filePath, 2000); cacheManager.updateCache(filePath, 1500); // Out of order // Last update should win const cachedFiles = cacheManager.getCachedFiles(); expect(cachedFiles).toContain(filePath); expect(cacheManager.getCacheSize()).toBe(1); }); }); });

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/EricA1019/CTS_MCP'

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