syntropylog
Version:
An instance manager with observability for Node.js applications
178 lines (177 loc) • 7.59 kB
TypeScript
/**
* @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;
}