| import { describe, expect, it, vi } from 'vitest'; | |
| const errorSpy = vi.fn(); | |
| const infoSpy = vi.fn(); | |
| vi.mock('@/utils/logger', () => ({ | |
| default: { | |
| error: errorSpy, | |
| info: infoSpy, | |
| }, | |
| })); | |
| class RedisMock extends EventTarget { | |
| mget = vi.fn(); | |
| expire = vi.fn(); | |
| set = vi.fn(); | |
| on(event: string, listener: (...args: any[]) => void) { | |
| this.addEventListener(event, (evt) => { | |
| listener((evt as Event & { detail?: unknown }).detail); | |
| }); | |
| return this; | |
| } | |
| emit(event: string, detail?: unknown) { | |
| const evt = new Event(event) as Event & { detail?: unknown }; | |
| evt.detail = detail; | |
| this.dispatchEvent(evt); | |
| return true; | |
| } | |
| } | |
| vi.mock('ioredis', () => ({ | |
| default: RedisMock, | |
| })); | |
| describe('redis cache module', () => { | |
| it('throws on reserved cache ttl key', async () => { | |
| const redisCache = (await import('@/utils/cache/redis')).default; | |
| redisCache.status.available = true; | |
| redisCache.clients.redisClient = new RedisMock() as any; | |
| await expect(redisCache.get('rsshub:cacheTtl:bad')).rejects.toThrow('reserved for the internal usage'); | |
| }); | |
| it('expires cache ttl key when present', async () => { | |
| const redisCache = (await import('@/utils/cache/redis')).default; | |
| const client = new RedisMock() as any; | |
| client.mget.mockResolvedValue(['value', '30']); | |
| redisCache.status.available = true; | |
| redisCache.clients.redisClient = client; | |
| const value = await redisCache.get('mock', true); | |
| expect(value).toBe('value'); | |
| expect(client.expire).toHaveBeenCalledWith('rsshub:cacheTtl:mock', '30'); | |
| expect(client.expire).toHaveBeenCalledWith('mock', '30'); | |
| }); | |
| it('marks redis unavailable on error', async () => { | |
| const redisCache = (await import('@/utils/cache/redis')).default; | |
| redisCache.init(); | |
| const client = redisCache.clients.redisClient as RedisMock; | |
| client.emit('error', new Error('boom')); | |
| expect(redisCache.status.available).toBe(false); | |
| expect(errorSpy).toHaveBeenCalled(); | |
| }); | |
| }); | |