203 lines
6 KiB
TypeScript
203 lines
6 KiB
TypeScript
import { beforeEach, describe, expect, it, mock } from 'bun:test';
|
|
import { createServiceCache, ServiceCache } from '../src/service-cache';
|
|
import {
|
|
generateCachePrefix,
|
|
getFullQueueName,
|
|
normalizeServiceName,
|
|
parseQueueName,
|
|
} from '../src/service-utils';
|
|
import type { BatchJobData } from '../src/types';
|
|
|
|
describe('Service Utilities', () => {
|
|
describe('normalizeServiceName', () => {
|
|
it('should normalize service names', () => {
|
|
expect(normalizeServiceName('MyService')).toBe('my-service');
|
|
expect(normalizeServiceName('webApi')).toBe('web-api');
|
|
expect(normalizeServiceName('dataIngestion')).toBe('data-ingestion');
|
|
expect(normalizeServiceName('data-pipeline')).toBe('data-pipeline');
|
|
expect(normalizeServiceName('UPPERCASE')).toBe('uppercase');
|
|
});
|
|
|
|
it('should handle empty string', () => {
|
|
expect(normalizeServiceName('')).toBe('');
|
|
});
|
|
|
|
it('should handle special characters', () => {
|
|
// The function only handles camelCase, not special characters
|
|
expect(normalizeServiceName('my@service#123')).toBe('my@service#123');
|
|
expect(normalizeServiceName('serviceWithCamelCase')).toBe('service-with-camel-case');
|
|
});
|
|
});
|
|
|
|
describe('generateCachePrefix', () => {
|
|
it('should generate cache prefix', () => {
|
|
expect(generateCachePrefix('service')).toBe('cache:service');
|
|
expect(generateCachePrefix('webApi')).toBe('cache:web-api');
|
|
});
|
|
|
|
it('should handle empty parts', () => {
|
|
expect(generateCachePrefix('')).toBe('cache:');
|
|
});
|
|
});
|
|
|
|
describe('getFullQueueName', () => {
|
|
it('should generate full queue name', () => {
|
|
expect(getFullQueueName('service', 'handler')).toBe('{service_handler}');
|
|
expect(getFullQueueName('webApi', 'handler')).toBe('{web-api_handler}');
|
|
});
|
|
|
|
it('should normalize service name', () => {
|
|
expect(getFullQueueName('MyService', 'handler')).toBe('{my-service_handler}');
|
|
});
|
|
});
|
|
|
|
describe('parseQueueName', () => {
|
|
it('should parse queue name', () => {
|
|
expect(parseQueueName('{service_handler}')).toEqual({
|
|
service: 'service',
|
|
handler: 'handler',
|
|
});
|
|
expect(parseQueueName('{web-api_data-processor}')).toEqual({
|
|
service: 'web-api',
|
|
handler: 'data-processor',
|
|
});
|
|
});
|
|
|
|
it('should handle invalid formats', () => {
|
|
expect(parseQueueName('service:handler')).toBeNull();
|
|
expect(parseQueueName('service')).toBeNull();
|
|
expect(parseQueueName('')).toBeNull();
|
|
});
|
|
|
|
it('should handle edge cases', () => {
|
|
expect(parseQueueName('{}_handler')).toBeNull();
|
|
expect(parseQueueName('{service_}')).toBeNull();
|
|
expect(parseQueueName('not-a-valid-format')).toBeNull();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('ServiceCache', () => {
|
|
it('should create service cache', () => {
|
|
const mockRedisConfig = {
|
|
host: 'localhost',
|
|
port: 6379,
|
|
};
|
|
|
|
// Since ServiceCache constructor internally creates a real cache,
|
|
// we can't easily test it without mocking the createCache function
|
|
// For now, just test that the function exists and returns something
|
|
const serviceCache = createServiceCache('myservice', mockRedisConfig);
|
|
expect(serviceCache).toBeDefined();
|
|
expect(serviceCache).toBeInstanceOf(ServiceCache);
|
|
});
|
|
|
|
it('should handle cache prefix correctly', () => {
|
|
const mockRedisConfig = {
|
|
host: 'localhost',
|
|
port: 6379,
|
|
};
|
|
|
|
const serviceCache = createServiceCache('webApi', mockRedisConfig);
|
|
expect(serviceCache).toBeDefined();
|
|
// The prefix is set internally as cache:web-api
|
|
expect(serviceCache.getKey('test')).toBe('cache:web-api:test');
|
|
});
|
|
|
|
it('should support global cache option', () => {
|
|
const mockRedisConfig = {
|
|
host: 'localhost',
|
|
port: 6379,
|
|
};
|
|
|
|
const globalCache = createServiceCache('myservice', mockRedisConfig, { global: true });
|
|
expect(globalCache).toBeDefined();
|
|
// Global cache uses a different prefix
|
|
expect(globalCache.getKey('test')).toBe('stock-bot:shared:test');
|
|
});
|
|
});
|
|
|
|
describe('Batch Processing', () => {
|
|
it('should handle batch job data types', () => {
|
|
const batchJob: BatchJobData = {
|
|
items: [1, 2, 3],
|
|
options: {
|
|
batchSize: 10,
|
|
concurrency: 2,
|
|
},
|
|
};
|
|
|
|
expect(batchJob.items).toHaveLength(3);
|
|
expect(batchJob.options.batchSize).toBe(10);
|
|
expect(batchJob.options.concurrency).toBe(2);
|
|
});
|
|
|
|
it('should process batch results', () => {
|
|
const results = {
|
|
totalItems: 10,
|
|
successful: 8,
|
|
failed: 2,
|
|
errors: [
|
|
{ item: 5, error: 'Failed to process' },
|
|
{ item: 7, error: 'Invalid data' },
|
|
],
|
|
duration: 1000,
|
|
};
|
|
|
|
expect(results.successful + results.failed).toBe(results.totalItems);
|
|
expect(results.errors).toHaveLength(results.failed);
|
|
});
|
|
});
|
|
|
|
describe('Rate Limiting', () => {
|
|
it('should validate rate limit config', () => {
|
|
const config = {
|
|
rules: [
|
|
{
|
|
name: 'default',
|
|
maxJobs: 100,
|
|
window: 60000,
|
|
},
|
|
{
|
|
name: 'api',
|
|
maxJobs: 10,
|
|
window: 1000,
|
|
},
|
|
],
|
|
};
|
|
|
|
expect(config.rules).toHaveLength(2);
|
|
expect(config.rules[0].name).toBe('default');
|
|
expect(config.rules[1].maxJobs).toBe(10);
|
|
});
|
|
});
|
|
|
|
describe('Queue Types', () => {
|
|
it('should validate job data structure', () => {
|
|
const jobData = {
|
|
handler: 'TestHandler',
|
|
operation: 'process',
|
|
payload: { data: 'test' },
|
|
};
|
|
|
|
expect(jobData.handler).toBe('TestHandler');
|
|
expect(jobData.operation).toBe('process');
|
|
expect(jobData.payload).toBeDefined();
|
|
});
|
|
|
|
it('should validate queue stats structure', () => {
|
|
const stats = {
|
|
waiting: 10,
|
|
active: 2,
|
|
completed: 100,
|
|
failed: 5,
|
|
delayed: 3,
|
|
paused: false,
|
|
workers: 4,
|
|
};
|
|
|
|
expect(stats.waiting + stats.active + stats.completed + stats.failed + stats.delayed).toBe(120);
|
|
expect(stats.paused).toBe(false);
|
|
expect(stats.workers).toBe(4);
|
|
});
|
|
});
|