UNPKG

@sailboat-computer/event-bus

Version:

Standardized event bus for sailboat computer v3 with resilience features and offline capabilities

318 lines (257 loc) 9.66 kB
/** * Dead letter queue tests */ import { DeadLetterQueueManager } from '../../src/dead-letter-queue'; import { EventPriority, EventCategory, DeadLetterEvent } from '../../src/types'; // Extended type for DeadLetterEvent with id property added by getEvents() interface DeadLetterEventWithId extends DeadLetterEvent { id: string; } describe('DeadLetterQueueManager', () => { let deadLetterQueue: DeadLetterQueueManager; beforeEach(() => { // Create a new dead letter queue manager for each test deadLetterQueue = new DeadLetterQueueManager(10, 3); }); describe('initialization', () => { it('should initialize with default values', () => { const defaultQueue = new DeadLetterQueueManager(); expect(defaultQueue).toBeDefined(); }); it('should initialize with custom values', () => { const customQueue = new DeadLetterQueueManager(20, 5); expect(customQueue).toBeDefined(); }); }); describe('addEvent', () => { it('should add an event to the queue', () => { const event = { id: 'test-id', type: 'test.event', timestamp: new Date(), source: 'test-service', version: '1.0', data: { message: 'Hello, world!' }, metadata: { priority: EventPriority.NORMAL, category: EventCategory.DATA } }; const error = new Error('Test error'); const attempts = 3; const eventId = deadLetterQueue.addEvent(event, error, attempts); expect(eventId).toBeDefined(); expect(deadLetterQueue.getSize()).toBe(1); }); it('should enforce the maximum queue size', () => { // Create a queue with max size 3 const smallQueue = new DeadLetterQueueManager(3, 3); // Add 4 events for (let i = 0; i < 4; i++) { const event = { id: `test-id-${i}`, type: 'test.event', timestamp: new Date(), source: 'test-service', version: '1.0', data: { message: `Event ${i}` }, metadata: { priority: EventPriority.NORMAL, category: EventCategory.DATA } }; const error = new Error(`Test error ${i}`); const attempts = 3; smallQueue.addEvent(event, error, attempts); } // Check that the queue size is still 3 expect(smallQueue.getSize()).toBe(3); // Check that the oldest event was removed const events = smallQueue.getEvents(); const ids = events.map(e => e.originalEventId); expect(ids).not.toContain('test-id-0'); expect(ids).toContain('test-id-1'); expect(ids).toContain('test-id-2'); expect(ids).toContain('test-id-3'); }); }); describe('getEvent', () => { it('should get an event by ID', () => { const event = { id: 'test-id', type: 'test.event', timestamp: new Date(), source: 'test-service', version: '1.0', data: { message: 'Hello, world!' }, metadata: { priority: EventPriority.NORMAL, category: EventCategory.DATA } }; const error = new Error('Test error'); const attempts = 3; const eventId = deadLetterQueue.addEvent(event, error, attempts); const retrievedEvent = deadLetterQueue.getEvent(eventId); expect(retrievedEvent).toBeDefined(); expect(retrievedEvent?.originalEventId).toBe('test-id'); expect(retrievedEvent?.eventType).toBe('test.event'); expect(retrievedEvent?.data).toEqual({ message: 'Hello, world!' }); expect(retrievedEvent?.attempts).toBe(3); expect(retrievedEvent?.error).toBeDefined(); expect(retrievedEvent?.error.message).toBe('Test error'); }); it('should return undefined for non-existent event ID', () => { const retrievedEvent = deadLetterQueue.getEvent('non-existent-id'); expect(retrievedEvent).toBeNull(); }); }); describe('getEvents', () => { beforeEach(() => { // Add some events of different types for (let i = 0; i < 5; i++) { const eventType = i % 2 === 0 ? 'test.event.even' : 'test.event.odd'; const event = { id: `test-id-${i}`, type: eventType, timestamp: new Date(), source: 'test-service', version: '1.0', data: { message: `Event ${i}` }, metadata: { priority: EventPriority.NORMAL, category: EventCategory.DATA } }; const error = new Error(`Test error ${i}`); const attempts = 3; deadLetterQueue.addEvent(event, error, attempts); } }); it('should get all events', () => { const events = deadLetterQueue.getEvents(); expect(events).toBeDefined(); expect(events.length).toBe(5); }); it('should get events by type', () => { const evenEvents = deadLetterQueue.getEvents('test.event.even'); const oddEvents = deadLetterQueue.getEvents('test.event.odd'); expect(evenEvents).toBeDefined(); expect(evenEvents.length).toBe(3); // 0, 2, 4 expect(oddEvents).toBeDefined(); expect(oddEvents.length).toBe(2); // 1, 3 }); it('should limit the number of events returned', () => { const limitedEvents = deadLetterQueue.getEvents(undefined, 3); expect(limitedEvents).toBeDefined(); expect(limitedEvents.length).toBe(3); }); it('should limit the number of events by type', () => { const limitedEvenEvents = deadLetterQueue.getEvents('test.event.even', 2); expect(limitedEvenEvents).toBeDefined(); expect(limitedEvenEvents.length).toBe(2); }); }); describe('removeEvent', () => { let eventId: string; beforeEach(() => { // Add an event const event = { id: 'test-id', type: 'test.event', timestamp: new Date(), source: 'test-service', version: '1.0', data: { message: 'Hello, world!' }, metadata: { priority: EventPriority.NORMAL, category: EventCategory.DATA } }; const error = new Error('Test error'); const attempts = 3; eventId = deadLetterQueue.addEvent(event, error, attempts); }); it('should remove an event by ID', () => { const removed = deadLetterQueue.removeEvent(eventId); expect(removed).toBe(true); expect(deadLetterQueue.getSize()).toBe(0); expect(deadLetterQueue.getEvent(eventId)).toBeNull(); }); it('should return false for non-existent event ID', () => { const removed = deadLetterQueue.removeEvent('non-existent-id'); expect(removed).toBe(false); expect(deadLetterQueue.getSize()).toBe(1); }); }); describe('clearEvents', () => { beforeEach(() => { // Add some events of different types for (let i = 0; i < 5; i++) { const eventType = i % 2 === 0 ? 'test.event.even' : 'test.event.odd'; const event = { id: `test-id-${i}`, type: eventType, timestamp: new Date(), source: 'test-service', version: '1.0', data: { message: `Event ${i}` }, metadata: { priority: EventPriority.NORMAL, category: EventCategory.DATA } }; const error = new Error(`Test error ${i}`); const attempts = 3; deadLetterQueue.addEvent(event, error, attempts); } }); it('should clear all events', () => { const clearedCount = deadLetterQueue.clearEvents(); expect(clearedCount).toBe(5); expect(deadLetterQueue.getSize()).toBe(0); }); it('should clear events by type', () => { const clearedCount = deadLetterQueue.clearEvents('test.event.even'); expect(clearedCount).toBe(3); // 0, 2, 4 expect(deadLetterQueue.getSize()).toBe(2); // 1, 3 remain const remainingEvents = deadLetterQueue.getEvents(); expect(remainingEvents.length).toBe(2); expect(remainingEvents[0]?.eventType).toBe('test.event.odd'); expect(remainingEvents[1]?.eventType).toBe('test.event.odd'); }); }); describe('getSize', () => { it('should return the correct queue size', () => { expect(deadLetterQueue.getSize()).toBe(0); // Add some events for (let i = 0; i < 3; i++) { const event = { id: `test-id-${i}`, type: 'test.event', timestamp: new Date(), source: 'test-service', version: '1.0', data: { message: `Event ${i}` }, metadata: { priority: EventPriority.NORMAL, category: EventCategory.DATA } }; const error = new Error(`Test error ${i}`); const attempts = 3; deadLetterQueue.addEvent(event, error, attempts); } expect(deadLetterQueue.getSize()).toBe(3); // Remove an event - getEvents() adds the id property to the returned events const events = deadLetterQueue.getEvents() as DeadLetterEventWithId[]; if (events.length > 0 && events[0]) { deadLetterQueue.removeEvent(events[0].id); } expect(deadLetterQueue.getSize()).toBe(2); // Clear all events deadLetterQueue.clearEvents(); expect(deadLetterQueue.getSize()).toBe(0); }); }); });