Skip to content

Commit 515a746

Browse files
committed
feat: add tests for adapter_ha functionality in WsSql and WsConsumer, ensuring pooled connector reuse
1 parent 7a4b4b6 commit 515a746

2 files changed

Lines changed: 141 additions & 0 deletions

File tree

nodejs/test/sql/sql.test.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { ClusterRegistry } from "@src/client/clusterRegistry";
12
import { WebSocketConnectionPool } from "@src/client/wsConnectorPool";
23
import { WSConfig } from "@src/common/config";
34
import { WsSql } from "@src/sql/wsSql";
@@ -7,6 +8,11 @@ import { setLevel } from "@src/common/log";
78
let dsn = "ws://localhost:6041";
89
let password1 = "Ab1!@#$%,.:?<>;~";
910
let password2 = "Bc%^&*()-_+=[]{}";
11+
12+
function resetClusterRegistrySingleton(): void {
13+
(ClusterRegistry as any)._instance = undefined;
14+
}
15+
1016
setLevel("debug");
1117
beforeAll(async () => {
1218
let conf: WSConfig = new WSConfig(dsn);
@@ -125,6 +131,47 @@ describe("TDWebSocket.WsSql()", () => {
125131
expect(version).toBeTruthy();
126132
});
127133

134+
test("adapter_ha connect reuses pooled connector across seed variants", async () => {
135+
const dsnA =
136+
`ws://${testUsername()}:${testPassword()}` +
137+
"@localhost:6041?adapter_ha=true";
138+
const dsnB =
139+
`ws://${testUsername()}:${testPassword()}` +
140+
"@localhost:6041,127.0.0.1:6041?adapter_ha=true";
141+
142+
let connA: WsSql | null = null;
143+
let connB: WsSql | null = null;
144+
145+
WebSocketConnectionPool.instance().destroyed();
146+
resetClusterRegistrySingleton();
147+
148+
try {
149+
connA = await WsSql.open(new WSConfig(dsnA));
150+
const firstResult = await connA.exec("select server_version()");
151+
expect(firstResult).toBeTruthy();
152+
153+
const connectorA = ((connA as any)._wsClient as any)._wsConnector;
154+
expect(connectorA).toBeDefined();
155+
expect(connectorA.getPoolKey()).toMatch(/^ws:\/\/[0-9a-f-]{36}\/ws#auth=/);
156+
157+
connB = await WsSql.open(new WSConfig(dsnB));
158+
const connectorB = ((connB as any)._wsClient as any)._wsConnector;
159+
expect(connectorB).toBe(connectorA);
160+
161+
const secondResult = await connB.exec("select server_version()");
162+
expect(secondResult).toBeTruthy();
163+
} finally {
164+
if (connB) {
165+
await connB.close();
166+
}
167+
if (connA) {
168+
await connA.close();
169+
}
170+
WebSocketConnectionPool.instance().destroyed();
171+
resetClusterRegistrySingleton();
172+
}
173+
});
174+
128175
test("show databases", async () => {
129176
let conf: WSConfig = new WSConfig(dsn);
130177
conf.setUser(testUsername());

nodejs/test/tmq/tmq.test.ts

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { ClusterRegistry } from "@src/client/clusterRegistry";
12
import { TMQConstants } from "@src/tmq/constant";
23
import { WsConsumer } from "@src/tmq/wsTmq";
34
import { WSConfig } from "@src/common/config";
@@ -19,6 +20,10 @@ let dropTopic = `DROP TOPIC IF EXISTS ${topics[0]};`;
1920
let dsn = `ws://${testUsername()}:${testPassword()}@localhost:6041`;
2021
let tmqDsn = "ws://localhost:6041";
2122

23+
function resetClusterRegistrySingleton(): void {
24+
(ClusterRegistry as any)._instance = undefined;
25+
}
26+
2227
beforeAll(async () => {
2328
let conf: WSConfig = new WSConfig(dsn);
2429
const createDB = `create database if not exists ${db} keep 3650`;
@@ -395,6 +400,95 @@ describe("TDWebSocket.Tmq()", () => {
395400
await consumer.close();
396401
});
397402

403+
test("adapter_ha consumes data and reuses pooled connector across seed variants", async () => {
404+
const now = Date.now();
405+
const dsnA = "ws://localhost:6041?adapter_ha=true";
406+
const dsnB = "ws://localhost:6041,127.0.0.1:6041?adapter_ha=true";
407+
const buildConfig = (
408+
groupId: string,
409+
clientId: string,
410+
url: string
411+
): Map<string, any> => {
412+
const cfg = new Map<string, any>();
413+
cfg.set(TMQConstants.GROUP_ID, groupId);
414+
cfg.set(TMQConstants.CONNECT_USER, testUsername());
415+
cfg.set(TMQConstants.CONNECT_PASS, testPassword());
416+
cfg.set(TMQConstants.AUTO_OFFSET_RESET, "earliest");
417+
cfg.set(TMQConstants.CLIENT_ID, clientId);
418+
cfg.set(TMQConstants.WS_URL, url);
419+
cfg.set(TMQConstants.ENABLE_AUTO_COMMIT, false);
420+
cfg.set(TMQConstants.AUTO_COMMIT_INTERVAL_MS, 1000);
421+
cfg.set("session.timeout.ms", "10000");
422+
cfg.set("max.poll.interval.ms", "30000");
423+
cfg.set("msg.with.table.name", "true");
424+
return cfg;
425+
};
426+
427+
let consumerA: WsConsumer | null = null;
428+
let consumerB: WsConsumer | null = null;
429+
430+
WebSocketConnectionPool.instance().destroyed();
431+
resetClusterRegistrySingleton();
432+
433+
try {
434+
const cfgA = buildConfig(
435+
`g_adapter_ha_${now}_a`,
436+
`c_adapter_ha_${now}_a`,
437+
dsnA
438+
);
439+
consumerA = await WsConsumer.newConsumer(cfgA);
440+
await consumerA.subscribe(topics);
441+
442+
const connectorA = ((consumerA as any)._wsClient as any)._wsConnector;
443+
expect(connectorA).toBeDefined();
444+
expect(connectorA.getPoolKey()).toMatch(/^ws:\/\/[0-9a-f-]{36}\/rest\/tmq#auth=/);
445+
446+
let count = 0;
447+
for (let i = 0; i < 20 && count < 10; i++) {
448+
const res = await consumerA.poll(500);
449+
for (const [, value] of res) {
450+
const data = value.getData();
451+
if (!data || data.length === 0) {
452+
continue;
453+
}
454+
count += data.length;
455+
}
456+
}
457+
expect(count).toBeGreaterThanOrEqual(10);
458+
459+
await consumerA.unsubscribe();
460+
await consumerA.close();
461+
consumerA = null;
462+
463+
const cfgB = buildConfig(
464+
`g_adapter_ha_${now}_b`,
465+
`c_adapter_ha_${now}_b`,
466+
dsnB
467+
);
468+
consumerB = await WsConsumer.newConsumer(cfgB);
469+
470+
const connectorB = ((consumerB as any)._wsClient as any)._wsConnector;
471+
expect(connectorB).toBe(connectorA);
472+
473+
await consumerB.subscribe(topics);
474+
const res = await consumerB.poll(500);
475+
expect(res).toBeTruthy();
476+
477+
await consumerB.unsubscribe();
478+
await consumerB.close();
479+
consumerB = null;
480+
} finally {
481+
if (consumerB) {
482+
await consumerB.close();
483+
}
484+
if (consumerA) {
485+
await consumerA.close();
486+
}
487+
WebSocketConnectionPool.instance().destroyed();
488+
resetClusterRegistrySingleton();
489+
}
490+
});
491+
398492
testEnterprise("connect with token", async () => {
399493
const conf = new WSConfig(dsn);
400494
const wsSql = await WsSql.open(conf);

0 commit comments

Comments
 (0)