/** * In-Memory Health Event Publisher * * Tracks health-related events for testing purposes. * This publisher allows verification of event emission patterns * without requiring external event bus infrastructure. */ import { HealthEventPublisher, HealthCheckCompletedEvent, HealthCheckFailedEvent, HealthCheckTimeoutEvent, ConnectedEvent, DisconnectedEvent, DegradedEvent, CheckingEvent, } from '../../../core/health/ports/HealthEventPublisher'; export interface HealthCheckCompletedEventWithType { type: 'HealthCheckCompleted'; healthy: boolean; responseTime: number; timestamp: Date; endpoint?: string; } export interface HealthCheckFailedEventWithType { type: 'HealthCheckFailed'; error: string; timestamp: Date; endpoint?: string; } export interface HealthCheckTimeoutEventWithType { type: 'HealthCheckTimeout'; timestamp: Date; endpoint?: string; } export interface ConnectedEventWithType { type: 'Connected'; timestamp: Date; responseTime: number; } export interface DisconnectedEventWithType { type: 'Disconnected'; timestamp: Date; consecutiveFailures: number; } export interface DegradedEventWithType { type: 'Degraded'; timestamp: Date; reliability: number; } export interface CheckingEventWithType { type: 'Checking'; timestamp: Date; } export type HealthEvent = | HealthCheckCompletedEventWithType | HealthCheckFailedEventWithType | HealthCheckTimeoutEventWithType | ConnectedEventWithType | DisconnectedEventWithType | DegradedEventWithType | CheckingEventWithType; export class InMemoryHealthEventPublisher implements HealthEventPublisher { private events: HealthEvent[] = []; private shouldFail: boolean = false; /** * Publish a health check completed event */ async publishHealthCheckCompleted(event: HealthCheckCompletedEvent): Promise { if (this.shouldFail) throw new Error('Event publisher failed'); this.events.push({ type: 'HealthCheckCompleted', ...event }); } /** * Publish a health check failed event */ async publishHealthCheckFailed(event: HealthCheckFailedEvent): Promise { if (this.shouldFail) throw new Error('Event publisher failed'); this.events.push({ type: 'HealthCheckFailed', ...event }); } /** * Publish a health check timeout event */ async publishHealthCheckTimeout(event: HealthCheckTimeoutEvent): Promise { if (this.shouldFail) throw new Error('Event publisher failed'); this.events.push({ type: 'HealthCheckTimeout', ...event }); } /** * Publish a connected event */ async publishConnected(event: ConnectedEvent): Promise { if (this.shouldFail) throw new Error('Event publisher failed'); this.events.push({ type: 'Connected', ...event }); } /** * Publish a disconnected event */ async publishDisconnected(event: DisconnectedEvent): Promise { if (this.shouldFail) throw new Error('Event publisher failed'); this.events.push({ type: 'Disconnected', ...event }); } /** * Publish a degraded event */ async publishDegraded(event: DegradedEvent): Promise { if (this.shouldFail) throw new Error('Event publisher failed'); this.events.push({ type: 'Degraded', ...event }); } /** * Publish a checking event */ async publishChecking(event: CheckingEvent): Promise { if (this.shouldFail) throw new Error('Event publisher failed'); this.events.push({ type: 'Checking', ...event }); } /** * Get all published events */ getEvents(): HealthEvent[] { return [...this.events]; } /** * Get events by type */ getEventsByType(type: T): Extract[] { return this.events.filter((event): event is Extract => event.type === type); } /** * Get the count of events */ getEventCount(): number { return this.events.length; } /** * Get the count of events by type */ getEventCountByType(type: HealthEvent['type']): number { return this.events.filter(event => event.type === type).length; } /** * Clear all published events */ clear(): void { this.events = []; this.shouldFail = false; } /** * Configure the publisher to fail on publish */ setShouldFail(shouldFail: boolean): void { this.shouldFail = shouldFail; } }