Skip to main content
Glama
cache.test.tsβ€’7.46 kB
import { describe, it, expect, beforeAll, afterAll, beforeEach } from 'vitest'; import { redisCache, CacheKeys } from '../../src/cache/redis.js'; describe('Redis Cache', () => { beforeAll(async () => { // Ensure Redis is connected await new Promise((resolve) => setTimeout(resolve, 100)); }); afterAll(async () => { // Clean up test keys const testKeys = ['test:key', 'test:object', 'test:multi:*']; for (const pattern of testKeys) { try { if (pattern.includes('*')) { // Scan and delete pattern-matched keys const keys = await redisCache['client']?.keys(pattern); if (keys && keys.length > 0) { await redisCache['client']?.del(...keys); } } else { await redisCache.del(pattern); } } catch { // Ignore errors during cleanup } } await redisCache.close(); }); beforeEach(async () => { // Clean up between tests await redisCache.del('test:key'); await redisCache.del('test:object'); }); describe('Basic Operations', () => { it('should set and get a string value', async () => { const key = 'test:key'; const value = 'test-value'; await redisCache.set(key, value); const retrieved = await redisCache.get<string>(key); expect(retrieved).toBe(value); }); it('should set and get an object value', async () => { const key = 'test:object'; const value = { foo: 'bar', count: 42 }; await redisCache.set(key, value); const retrieved = await redisCache.get<typeof value>(key); expect(retrieved).toEqual(value); }); it('should return null for non-existent key', async () => { const retrieved = await redisCache.get<string>('nonexistent:key'); expect(retrieved).toBeNull(); }); it('should delete a key', async () => { const key = 'test:key'; await redisCache.set(key, 'value'); const deleted = await redisCache.del(key); expect(deleted).toBe(true); const retrieved = await redisCache.get<string>(key); expect(retrieved).toBeNull(); }); it('should check if key exists', async () => { const key = 'test:key'; let exists = await redisCache.exists(key); expect(exists).toBe(false); await redisCache.set(key, 'value'); exists = await redisCache.exists(key); expect(exists).toBe(true); }); }); describe('TTL Support', () => { it('should set value with TTL', async () => { const key = 'test:key'; const value = 'expiring-value'; const ttl = 1; // 1 second await redisCache.set(key, value, ttl); const retrieved = await redisCache.get<string>(key); expect(retrieved).toBe(value); // Wait for expiration await new Promise((resolve) => setTimeout(resolve, 1500)); const expired = await redisCache.get<string>(key); expect(expired).toBeNull(); }); it('should respect default TTL from CacheKeys', async () => { const key = CacheKeys.llmResponse('gpt-4', 'hash123'); const value = { response: 'cached response' }; await redisCache.set(key, value); const retrieved = await redisCache.get<typeof value>(key); expect(retrieved).toEqual(value); }); }); describe('Multi-get Operations', () => { it('should get multiple keys at once', async () => { const keys = ['test:multi:1', 'test:multi:2', 'test:multi:3']; const values = ['value1', 'value2', 'value3']; // Set values for (let i = 0; i < keys.length; i++) { await redisCache.set(keys[i], values[i]); } // Get all at once const retrieved = await redisCache.mget<string>(keys); expect(retrieved).toEqual(values); }); it('should handle missing keys in multi-get', async () => { const keys = ['test:multi:exists', 'test:multi:missing']; await redisCache.set(keys[0], 'exists'); const retrieved = await redisCache.mget<string>(keys); expect(retrieved).toEqual(['exists', null]); }); }); describe('CacheKeys Helper', () => { it('should generate llmResponse key', () => { const key = CacheKeys.llmResponse('gpt-4', 'abc123'); expect(key).toBe('llm:cache:gpt-4:abc123'); }); it('should generate conversationSummary key', () => { const key = CacheKeys.conversationSummary('conv-456'); expect(key).toBe('conv:summary:conv-456'); }); it('should generate routingHints key', () => { const key = CacheKeys.routingHints('project-789'); expect(key).toBe('routing:hints:project-789'); }); it('should generate todoList key', () => { const key = CacheKeys.todoList('session-abc'); expect(key).toBe('todo:list:session-abc'); }); it('should generate contextMessages key', () => { const key = CacheKeys.contextMessages('conv-xyz'); expect(key).toBe('conv:messages:conv-xyz'); }); }); describe('Error Handling', () => { it('should handle gracefully when Redis is unavailable', async () => { // Close connection await redisCache.close(); // Operations should not throw await expect(redisCache.get('test:key')).resolves.toBeNull(); await expect(redisCache.set('test:key', 'value')).resolves.toBeUndefined(); await expect(redisCache.del('test:key')).resolves.toBe(false); await expect(redisCache.exists('test:key')).resolves.toBe(false); }); }); describe('Complex Data Types', () => { it('should handle nested objects', async () => { const key = 'test:object'; const value = { user: { id: 1, name: 'Test' }, settings: { theme: 'dark', notifications: true }, metadata: { tags: ['a', 'b', 'c'] }, }; await redisCache.set(key, value); const retrieved = await redisCache.get<typeof value>(key); expect(retrieved).toEqual(value); }); it('should handle arrays', async () => { const key = 'test:array'; const value = [1, 2, 3, 4, 5]; await redisCache.set(key, value); const retrieved = await redisCache.get<number[]>(key); expect(retrieved).toEqual(value); }); it('should handle null and undefined correctly', async () => { const key = 'test:key'; await redisCache.set(key, null); let retrieved = await redisCache.get(key); expect(retrieved).toBeNull(); await redisCache.set(key, undefined); retrieved = await redisCache.get(key); expect(retrieved).toBeNull(); }); }); });

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/babasida246/ai-mcp-gateway'

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