/** * Tests for Redis cache client */ import { describe, it, expect, vi, beforeEach } from 'vitest'; import { CacheClient } from './redis'; // Mock redis client vi.mock('redis', () => { const mockClient = { get: vi.fn(), setEx: vi.fn(), del: vi.fn(), exists: vi.fn(), keys: vi.fn(), on: vi.fn(), connect: vi.fn().mockResolvedValue(undefined), quit: vi.fn().mockResolvedValue(undefined), }; return { createClient: vi.fn(() => mockClient), }; }); describe('CacheClient', () => { let cacheClient: CacheClient; let mockRedisClient: any; beforeEach(async () => { vi.clearAllMocks(); const redis = await import('redis'); mockRedisClient = (redis.createClient as any)(); cacheClient = new CacheClient({ url: 'redis://localhost:6379' }); await cacheClient.connect(); }); describe('get', () => { it('should get value from cache', async () => { mockRedisClient.get.mockResolvedValue('{"key": "value"}'); const value = await cacheClient.get<{ key: string }>('test-key'); expect(value).toEqual({ key: 'value' }); expect(mockRedisClient.get).toHaveBeenCalledWith('the-order:test-key'); }); it('should return null if key not found', async () => { mockRedisClient.get.mockResolvedValue(null); const value = await cacheClient.get('nonexistent-key'); expect(value).toBeNull(); }); it('should handle errors gracefully', async () => { mockRedisClient.get.mockRejectedValue(new Error('Redis error')); const value = await cacheClient.get('error-key'); expect(value).toBeNull(); }); }); describe('set', () => { it('should set value in cache', async () => { mockRedisClient.setEx.mockResolvedValue('OK'); await cacheClient.set('test-key', { key: 'value' }, 3600); expect(mockRedisClient.setEx).toHaveBeenCalledWith( 'the-order:test-key', 3600, '{"key":"value"}' ); }); it('should use default TTL if not provided', async () => { mockRedisClient.setEx.mockResolvedValue('OK'); const client = new CacheClient({ url: 'redis://localhost:6379', ttl: 7200 }); await client.connect(); await client.set('test-key', 'value'); expect(mockRedisClient.setEx).toHaveBeenCalledWith( 'the-order:test-key', 7200, '"value"' ); }); }); describe('delete', () => { it('should delete key from cache', async () => { mockRedisClient.del.mockResolvedValue(1); await cacheClient.delete('test-key'); expect(mockRedisClient.del).toHaveBeenCalledWith('the-order:test-key'); }); }); describe('invalidate', () => { it('should invalidate keys by pattern', async () => { mockRedisClient.keys.mockResolvedValue(['the-order:test-key1', 'the-order:test-key2']); mockRedisClient.del.mockResolvedValue(2); const deleted = await cacheClient.invalidate('test-key*'); expect(deleted).toBe(2); expect(mockRedisClient.keys).toHaveBeenCalledWith('the-order:test-key*'); }); it('should return 0 if no keys found', async () => { mockRedisClient.keys.mockResolvedValue([]); const deleted = await cacheClient.invalidate('nonexistent*'); expect(deleted).toBe(0); }); }); describe('exists', () => { it('should check if key exists', async () => { mockRedisClient.exists.mockResolvedValue(1); const exists = await cacheClient.exists('test-key'); expect(exists).toBe(true); expect(mockRedisClient.exists).toHaveBeenCalledWith('the-order:test-key'); }); it('should return false if key does not exist', async () => { mockRedisClient.exists.mockResolvedValue(0); const exists = await cacheClient.exists('nonexistent-key'); expect(exists).toBe(false); }); }); describe('getStats', () => { it('should return cache statistics', () => { const stats = cacheClient.getStats(); expect(stats).toHaveProperty('hits'); expect(stats).toHaveProperty('misses'); expect(stats).toHaveProperty('sets'); expect(stats).toHaveProperty('deletes'); expect(stats).toHaveProperty('errors'); }); }); describe('resetStats', () => { it('should reset cache statistics', async () => { mockRedisClient.get.mockResolvedValue('{"key": "value"}'); await cacheClient.get('test-key'); cacheClient.resetStats(); const stats = cacheClient.getStats(); expect(stats.hits).toBe(0); expect(stats.misses).toBe(0); }); }); });