Skip to main content
Glama
waldzellai

Exa Websets MCP Server

by waldzellai
EventProcessor.test.ts12.6 kB
/** * Unit Tests for EventProcessor * * Tests the EventProcessor with mocked event handlers. * Following TDD London School methodology. */ import { jest, describe, it, expect, beforeEach, afterEach } from '@jest/globals'; import { EventProcessor, DefaultEventHandlerRegistry } from '../../../src/events/EventProcessor.js'; import { EventHandler, EventHandlerRegistry } from '../../../src/events/EventTypes.js'; import { mockWebsetEvent, createMockWebsetEvent } from '../../fixtures/websets.js'; // Mock dependencies jest.mock('../../../src/utils/logger.js'); describe('EventProcessor', () => { let eventProcessor: EventProcessor; let mockHandlerRegistry: jest.Mocked<EventHandlerRegistry>; let mockHandler: jest.Mocked<EventHandler>; beforeEach(() => { // Reset mocks jest.clearAllMocks(); // Create mock handler mockHandler = { eventType: 'webset.created', priority: 100, canHandle: global.testUtils.createMockFn(() => true), handle: global.testUtils.createAsyncMockFn() }; // Create mock handler registry mockHandlerRegistry = { handlers: new Map(), register: global.testUtils.createMockFn(), unregister: global.testUtils.createMockFn(), getHandlers: global.testUtils.createMockFn(() => [mockHandler]), getAllHandlers: global.testUtils.createMockFn(() => [mockHandler]), clear: global.testUtils.createMockFn() } as any; // Create processor instance eventProcessor = new EventProcessor({ concurrency: 2, timeout: 5000, enableDeadLetterQueue: true }, mockHandlerRegistry); }); afterEach(() => { jest.clearAllMocks(); }); describe('constructor', () => { it('should create instance with default configuration', () => { const processor = new EventProcessor(); expect(processor).toBeInstanceOf(EventProcessor); }); it('should create instance with custom configuration', () => { const config = { concurrency: 5, timeout: 10000, enableDeadLetterQueue: false }; const processor = new EventProcessor(config); expect(processor).toBeInstanceOf(EventProcessor); }); it('should use provided handler registry', () => { const customRegistry = new DefaultEventHandlerRegistry(); const processor = new EventProcessor({}, customRegistry); expect(processor).toBeInstanceOf(EventProcessor); }); }); describe('processEvent', () => { it('should process event successfully with handlers', async () => { // Arrange const event = createMockWebsetEvent({ type: 'webset.created' }); mockHandler.handle.mockResolvedValue(undefined); // Act const result = await eventProcessor.processEvent(event); // Assert expect(mockHandlerRegistry.getHandlers).toHaveBeenCalledWith('webset.created'); expect(mockHandler.handle).toHaveBeenCalledWith(event); expect(result.duration).toBeGreaterThan(0); expect(result.error).toBeUndefined(); }); it('should handle event with no registered handlers', async () => { // Arrange const event = createMockWebsetEvent({ type: 'webset.created' }); mockHandlerRegistry.getHandlers.mockReturnValue([]); // Act const result = await eventProcessor.processEvent(event); // Assert expect(result.duration).toBeGreaterThan(0); expect(result.metadata?.reason).toBe('no_handlers'); expect(result.error).toBeUndefined(); }); it('should handle handler errors gracefully', async () => { // Arrange const event = createMockWebsetEvent({ type: 'webset.created' }); const handlerError = new Error('Handler failed'); mockHandler.handle.mockRejectedValue(handlerError); // Act const result = await eventProcessor.processEvent(event); // Assert expect(result.error).toBe(handlerError); expect(result.duration).toBeGreaterThan(0); }); it('should handle processing timeout', async () => { // Arrange const event = createMockWebsetEvent({ type: 'webset.created' }); mockHandler.handle.mockImplementation(async () => { // Simulate long-running operation await new Promise(resolve => setTimeout(resolve, 10000)); }); // Create processor with short timeout const shortTimeoutProcessor = new EventProcessor({ timeout: 100 }, mockHandlerRegistry); // Act const result = await shortTimeoutProcessor.processEvent(event); // Assert expect(result.error?.message).toContain('Event processing timeout'); }); }); describe('handler management', () => { it('should register handler', () => { // Act eventProcessor.registerHandler(mockHandler); // Assert expect(mockHandlerRegistry.register).toHaveBeenCalledWith(mockHandler); }); it('should unregister handler', () => { // Act eventProcessor.unregisterHandler(mockHandler); // Assert expect(mockHandlerRegistry.unregister).toHaveBeenCalledWith(mockHandler); }); it('should get handlers for event type', () => { // Act const handlers = eventProcessor.getHandlers('webset.created'); // Assert expect(mockHandlerRegistry.getHandlers).toHaveBeenCalledWith('webset.created'); expect(handlers).toEqual([mockHandler]); }); it('should clear all handlers', () => { // Act eventProcessor.clearHandlers(); // Assert expect(mockHandlerRegistry.clear).toHaveBeenCalled(); }); }); describe('statistics and monitoring', () => { it('should track processing statistics', async () => { // Arrange const event = createMockWebsetEvent({ type: 'webset.created' }); mockHandler.handle.mockResolvedValue(undefined); // Act await eventProcessor.processEvent(event); const stats = eventProcessor.getStats(); // Assert expect(stats.totalProcessed).toBe(1); expect(stats.successful).toBe(1); expect(stats.failed).toBe(0); expect(stats.averageProcessingTime).toBeGreaterThan(0); }); it('should track failed processing statistics', async () => { // Arrange const event = createMockWebsetEvent({ type: 'webset.created' }); mockHandler.handle.mockRejectedValue(new Error('Handler failed')); // Act await eventProcessor.processEvent(event); const stats = eventProcessor.getStats(); // Assert expect(stats.totalProcessed).toBe(1); expect(stats.successful).toBe(0); expect(stats.failed).toBe(1); }); it('should reset statistics', async () => { // Arrange const event = createMockWebsetEvent({ type: 'webset.created' }); mockHandler.handle.mockResolvedValue(undefined); await eventProcessor.processEvent(event); // Act eventProcessor.resetStats(); const stats = eventProcessor.getStats(); // Assert expect(stats.totalProcessed).toBe(0); expect(stats.successful).toBe(0); expect(stats.failed).toBe(0); expect(stats.averageProcessingTime).toBe(0); }); it('should provide health check information', () => { // Act const health = eventProcessor.healthCheck(); // Assert expect(health).toHaveProperty('healthy'); expect(health).toHaveProperty('activeWorkers'); expect(health).toHaveProperty('deadLetterQueueSize'); expect(health).toHaveProperty('processingRate'); expect(health).toHaveProperty('errorRate'); }); }); describe('dead letter queue', () => { it('should add failed events to dead letter queue when enabled', async () => { // Arrange const event = createMockWebsetEvent({ type: 'webset.created' }); mockHandler.handle.mockRejectedValue(new Error('Handler failed')); // Act await eventProcessor.processEvent(event); const deadLetterQueue = eventProcessor.getDeadLetterQueue(); // Assert expect(deadLetterQueue).toHaveLength(1); expect(deadLetterQueue[0]).toEqual(event); }); it('should not add events to dead letter queue when disabled', async () => { // Arrange const processorWithoutDLQ = new EventProcessor({ enableDeadLetterQueue: false }, mockHandlerRegistry); const event = createMockWebsetEvent({ type: 'webset.created' }); mockHandler.handle.mockRejectedValue(new Error('Handler failed')); // Act await processorWithoutDLQ.processEvent(event); const deadLetterQueue = processorWithoutDLQ.getDeadLetterQueue(); // Assert expect(deadLetterQueue).toHaveLength(0); }); it('should clear dead letter queue', async () => { // Arrange const event = createMockWebsetEvent({ type: 'webset.created' }); mockHandler.handle.mockRejectedValue(new Error('Handler failed')); await eventProcessor.processEvent(event); // Act eventProcessor.clearDeadLetterQueue(); const deadLetterQueue = eventProcessor.getDeadLetterQueue(); // Assert expect(deadLetterQueue).toHaveLength(0); }); }); describe('shutdown', () => { it('should shutdown gracefully', async () => { // Act await eventProcessor.shutdown(1000); // Assert const health = eventProcessor.healthCheck(); expect(health.healthy).toBe(false); }); it('should reject new events during shutdown', async () => { // Arrange const event = createMockWebsetEvent({ type: 'webset.created' }); await eventProcessor.shutdown(100); // Act & Assert await expect(eventProcessor.processEvent(event)) .rejects.toThrow('Processor is shutting down'); }); }); }); describe('DefaultEventHandlerRegistry', () => { let registry: DefaultEventHandlerRegistry; let mockHandler: EventHandler; beforeEach(() => { registry = new DefaultEventHandlerRegistry(); mockHandler = { eventType: 'webset.created', priority: 100, canHandle: (event) => event.type === 'webset.created', handle: global.testUtils.createAsyncMockFn() }; }); describe('register', () => { it('should register handler for matching event types', () => { // Act registry.register(mockHandler); // Assert const handlers = registry.getHandlers('webset.created'); expect(handlers).toContain(mockHandler); }); it('should sort handlers by priority', () => { // Arrange const lowPriorityHandler = { eventType: 'webset.created' as const, priority: 50, canHandle: (event: any) => event.type === 'webset.created', handle: global.testUtils.createAsyncMockFn() }; const highPriorityHandler = { eventType: 'webset.created' as const, priority: 200, canHandle: (event: any) => event.type === 'webset.created', handle: global.testUtils.createAsyncMockFn() }; // Act registry.register(lowPriorityHandler); registry.register(highPriorityHandler); registry.register(mockHandler); // Assert const handlers = registry.getHandlers('webset.created'); expect(handlers[0]).toBe(highPriorityHandler); expect(handlers[1]).toBe(mockHandler); expect(handlers[2]).toBe(lowPriorityHandler); }); }); describe('unregister', () => { it('should unregister handler', () => { // Arrange registry.register(mockHandler); // Act registry.unregister(mockHandler); // Assert const handlers = registry.getHandlers('webset.created'); expect(handlers).not.toContain(mockHandler); }); }); describe('clear', () => { it('should clear all handlers', () => { // Arrange registry.register(mockHandler); // Act registry.clear(); // Assert const handlers = registry.getHandlers('webset.created'); expect(handlers).toHaveLength(0); }); }); describe('getAllHandlers', () => { it('should return all registered handlers', () => { // Arrange const handler2 = { eventType: 'webset.deleted' as const, priority: 90, canHandle: (event: any) => event.type === 'webset.deleted', handle: global.testUtils.createAsyncMockFn() }; registry.register(mockHandler); registry.register(handler2); // Act const allHandlers = registry.getAllHandlers(); // Assert expect(allHandlers).toContain(mockHandler); expect(allHandlers).toContain(handler2); }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/waldzellai/exa-mcp-server-websets'

If you have feedback or need assistance with the MCP directory API, please join our Discord server