Skip to main content
Glama
InMemoryCacheProvider.test.js10.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const vitest_1 = require("vitest"); const InMemoryCacheProvider_1 = require("./InMemoryCacheProvider"); (0, vitest_1.describe)('InMemoryCacheProvider', () => { let cache; (0, vitest_1.beforeEach)(() => { cache = new InMemoryCacheProvider_1.InMemoryCacheProvider(); vitest_1.vi.useFakeTimers(); }); (0, vitest_1.afterEach)(() => { vitest_1.vi.useRealTimers(); }); (0, vitest_1.describe)('constructor', () => { (0, vitest_1.it)('should create empty cache', () => { (0, vitest_1.expect)(cache.getSize()).toBe(0); }); (0, vitest_1.it)('should freeze instance', () => { (0, vitest_1.expect)(Object.isFrozen(cache)).toBe(true); }); }); (0, vitest_1.describe)('set() and get()', () => { (0, vitest_1.it)('should store and retrieve value', async () => { await cache.set('key1', 'value1', 60); const value = await cache.get('key1'); (0, vitest_1.expect)(value).toBe('value1'); }); (0, vitest_1.it)('should store complex objects', async () => { const obj = { name: 'test', count: 42 }; await cache.set('obj1', obj, 60); const value = await cache.get('obj1'); (0, vitest_1.expect)(value).toEqual(obj); }); (0, vitest_1.it)('should return undefined for non-existent key', async () => { const value = await cache.get('nonexistent'); (0, vitest_1.expect)(value).toBeUndefined(); }); (0, vitest_1.it)('should overwrite existing key', async () => { await cache.set('key1', 'value1', 60); await cache.set('key1', 'value2', 60); const value = await cache.get('key1'); (0, vitest_1.expect)(value).toBe('value2'); }); }); (0, vitest_1.describe)('TTL expiration', () => { (0, vitest_1.it)('should expire after TTL', async () => { await cache.set('key1', 'value1', 10); // 10 seconds // Before expiration let value = await cache.get('key1'); (0, vitest_1.expect)(value).toBe('value1'); // Advance time by 9 seconds (not expired yet) vitest_1.vi.advanceTimersByTime(9000); value = await cache.get('key1'); (0, vitest_1.expect)(value).toBe('value1'); // Advance time by 2 more seconds (expired) vitest_1.vi.advanceTimersByTime(2000); value = await cache.get('key1'); (0, vitest_1.expect)(value).toBeUndefined(); }); (0, vitest_1.it)('should never expire with TTL of 0', async () => { await cache.set('key1', 'value1', 0); // Advance time by 1 year vitest_1.vi.advanceTimersByTime(365 * 24 * 60 * 60 * 1000); const value = await cache.get('key1'); (0, vitest_1.expect)(value).toBe('value1'); }); (0, vitest_1.it)('should remove expired entry from cache', async () => { await cache.set('key1', 'value1', 10); (0, vitest_1.expect)(cache.getSize()).toBe(1); // Expire the entry vitest_1.vi.advanceTimersByTime(11000); await cache.get('key1'); // Entry should be removed (0, vitest_1.expect)(cache.getSize()).toBe(0); }); (0, vitest_1.it)('should throw error for negative TTL', async () => { await (0, vitest_1.expect)(cache.set('key1', 'value1', -1)).rejects.toThrow('TTL cannot be negative'); }); }); (0, vitest_1.describe)('delete()', () => { (0, vitest_1.it)('should delete existing key', async () => { await cache.set('key1', 'value1', 60); await cache.delete('key1'); const value = await cache.get('key1'); (0, vitest_1.expect)(value).toBeUndefined(); }); (0, vitest_1.it)('should be idempotent for non-existent key', async () => { await cache.delete('nonexistent'); // Should not throw error }); (0, vitest_1.it)('should decrease cache size', async () => { await cache.set('key1', 'value1', 60); (0, vitest_1.expect)(cache.getSize()).toBe(1); await cache.delete('key1'); (0, vitest_1.expect)(cache.getSize()).toBe(0); }); }); (0, vitest_1.describe)('clear()', () => { (0, vitest_1.it)('should remove all entries', async () => { await cache.set('key1', 'value1', 60); await cache.set('key2', 'value2', 60); await cache.set('key3', 'value3', 60); (0, vitest_1.expect)(cache.getSize()).toBe(3); await cache.clear(); (0, vitest_1.expect)(cache.getSize()).toBe(0); }); (0, vitest_1.it)('should work on empty cache', async () => { await cache.clear(); (0, vitest_1.expect)(cache.getSize()).toBe(0); }); }); (0, vitest_1.describe)('has()', () => { (0, vitest_1.it)('should return true for existing key', async () => { await cache.set('key1', 'value1', 60); const exists = await cache.has('key1'); (0, vitest_1.expect)(exists).toBe(true); }); (0, vitest_1.it)('should return false for non-existent key', async () => { const exists = await cache.has('nonexistent'); (0, vitest_1.expect)(exists).toBe(false); }); (0, vitest_1.it)('should return false for expired key', async () => { await cache.set('key1', 'value1', 10); // Expire the entry vitest_1.vi.advanceTimersByTime(11000); const exists = await cache.has('key1'); (0, vitest_1.expect)(exists).toBe(false); }); }); (0, vitest_1.describe)('cleanup()', () => { (0, vitest_1.it)('should remove all expired entries', async () => { await cache.set('key1', 'value1', 10); // Expires in 10s await cache.set('key2', 'value2', 20); // Expires in 20s await cache.set('key3', 'value3', 0); // Never expires (0, vitest_1.expect)(cache.getSize()).toBe(3); // Advance time by 15 seconds (key1 expired, key2 not yet) vitest_1.vi.advanceTimersByTime(15000); cache.cleanup(); (0, vitest_1.expect)(cache.getSize()).toBe(2); // Verify correct keys remain (0, vitest_1.expect)(await cache.get('key1')).toBeUndefined(); (0, vitest_1.expect)(await cache.get('key2')).toBe('value2'); (0, vitest_1.expect)(await cache.get('key3')).toBe('value3'); }); (0, vitest_1.it)('should work on empty cache', () => { cache.cleanup(); (0, vitest_1.expect)(cache.getSize()).toBe(0); }); (0, vitest_1.it)('should not remove non-expired entries', async () => { await cache.set('key1', 'value1', 60); await cache.set('key2', 'value2', 60); cache.cleanup(); (0, vitest_1.expect)(cache.getSize()).toBe(2); }); }); (0, vitest_1.describe)('getSize()', () => { (0, vitest_1.it)('should return 0 for empty cache', () => { (0, vitest_1.expect)(cache.getSize()).toBe(0); }); (0, vitest_1.it)('should return correct count', async () => { await cache.set('key1', 'value1', 60); (0, vitest_1.expect)(cache.getSize()).toBe(1); await cache.set('key2', 'value2', 60); (0, vitest_1.expect)(cache.getSize()).toBe(2); }); (0, vitest_1.it)('should include expired entries until accessed or cleaned', async () => { await cache.set('key1', 'value1', 10); // Expire the entry vitest_1.vi.advanceTimersByTime(11000); // Size still includes expired entry (0, vitest_1.expect)(cache.getSize()).toBe(1); // Access triggers removal await cache.get('key1'); (0, vitest_1.expect)(cache.getSize()).toBe(0); }); }); (0, vitest_1.describe)('multiple concurrent operations', () => { (0, vitest_1.it)('should handle multiple keys independently', async () => { await cache.set('key1', 'value1', 10); await cache.set('key2', 'value2', 20); await cache.set('key3', 'value3', 30); // Advance to expire key1 only vitest_1.vi.advanceTimersByTime(11000); (0, vitest_1.expect)(await cache.get('key1')).toBeUndefined(); (0, vitest_1.expect)(await cache.get('key2')).toBe('value2'); (0, vitest_1.expect)(await cache.get('key3')).toBe('value3'); }); (0, vitest_1.it)('should handle mixed operations', async () => { await cache.set('key1', 'value1', 60); await cache.set('key2', 'value2', 60); (0, vitest_1.expect)(await cache.has('key1')).toBe(true); await cache.delete('key1'); (0, vitest_1.expect)(await cache.has('key1')).toBe(false); (0, vitest_1.expect)(await cache.has('key2')).toBe(true); await cache.clear(); (0, vitest_1.expect)(await cache.has('key2')).toBe(false); (0, vitest_1.expect)(cache.getSize()).toBe(0); }); }); (0, vitest_1.describe)('domain entity caching', () => { (0, vitest_1.it)('should cache frozen domain entities', async () => { const entity = Object.freeze({ id: '123', name: 'Test Entity', createdAt: new Date(), }); await cache.set('entity:123', entity, 60); const cached = await cache.get('entity:123'); (0, vitest_1.expect)(cached).toEqual(entity); (0, vitest_1.expect)(Object.isFrozen(cached)).toBe(true); }); (0, vitest_1.it)('should cache arrays of entities', async () => { const entities = Object.freeze([ Object.freeze({ id: '1', name: 'Entity 1' }), Object.freeze({ id: '2', name: 'Entity 2' }), ]); await cache.set('entities:all', entities, 60); const cached = await cache.get('entities:all'); (0, vitest_1.expect)(cached).toEqual(entities); (0, vitest_1.expect)(cached?.length).toBe(2); }); }); }); //# sourceMappingURL=InMemoryCacheProvider.test.js.map

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/semanticintent/semantic-d1-mcp'

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