195 lines
5.7 KiB
TypeScript
195 lines
5.7 KiB
TypeScript
import { beforeEach, describe, expect, it } from 'bun:test';
|
|
import { HandlerRegistry } from '../src/registry';
|
|
import type { HandlerConfiguration, HandlerMetadata } from '../src/types';
|
|
|
|
describe('HandlerRegistry', () => {
|
|
let registry: HandlerRegistry;
|
|
|
|
beforeEach(() => {
|
|
registry = new HandlerRegistry();
|
|
});
|
|
|
|
describe('register', () => {
|
|
it('should register a handler', () => {
|
|
const metadata: HandlerMetadata = {
|
|
name: 'test-handler',
|
|
service: 'test-service',
|
|
operations: [
|
|
{ name: 'operation1', method: 'method1' },
|
|
{ name: 'operation2', method: 'method2' },
|
|
],
|
|
};
|
|
|
|
const config: HandlerConfiguration = {
|
|
name: 'test-handler',
|
|
operations: {
|
|
operation1: async () => {},
|
|
operation2: async () => {},
|
|
},
|
|
};
|
|
|
|
registry.register(metadata, config);
|
|
|
|
expect(registry.hasHandler('test-handler')).toBe(true);
|
|
expect(registry.getHandlerNames()).toContain('test-handler');
|
|
});
|
|
|
|
it('should allow duplicate registration', () => {
|
|
const metadata: HandlerMetadata = {
|
|
name: 'duplicate',
|
|
operations: [],
|
|
};
|
|
|
|
const config: HandlerConfiguration = {
|
|
name: 'duplicate',
|
|
operations: {},
|
|
};
|
|
|
|
registry.register(metadata, config);
|
|
|
|
// Should not throw on duplicate registration
|
|
expect(() => {
|
|
registry.register(metadata, config);
|
|
}).not.toThrow();
|
|
});
|
|
});
|
|
|
|
describe('getConfiguration', () => {
|
|
it('should return registered handler config', () => {
|
|
const config: HandlerConfiguration = {
|
|
name: 'my-handler',
|
|
operations: {
|
|
doSomething: async () => 'result',
|
|
},
|
|
};
|
|
|
|
registry.register({ name: 'my-handler', operations: [] }, config);
|
|
|
|
const retrieved = registry.getConfiguration('my-handler');
|
|
expect(retrieved).toBe(config);
|
|
});
|
|
|
|
it('should return undefined for unknown handler', () => {
|
|
const result = registry.getConfiguration('unknown');
|
|
expect(result).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
describe('getOperation', () => {
|
|
it('should return operation handler', () => {
|
|
const operationFn = async () => 'test';
|
|
|
|
registry.register(
|
|
{ name: 'handler1', operations: [{ name: 'op1', method: 'method1' }] },
|
|
{ name: 'handler1', operations: { op1: operationFn } }
|
|
);
|
|
|
|
const retrieved = registry.getOperation('handler1', 'op1');
|
|
expect(retrieved).toBe(operationFn);
|
|
});
|
|
|
|
it('should return undefined for unknown operation', () => {
|
|
registry.register({ name: 'handler1', operations: [] }, { name: 'handler1', operations: {} });
|
|
|
|
const result = registry.getOperation('handler1', 'unknown');
|
|
expect(result).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
describe('scheduled jobs', () => {
|
|
it('should register handler with scheduled jobs', () => {
|
|
const metadata: HandlerMetadata = {
|
|
name: 'scheduled-handler',
|
|
operations: [],
|
|
schedules: [
|
|
{
|
|
operation: 'scheduled-op',
|
|
cronPattern: '* * * * *',
|
|
priority: 5,
|
|
},
|
|
],
|
|
};
|
|
|
|
const config: HandlerConfiguration = {
|
|
name: 'scheduled-handler',
|
|
operations: {},
|
|
scheduledJobs: [
|
|
{
|
|
type: 'scheduled-handler-scheduled-op',
|
|
operation: 'scheduled-op',
|
|
cronPattern: '* * * * *',
|
|
priority: 5,
|
|
},
|
|
],
|
|
};
|
|
|
|
registry.register(metadata, config);
|
|
|
|
const handlers = registry.getAllHandlersWithSchedule();
|
|
expect(handlers.size).toBe(1);
|
|
expect(handlers.has('scheduled-handler')).toBe(true);
|
|
|
|
const handlerData = handlers.get('scheduled-handler');
|
|
expect(handlerData?.scheduledJobs).toHaveLength(1);
|
|
});
|
|
|
|
it('should return all handlers including those without schedules', () => {
|
|
registry.register(
|
|
{ name: 'no-schedule', operations: [] },
|
|
{ name: 'no-schedule', operations: {} }
|
|
);
|
|
|
|
registry.register(
|
|
{
|
|
name: 'with-schedule',
|
|
operations: [],
|
|
schedules: [{ operation: 'op', cronPattern: '* * * * *' }],
|
|
},
|
|
{
|
|
name: 'with-schedule',
|
|
operations: {},
|
|
scheduledJobs: [{ type: 'job', operation: 'op', cronPattern: '* * * * *' }],
|
|
}
|
|
);
|
|
|
|
const handlers = registry.getAllHandlersWithSchedule();
|
|
expect(handlers.size).toBe(2);
|
|
|
|
const noScheduleData = handlers.get('no-schedule');
|
|
expect(noScheduleData?.scheduledJobs).toHaveLength(0);
|
|
|
|
const withScheduleData = handlers.get('with-schedule');
|
|
expect(withScheduleData?.scheduledJobs).toHaveLength(1);
|
|
});
|
|
});
|
|
|
|
describe('service mapping', () => {
|
|
it('should track handler service', () => {
|
|
registry.register(
|
|
{ name: 'handler1', service: 'service-a', operations: [] },
|
|
{ name: 'handler1', operations: {} }
|
|
);
|
|
|
|
expect(registry.getHandlerService('handler1')).toBe('service-a');
|
|
});
|
|
|
|
it('should return undefined for handler without service', () => {
|
|
registry.register({ name: 'handler2', operations: [] }, { name: 'handler2', operations: {} });
|
|
|
|
expect(registry.getHandlerService('handler2')).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
describe('getAllMetadata', () => {
|
|
it('should return all registered handlers', () => {
|
|
registry.register({ name: 'h1', operations: [] }, { name: 'h1', operations: {} });
|
|
|
|
registry.register({ name: 'h2', operations: [] }, { name: 'h2', operations: {} });
|
|
|
|
const all = registry.getAllMetadata();
|
|
expect(all.size).toBe(2);
|
|
expect(all.has('h1')).toBe(true);
|
|
expect(all.has('h2')).toBe(true);
|
|
});
|
|
});
|
|
});
|