UNPKG

syntropylog

Version:

An instance manager with observability for Node.js applications

178 lines (177 loc) 7.59 kB
/** * @file src/redis/BeaconRedisMock.ts * @description * A comprehensive, in-memory mock implementation of the `IBeaconRedis` interface. * It simulates Redis behavior for fast and reliable unit and integration testing, * supporting strings, hashes, lists, sets, sorted sets, and expirations. */ import { IBeaconRedis, IBeaconRedisTransaction } from './IBeaconRedis'; import { ILogger } from '../logger'; import { RedisZMember } from './redis.types'; /** * A full in-memory mock of a Redis client, implementing the `IBeaconRedis` interface. * This class is designed for testing purposes, providing a predictable and fast * alternative to a real Redis server. It supports most common commands and data types. * @implements {IBeaconRedis} */ export declare class BeaconRedisMock implements IBeaconRedis { /** The internal in-memory data store. */ private store; private readonly logger; private readonly instanceName; /** * Constructs a new BeaconRedisMock instance. * @param {string} [instanceName='default_mock'] - A name for this mock instance. * @param {ILogger} [parentLogger] - An optional parent logger to create a child logger from. */ constructor(instanceName?: string, parentLogger?: ILogger); /** * Retrieves an entry from the store if it exists and has not expired. * Also validates that the entry is of the expected type. * @private * @param {string} key - The key of the entry to retrieve. * @param {StoreEntry['type']} [expectedType] - The expected data type for the key. * @returns {StoreEntry | null} The store entry, or null if not found or expired. * @throws {Error} WRONGTYPE error if the key holds a value of the wrong type. */ private _getValidEntry; /** * Serializes a value to a string for storage, similar to how Redis stores data. * @private * @param {any} value - The value to serialize. * @returns {string} A string representation of the value. */ private _serialize; /** @inheritdoc */ get(key: string): Promise<string | null>; /** @inheritdoc */ set(key: string, value: any, ttlSeconds?: number): Promise<string | null>; /** @inheritdoc */ del(keys: string | string[]): Promise<number>; /** @inheritdoc */ exists(keys: string | string[]): Promise<number>; /** @inheritdoc */ expire(key: string, seconds: number): Promise<boolean>; /** @inheritdoc */ ttl(key: string): Promise<number>; /** @inheritdoc */ incr(key: string): Promise<number>; /** @inheritdoc */ decr(key: string): Promise<number>; /** @inheritdoc */ incrBy(key: string, increment: number): Promise<number>; /** @inheritdoc */ decrBy(key: string, decrement: number): Promise<number>; /** @inheritdoc */ hGet(key: string, field: string): Promise<string | null>; /** @inheritdoc */ hSet(key: string, field: string, value: any): Promise<number>; /** @inheritdoc */ hSet(key: string, fieldsAndValues: Record<string, any>): Promise<number>; /** @inheritdoc */ hGetAll(key: string): Promise<Record<string, string>>; /** @inheritdoc */ hDel(key: string, fields: string | string[]): Promise<number>; /** @inheritdoc */ hExists(key: string, field: string): Promise<boolean>; /** @inheritdoc */ hIncrBy(key: string, field: string, increment: number): Promise<number>; /** @inheritdoc */ lPush(key: string, elements: any | any[]): Promise<number>; /** @inheritdoc */ rPush(key: string, elements: any | any[]): Promise<number>; /** @inheritdoc */ lPop(key: string): Promise<string | null>; /** @inheritdoc */ rPop(key: string): Promise<string | null>; /** @inheritdoc */ lRange(key: string, start: number, stop: number): Promise<string[]>; /** @inheritdoc */ lLen(key: string): Promise<number>; /** @inheritdoc */ lTrim(key: string, start: number, stop: number): Promise<string>; /** @inheritdoc */ sAdd(key: string, members: any | any[]): Promise<number>; /** @inheritdoc */ sMembers(key: string): Promise<string[]>; /** @inheritdoc */ sIsMember(key: string, member: any): Promise<boolean>; /** @inheritdoc */ sRem(key: string, members: any | any[]): Promise<number>; /** @inheritdoc */ sCard(key: string): Promise<number>; /** @inheritdoc */ zAdd(key: string, score: number, member: any): Promise<number>; /** @inheritdoc */ zAdd(key: string, members: { score: number; value: any; }[]): Promise<number>; /** @inheritdoc */ zRange(key: string, min: string | number, max: string | number, options?: any): Promise<string[]>; /** @inheritdoc */ zRangeWithScores(key: string, min: string | number, max: string | number, options?: any): Promise<RedisZMember[]>; /** @inheritdoc */ zRem(key: string, members: any | any[]): Promise<number>; /** @inheritdoc */ zCard(key: string): Promise<number>; /** @inheritdoc */ zScore(key: string, member: any): Promise<number | null>; private pubSubListeners; /** * Simulates the SUBSCRIBE command for testing Pub/Sub. * @param {string | string[]} channels - The channel or channels to subscribe to. * @param {(message: string, channel: string) => void} listener - The callback to execute on message receipt. * @returns {Promise<void>} */ subscribe(channels: string | string[], listener: (message: string, channel: string) => void): Promise<void>; /** * Simulates the UNSUBSCRIBE command. * @param {string | string[]} [channels] - The channel or channels to unsubscribe from. If omitted, unsubscribes from all. * @returns {Promise<void>} */ unsubscribe(channels?: string | string[]): Promise<void>; /** * Simulates the PUBLISH command for testing purposes. * @param {string} channel - The channel to publish the message to. * @param {string} message - The message to publish. * @returns {Promise<number>} A promise that resolves with the number of clients that received the message. */ publish(channel: string, message: string): Promise<number>; /** * Simulates the EVAL command. This is not implemented and will throw an error. * @throws {Error} */ eval(_script: string, _keys: string[], _args: string[]): Promise<any>; /** @inheritdoc */ ping(message?: string): Promise<string>; /** @inheritdoc */ info(section?: string): Promise<string>; /** @inheritdoc */ multi(): IBeaconRedisTransaction; /** * Checks if the mock client is "healthy". For the mock, this always returns true. * @returns {Promise<boolean>} A promise that resolves to true. */ isHealthy(): Promise<boolean>; /** A no-op connect method to satisfy the interface. */ connect(): Promise<void>; /** A no-op quit method to satisfy the interface. */ quit(): Promise<void>; /** * Returns the mock instance itself, as it acts as the native client for testing. * @returns {this} The mock instance. */ getNativeClient(): any; /** * Gets the configured name of this mock Redis instance. * @returns {string} The instance name. */ getInstanceName(): string; /** * A mock implementation of `updateConfig` for testing purposes. * It logs the call and does nothing else, satisfying the `IBeaconRedis` interface. * @param {Partial<any>} newConfig - The configuration object. */ updateConfig(newConfig: Partial<any>): void; }