You've already forked node-redis
mirror of
https://github.com/redis/node-redis.git
synced 2025-12-09 21:21:11 +03:00
* refactor(test): improve test scenario reliability and maintainability * tests: add resp3 check test (#1) * test: refactor connection handoff tests with enhanced spy utility (#2) * test: add comprehensive push notification disabled scenarios (#3) * tests: add params config tests (#4) * tests: add feature enablement tests (#5) --------- Co-authored-by: Nikolay Karadzhov <nikolay.karadzhov@redis.com>
175 lines
4.5 KiB
TypeScript
175 lines
4.5 KiB
TypeScript
import { readFileSync } from "fs";
|
|
import { createClient, RedisClientOptions } from "../../..";
|
|
import { stub } from "sinon";
|
|
|
|
type DatabaseEndpoint = {
|
|
addr: string[];
|
|
addr_type: string;
|
|
dns_name: string;
|
|
oss_cluster_api_preferred_endpoint_type: string;
|
|
oss_cluster_api_preferred_ip_type: string;
|
|
port: number;
|
|
proxy_policy: string;
|
|
uid: string;
|
|
};
|
|
|
|
type DatabaseConfig = {
|
|
bdb_id: number;
|
|
username: string;
|
|
password: string;
|
|
tls: boolean;
|
|
raw_endpoints: DatabaseEndpoint[];
|
|
endpoints: string[];
|
|
};
|
|
|
|
type DatabasesConfig = {
|
|
[databaseName: string]: DatabaseConfig;
|
|
};
|
|
|
|
type EnvConfig = {
|
|
redisEndpointsConfigPath: string;
|
|
faultInjectorUrl: string;
|
|
};
|
|
|
|
/**
|
|
* Reads environment variables required for the test scenario
|
|
* @returns Environment configuration object
|
|
* @throws Error if required environment variables are not set
|
|
*/
|
|
export function getEnvConfig(): EnvConfig {
|
|
if (!process.env.REDIS_ENDPOINTS_CONFIG_PATH) {
|
|
throw new Error(
|
|
"REDIS_ENDPOINTS_CONFIG_PATH environment variable must be set"
|
|
);
|
|
}
|
|
|
|
if (!process.env.FAULT_INJECTION_API_URL) {
|
|
throw new Error("FAULT_INJECTION_API_URL environment variable must be set");
|
|
}
|
|
|
|
return {
|
|
redisEndpointsConfigPath: process.env.REDIS_ENDPOINTS_CONFIG_PATH,
|
|
faultInjectorUrl: process.env.FAULT_INJECTION_API_URL,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Reads database configuration from a file
|
|
* @param filePath - The path to the database configuration file
|
|
* @returns Parsed database configuration object
|
|
* @throws Error if file doesn't exist or JSON is invalid
|
|
*/
|
|
export function getDatabaseConfigFromEnv(filePath: string): DatabasesConfig {
|
|
try {
|
|
const fileContent = readFileSync(filePath, "utf8");
|
|
return JSON.parse(fileContent) as DatabasesConfig;
|
|
} catch (error) {
|
|
throw new Error(`Failed to read or parse database config from ${filePath}`);
|
|
}
|
|
}
|
|
|
|
export interface RedisConnectionConfig {
|
|
host: string;
|
|
port: number;
|
|
username: string;
|
|
password: string;
|
|
tls: boolean;
|
|
bdbId: number;
|
|
}
|
|
|
|
/**
|
|
* Gets Redis connection parameters for a specific database
|
|
* @param databasesConfig - The parsed database configuration object
|
|
* @param databaseName - Optional name of the database to retrieve (defaults to the first one)
|
|
* @returns Redis connection configuration with host, port, username, password, and tls
|
|
* @throws Error if the specified database is not found in the configuration
|
|
*/
|
|
export function getDatabaseConfig(
|
|
databasesConfig: DatabasesConfig,
|
|
databaseName?: string
|
|
): RedisConnectionConfig {
|
|
const dbConfig = databaseName
|
|
? databasesConfig[databaseName]
|
|
: Object.values(databasesConfig)[0];
|
|
|
|
if (!dbConfig) {
|
|
throw new Error(
|
|
`Database ${databaseName ? databaseName : ""} not found in configuration`
|
|
);
|
|
}
|
|
|
|
const endpoint = dbConfig.raw_endpoints[0]; // Use the first endpoint
|
|
|
|
return {
|
|
host: endpoint.dns_name,
|
|
port: endpoint.port,
|
|
username: dbConfig.username,
|
|
password: dbConfig.password,
|
|
tls: dbConfig.tls,
|
|
bdbId: dbConfig.bdb_id,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Executes the provided function in a context where setImmediate is stubbed to not do anything.
|
|
* This blocks setImmediate callbacks from executing
|
|
*
|
|
* @param command - The command to execute
|
|
* @returns The error and duration of the command execution
|
|
*/
|
|
export async function blockCommand(command: () => Promise<unknown>) {
|
|
let error: any;
|
|
|
|
const start = performance.now();
|
|
|
|
let setImmediateStub: any;
|
|
|
|
try {
|
|
setImmediateStub = stub(global, "setImmediate");
|
|
setImmediateStub.callsFake(() => {
|
|
//Dont call the callback, effectively blocking execution
|
|
});
|
|
await command();
|
|
} catch (err: any) {
|
|
error = err;
|
|
} finally {
|
|
if (setImmediateStub) {
|
|
setImmediateStub.restore();
|
|
}
|
|
}
|
|
|
|
return {
|
|
error,
|
|
duration: performance.now() - start,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Creates a test client with the provided configuration, connects it and attaches an error handler listener
|
|
* @param clientConfig - The Redis connection configuration
|
|
* @param options - Optional client options
|
|
* @returns The created Redis client
|
|
*/
|
|
export async function createTestClient(
|
|
clientConfig: RedisConnectionConfig,
|
|
options: Partial<RedisClientOptions> = {}
|
|
) {
|
|
const client = createClient({
|
|
socket: {
|
|
host: clientConfig.host,
|
|
port: clientConfig.port,
|
|
...(clientConfig.tls === true ? { tls: true } : {}),
|
|
},
|
|
password: clientConfig.password,
|
|
username: clientConfig.username,
|
|
RESP: 3,
|
|
maintPushNotifications: "auto",
|
|
maintMovingEndpointType: "auto",
|
|
...options,
|
|
});
|
|
|
|
await client.connect();
|
|
|
|
return client;
|
|
}
|