Skip to main content
Glama

Motion.dev MCP Server

cache.test.ts6.64 kB
/** * Test suite for documentation caching system */ import { DocumentationCache } from '../../src/docs/cache.js'; import { generateMockMotionDoc } from '../setup.js'; describe('DocumentationCache', () => { let cache: DocumentationCache; const mockDoc = generateMockMotionDoc(); beforeEach(() => { cache = new DocumentationCache({ ttl: 1000, maxSize: 100 }); }); afterEach(() => { cache.clear(); }); describe('Basic Cache Operations', () => { test('should store and retrieve documents', () => { const key = 'test-doc'; cache.set(key, mockDoc); const retrieved = cache.get(key); expect(retrieved).toEqual(mockDoc); }); test('should return undefined for non-existent keys', () => { const retrieved = cache.get('non-existent'); expect(retrieved).toBeUndefined(); }); test('should check if key exists', () => { const key = 'test-doc'; expect(cache.has(key)).toBe(false); cache.set(key, mockDoc); expect(cache.has(key)).toBe(true); }); test('should delete entries', () => { const key = 'test-doc'; cache.set(key, mockDoc); expect(cache.has(key)).toBe(true); cache.delete(key); expect(cache.has(key)).toBe(false); }); test('should clear all entries', () => { cache.set('doc1', mockDoc); cache.set('doc2', mockDoc); expect(cache.size()).toBe(2); cache.clear(); expect(cache.size()).toBe(0); }); }); describe('TTL (Time To Live)', () => { test('should expire entries after TTL', (done) => { const shortTTLCache = new DocumentationCache({ ttl: 50, maxSize: 100 }); const key = 'test-doc'; shortTTLCache.set(key, mockDoc); expect(shortTTLCache.has(key)).toBe(true); setTimeout(() => { expect(shortTTLCache.has(key)).toBe(false); done(); }, 100); }); test('should refresh TTL when accessing entry', (done) => { const shortTTLCache = new DocumentationCache({ ttl: 100, maxSize: 100 }); const key = 'test-doc'; shortTTLCache.set(key, mockDoc); setTimeout(() => { // Access the entry to refresh TTL shortTTLCache.get(key); setTimeout(() => { // Should still be available after refresh expect(shortTTLCache.has(key)).toBe(true); done(); }, 50); }, 50); }); }); describe('Size Limits', () => { test('should respect max size limit', () => { const smallCache = new DocumentationCache({ ttl: 10000, maxSize: 2 }); smallCache.set('doc1', mockDoc); smallCache.set('doc2', mockDoc); expect(smallCache.size()).toBe(2); // Adding third entry should evict the oldest smallCache.set('doc3', mockDoc); expect(smallCache.size()).toBe(2); expect(smallCache.has('doc1')).toBe(false); // Should be evicted expect(smallCache.has('doc2')).toBe(true); expect(smallCache.has('doc3')).toBe(true); }); test('should use LRU eviction strategy', () => { const smallCache = new DocumentationCache({ ttl: 10000, maxSize: 2 }); smallCache.set('doc1', mockDoc); smallCache.set('doc2', mockDoc); // Access doc1 to make it recently used smallCache.get('doc1'); // Add doc3, should evict doc2 (least recently used) smallCache.set('doc3', mockDoc); expect(smallCache.has('doc1')).toBe(true); expect(smallCache.has('doc2')).toBe(false); expect(smallCache.has('doc3')).toBe(true); }); }); describe('Cache Statistics', () => { test('should track hit/miss statistics', () => { const key = 'test-doc'; // Miss cache.get(key); expect(cache.getStats().misses).toBe(1); expect(cache.getStats().hits).toBe(0); // Hit cache.set(key, mockDoc); cache.get(key); expect(cache.getStats().hits).toBe(1); expect(cache.getStats().misses).toBe(1); }); test('should calculate hit rate correctly', () => { const key = 'test-doc'; cache.set(key, mockDoc); // 3 hits, 1 miss cache.get(key); // hit cache.get(key); // hit cache.get(key); // hit cache.get('non-existent'); // miss const stats = cache.getStats(); expect(stats.hitRate).toBeCloseTo(0.75); // 3/4 = 0.75 }); }); describe('Memory Management', () => { test('should handle large documents', () => { const largeDoc = { ...mockDoc, content: 'x'.repeat(10000) // 10KB content }; cache.set('large-doc', largeDoc); const retrieved = cache.get('large-doc'); expect(retrieved?.content).toBe(largeDoc.content); }); test('should handle special characters in keys', () => { const specialKey = 'docs/react-animations#section-1?param=value'; cache.set(specialKey, mockDoc); expect(cache.has(specialKey)).toBe(true); expect(cache.get(specialKey)).toEqual(mockDoc); }); }); describe('Concurrent Access', () => { test('should handle concurrent read/write operations', async () => { const promises: Promise<any>[] = []; // Concurrent writes for (let i = 0; i < 10; i++) { promises.push( new Promise(resolve => { cache.set(`doc-${i}`, { ...mockDoc, url: `test-${i}` }); resolve(cache.get(`doc-${i}`)); }) ); } const results = await Promise.all(promises); // All operations should complete successfully expect(results).toHaveLength(10); results.forEach((result, index) => { expect(result.url).toBe(`test-${index}`); }); }); }); describe('Error Handling', () => { test('should handle null/undefined values gracefully', () => { expect(() => cache.set('null-test', null as any)).not.toThrow(); expect(() => cache.set('undefined-test', undefined as any)).not.toThrow(); expect(cache.get('null-test')).toBeNull(); expect(cache.get('undefined-test')).toBeUndefined(); }); test('should handle invalid TTL values', () => { expect(() => new DocumentationCache({ ttl: -1, maxSize: 100 })).toThrow(); expect(() => new DocumentationCache({ ttl: 0, maxSize: 100 })).not.toThrow(); }); test('should handle invalid maxSize values', () => { expect(() => new DocumentationCache({ ttl: 1000, maxSize: 0 })).toThrow(); expect(() => new DocumentationCache({ ttl: 1000, maxSize: -1 })).toThrow(); }); }); });

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/Abhishekrajpurohit/motion-dev-mcp'

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