Skip to main content
Glama
DynamicEndpoints

ESPN MCP Server

cache.test.ts5.74 kB
/** * Tests for EnhancedCache */ import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { EnhancedCache, generateCacheKey, memoize } from '../../src/utils/cache.js'; describe('EnhancedCache', () => { let cache: EnhancedCache; beforeEach(() => { cache = new EnhancedCache(5000, 100, 1024 * 1024); }); afterEach(() => { cache.destroy(); }); describe('basic operations', () => { it('should set and get values', async () => { await cache.set('key1', 'value1'); const value = await cache.get('key1'); expect(value).toBe('value1'); }); it('should return undefined for missing keys', async () => { try { await cache.get('nonexistent'); } catch (error) { expect(error.message).toContain('Cache miss'); } }); it('should use fetcher on cache miss', async () => { const fetcher = async () => 'fetched value'; const value = await cache.get('key1', fetcher); expect(value).toBe('fetched value'); }); it('should cache fetched values', async () => { let callCount = 0; const fetcher = async () => { callCount++; return 'value'; }; await cache.get('key1', fetcher); await cache.get('key1', fetcher); expect(callCount).toBe(1); // Fetcher should only be called once }); }); describe('TTL and expiration', () => { it('should expire entries after TTL', async () => { const shortTtl = 100; // 100ms await cache.set('key1', 'value1', shortTtl); // Value should exist immediately expect(await cache.get('key1')).toBe('value1'); // Wait for expiration await new Promise(resolve => setTimeout(resolve, 150)); // Value should be expired try { await cache.get('key1'); } catch (error) { expect(error.message).toContain('Cache miss'); } }); }); describe('statistics', () => { it('should track hits and misses', async () => { await cache.set('key1', 'value1'); // Hit await cache.get('key1'); // Miss try { await cache.get('key2'); } catch (error) { // Expected } const stats = cache.getStats(); expect(stats.hits).toBe(1); expect(stats.misses).toBe(1); expect(stats.hitRate).toBe(0.5); }); it('should track sets and deletes', async () => { await cache.set('key1', 'value1'); await cache.set('key2', 'value2'); cache.delete('key1'); const stats = cache.getStats(); expect(stats.sets).toBe(2); expect(stats.deletes).toBe(1); }); }); describe('deletion', () => { it('should delete specific keys', async () => { await cache.set('key1', 'value1'); expect(cache.has('key1')).toBe(true); cache.delete('key1'); expect(cache.has('key1')).toBe(false); }); it('should delete by pattern', async () => { await cache.set('user:1', 'data1'); await cache.set('user:2', 'data2'); await cache.set('post:1', 'data3'); const count = cache.deletePattern('user:*'); expect(count).toBe(2); expect(cache.has('user:1')).toBe(false); expect(cache.has('user:2')).toBe(false); expect(cache.has('post:1')).toBe(true); }); it('should clear all entries', async () => { await cache.set('key1', 'value1'); await cache.set('key2', 'value2'); cache.clear(); expect(cache.size()).toBe(0); }); }); describe('events', () => { it('should emit hit events', async () => { let hitKey: string | undefined; cache.on('hit', (key) => { hitKey = key; }); await cache.set('key1', 'value1'); await cache.get('key1'); expect(hitKey).toBe('key1'); }); it('should emit miss events', async () => { let missKey: string | undefined; cache.on('miss', (key) => { missKey = key; }); try { await cache.get('nonexistent'); } catch (error) { // Expected } expect(missKey).toBe('nonexistent'); }); it('should emit set events', async () => { let setKey: string | undefined; let setValue: any; cache.on('set', (key, value) => { setKey = key; setValue = value; }); await cache.set('key1', 'value1'); expect(setKey).toBe('key1'); expect(setValue).toBe('value1'); }); }); }); describe('cache utilities', () => { describe('generateCacheKey', () => { it('should generate consistent keys', () => { const key1 = generateCacheKey('sport', 'nfl', { date: '20250101' }); const key2 = generateCacheKey('sport', 'nfl', { date: '20250101' }); expect(key1).toBe(key2); }); it('should generate different keys for different inputs', () => { const key1 = generateCacheKey('sport', 'nfl'); const key2 = generateCacheKey('sport', 'nba'); expect(key1).not.toBe(key2); }); }); describe('memoize', () => { it('should memoize function results', async () => { const cache = new EnhancedCache(); let callCount = 0; const fn = async (x: number) => { callCount++; return x * 2; }; const memoized = memoize(fn, cache); const result1 = await memoized(5); const result2 = await memoized(5); expect(result1).toBe(10); expect(result2).toBe(10); expect(callCount).toBe(1); cache.destroy(); }); }); });

Latest Blog Posts

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/DynamicEndpoints/espn-mcp'

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