@tdengine/websocket 3.2.1 → 3.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/package.json +64 -0
- package/lib/src/client/retryConfig.d.ts +10 -0
- package/lib/src/client/retryConfig.d.ts.map +1 -0
- package/lib/src/client/retryConfig.js +46 -0
- package/lib/src/client/wsClient.d.ts +1 -0
- package/lib/src/client/wsClient.d.ts.map +1 -1
- package/lib/src/client/wsClient.js +31 -19
- package/lib/src/client/wsConnector.d.ts.map +1 -1
- package/lib/src/client/wsConnector.js +12 -11
- package/lib/src/client/wsConnectorPool.d.ts.map +1 -1
- package/lib/src/client/wsConnectorPool.js +13 -16
- package/lib/src/client/wsEventCallback.d.ts.map +1 -1
- package/lib/src/client/wsResponse.d.ts +0 -3
- package/lib/src/client/wsResponse.d.ts.map +1 -1
- package/lib/src/client/wsResponse.js +0 -3
- package/lib/src/common/config.d.ts +3 -0
- package/lib/src/common/config.d.ts.map +1 -1
- package/lib/src/common/config.js +6 -0
- package/lib/src/common/constant.d.ts +1 -0
- package/lib/src/common/constant.d.ts.map +1 -1
- package/lib/src/common/constant.js +6 -1
- package/lib/src/common/dsn.d.ts +18 -0
- package/lib/src/common/dsn.d.ts.map +1 -0
- package/lib/src/common/dsn.js +152 -0
- package/lib/src/common/taosResult.d.ts.map +1 -1
- package/lib/src/common/utils.d.ts +4 -0
- package/lib/src/common/utils.d.ts.map +1 -1
- package/lib/src/common/utils.js +54 -3
- package/lib/src/index.d.ts.map +1 -1
- package/lib/src/sql/wsSql.d.ts.map +1 -1
- package/lib/src/sql/wsSql.js +0 -3
- package/lib/src/tmq/config.d.ts +1 -0
- package/lib/src/tmq/config.d.ts.map +1 -1
- package/lib/src/tmq/config.js +18 -1
- package/lib/src/tmq/constant.d.ts +4 -0
- package/lib/src/tmq/constant.d.ts.map +1 -1
- package/lib/src/tmq/constant.js +4 -0
- package/lib/src/tmq/tmqResponse.d.ts.map +1 -1
- package/lib/src/tmq/tmqResponse.js +1 -4
- package/lib/src/tmq/wsTmq.d.ts.map +1 -1
- package/lib/src/tmq/wsTmq.js +10 -5
- package/lib/test/bulkPulling/cloud.tmq.test.js +3 -2
- package/lib/test/bulkPulling/decimal.test.js +8 -8
- package/lib/test/bulkPulling/dsn.test.d.ts +2 -0
- package/lib/test/bulkPulling/dsn.test.d.ts.map +1 -0
- package/lib/test/bulkPulling/dsn.test.js +378 -0
- package/lib/test/bulkPulling/queryTables.test.js +1 -1
- package/lib/test/bulkPulling/retryConfig.test.d.ts +2 -0
- package/lib/test/bulkPulling/retryConfig.test.d.ts.map +1 -0
- package/lib/test/bulkPulling/retryConfig.test.js +34 -0
- package/lib/test/bulkPulling/schemaless.test.js +15 -14
- package/lib/test/bulkPulling/sql.test.js +116 -44
- package/lib/test/bulkPulling/stmt1.func.test.js +31 -30
- package/lib/test/bulkPulling/stmt1.type.test.js +1 -1
- package/lib/test/bulkPulling/stmt2.func.test.js +37 -36
- package/lib/test/bulkPulling/stmt2.type.test.js +1 -1
- package/lib/test/bulkPulling/tmq.config.test.d.ts +2 -0
- package/lib/test/bulkPulling/tmq.config.test.d.ts.map +1 -0
- package/lib/test/bulkPulling/tmq.config.test.js +77 -0
- package/lib/test/bulkPulling/tmq.test.js +135 -14
- package/lib/test/bulkPulling/wsClient.reconnect.integration.test.d.ts +2 -0
- package/lib/test/bulkPulling/wsClient.reconnect.integration.test.d.ts.map +1 -0
- package/lib/test/bulkPulling/wsClient.reconnect.integration.test.js +184 -0
- package/lib/test/bulkPulling/wsConfig.dsn.test.d.ts +2 -0
- package/lib/test/bulkPulling/wsConfig.dsn.test.d.ts.map +1 -0
- package/lib/test/bulkPulling/wsConfig.dsn.test.js +37 -0
- package/lib/test/bulkPulling/wsConnectPool.test.js +7 -7
- package/lib/test/bulkPulling/wsConnector.failover.test.d.ts +2 -0
- package/lib/test/bulkPulling/wsConnector.failover.test.d.ts.map +1 -0
- package/lib/test/bulkPulling/wsConnector.failover.test.js +128 -0
- package/lib/test/bulkPulling/wsConnectorPool.key.test.d.ts +2 -0
- package/lib/test/bulkPulling/wsConnectorPool.key.test.d.ts.map +1 -0
- package/lib/test/bulkPulling/wsConnectorPool.key.test.js +50 -0
- package/lib/test/bulkPulling/wsEventCallback.test.d.ts +2 -0
- package/lib/test/bulkPulling/wsEventCallback.test.d.ts.map +1 -0
- package/lib/test/bulkPulling/wsEventCallback.test.js +54 -0
- package/lib/test/utils.d.ts +4 -0
- package/lib/test/utils.d.ts.map +1 -1
- package/lib/test/utils.js +11 -17
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tmq.config.test.d.ts","sourceRoot":"","sources":["../../../test/bulkPulling/tmq.config.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const config_1 = require("../../src/tmq/config");
|
|
4
|
+
const constant_1 = require("../../src/tmq/constant");
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
|
+
describe("TmqConfig - td.connect.token", () => {
|
|
7
|
+
const baseUrl = "ws://localhost:6041";
|
|
8
|
+
test("token field is null when CONNECT_TOKEN not provided", () => {
|
|
9
|
+
const configMap = new Map([
|
|
10
|
+
[constant_1.TMQConstants.WS_URL, baseUrl],
|
|
11
|
+
[constant_1.TMQConstants.CONNECT_USER, (0, utils_1.testUsername)()],
|
|
12
|
+
[constant_1.TMQConstants.CONNECT_PASS, (0, utils_1.testPassword)()],
|
|
13
|
+
[constant_1.TMQConstants.GROUP_ID, "g1"],
|
|
14
|
+
]);
|
|
15
|
+
const cfg = new config_1.TmqConfig(configMap);
|
|
16
|
+
expect(cfg.token).toBeNull();
|
|
17
|
+
});
|
|
18
|
+
test("token field is set when CONNECT_TOKEN is provided", () => {
|
|
19
|
+
const configMap = new Map([
|
|
20
|
+
[constant_1.TMQConstants.WS_URL, baseUrl],
|
|
21
|
+
[constant_1.TMQConstants.CONNECT_TOKEN, "mytoken123"],
|
|
22
|
+
[constant_1.TMQConstants.GROUP_ID, "g1"],
|
|
23
|
+
]);
|
|
24
|
+
const cfg = new config_1.TmqConfig(configMap);
|
|
25
|
+
expect(cfg.token).toBe("mytoken123");
|
|
26
|
+
});
|
|
27
|
+
test("bearer_token is appended to url search params when token is provided", () => {
|
|
28
|
+
const configMap = new Map([
|
|
29
|
+
[constant_1.TMQConstants.WS_URL, baseUrl],
|
|
30
|
+
[constant_1.TMQConstants.CONNECT_TOKEN, "mytoken123"],
|
|
31
|
+
[constant_1.TMQConstants.GROUP_ID, "g1"],
|
|
32
|
+
]);
|
|
33
|
+
const cfg = new config_1.TmqConfig(configMap);
|
|
34
|
+
expect(cfg.url?.searchParams.get("bearer_token")).toBe("mytoken123");
|
|
35
|
+
});
|
|
36
|
+
test("bearer_token is appended to sql_url search params when token is provided", () => {
|
|
37
|
+
const configMap = new Map([
|
|
38
|
+
[constant_1.TMQConstants.WS_URL, baseUrl],
|
|
39
|
+
[constant_1.TMQConstants.CONNECT_TOKEN, "mytoken123"],
|
|
40
|
+
[constant_1.TMQConstants.GROUP_ID, "g1"],
|
|
41
|
+
]);
|
|
42
|
+
const cfg = new config_1.TmqConfig(configMap);
|
|
43
|
+
expect(cfg.sql_url?.searchParams.get("bearer_token")).toBe("mytoken123");
|
|
44
|
+
});
|
|
45
|
+
test("sql_url pathname is /ws when token is provided", () => {
|
|
46
|
+
const configMap = new Map([
|
|
47
|
+
[constant_1.TMQConstants.WS_URL, baseUrl],
|
|
48
|
+
[constant_1.TMQConstants.CONNECT_TOKEN, "mytoken123"],
|
|
49
|
+
[constant_1.TMQConstants.GROUP_ID, "g1"],
|
|
50
|
+
]);
|
|
51
|
+
const cfg = new config_1.TmqConfig(configMap);
|
|
52
|
+
expect(cfg.sql_url?.pathname).toBe("/ws");
|
|
53
|
+
});
|
|
54
|
+
test("url pathname is /rest/tmq when token is provided", () => {
|
|
55
|
+
const configMap = new Map([
|
|
56
|
+
[constant_1.TMQConstants.WS_URL, baseUrl],
|
|
57
|
+
[constant_1.TMQConstants.CONNECT_TOKEN, "mytoken123"],
|
|
58
|
+
[constant_1.TMQConstants.GROUP_ID, "g1"],
|
|
59
|
+
]);
|
|
60
|
+
const cfg = new config_1.TmqConfig(configMap);
|
|
61
|
+
expect(cfg.url?.pathname).toBe("/rest/tmq");
|
|
62
|
+
});
|
|
63
|
+
test("bearer_token not set on urls when token is not provided", () => {
|
|
64
|
+
const configMap = new Map([
|
|
65
|
+
[constant_1.TMQConstants.WS_URL, baseUrl],
|
|
66
|
+
[constant_1.TMQConstants.CONNECT_USER, (0, utils_1.testUsername)()],
|
|
67
|
+
[constant_1.TMQConstants.CONNECT_PASS, (0, utils_1.testPassword)()],
|
|
68
|
+
[constant_1.TMQConstants.GROUP_ID, "g1"],
|
|
69
|
+
]);
|
|
70
|
+
const cfg = new config_1.TmqConfig(configMap);
|
|
71
|
+
expect(cfg.url?.searchParams.has("bearer_token")).toBe(false);
|
|
72
|
+
expect(cfg.sql_url?.searchParams.has("bearer_token")).toBe(false);
|
|
73
|
+
});
|
|
74
|
+
test("CONNECT_TOKEN constant value is td.connect.token", () => {
|
|
75
|
+
expect(constant_1.TMQConstants.CONNECT_TOKEN).toBe("td.connect.token");
|
|
76
|
+
});
|
|
77
|
+
});
|
|
@@ -11,13 +11,10 @@ const log_1 = require("../../src/common/log");
|
|
|
11
11
|
const stable = "st";
|
|
12
12
|
const db = "ws_tmq_test";
|
|
13
13
|
const topics = ["topic_ws_bean"];
|
|
14
|
-
|
|
15
|
-
// let createTopic = `create topic if not exists ${topic} as select ts, c1, c2, c3, c4, c5, t1 from ${db}.${stable}`
|
|
16
|
-
// let createTopic2 = `create topic if not exists ${topic2} as select ts, c1, c4, c5, t1 from ${db}.${stable}`
|
|
14
|
+
const tokenTopic = "topic_token_test";
|
|
17
15
|
let createTopic = `create topic if not exists ${topics[0]} as select * from ${db}.${stable}`;
|
|
18
16
|
let dropTopic = `DROP TOPIC IF EXISTS ${topics[0]};`;
|
|
19
|
-
|
|
20
|
-
let dsn = "ws://root:taosdata@localhost:6041";
|
|
17
|
+
let dsn = `ws://${(0, utils_1.testUsername)()}:${(0, utils_1.testPassword)()}@localhost:6041`;
|
|
21
18
|
let tmqDsn = "ws://localhost:6041";
|
|
22
19
|
beforeAll(async () => {
|
|
23
20
|
let conf = new config_1.WSConfig(dsn);
|
|
@@ -235,25 +232,24 @@ beforeAll(async () => {
|
|
|
235
232
|
];
|
|
236
233
|
let ws = await wsSql_1.WsSql.open(conf);
|
|
237
234
|
await ws.exec(dropTopic);
|
|
238
|
-
// await ws.Exec(dropTopic2);
|
|
239
235
|
await ws.exec(dropDB);
|
|
240
236
|
await ws.exec(createDB);
|
|
241
237
|
await ws.exec(useDB);
|
|
242
238
|
await ws.exec((0, utils_1.createSTable)(stable));
|
|
243
239
|
await ws.exec(createTopic);
|
|
244
|
-
// await ws.Exec(createTopic2);
|
|
245
240
|
let insert = (0, utils_1.insertStable)(tableValues, stableTags, stable);
|
|
246
241
|
let insertRes = await ws.exec(insert);
|
|
247
242
|
insert = (0, utils_1.insertStable)(tableCNValues, stableTags, stable);
|
|
248
243
|
insertRes = await ws.exec(insert);
|
|
244
|
+
await ws.exec(`create topic if not exists ${tokenTopic} as select * from ${db}.${stable}`);
|
|
249
245
|
await ws.close();
|
|
250
246
|
});
|
|
251
247
|
describe("TDWebSocket.Tmq()", () => {
|
|
252
248
|
jest.setTimeout(20 * 1000);
|
|
253
249
|
let configMap = new Map([
|
|
254
250
|
[constant_1.TMQConstants.GROUP_ID, "gId"],
|
|
255
|
-
[constant_1.TMQConstants.CONNECT_USER,
|
|
256
|
-
[constant_1.TMQConstants.CONNECT_PASS,
|
|
251
|
+
[constant_1.TMQConstants.CONNECT_USER, (0, utils_1.testUsername)()],
|
|
252
|
+
[constant_1.TMQConstants.CONNECT_PASS, (0, utils_1.testPassword)()],
|
|
257
253
|
[constant_1.TMQConstants.AUTO_OFFSET_RESET, "earliest"],
|
|
258
254
|
[constant_1.TMQConstants.CLIENT_ID, "test_tmq_client"],
|
|
259
255
|
[constant_1.TMQConstants.WS_URL, tmqDsn],
|
|
@@ -290,7 +286,7 @@ describe("TDWebSocket.Tmq()", () => {
|
|
|
290
286
|
}
|
|
291
287
|
catch (e) {
|
|
292
288
|
console.log(e);
|
|
293
|
-
expect(e.code)
|
|
289
|
+
expect([280, 65535]).toContain(e.code);
|
|
294
290
|
}
|
|
295
291
|
finally {
|
|
296
292
|
if (consumer) {
|
|
@@ -320,7 +316,6 @@ describe("TDWebSocket.Tmq()", () => {
|
|
|
320
316
|
console.log("-----===>>", record);
|
|
321
317
|
}
|
|
322
318
|
}
|
|
323
|
-
// await Sleep(100)
|
|
324
319
|
}
|
|
325
320
|
await consumer.seekToBeginning(assignment);
|
|
326
321
|
for (let i = 0; i < 5; i++) {
|
|
@@ -336,7 +331,6 @@ describe("TDWebSocket.Tmq()", () => {
|
|
|
336
331
|
}
|
|
337
332
|
counts += data.length;
|
|
338
333
|
}
|
|
339
|
-
// await Sleep(100)
|
|
340
334
|
}
|
|
341
335
|
let topicArray = await consumer.subscription();
|
|
342
336
|
expect(topics.length).toEqual(topicArray.length);
|
|
@@ -380,12 +374,139 @@ describe("TDWebSocket.Tmq()", () => {
|
|
|
380
374
|
await consumer.unsubscribe();
|
|
381
375
|
await consumer.close();
|
|
382
376
|
});
|
|
377
|
+
(0, utils_1.testEnterprise)("connect with token", async () => {
|
|
378
|
+
const conf = new config_1.WSConfig(dsn);
|
|
379
|
+
const wsSql = await wsSql_1.WsSql.open(conf);
|
|
380
|
+
await wsSql.exec("drop token if exists test_tmq_token");
|
|
381
|
+
const wsRows = await wsSql.query(`create token test_tmq_token from user ${(0, utils_1.testUsername)()}`);
|
|
382
|
+
await wsRows.next();
|
|
383
|
+
const token = wsRows.getData()?.[0];
|
|
384
|
+
expect(token).toBeTruthy();
|
|
385
|
+
await wsRows.close();
|
|
386
|
+
const tmqConf = new Map([
|
|
387
|
+
[constant_1.TMQConstants.WS_URL, "ws://localhost:6041"],
|
|
388
|
+
[constant_1.TMQConstants.CONNECT_USER, "invalid_user"],
|
|
389
|
+
[constant_1.TMQConstants.CONNECT_PASS, "invalid_pass"],
|
|
390
|
+
[constant_1.TMQConstants.CONNECT_TOKEN, token],
|
|
391
|
+
[constant_1.TMQConstants.GROUP_ID, "g1101"],
|
|
392
|
+
[constant_1.TMQConstants.CLIENT_ID, "c1101"],
|
|
393
|
+
[constant_1.TMQConstants.AUTO_OFFSET_RESET, "earliest"],
|
|
394
|
+
[constant_1.TMQConstants.ENABLE_AUTO_COMMIT, "false"],
|
|
395
|
+
[constant_1.TMQConstants.AUTO_COMMIT_INTERVAL_MS, "1000"],
|
|
396
|
+
]);
|
|
397
|
+
const consumer = await wsTmq_1.WsConsumer.newConsumer(tmqConf);
|
|
398
|
+
await consumer.subscribe([tokenTopic]);
|
|
399
|
+
let count = 0;
|
|
400
|
+
for (let i = 0; i < 5; i++) {
|
|
401
|
+
const res = await consumer.poll(500);
|
|
402
|
+
for (const [, value] of res) {
|
|
403
|
+
const data = value.getData();
|
|
404
|
+
if (data == null || data.length == 0) {
|
|
405
|
+
break;
|
|
406
|
+
}
|
|
407
|
+
count += data.length;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
expect(count).toEqual(10);
|
|
411
|
+
await (0, utils_1.Sleep)(3000);
|
|
412
|
+
await consumer.unsubscribe();
|
|
413
|
+
await consumer.close();
|
|
414
|
+
await wsSql.exec("drop token if exists test_tmq_token");
|
|
415
|
+
await wsSql.close();
|
|
416
|
+
});
|
|
417
|
+
(0, utils_1.testEnterprise)("connect with token url", async () => {
|
|
418
|
+
const conf = new config_1.WSConfig(dsn);
|
|
419
|
+
const wsSql = await wsSql_1.WsSql.open(conf);
|
|
420
|
+
await wsSql.exec("drop token if exists test_tmq_token_url");
|
|
421
|
+
const wsRows = await wsSql.query(`create token test_tmq_token_url from user ${(0, utils_1.testUsername)()}`);
|
|
422
|
+
await wsRows.next();
|
|
423
|
+
const token = wsRows.getData()?.[0];
|
|
424
|
+
expect(token).toBeTruthy();
|
|
425
|
+
await wsRows.close();
|
|
426
|
+
const tmqConf = new Map([
|
|
427
|
+
[constant_1.TMQConstants.WS_URL, `ws://localhost:6041?bearer_token=${token}`],
|
|
428
|
+
[constant_1.TMQConstants.CONNECT_USER, "invalid_user"],
|
|
429
|
+
[constant_1.TMQConstants.CONNECT_PASS, "invalid_pass"],
|
|
430
|
+
[constant_1.TMQConstants.GROUP_ID, "g1103"],
|
|
431
|
+
[constant_1.TMQConstants.CLIENT_ID, "c1103"],
|
|
432
|
+
[constant_1.TMQConstants.AUTO_OFFSET_RESET, "earliest"],
|
|
433
|
+
[constant_1.TMQConstants.ENABLE_AUTO_COMMIT, false],
|
|
434
|
+
[constant_1.TMQConstants.AUTO_COMMIT_INTERVAL_MS, 1000],
|
|
435
|
+
]);
|
|
436
|
+
const consumer = await wsTmq_1.WsConsumer.newConsumer(tmqConf);
|
|
437
|
+
await consumer.subscribe([tokenTopic]);
|
|
438
|
+
let count = 0;
|
|
439
|
+
for (let i = 0; i < 5; i++) {
|
|
440
|
+
const res = await consumer.poll(500);
|
|
441
|
+
for (const [, value] of res) {
|
|
442
|
+
const data = value.getData();
|
|
443
|
+
if (data == null || data.length == 0) {
|
|
444
|
+
break;
|
|
445
|
+
}
|
|
446
|
+
count += data.length;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
expect(count).toEqual(10);
|
|
450
|
+
await (0, utils_1.Sleep)(3000);
|
|
451
|
+
await consumer.unsubscribe();
|
|
452
|
+
await consumer.close();
|
|
453
|
+
await wsSql.exec("drop token if exists test_tmq_token_url");
|
|
454
|
+
await wsSql.close();
|
|
455
|
+
});
|
|
456
|
+
(0, utils_1.testEnterprise)("connect with invalid token", async () => {
|
|
457
|
+
const conf = new Map([
|
|
458
|
+
[constant_1.TMQConstants.GROUP_ID, "g1102"],
|
|
459
|
+
[constant_1.TMQConstants.CLIENT_ID, "c1102"],
|
|
460
|
+
[constant_1.TMQConstants.WS_URL, "ws://localhost:6041?bearer_token=invalid_token"],
|
|
461
|
+
]);
|
|
462
|
+
await expect(wsTmq_1.WsConsumer.newConsumer(conf)).rejects.toMatchObject({
|
|
463
|
+
message: expect.stringMatching(/invalid token/i),
|
|
464
|
+
});
|
|
465
|
+
conf.set(constant_1.TMQConstants.WS_URL, "ws://localhost:6041");
|
|
466
|
+
conf.set(constant_1.TMQConstants.CONNECT_TOKEN, "invalid_token1");
|
|
467
|
+
await expect(wsTmq_1.WsConsumer.newConsumer(conf)).rejects.toMatchObject({
|
|
468
|
+
message: expect.stringMatching(/invalid token/i),
|
|
469
|
+
});
|
|
470
|
+
conf.set(constant_1.TMQConstants.WS_URL, "ws://localhost:6041?bearer_token=");
|
|
471
|
+
conf.delete(constant_1.TMQConstants.CONNECT_TOKEN);
|
|
472
|
+
await expect(wsTmq_1.WsConsumer.newConsumer(conf)).rejects.toMatchObject({
|
|
473
|
+
message: expect.stringMatching(/invalid url/i),
|
|
474
|
+
});
|
|
475
|
+
conf.set(constant_1.TMQConstants.WS_URL, "ws://localhost:6041");
|
|
476
|
+
conf.set(constant_1.TMQConstants.CONNECT_TOKEN, "");
|
|
477
|
+
await expect(wsTmq_1.WsConsumer.newConsumer(conf)).rejects.toMatchObject({
|
|
478
|
+
message: expect.stringMatching(/invalid url/i),
|
|
479
|
+
});
|
|
480
|
+
});
|
|
481
|
+
(0, utils_1.testNon3360)("connector version info", async () => {
|
|
482
|
+
const consumer = await wsTmq_1.WsConsumer.newConsumer(configMap);
|
|
483
|
+
await consumer.subscribe(topics);
|
|
484
|
+
const conf = new config_1.WSConfig("ws://localhost:6041");
|
|
485
|
+
conf.setUser((0, utils_1.testUsername)());
|
|
486
|
+
conf.setPwd((0, utils_1.testPassword)());
|
|
487
|
+
const wsSql = await wsSql_1.WsSql.open(conf);
|
|
488
|
+
await (0, utils_1.Sleep)(2000);
|
|
489
|
+
const wsRows = await wsSql.query("show connections");
|
|
490
|
+
let count = 0;
|
|
491
|
+
while (await wsRows.next()) {
|
|
492
|
+
const data = wsRows.getData();
|
|
493
|
+
if (Array.isArray(data) && data.some(v => typeof v === "string" && v.includes("nodejs-ws"))) {
|
|
494
|
+
count++;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
expect(count).toBeGreaterThanOrEqual(2);
|
|
498
|
+
await wsRows.close();
|
|
499
|
+
await wsSql.close();
|
|
500
|
+
await consumer.unsubscribe();
|
|
501
|
+
await consumer.close();
|
|
502
|
+
});
|
|
383
503
|
});
|
|
384
504
|
afterAll(async () => {
|
|
385
505
|
const dropDB = `drop database if exists ${db}`;
|
|
386
|
-
|
|
387
|
-
|
|
506
|
+
const conf = new config_1.WSConfig(dsn);
|
|
507
|
+
const ws = await wsSql_1.WsSql.open(conf);
|
|
388
508
|
await ws.exec(dropTopic);
|
|
509
|
+
await ws.exec(`drop topic if exists ${tokenTopic}`);
|
|
389
510
|
await ws.exec(dropDB);
|
|
390
511
|
await ws.close();
|
|
391
512
|
wsConnectorPool_1.WebSocketConnectionPool.instance().destroyed();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wsClient.reconnect.integration.test.d.ts","sourceRoot":"","sources":["../../../test/bulkPulling/wsClient.reconnect.integration.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
function createMockWebsocketState() {
|
|
4
|
+
let behaviors = [];
|
|
5
|
+
let sendLog = [];
|
|
6
|
+
let socketCounter = 0;
|
|
7
|
+
class FakeWebSocket {
|
|
8
|
+
constructor(url) {
|
|
9
|
+
this.readyState = FakeWebSocket.CONNECTING;
|
|
10
|
+
this.url = url;
|
|
11
|
+
this.id = ++socketCounter;
|
|
12
|
+
this.behavior = behaviors.shift() || {};
|
|
13
|
+
setTimeout(() => {
|
|
14
|
+
if (this.behavior.openFails) {
|
|
15
|
+
this.readyState = FakeWebSocket.CLOSED;
|
|
16
|
+
this.onerror?.(new Error("open failed"));
|
|
17
|
+
this.onclose?.({ code: 1006, reason: "open failed" });
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
this.readyState = FakeWebSocket.OPEN;
|
|
21
|
+
this.onopen?.();
|
|
22
|
+
}, 0);
|
|
23
|
+
}
|
|
24
|
+
send(data) {
|
|
25
|
+
if (typeof data !== "string") {
|
|
26
|
+
throw new Error("binary is not supported in this fake");
|
|
27
|
+
}
|
|
28
|
+
const parsed = JSON.parse(data);
|
|
29
|
+
const action = parsed.action || "";
|
|
30
|
+
sendLog.push({ socketId: this.id, action, raw: data });
|
|
31
|
+
if (this.behavior.disconnectOnActions?.includes(action)) {
|
|
32
|
+
this.readyState = FakeWebSocket.CLOSED;
|
|
33
|
+
if (this.behavior.emitErrorBeforeClose) {
|
|
34
|
+
this.onerror?.(new Error("simulated disconnection"));
|
|
35
|
+
}
|
|
36
|
+
this.onclose?.({
|
|
37
|
+
code: 1006,
|
|
38
|
+
reason: "simulated disconnection",
|
|
39
|
+
});
|
|
40
|
+
throw new Error("simulated disconnection");
|
|
41
|
+
}
|
|
42
|
+
setTimeout(() => {
|
|
43
|
+
const reqId = parsed?.args?.req_id;
|
|
44
|
+
this.onmessage?.({
|
|
45
|
+
data: JSON.stringify({
|
|
46
|
+
action,
|
|
47
|
+
req_id: reqId,
|
|
48
|
+
code: 0,
|
|
49
|
+
message: "ok",
|
|
50
|
+
}),
|
|
51
|
+
});
|
|
52
|
+
}, 0);
|
|
53
|
+
}
|
|
54
|
+
close() {
|
|
55
|
+
this.readyState = FakeWebSocket.CLOSED;
|
|
56
|
+
this.onclose?.({ code: 1000, reason: "normal close" });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
FakeWebSocket.CONNECTING = 0;
|
|
60
|
+
FakeWebSocket.OPEN = 1;
|
|
61
|
+
FakeWebSocket.CLOSING = 2;
|
|
62
|
+
FakeWebSocket.CLOSED = 3;
|
|
63
|
+
return {
|
|
64
|
+
FakeWebSocket,
|
|
65
|
+
reset() {
|
|
66
|
+
behaviors = [];
|
|
67
|
+
sendLog = [];
|
|
68
|
+
socketCounter = 0;
|
|
69
|
+
},
|
|
70
|
+
setBehaviors(nextBehaviors) {
|
|
71
|
+
behaviors = [...nextBehaviors];
|
|
72
|
+
},
|
|
73
|
+
getSendLog() {
|
|
74
|
+
return [...sendLog];
|
|
75
|
+
},
|
|
76
|
+
getSocketCount() {
|
|
77
|
+
return socketCounter;
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
var mockWebsocketState;
|
|
82
|
+
jest.mock("websocket", () => ({
|
|
83
|
+
w3cwebsocket: (() => {
|
|
84
|
+
mockWebsocketState = createMockWebsocketState();
|
|
85
|
+
return mockWebsocketState.FakeWebSocket;
|
|
86
|
+
})(),
|
|
87
|
+
}));
|
|
88
|
+
const dsn_1 = require("../../src/common/dsn");
|
|
89
|
+
const wsClient_1 = require("../../src/client/wsClient");
|
|
90
|
+
const wsConnectorPool_1 = require("../../src/client/wsConnectorPool");
|
|
91
|
+
const constant_1 = require("../../src/common/constant");
|
|
92
|
+
const wsEventCallback_1 = require("../../src/client/wsEventCallback");
|
|
93
|
+
function resetPoolSingleton() {
|
|
94
|
+
const PoolClass = wsConnectorPool_1.WebSocketConnectionPool;
|
|
95
|
+
if (PoolClass._instance) {
|
|
96
|
+
PoolClass._instance.destroyed();
|
|
97
|
+
PoolClass._instance = undefined;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
function resetEventCallbacks() {
|
|
101
|
+
wsEventCallback_1.WsEventCallback._msgActionRegister = new Map();
|
|
102
|
+
}
|
|
103
|
+
describe("WsClient reconnect integration", () => {
|
|
104
|
+
beforeEach(() => {
|
|
105
|
+
mockWebsocketState.reset();
|
|
106
|
+
resetPoolSingleton();
|
|
107
|
+
resetEventCallbacks();
|
|
108
|
+
jest.spyOn(Math, "random").mockReturnValue(0);
|
|
109
|
+
});
|
|
110
|
+
afterEach(async () => {
|
|
111
|
+
jest.restoreAllMocks();
|
|
112
|
+
mockWebsocketState.reset();
|
|
113
|
+
resetEventCallbacks();
|
|
114
|
+
resetPoolSingleton();
|
|
115
|
+
});
|
|
116
|
+
test("recovers conn/options context before replaying inflight insert", async () => {
|
|
117
|
+
mockWebsocketState.setBehaviors([
|
|
118
|
+
{ disconnectOnActions: ["insert"] },
|
|
119
|
+
{},
|
|
120
|
+
]);
|
|
121
|
+
const dsn = (0, dsn_1.parse)("ws://root:taosdata@host1:6041,host2:6042/mydb?timezone=UTC&retries=0&retry_backoff_ms=1");
|
|
122
|
+
const client = new wsClient_1.WsClient(dsn, 1000);
|
|
123
|
+
await client.connect("mydb");
|
|
124
|
+
await client.setOptionConnection(constant_1.TSDB_OPTION_CONNECTION.TSDB_OPTION_CONNECTION_TIMEZONE, "UTC");
|
|
125
|
+
const pending = client.exec(JSON.stringify({
|
|
126
|
+
action: "insert",
|
|
127
|
+
args: {
|
|
128
|
+
req_id: 999001,
|
|
129
|
+
data: "insert into t values(now, 1)",
|
|
130
|
+
},
|
|
131
|
+
}), false);
|
|
132
|
+
await expect(pending).resolves.toBeDefined();
|
|
133
|
+
const secondSocketActions = mockWebsocketState
|
|
134
|
+
.getSendLog()
|
|
135
|
+
.filter((entry) => entry.socketId === 2)
|
|
136
|
+
.map((entry) => entry.action);
|
|
137
|
+
expect(secondSocketActions[0]).toBe("conn");
|
|
138
|
+
expect(secondSocketActions[1]).toBe("options_connection");
|
|
139
|
+
expect(secondSocketActions[2]).toBe("insert");
|
|
140
|
+
expect(mockWebsocketState.getSocketCount()).toBe(2);
|
|
141
|
+
await client.close();
|
|
142
|
+
});
|
|
143
|
+
test("deduplicates reconnect when both onerror and onclose are raised", async () => {
|
|
144
|
+
mockWebsocketState.setBehaviors([
|
|
145
|
+
{
|
|
146
|
+
disconnectOnActions: ["insert"],
|
|
147
|
+
emitErrorBeforeClose: true,
|
|
148
|
+
},
|
|
149
|
+
{},
|
|
150
|
+
]);
|
|
151
|
+
const dsn = (0, dsn_1.parse)("ws://root:taosdata@host1:6041,host2:6042/mydb?retries=0&retry_backoff_ms=1");
|
|
152
|
+
const client = new wsClient_1.WsClient(dsn, 1000);
|
|
153
|
+
await client.connect("mydb");
|
|
154
|
+
const pending = client.exec(JSON.stringify({
|
|
155
|
+
action: "insert",
|
|
156
|
+
args: {
|
|
157
|
+
req_id: 999002,
|
|
158
|
+
data: "insert into t values(now, 2)",
|
|
159
|
+
},
|
|
160
|
+
}), false);
|
|
161
|
+
await expect(pending).resolves.toBeDefined();
|
|
162
|
+
expect(mockWebsocketState.getSocketCount()).toBe(2);
|
|
163
|
+
await client.close();
|
|
164
|
+
});
|
|
165
|
+
test("rejects retriable inflight request when all reconnect attempts fail", async () => {
|
|
166
|
+
mockWebsocketState.setBehaviors([
|
|
167
|
+
{ disconnectOnActions: ["insert"] },
|
|
168
|
+
{ openFails: true },
|
|
169
|
+
{ openFails: true },
|
|
170
|
+
]);
|
|
171
|
+
const dsn = (0, dsn_1.parse)("ws://root:taosdata@host1:6041,host2:6042/mydb?retries=0&retry_backoff_ms=1");
|
|
172
|
+
const client = new wsClient_1.WsClient(dsn, 200);
|
|
173
|
+
await client.connect("mydb");
|
|
174
|
+
const pending = client.exec(JSON.stringify({
|
|
175
|
+
action: "insert",
|
|
176
|
+
args: {
|
|
177
|
+
req_id: 999003,
|
|
178
|
+
data: "insert into t values(now, 3)",
|
|
179
|
+
},
|
|
180
|
+
}), false);
|
|
181
|
+
await expect(pending).rejects.toThrow("Failed to reconnect to any available address");
|
|
182
|
+
await client.close();
|
|
183
|
+
});
|
|
184
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wsConfig.dsn.test.d.ts","sourceRoot":"","sources":["../../../test/bulkPulling/wsConfig.dsn.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const config_1 = require("../../src/common/config");
|
|
4
|
+
const utils_1 = require("../../src/common/utils");
|
|
5
|
+
describe("WSConfig to Dsn conversion", () => {
|
|
6
|
+
test("parses multi-address dsn and keeps connector-level params", () => {
|
|
7
|
+
const conf = new config_1.WSConfig("ws://root:taosdata@host1:6041,host2:6042/mydb?retries=5&retry_backoff_ms=120&timezone=UTC");
|
|
8
|
+
const dsn = (0, utils_1.getDsn)(conf);
|
|
9
|
+
expect(dsn.scheme).toBe("ws");
|
|
10
|
+
expect(dsn.addresses).toEqual([
|
|
11
|
+
{ host: "host1", port: 6041 },
|
|
12
|
+
{ host: "host2", port: 6042 },
|
|
13
|
+
]);
|
|
14
|
+
expect(dsn.database).toBe("mydb");
|
|
15
|
+
expect(dsn.params.get("retries")).toBe("5");
|
|
16
|
+
expect(dsn.params.get("retry_backoff_ms")).toBe("120");
|
|
17
|
+
expect(dsn.params.get("timezone")).toBe("UTC");
|
|
18
|
+
expect(conf.getDb()).toBe("mydb");
|
|
19
|
+
expect(conf.getTimezone()).toBe("UTC");
|
|
20
|
+
});
|
|
21
|
+
test("applies WSConfig overrides on top of dsn", () => {
|
|
22
|
+
const conf = new config_1.WSConfig("ws://root:taosdata@host1:6041/mydb");
|
|
23
|
+
conf.setUser("admin");
|
|
24
|
+
conf.setPwd("secret");
|
|
25
|
+
conf.setToken("token-1");
|
|
26
|
+
conf.setBearerToken("bearer-1");
|
|
27
|
+
conf.setTimezone("Asia/Shanghai");
|
|
28
|
+
conf.setDb("override_db");
|
|
29
|
+
const dsn = (0, utils_1.getDsn)(conf);
|
|
30
|
+
expect(dsn.username).toBe("admin");
|
|
31
|
+
expect(dsn.password).toBe("secret");
|
|
32
|
+
expect(dsn.database).toBe("override_db");
|
|
33
|
+
expect(dsn.params.get("token")).toBe("token-1");
|
|
34
|
+
expect(dsn.params.get("bearer_token")).toBe("bearer-1");
|
|
35
|
+
expect(dsn.params.get("timezone")).toBe("Asia/Shanghai");
|
|
36
|
+
});
|
|
37
|
+
});
|
|
@@ -8,7 +8,7 @@ const constant_1 = require("../../src/tmq/constant");
|
|
|
8
8
|
const wsTmq_1 = require("../../src/tmq/wsTmq");
|
|
9
9
|
const utils_1 = require("../utils");
|
|
10
10
|
const log_1 = require("../../src/common/log");
|
|
11
|
-
let dsn =
|
|
11
|
+
let dsn = `ws://${(0, utils_1.testUsername)()}:${(0, utils_1.testPassword)()}@localhost:6041`;
|
|
12
12
|
let tags = ["California.SanFrancisco", 3];
|
|
13
13
|
let multi = [
|
|
14
14
|
[1709183268567, 1709183268568, 1709183268569],
|
|
@@ -18,8 +18,8 @@ let multi = [
|
|
|
18
18
|
];
|
|
19
19
|
let configMap = new Map([
|
|
20
20
|
[constant_1.TMQConstants.GROUP_ID, "gId"],
|
|
21
|
-
[constant_1.TMQConstants.CONNECT_USER,
|
|
22
|
-
[constant_1.TMQConstants.CONNECT_PASS,
|
|
21
|
+
[constant_1.TMQConstants.CONNECT_USER, (0, utils_1.testUsername)()],
|
|
22
|
+
[constant_1.TMQConstants.CONNECT_PASS, (0, utils_1.testPassword)()],
|
|
23
23
|
[constant_1.TMQConstants.AUTO_OFFSET_RESET, "earliest"],
|
|
24
24
|
[constant_1.TMQConstants.CLIENT_ID, "test_tmq_client"],
|
|
25
25
|
[constant_1.TMQConstants.WS_URL, "ws://localhost:6041"],
|
|
@@ -33,7 +33,7 @@ let createTopic = `create topic if not exists ${topics[0]} as select * from ${db
|
|
|
33
33
|
let stmtIds = [];
|
|
34
34
|
(0, log_1.setLevel)("debug");
|
|
35
35
|
async function connect() {
|
|
36
|
-
let dsn =
|
|
36
|
+
let dsn = `ws://${(0, utils_1.testUsername)()}:${(0, utils_1.testPassword)()}@localhost:6041`;
|
|
37
37
|
let wsSql = null;
|
|
38
38
|
let conf = new config_1.WSConfig(dsn);
|
|
39
39
|
conf.setDb(db);
|
|
@@ -43,7 +43,7 @@ async function connect() {
|
|
|
43
43
|
await wsSql.close();
|
|
44
44
|
}
|
|
45
45
|
async function stmtConnect() {
|
|
46
|
-
let dsn =
|
|
46
|
+
let dsn = `ws://${(0, utils_1.testUsername)()}:${(0, utils_1.testPassword)()}@localhost:6041`;
|
|
47
47
|
let wsConf = new config_1.WSConfig(dsn, "100.100.100.100");
|
|
48
48
|
wsConf.setDb(db);
|
|
49
49
|
// let connector = WsStmtConnect.NewConnector(wsConf)
|
|
@@ -139,8 +139,8 @@ describe("TDWebSocket.WsSql()", () => {
|
|
|
139
139
|
});
|
|
140
140
|
afterAll(async () => {
|
|
141
141
|
let conf = new config_1.WSConfig(dsn);
|
|
142
|
-
conf.setUser(
|
|
143
|
-
conf.setPwd(
|
|
142
|
+
conf.setUser((0, utils_1.testUsername)());
|
|
143
|
+
conf.setPwd((0, utils_1.testPassword)());
|
|
144
144
|
let wsSql = await wsSql_1.WsSql.open(conf);
|
|
145
145
|
await wsSql.exec(`drop topic if exists ${topics[0]};`);
|
|
146
146
|
await wsSql.exec(`drop database if exists ${db};`);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wsConnector.failover.test.d.ts","sourceRoot":"","sources":["../../../test/bulkPulling/wsConnector.failover.test.ts"],"names":[],"mappings":""}
|