stock-bot/libs/core/cache/test/cache.test.ts
2025-06-25 08:29:53 -04:00

113 lines
3.6 KiB
TypeScript

import { beforeEach, describe, expect, it, mock } from 'bun:test';
import { CacheFactory, createNamespacedCache } from '../src/cache-factory';
import { generateKey } from '../src/key-generator';
import type { ICache } from '../src/types';
describe('CacheFactory', () => {
it('should create null cache when no config provided', () => {
const cache = CacheFactory.create(null as any, 'test');
expect(cache).toBeDefined();
expect(cache.type).toBe('null');
});
it('should create cache with namespace', () => {
const mockConfig = {
cache: {
provider: 'memory',
redis: { host: 'localhost', port: 6379 },
},
};
const cache = CacheFactory.create(mockConfig as any, 'test-namespace');
expect(cache).toBeDefined();
});
});
describe('NamespacedCache', () => {
let mockCache: ICache;
beforeEach(() => {
mockCache = {
type: 'mock',
get: mock(() => Promise.resolve(null)),
set: mock(() => Promise.resolve()),
del: mock(() => Promise.resolve()),
clear: mock(() => Promise.resolve()),
exists: mock(() => Promise.resolve(false)),
ttl: mock(() => Promise.resolve(-1)),
keys: mock(() => Promise.resolve([])),
mget: mock(() => Promise.resolve([])),
mset: mock(() => Promise.resolve()),
mdel: mock(() => Promise.resolve()),
size: mock(() => Promise.resolve(0)),
flush: mock(() => Promise.resolve()),
ping: mock(() => Promise.resolve(true)),
disconnect: mock(() => Promise.resolve()),
isConnected: mock(() => true),
};
});
it('should create namespaced cache', () => {
const nsCache = createNamespacedCache(mockCache, 'sub-namespace');
expect(nsCache).toBeDefined();
expect(nsCache).toHaveProperty('get');
expect(nsCache).toHaveProperty('set');
});
it('should prefix keys with namespace', async () => {
const nsCache = createNamespacedCache(mockCache, 'test');
await nsCache.set('key', 'value');
expect(mockCache.set).toHaveBeenCalledWith('test:key', 'value', undefined);
});
it('should handle null cache gracefully', async () => {
const nsCache = createNamespacedCache(null, 'test');
expect(nsCache).toBeDefined();
// Should return null for get operations
const value = await nsCache.get('key');
expect(value).toBeNull();
});
it('should prefix multiple operations', async () => {
const nsCache = createNamespacedCache(mockCache, 'prefix');
await nsCache.get('key1');
expect(mockCache.get).toHaveBeenCalledWith('prefix:key1');
await nsCache.del('key2');
expect(mockCache.del).toHaveBeenCalledWith('prefix:key2');
await nsCache.exists('key3');
expect(mockCache.exists).toHaveBeenCalledWith('prefix:key3');
});
it('should handle pattern operations', async () => {
const nsCache = createNamespacedCache(mockCache, 'ns');
mockCache.keys = mock(() => Promise.resolve(['ns:key1', 'ns:key2', 'other:key']));
const keys = await nsCache.keys('*');
expect(mockCache.keys).toHaveBeenCalledWith('ns:*');
expect(keys).toEqual(['key1', 'key2']);
});
});
describe('KeyGenerator', () => {
it('should generate key from parts', () => {
const key = generateKey('part1', 'part2', 'part3');
expect(key).toBe('part1:part2:part3');
});
it('should handle empty parts', () => {
const key = generateKey();
expect(key).toBe('');
});
it('should skip undefined parts', () => {
const key = generateKey('part1', undefined, 'part3');
expect(key).toBe('part1:part3');
});
it('should convert non-string parts', () => {
const key = generateKey('prefix', 123, true);
expect(key).toBe('prefix:123:true');
});
});