1
0
mirror of https://github.com/redis/node-redis.git synced 2025-12-09 21:21:11 +03:00
Files
node-redis/packages/client/lib/tests/test-scenario/push-notification.e2e.ts
Pavel Pashov b97bbbe8c6 refactor(test): improve test scenario reliability and maintainability (#3077)
* 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>
2025-09-18 12:45:55 +03:00

350 lines
10 KiB
TypeScript

import assert from "node:assert";
import diagnostics_channel from "node:diagnostics_channel";
import { FaultInjectorClient } from "./fault-injector-client";
import {
createTestClient,
getDatabaseConfig,
getDatabaseConfigFromEnv,
getEnvConfig,
RedisConnectionConfig,
} from "./test-scenario.util";
import { createClient } from "../../..";
import { DiagnosticsEvent } from "../../client/enterprise-maintenance-manager";
import { before } from "mocha";
describe("Push Notifications", () => {
const createNotificationMessageHandler = (
result: Record<DiagnosticsEvent["type"], number>,
notifications: Array<DiagnosticsEvent["type"]>
) => {
return (message: unknown) => {
if (notifications.includes((message as DiagnosticsEvent).type)) {
const event = message as DiagnosticsEvent;
result[event.type] = (result[event.type] ?? 0) + 1;
}
};
};
let onMessageHandler: ReturnType<typeof createNotificationMessageHandler>;
let clientConfig: RedisConnectionConfig;
let client: ReturnType<typeof createClient<any, any, any, any>>;
let faultInjectorClient: FaultInjectorClient;
before(() => {
const envConfig = getEnvConfig();
const redisConfig = getDatabaseConfigFromEnv(
envConfig.redisEndpointsConfigPath
);
faultInjectorClient = new FaultInjectorClient(envConfig.faultInjectorUrl);
clientConfig = getDatabaseConfig(redisConfig);
});
afterEach(() => {
if (onMessageHandler!) {
diagnostics_channel.unsubscribe("redis.maintenance", onMessageHandler);
}
if (client && client.isOpen) {
client.destroy();
}
});
describe("Push Notifications Enabled", () => {
beforeEach(async () => {
client = await createTestClient(clientConfig);
await client.flushAll();
});
it("should receive MOVING, MIGRATING, and MIGRATED push notifications", async () => {
const notifications: Array<DiagnosticsEvent["type"]> = [
"MOVING",
"MIGRATING",
"MIGRATED",
];
const diagnosticsMap: Record<DiagnosticsEvent["type"], number> = {};
onMessageHandler = createNotificationMessageHandler(
diagnosticsMap,
notifications
);
diagnostics_channel.subscribe("redis.maintenance", onMessageHandler);
const { action_id: bindAndMigrateActionId } =
await faultInjectorClient.migrateAndBindAction({
bdbId: clientConfig.bdbId,
clusterIndex: 0,
});
await faultInjectorClient.waitForAction(bindAndMigrateActionId);
assert.strictEqual(
diagnosticsMap.MOVING,
1,
"Should have received exactly one MOVING notification"
);
assert.strictEqual(
diagnosticsMap.MIGRATING,
1,
"Should have received exactly one MIGRATING notification"
);
assert.strictEqual(
diagnosticsMap.MIGRATED,
1,
"Should have received exactly one MIGRATED notification"
);
});
it("should receive FAILING_OVER and FAILED_OVER push notifications", async () => {
const notifications: Array<DiagnosticsEvent["type"]> = [
"FAILING_OVER",
"FAILED_OVER",
];
const diagnosticsMap: Record<DiagnosticsEvent["type"], number> = {};
onMessageHandler = createNotificationMessageHandler(
diagnosticsMap,
notifications
);
diagnostics_channel.subscribe("redis.maintenance", onMessageHandler);
const { action_id: failoverActionId } =
await faultInjectorClient.triggerAction({
type: "failover",
parameters: {
bdb_id: clientConfig.bdbId.toString(),
cluster_index: 0,
},
});
await faultInjectorClient.waitForAction(failoverActionId);
assert.strictEqual(
diagnosticsMap.FAILING_OVER,
1,
"Should have received exactly one FAILING_OVER notification"
);
assert.strictEqual(
diagnosticsMap.FAILED_OVER,
1,
"Should have received exactly one FAILED_OVER notification"
);
});
});
describe("Push Notifications Disabled - Client", () => {
beforeEach(async () => {
client = await createTestClient(clientConfig, {
maintPushNotifications: "disabled",
});
client.on("error", (_err) => {
// Expect the socket to be closed
// Ignore errors
});
await client.flushAll();
});
it("should NOT receive MOVING, MIGRATING, and MIGRATED push notifications", async () => {
const notifications: Array<DiagnosticsEvent["type"]> = [
"MOVING",
"MIGRATING",
"MIGRATED",
];
const diagnosticsMap: Record<DiagnosticsEvent["type"], number> = {};
onMessageHandler = createNotificationMessageHandler(
diagnosticsMap,
notifications
);
diagnostics_channel.subscribe("redis.maintenance", onMessageHandler);
const { action_id: bindAndMigrateActionId } =
await faultInjectorClient.migrateAndBindAction({
bdbId: clientConfig.bdbId,
clusterIndex: 0,
});
await faultInjectorClient.waitForAction(bindAndMigrateActionId);
assert.strictEqual(
diagnosticsMap.MOVING,
undefined,
"Should NOT have received exactly one MOVING notification"
);
assert.strictEqual(
diagnosticsMap.MIGRATING,
undefined,
"Should NOT have received exactly one MIGRATING notification"
);
assert.strictEqual(
diagnosticsMap.MIGRATED,
undefined,
"Should NOT have received exactly one MIGRATED notification"
);
});
it("should NOT receive FAILING_OVER and FAILED_OVER push notifications", async () => {
const notifications: Array<DiagnosticsEvent["type"]> = [
"FAILING_OVER",
"FAILED_OVER",
];
const diagnosticsMap: Record<DiagnosticsEvent["type"], number> = {};
onMessageHandler = createNotificationMessageHandler(
diagnosticsMap,
notifications
);
diagnostics_channel.subscribe("redis.maintenance", onMessageHandler);
const { action_id: failoverActionId } =
await faultInjectorClient.triggerAction({
type: "failover",
parameters: {
bdb_id: clientConfig.bdbId.toString(),
cluster_index: 0,
},
});
await faultInjectorClient.waitForAction(failoverActionId);
assert.strictEqual(
diagnosticsMap.FAILING_OVER,
undefined,
"Should have received exactly one FAILING_OVER notification"
);
assert.strictEqual(
diagnosticsMap.FAILED_OVER,
undefined,
"Should have received exactly one FAILED_OVER notification"
);
});
});
describe("Push Notifications Disabled - Server", () => {
beforeEach(async () => {
client = await createTestClient(clientConfig);
client.on("error", (_err) => {
// Expect the socket to be closed
// Ignore errors
});
await client.flushAll();
});
before(async () => {
const { action_id: disablePushNotificationsActionId } =
await faultInjectorClient.triggerAction({
type: "update_cluster_config",
parameters: {
config: { client_maint_notifications: false },
},
});
await faultInjectorClient.waitForAction(disablePushNotificationsActionId);
});
after(async () => {
const { action_id: enablePushNotificationsActionId } =
await faultInjectorClient.triggerAction({
type: "update_cluster_config",
parameters: {
config: { client_maint_notifications: true },
},
});
await faultInjectorClient.waitForAction(enablePushNotificationsActionId);
});
it("should NOT receive MOVING, MIGRATING, and MIGRATED push notifications", async () => {
const notifications: Array<DiagnosticsEvent["type"]> = [
"MOVING",
"MIGRATING",
"MIGRATED",
];
const diagnosticsMap: Record<DiagnosticsEvent["type"], number> = {};
onMessageHandler = createNotificationMessageHandler(
diagnosticsMap,
notifications
);
diagnostics_channel.subscribe("redis.maintenance", onMessageHandler);
const { action_id: bindAndMigrateActionId } =
await faultInjectorClient.migrateAndBindAction({
bdbId: clientConfig.bdbId,
clusterIndex: 0,
});
await faultInjectorClient.waitForAction(bindAndMigrateActionId);
assert.strictEqual(
diagnosticsMap.MOVING,
undefined,
"Should NOT have received exactly one MOVING notification"
);
assert.strictEqual(
diagnosticsMap.MIGRATING,
undefined,
"Should NOT have received exactly one MIGRATING notification"
);
assert.strictEqual(
diagnosticsMap.MIGRATED,
undefined,
"Should NOT have received exactly one MIGRATED notification"
);
});
it("should NOT receive FAILING_OVER and FAILED_OVER push notifications", async () => {
const notifications: Array<DiagnosticsEvent["type"]> = [
"FAILING_OVER",
"FAILED_OVER",
];
const diagnosticsMap: Record<DiagnosticsEvent["type"], number> = {};
onMessageHandler = createNotificationMessageHandler(
diagnosticsMap,
notifications
);
diagnostics_channel.subscribe("redis.maintenance", onMessageHandler);
const { action_id: failoverActionId } =
await faultInjectorClient.triggerAction({
type: "failover",
parameters: {
bdb_id: clientConfig.bdbId.toString(),
cluster_index: 0,
},
});
await faultInjectorClient.waitForAction(failoverActionId);
assert.strictEqual(
diagnosticsMap.FAILING_OVER,
undefined,
"Should have received exactly one FAILING_OVER notification"
);
assert.strictEqual(
diagnosticsMap.FAILED_OVER,
undefined,
"Should have received exactly one FAILED_OVER notification"
);
});
});
});