UNPKG

iostress

Version:

🚀 Blast your Socket.IO server with this quick and powerful JavaScript testing tool!

189 lines (182 loc) • 7.53 kB
import { ManagerOptions, SocketOptions, Socket } from 'socket.io-client'; import EventEmitter from 'events'; type ClientStatus = { readyClients: number; runningClients: number; finishedClients: number; }; interface ILogger { log: (message: string, type?: string) => void; error: (message: string | Error, type?: string) => void; warn: (message: string, type?: string) => void; debug: (message: string, type?: string) => void; } declare class StressEventsEmitter extends EventEmitter { on<K extends keyof StressEvents>(eventName: K, listener: StressEvents[K]): this; emit<K extends keyof StressEvents>(eventName: K, ...args: Parameters<StressEvents[K]>): boolean; once<K extends keyof StressEvents>(eventName: K, listener: StressEvents[K]): this; off<K extends keyof StressEvents>(eventName: K, listener: StressEvents[K]): this; } /** * Configuration options for running IO stress tests * @interface IOStressOptions * @property {string} target - The target URL/endpoint to stress test * @property {StressInterfaceOptions} [interfaceOptions] - Optional stress test input and output configuration. Default: defaultTerminalInterface() * @property {StressPhase[]} phases - Array of test phases defining the stress test scenarios */ interface IOStressOptions { target: string; interfaceOptions?: StressInterfaceOptions; phases: StressPhase[]; } /** * Configuration for a single phase of stress testing * @interface StressPhase * @property {string} name - Name of the stress test phase * @property {number} minClients - Minimum number of concurrent clients to run * @property {number} [maxClients] - Optional maximum number of concurrent clients * @property {number} [rampDelayRate] - Default: 100 * @property {StressScenarioInitializer} [scenarioInitializer] - Optional function to initialize the socket connection * @property {string} scenarioPath - The js file that exports stress test scenario function to execute * @property {number} [scenarioTimeout] - Optional timeout in milliseconds for the scenario * @property {StressInterfaceOptions} [interfaceOptions] - Optional interface options that overrides that top level options for this specific phase. */ interface StressPhase { name: string; minClients: number; maxClients?: number; rampDelayRate?: number; scenarioInitializer?: StressScenarioInitializer; scenarioPath: string; scenarioTimeout?: number; interfaceOptions?: StressInterfaceOptions; } /** * Configuration options for stress test input and output interface * @interface StressInterfaceOptions * @property {TerminatorFactory} [terminator] - Optional AbortController factory function for terminating the stress test gracefully/forcefully. Default: defaultTerminalTerminator() * @property {StressEventsHandler} [eventsHandler] - Optional events updates handler. Default: defaultTerminalEventsHandler() * @property {string} [logsDir] - Optional logs directory. Default: process.cwd() */ interface StressInterfaceOptions { terminator?: TerminatorFactory; eventsHandler?: StressEventsHandler; logsDir?: string; } type TerminatorFactory = () => AbortController; declare enum TerminationSignal { SIG_SOFT = 0, SIG_HARD = 1, SIG_CLEANUP = 2 } /** * Stress test events * @interface StressEvents */ interface StressEvents { /** * Emitted when the overall stress process has started. */ 'process-started': () => void | Promise<void>; /** * Emitted when a new phase begins. * * @param phaseName - The name of the phase (e.g. "Warmup", "Load"). */ 'phase-started': (phaseName: string) => void | Promise<void>; /** * Emitted when a task within a phase is started or updated. * * @param description - Human-readable description of the task. * @param data - Optional task-related metadata. */ 'phase-task': (id: Task, description: string, data?: unknown) => void | Promise<void>; /** * Emitted when a task within a phase finishes. * * @param description - Updated description string. * @param success - Whether the task completed successfully. */ 'phase-task-result': (id: Task, description: string, success: boolean) => void | Promise<void>; /** * Emitted after a phase is completed with aggregated results. * * @param report - Aggregated stress test report for the phase. * @param workersErrors - Map of worker IDs to arrays of errors. */ 'phase-result': (report: StressReport, workersErrors: Record<number, any[]>) => void | Promise<void>; } declare enum Task { INITIALIZERS_BUILD = 0, TEST_RUN = 1, REPORT_GENERATE = 2 } /** * A function that handles stress test events updates * @param {StressEventsEmitter} eventEmitter - event emitter, that emits stress test events * @returns {void} */ type StressEventsHandler = (eventEmitter: StressEventsEmitter) => void; /** * A function that returns Socket.io client connection configuration options * @param {number} clientNumber - The client number (attempt) to initialize * @returns {Partial<ManagerOptions & SocketOptions> | Promise<Partial<ManagerOptions & SocketOptions>>} Socket configuration options */ type StressScenarioInitializer = (clientNumber: number) => Partial<ManagerOptions & SocketOptions> | Promise<Partial<ManagerOptions & SocketOptions>>; /** * A stress test scenario function that executes socket operations * @param {Socket} socket - The initialized Socket.io client connection * @param {ILogger} logger - console.log won't work while executing scenario, use logger instead * @returns {void | Promise<void>} */ type StressScenario = (socket: Socket, logger: ILogger) => void | Promise<void>; /** * A stress test report (array of phases report) */ interface StressReport { phase: string; testDuration: number; connections: { attempted: number; successful: number; failed: number; averageConnectionTime: number; reconnectAttempts: number; }; events: { sent: number; received: number; successful: number; failed: number; throughput: number; }; latency: { average: number; min: number; max: number; p50: number; p85: number; p95: number; p99: number; }; errors: { total: number; byType: Record<string, number>; }; } declare function defaultTerminalInterface({ softTerminatorSignal, hardTerminatorSignal, reportsDir, logsDir, }?: { softTerminatorSignal?: string; hardTerminatorSignal?: string; reportsDir?: string; logsDir?: string; }): Required<StressInterfaceOptions>; declare function defaultTerminalTerminator(softTerminatorSignal?: string, hardTerminatorSignal?: string): () => AbortController; declare function defaultTerminalEventsHandler(reportsDir?: string): StressEventsHandler; declare class IOStress { private readonly options; constructor(options: IOStressOptions); run(): Promise<void>; private testPhase; private buildPhaseInitializers; } export { type ClientStatus, type ILogger, IOStress, type IOStressOptions, type StressEvents, type StressEventsHandler, type StressInterfaceOptions, type StressPhase, type StressReport, type StressScenario, type StressScenarioInitializer, Task, TerminationSignal, type TerminatorFactory, defaultTerminalEventsHandler, defaultTerminalInterface, defaultTerminalTerminator };