diff --git a/node/tests/GlideClusterClient.test.ts b/node/tests/GlideClusterClient.test.ts index c97c34edb5..dfb0e41bd7 100644 --- a/node/tests/GlideClusterClient.test.ts +++ b/node/tests/GlideClusterClient.test.ts @@ -73,7 +73,7 @@ describe("GlideClusterClient", () => { getServerVersion, ) : // setting replicaCount to 1 to facilitate tests routed to replicas - await ValkeyCluster.createCluster(true, 3, 1, getServerVersion); + await ValkeyCluster.createCluster(true, 3, 2, getServerVersion); }, 40000); afterEach(async () => { @@ -1968,13 +1968,59 @@ describe("GlideClusterClient", () => { }, ); describe("GlideClusterClient - AZAffinity Read Strategy Test", () => { + async function getNumberOfReplicas( + client: GlideClusterClient, + ): Promise { + const replicationInfo = await client.customCommand([ + "INFO", + "REPLICATION", + ]); + + if (Array.isArray(replicationInfo)) { + // Handle array response from cluster (CME Mode) + let totalReplicas = 0; + for (const node of replicationInfo) { + const nodeInfo = node as { + key: string; + value: string | string[] | null; + }; + + if (typeof nodeInfo.value === "string") { + const lines = nodeInfo.value.split(/\r?\n/); + const connectedReplicasLine = lines.find( + (line) => + line.startsWith("connected_slaves:") || + line.startsWith("connected_replicas:"), + ); + + if (connectedReplicasLine) { + const parts = connectedReplicasLine.split(":"); + const numReplicas = parseInt(parts[1], 10); + if (!isNaN(numReplicas)) { + // Sum up replicas from each primary node + totalReplicas += numReplicas; + } + } + } + } + + if (totalReplicas > 0) { + return totalReplicas; + } + throw new Error( + "Could not find replica information in any node's response", + ); + } + throw new Error( + "Unexpected response format from INFO REPLICATION command", + ); + } + it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])( "should route GET commands to all replicas with the same AZ using protocol %p", async (protocol) => { const az = "us-east-1a"; - const n_replicas = 6; - const GET_CALLS = 3 * n_replicas; - const get_cmdstat = `calls=${GET_CALLS / n_replicas}`; + const GET_CALLS_PER_REPLICA = 3; let client_for_config_set; let client_for_testing_az; @@ -2006,6 +2052,19 @@ describe("GlideClusterClient", () => { { route: "allNodes" }, ); + // Retrieve the number of replicas dynamically + const n_replicas = await getNumberOfReplicas( + client_for_config_set, + ); + console.log(n_replicas); + if (n_replicas === 0) { + throw new Error( + "No replicas found in the cluster. Test requires at least one replica.", + ); + } + const GET_CALLS = GET_CALLS_PER_REPLICA * n_replicas; + const get_cmdstat = `calls=${GET_CALLS_PER_REPLICA}`; + // Stage 2: Create AZ affinity client and verify configuration client_for_testing_az = await GlideClusterClient.createClient( @@ -2064,7 +2123,7 @@ describe("GlideClusterClient", () => { // Stage 4: Verify GET commands were routed correctly const info_result = await client_for_testing_az.customCommand( - ["INFO", "COMMANDSTATS"], + ["INFO", "ALL"], // Get both replication and commandstats info { route: "allNodes" }, ); @@ -2077,11 +2136,20 @@ describe("GlideClusterClient", () => { }; const infoStr = nodeInfo.value?.toString() || ""; - return infoStr.includes(get_cmdstat); + + // Check if this is a replica node AND it has the expected number of GET calls + const isReplicaNode = + infoStr.includes("role:slave") || + infoStr.includes("role:replica"); + + return ( + isReplicaNode && + infoStr.includes(get_cmdstat) + ); }, ).length; - expect(matching_entries_count).toBe(n_replicas); + expect(matching_entries_count).toBe(n_replicas); // Should expect 6 as the cluster was created with 3 primary and 2 replicas, totalling 6 replica nodes } else { throw new Error( "Unexpected response format from INFO command",