biz-a-cli 2.3.71 → 2.3.73
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/.editorconfig +16 -0
- package/bin/app.js +638 -475
- package/bin/directHubEvent.js +93 -79
- package/bin/hub.js +185 -134
- package/bin/hubEvent.js +426 -335
- package/log/debug.log +0 -180
- package/log/error.log +0 -5
- package/log/info.log +0 -5
- package/package.json +72 -70
- package/scheduler/datalib.js +1 -1
- package/tests/app.test.js +1096 -708
- package/tests/hub.test.js +389 -48
- package/tests/hubPublish.test.js +218 -207
- package/worker/cliScriptWorker.js +30 -0
- package/worker/cliWorkerPool.js +18 -0
- package/bin/log/debug.log +0 -12
- package/bin/log/error.log +0 -12
- package/bin/log/exception.log +0 -6
- package/bin/log/info.log +0 -12
package/tests/hub.test.js
CHANGED
|
@@ -11,6 +11,9 @@ import { Writable, pipeline } from "node:stream";
|
|
|
11
11
|
import { text } from "node:stream/consumers";
|
|
12
12
|
import { directHubEvent, createSocketServer } from "../bin/directHubEvent.js";
|
|
13
13
|
import os from "node:os";
|
|
14
|
+
import { cliScriptWorkerPool } from "../worker/cliWorkerPool.js";
|
|
15
|
+
import workerpool from "workerpool";
|
|
16
|
+
import { isAsyncFunction } from "node:util/types";
|
|
14
17
|
|
|
15
18
|
let socketsBySubdomain = {};
|
|
16
19
|
|
|
@@ -82,7 +85,9 @@ describe("Hub event tests", () => {
|
|
|
82
85
|
|
|
83
86
|
test("request to cli", async () => {
|
|
84
87
|
const logSpy = jest.spyOn(console, "log").mockImplementation();
|
|
85
|
-
let mockedRequest = jest
|
|
88
|
+
let mockedRequest = jest
|
|
89
|
+
.spyOn(axios, "request")
|
|
90
|
+
.mockReturnValue({ data: "OK" });
|
|
86
91
|
|
|
87
92
|
let socket;
|
|
88
93
|
try {
|
|
@@ -103,8 +108,8 @@ describe("Hub event tests", () => {
|
|
|
103
108
|
query: { subdomain: "abc" },
|
|
104
109
|
body: { data: "xyz" },
|
|
105
110
|
},
|
|
106
|
-
(cb) => resolve(cb)
|
|
107
|
-
)
|
|
111
|
+
(cb) => resolve(cb),
|
|
112
|
+
),
|
|
108
113
|
);
|
|
109
114
|
|
|
110
115
|
expect(result).toStrictEqual("OK");
|
|
@@ -123,8 +128,8 @@ describe("Hub event tests", () => {
|
|
|
123
128
|
query: { subdomain: "abc" },
|
|
124
129
|
body: { data: "xyz" },
|
|
125
130
|
},
|
|
126
|
-
(cb) => resolve(cb)
|
|
127
|
-
)
|
|
131
|
+
(cb) => resolve(cb),
|
|
132
|
+
),
|
|
128
133
|
);
|
|
129
134
|
|
|
130
135
|
expect(result).toStrictEqual("OK");
|
|
@@ -166,7 +171,13 @@ describe("Hub event tests", () => {
|
|
|
166
171
|
port: 212,
|
|
167
172
|
serverport: 3002,
|
|
168
173
|
cliAddress: () => {
|
|
169
|
-
return {
|
|
174
|
+
return {
|
|
175
|
+
ip: "59.60.1.22",
|
|
176
|
+
port: "3002",
|
|
177
|
+
address: `59.60.1.22:3002`,
|
|
178
|
+
publicUrl: "https://some.tunnel.url",
|
|
179
|
+
hubUrl: "https://some.hub.url",
|
|
180
|
+
};
|
|
170
181
|
},
|
|
171
182
|
hubServer: "https://some.hub.url",
|
|
172
183
|
});
|
|
@@ -174,10 +185,19 @@ describe("Hub event tests", () => {
|
|
|
174
185
|
mockAPIServer = net.createServer((clientSocket) => {
|
|
175
186
|
cliToAPISocket = clientSocket;
|
|
176
187
|
clientSocket.on("data", (data) => {
|
|
177
|
-
if (
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
188
|
+
if (
|
|
189
|
+
data.toString().toUpperCase() ===
|
|
190
|
+
"POST /SUCCESS HTTP/1.1"
|
|
191
|
+
) {
|
|
192
|
+
clientSocket.write(
|
|
193
|
+
"HTTP/1.1 200 Ok\r\nServer: datasnapHTTPService\r\n\r\n",
|
|
194
|
+
);
|
|
195
|
+
} else if (
|
|
196
|
+
data.toString().toUpperCase() === "POST /FAIL HTTP/1.1"
|
|
197
|
+
) {
|
|
198
|
+
clientSocket.write(
|
|
199
|
+
"HTTP/1.1 403 Forbidden\r\nServer: datasnapHTTPService\r\n\r\n",
|
|
200
|
+
);
|
|
181
201
|
}
|
|
182
202
|
});
|
|
183
203
|
});
|
|
@@ -200,13 +220,19 @@ describe("Hub event tests", () => {
|
|
|
200
220
|
},
|
|
201
221
|
});
|
|
202
222
|
tunnelStream = await toPromise((resolve) => {
|
|
203
|
-
ss(socketsBySubdomain[subdomain]).once(
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
223
|
+
ss(socketsBySubdomain[subdomain]).once(
|
|
224
|
+
uniqueId,
|
|
225
|
+
(stream) => {
|
|
226
|
+
pipeline(stream, outputStream, (err) => {
|
|
227
|
+
if (err) console.error(err);
|
|
228
|
+
});
|
|
229
|
+
resolve(stream);
|
|
230
|
+
},
|
|
231
|
+
);
|
|
232
|
+
socketsBySubdomain[subdomain].emit(
|
|
233
|
+
"incomingClient",
|
|
234
|
+
uniqueId,
|
|
235
|
+
);
|
|
210
236
|
});
|
|
211
237
|
|
|
212
238
|
tunnelStream.write(httpRawRequest);
|
|
@@ -224,10 +250,13 @@ describe("Hub event tests", () => {
|
|
|
224
250
|
"Server: datasnapHTTPService\r\n" +
|
|
225
251
|
"Access-Control-Expose-Headers: biza-cli-address, biza-hub-address\r\n" +
|
|
226
252
|
"biza-cli-address: https://some.tunnel.url\r\n" +
|
|
227
|
-
"biza-hub-address: https://some.hub.url\r\n\r\n"
|
|
253
|
+
"biza-hub-address: https://some.hub.url\r\n\r\n",
|
|
228
254
|
);
|
|
229
255
|
|
|
230
|
-
expect(await getResponse("POST /fail HTTP/1.1")).toBe(
|
|
256
|
+
expect(await getResponse("POST /fail HTTP/1.1")).toBe(
|
|
257
|
+
"HTTP/1.1 403 Forbidden\r\n" +
|
|
258
|
+
"Server: datasnapHTTPService\r\n\r\n",
|
|
259
|
+
);
|
|
231
260
|
} finally {
|
|
232
261
|
freeSocketClient(cliToBizAServerSocket);
|
|
233
262
|
if (mockAPIServer) mockAPIServer.close();
|
|
@@ -255,16 +284,26 @@ describe("Hub event tests", () => {
|
|
|
255
284
|
secure: false,
|
|
256
285
|
dbindex: 2,
|
|
257
286
|
cliAddress: () => {
|
|
258
|
-
return {
|
|
287
|
+
return {
|
|
288
|
+
ip: "59.60.1.22",
|
|
289
|
+
port: "3002",
|
|
290
|
+
address: `59.60.1.22:3002`,
|
|
291
|
+
publicUrl: "https://some.tunnel.url",
|
|
292
|
+
hubUrl: "https://some.hub.url",
|
|
293
|
+
};
|
|
259
294
|
},
|
|
260
295
|
});
|
|
261
|
-
clientToCliSocket = ioClient("http://localhost:9999", {
|
|
296
|
+
clientToCliSocket = ioClient("http://localhost:9999", {
|
|
297
|
+
query: { isClient: true },
|
|
298
|
+
});
|
|
262
299
|
});
|
|
263
300
|
|
|
264
301
|
afterAll(async () => {
|
|
265
302
|
freeSocketClient(clientToCliSocket);
|
|
266
303
|
if (cliSocketServer) {
|
|
267
|
-
await cliSocketServer
|
|
304
|
+
await cliSocketServer
|
|
305
|
+
.of("")
|
|
306
|
+
.sockets.forEach((sock) => sock.removeAllListeners());
|
|
268
307
|
await cliSocketServer.close();
|
|
269
308
|
}
|
|
270
309
|
});
|
|
@@ -282,17 +321,28 @@ describe("Hub event tests", () => {
|
|
|
282
321
|
const [error, response] = await toPromise((resolve) => {
|
|
283
322
|
clientToCliSocket.emit(
|
|
284
323
|
"apiRequest",
|
|
285
|
-
{
|
|
324
|
+
{
|
|
325
|
+
subDomain: subdomain,
|
|
326
|
+
method: "POST",
|
|
327
|
+
path: "/test",
|
|
328
|
+
headers: { "req-header": "aa" },
|
|
329
|
+
body: "body of request",
|
|
330
|
+
responseType: "json",
|
|
331
|
+
},
|
|
286
332
|
(err, res) => {
|
|
287
333
|
resolve([err, res]);
|
|
288
|
-
}
|
|
334
|
+
},
|
|
289
335
|
);
|
|
290
336
|
});
|
|
291
337
|
|
|
292
338
|
expect(response).toStrictEqual({
|
|
293
339
|
status: 200,
|
|
294
340
|
statusText: "Success",
|
|
295
|
-
headers: {
|
|
341
|
+
headers: {
|
|
342
|
+
"res-header": "aa",
|
|
343
|
+
"biza-cli-address": "https://some.tunnel.url",
|
|
344
|
+
"biza-hub-address": "https://some.hub.url",
|
|
345
|
+
},
|
|
296
346
|
body: "body of response",
|
|
297
347
|
url: `http://${apiAddress}:${port}/test`,
|
|
298
348
|
});
|
|
@@ -337,7 +387,7 @@ describe("Hub event tests", () => {
|
|
|
337
387
|
},
|
|
338
388
|
(err, res) => {
|
|
339
389
|
resolve([err, res]);
|
|
340
|
-
}
|
|
390
|
+
},
|
|
341
391
|
);
|
|
342
392
|
});
|
|
343
393
|
|
|
@@ -362,10 +412,16 @@ describe("Hub event tests", () => {
|
|
|
362
412
|
const [error, response] = await toPromise((resolve) => {
|
|
363
413
|
clientToCliSocket.emit(
|
|
364
414
|
"apiRequest",
|
|
365
|
-
{
|
|
415
|
+
{
|
|
416
|
+
subDomain: "wrong subdomain",
|
|
417
|
+
method: "POST",
|
|
418
|
+
path: "/test",
|
|
419
|
+
headers: { "req-header": "aa" },
|
|
420
|
+
body: "body of request",
|
|
421
|
+
},
|
|
366
422
|
(err, res) => {
|
|
367
423
|
resolve([err, res]);
|
|
368
|
-
}
|
|
424
|
+
},
|
|
369
425
|
);
|
|
370
426
|
});
|
|
371
427
|
|
|
@@ -385,15 +441,24 @@ describe("Hub event tests", () => {
|
|
|
385
441
|
test("status", async () => {
|
|
386
442
|
const runCommand = async (command) => {
|
|
387
443
|
return await toPromise((resolve) => {
|
|
388
|
-
clientToCliSocket.emit(
|
|
389
|
-
|
|
390
|
-
|
|
444
|
+
clientToCliSocket.emit(
|
|
445
|
+
"cliCommand",
|
|
446
|
+
{ command },
|
|
447
|
+
(err, res) => {
|
|
448
|
+
resolve([err, res]);
|
|
449
|
+
},
|
|
450
|
+
);
|
|
391
451
|
});
|
|
392
452
|
};
|
|
393
453
|
|
|
394
454
|
let [error, response] = await runCommand("StAtus ");
|
|
395
455
|
const cpuArchitecture = os.arch();
|
|
396
|
-
const osArchitecture = [
|
|
456
|
+
const osArchitecture = [
|
|
457
|
+
"x64",
|
|
458
|
+
"arm64",
|
|
459
|
+
"ppc64",
|
|
460
|
+
"s390x",
|
|
461
|
+
].includes(cpuArchitecture)
|
|
397
462
|
? "64-bit"
|
|
398
463
|
: ["ia32", "arm", "mips", "mipsel", "s390"].includes(cpuArchitecture)
|
|
399
464
|
? "32-bit"
|
|
@@ -413,6 +478,9 @@ describe("Hub event tests", () => {
|
|
|
413
478
|
minutes: expect.any(Number),
|
|
414
479
|
seconds: expect.any(Number),
|
|
415
480
|
}),
|
|
481
|
+
workers: {
|
|
482
|
+
cliScript: cliScriptWorkerPool.stats(),
|
|
483
|
+
},
|
|
416
484
|
},
|
|
417
485
|
api: {
|
|
418
486
|
address: `${apiAddress}:${port}`,
|
|
@@ -424,7 +492,10 @@ describe("Hub event tests", () => {
|
|
|
424
492
|
platform: os.platform(),
|
|
425
493
|
cpuCount: os.cpus().length,
|
|
426
494
|
memory: {
|
|
427
|
-
total:
|
|
495
|
+
total:
|
|
496
|
+
(os.totalmem / (1024 * 1024 * 1024)).toFixed(
|
|
497
|
+
2,
|
|
498
|
+
) + " GB",
|
|
428
499
|
free: expect.any(String),
|
|
429
500
|
used: expect.any(String),
|
|
430
501
|
},
|
|
@@ -436,6 +507,154 @@ describe("Hub event tests", () => {
|
|
|
436
507
|
expect(response).toBe(null);
|
|
437
508
|
expect(error).toBe("Unknown CLI command 'invalid command'");
|
|
438
509
|
});
|
|
510
|
+
|
|
511
|
+
describe("runCLIScript", () => {
|
|
512
|
+
const runCommand = () =>
|
|
513
|
+
toPromise((resolve) => {
|
|
514
|
+
clientToCliSocket.emit(
|
|
515
|
+
"cliCommand",
|
|
516
|
+
{
|
|
517
|
+
command: "runCliScript",
|
|
518
|
+
scriptName: "sumScript",
|
|
519
|
+
scriptData: { x: 1, y: 2 },
|
|
520
|
+
},
|
|
521
|
+
(err, res) => {
|
|
522
|
+
resolve([err, res]);
|
|
523
|
+
},
|
|
524
|
+
);
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
test("shall used worker pool", async () => {
|
|
528
|
+
expect(cliScriptWorkerPool.workerType).toBe("thread"); // used node.js worker thread
|
|
529
|
+
expect(cliScriptWorkerPool.workerThreadOpts).toStrictEqual({
|
|
530
|
+
env: { NODE_ENV: process.env.NODE_ENV },
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
const execSpy = jest.spyOn(cliScriptWorkerPool, "exec");
|
|
534
|
+
|
|
535
|
+
execSpy.mockResolvedValueOnce("success");
|
|
536
|
+
await expect(runCommand()).resolves.toStrictEqual([
|
|
537
|
+
null,
|
|
538
|
+
"success",
|
|
539
|
+
]);
|
|
540
|
+
expect(execSpy.mock.calls.length).toBe(1);
|
|
541
|
+
expect(execSpy).toHaveBeenCalledWith("run", [
|
|
542
|
+
{
|
|
543
|
+
dbindex: 2,
|
|
544
|
+
subdomain,
|
|
545
|
+
url: `http://${apiAddress}:${port}`,
|
|
546
|
+
},
|
|
547
|
+
"sumScript",
|
|
548
|
+
{ x: 1, y: 2 },
|
|
549
|
+
]);
|
|
550
|
+
execSpy.mockReset();
|
|
551
|
+
|
|
552
|
+
execSpy.mockRejectedValueOnce("fail");
|
|
553
|
+
await expect(runCommand()).resolves.toStrictEqual([
|
|
554
|
+
"fail",
|
|
555
|
+
null,
|
|
556
|
+
]);
|
|
557
|
+
expect(execSpy.mock.calls.length).toBe(1);
|
|
558
|
+
expect(execSpy).toHaveBeenCalledWith("run", [
|
|
559
|
+
{
|
|
560
|
+
dbindex: 2,
|
|
561
|
+
subdomain,
|
|
562
|
+
url: `http://${apiAddress}:${port}`,
|
|
563
|
+
},
|
|
564
|
+
"sumScript",
|
|
565
|
+
{ x: 1, y: 2 },
|
|
566
|
+
]);
|
|
567
|
+
execSpy.mockReset();
|
|
568
|
+
|
|
569
|
+
// process beforeexit can not be reliably triggered or handled as expected within Jest's test environment, especially in worker thread scenario
|
|
570
|
+
// so we trigger the function directly
|
|
571
|
+
const workerpoolBeforeExit = process
|
|
572
|
+
.listeners("beforeexit")
|
|
573
|
+
.find(
|
|
574
|
+
(listener) =>
|
|
575
|
+
listener
|
|
576
|
+
.toString()
|
|
577
|
+
.toLowerCase()
|
|
578
|
+
.indexOf("cliscriptworkerpool") !== -1,
|
|
579
|
+
);
|
|
580
|
+
expect(isAsyncFunction(workerpoolBeforeExit)).toBeTruthy();
|
|
581
|
+
const terminateSpy = jest.spyOn(
|
|
582
|
+
cliScriptWorkerPool,
|
|
583
|
+
"terminate",
|
|
584
|
+
);
|
|
585
|
+
terminateSpy.mockReset();
|
|
586
|
+
workerpoolBeforeExit();
|
|
587
|
+
expect(terminateSpy.mock.calls.length).toBe(1);
|
|
588
|
+
});
|
|
589
|
+
|
|
590
|
+
test("shall used worker thread", async () => {
|
|
591
|
+
let mockAPIServer;
|
|
592
|
+
let scriptWorkerPool;
|
|
593
|
+
try {
|
|
594
|
+
// cannot used jest mocking because worker thread is running in different context.
|
|
595
|
+
// We must create http mock server, then direct worker request to the mock server
|
|
596
|
+
mockAPIServer = createServer((req, res) => {
|
|
597
|
+
res.writeHead(200, {
|
|
598
|
+
"Content-Type": "application/json",
|
|
599
|
+
});
|
|
600
|
+
res.end(
|
|
601
|
+
JSON.stringify([
|
|
602
|
+
{
|
|
603
|
+
"SYS$CLI_SCRIPT.SCRIPT": `get = function (lib) {
|
|
604
|
+
return {
|
|
605
|
+
functions: {
|
|
606
|
+
onInit: function (data) {
|
|
607
|
+
return (data.x + data.y);
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
}`,
|
|
612
|
+
},
|
|
613
|
+
]),
|
|
614
|
+
);
|
|
615
|
+
});
|
|
616
|
+
await toPromise((resolve) => {
|
|
617
|
+
mockAPIServer.listen(
|
|
618
|
+
{ host: "127.0.0.1", port: 0 },
|
|
619
|
+
() => {
|
|
620
|
+
resolve();
|
|
621
|
+
},
|
|
622
|
+
);
|
|
623
|
+
});
|
|
624
|
+
scriptWorkerPool = workerpool.pool(
|
|
625
|
+
"./worker/cliScriptWorker.js",
|
|
626
|
+
{
|
|
627
|
+
workerType: "thread",
|
|
628
|
+
workerThreadOpts: {
|
|
629
|
+
env: { NODE_ENV: "production" },
|
|
630
|
+
},
|
|
631
|
+
},
|
|
632
|
+
); // set worker NODE_ENV, so logger will not print to console
|
|
633
|
+
const sumResult = await scriptWorkerPool
|
|
634
|
+
.exec("run", [
|
|
635
|
+
{
|
|
636
|
+
dbindex: 2,
|
|
637
|
+
subdomain,
|
|
638
|
+
url: `http://127.0.0.1:${mockAPIServer.address().port}`,
|
|
639
|
+
},
|
|
640
|
+
"sumScript",
|
|
641
|
+
{ x: 1, y: 2 },
|
|
642
|
+
])
|
|
643
|
+
.then(async (result) => {
|
|
644
|
+
await scriptWorkerPool.terminate();
|
|
645
|
+
return result;
|
|
646
|
+
})
|
|
647
|
+
.catch((err) => {
|
|
648
|
+
return err.message || err;
|
|
649
|
+
});
|
|
650
|
+
expect(sumResult).toBe(3);
|
|
651
|
+
} finally {
|
|
652
|
+
if (mockAPIServer) {
|
|
653
|
+
mockAPIServer.close();
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
});
|
|
657
|
+
});
|
|
439
658
|
});
|
|
440
659
|
});
|
|
441
660
|
|
|
@@ -472,9 +691,11 @@ describe("Hub event tests", () => {
|
|
|
472
691
|
},
|
|
473
692
|
(hubUrl) => {
|
|
474
693
|
expect(hubUrl).toBe("https://some.hub.url");
|
|
475
|
-
}
|
|
694
|
+
},
|
|
695
|
+
);
|
|
696
|
+
await toPromise((resolve) =>
|
|
697
|
+
cliToHubSocket.once("connect", () => resolve()),
|
|
476
698
|
);
|
|
477
|
-
await toPromise((resolve) => cliToHubSocket.once("connect", () => resolve()));
|
|
478
699
|
});
|
|
479
700
|
|
|
480
701
|
afterAll(async () => {
|
|
@@ -489,10 +710,17 @@ describe("Hub event tests", () => {
|
|
|
489
710
|
const [error, response] = await toPromise((resolve) => {
|
|
490
711
|
hubToCLISocket.emit(
|
|
491
712
|
"apiRequest",
|
|
492
|
-
{
|
|
713
|
+
{
|
|
714
|
+
subDomain: subdomain,
|
|
715
|
+
method: "POST",
|
|
716
|
+
path: "/test",
|
|
717
|
+
headers: { "req-header": "aa" },
|
|
718
|
+
body: reqData,
|
|
719
|
+
responseType: "json",
|
|
720
|
+
},
|
|
493
721
|
(err, res) => {
|
|
494
722
|
resolve([err, res]);
|
|
495
|
-
}
|
|
723
|
+
},
|
|
496
724
|
);
|
|
497
725
|
});
|
|
498
726
|
return { error, response };
|
|
@@ -513,7 +741,11 @@ describe("Hub event tests", () => {
|
|
|
513
741
|
expect(result.response).toStrictEqual({
|
|
514
742
|
status: 200,
|
|
515
743
|
statusText: "Success",
|
|
516
|
-
headers: {
|
|
744
|
+
headers: {
|
|
745
|
+
"res-header": "aa",
|
|
746
|
+
"biza-cli-address": "https://some.tunnel.url",
|
|
747
|
+
"biza-hub-address": "https://some.hub.url",
|
|
748
|
+
},
|
|
517
749
|
body: "body of response",
|
|
518
750
|
url: `http://127.0.0.1:${port}/test`,
|
|
519
751
|
});
|
|
@@ -531,11 +763,20 @@ describe("Hub event tests", () => {
|
|
|
531
763
|
|
|
532
764
|
// parameterize API address as String
|
|
533
765
|
mockedRequest.mockClear();
|
|
534
|
-
result = await emitApiRequest(
|
|
766
|
+
result = await emitApiRequest(
|
|
767
|
+
JSON.stringify({
|
|
768
|
+
other: "data",
|
|
769
|
+
apiAddress: "http://apiHost:apiPort",
|
|
770
|
+
}),
|
|
771
|
+
);
|
|
535
772
|
expect(result.response).toStrictEqual({
|
|
536
773
|
status: 200,
|
|
537
774
|
statusText: "Success",
|
|
538
|
-
headers: {
|
|
775
|
+
headers: {
|
|
776
|
+
"res-header": "aa",
|
|
777
|
+
"biza-cli-address": "https://some.tunnel.url",
|
|
778
|
+
"biza-hub-address": "https://some.hub.url",
|
|
779
|
+
},
|
|
539
780
|
body: "body of response",
|
|
540
781
|
url: "http://apiHost:apiPort/test",
|
|
541
782
|
});
|
|
@@ -553,11 +794,18 @@ describe("Hub event tests", () => {
|
|
|
553
794
|
|
|
554
795
|
// parameterize API address as Object
|
|
555
796
|
mockedRequest.mockClear();
|
|
556
|
-
result = await emitApiRequest({
|
|
797
|
+
result = await emitApiRequest({
|
|
798
|
+
other: "data",
|
|
799
|
+
apiAddress: "http://apiHost:apiPort",
|
|
800
|
+
});
|
|
557
801
|
expect(result.response).toStrictEqual({
|
|
558
802
|
status: 200,
|
|
559
803
|
statusText: "Success",
|
|
560
|
-
headers: {
|
|
804
|
+
headers: {
|
|
805
|
+
"res-header": "aa",
|
|
806
|
+
"biza-cli-address": "https://some.tunnel.url",
|
|
807
|
+
"biza-hub-address": "https://some.hub.url",
|
|
808
|
+
},
|
|
561
809
|
body: "body of response",
|
|
562
810
|
url: "http://apiHost:apiPort/test",
|
|
563
811
|
});
|
|
@@ -578,17 +826,28 @@ describe("Hub event tests", () => {
|
|
|
578
826
|
test("status", async () => {
|
|
579
827
|
const runCommand = async (command) => {
|
|
580
828
|
return await toPromise((resolve) => {
|
|
581
|
-
hubToCLISocket.emit(
|
|
582
|
-
|
|
583
|
-
|
|
829
|
+
hubToCLISocket.emit(
|
|
830
|
+
"cliCommand",
|
|
831
|
+
{ command },
|
|
832
|
+
(err, res) => {
|
|
833
|
+
resolve([err, res]);
|
|
834
|
+
},
|
|
835
|
+
);
|
|
584
836
|
});
|
|
585
837
|
};
|
|
586
838
|
|
|
587
839
|
let [error, response] = await runCommand("StAtus ");
|
|
588
840
|
const cpuArchitecture = os.arch();
|
|
589
|
-
const osArchitecture = [
|
|
841
|
+
const osArchitecture = [
|
|
842
|
+
"x64",
|
|
843
|
+
"arm64",
|
|
844
|
+
"ppc64",
|
|
845
|
+
"s390x",
|
|
846
|
+
].includes(cpuArchitecture)
|
|
590
847
|
? "64-bit"
|
|
591
|
-
: ["ia32", "arm", "mips", "mipsel", "s390"].includes(
|
|
848
|
+
: ["ia32", "arm", "mips", "mipsel", "s390"].includes(
|
|
849
|
+
cpuArchitecture,
|
|
850
|
+
)
|
|
592
851
|
? "32-bit"
|
|
593
852
|
: `Unknown CPU architecture: ${cpuArchitecture}`;
|
|
594
853
|
expect(response).toMatchObject({
|
|
@@ -606,6 +865,9 @@ describe("Hub event tests", () => {
|
|
|
606
865
|
minutes: expect.any(Number),
|
|
607
866
|
seconds: expect.any(Number),
|
|
608
867
|
}),
|
|
868
|
+
workers: {
|
|
869
|
+
cliScript: cliScriptWorkerPool.stats(),
|
|
870
|
+
},
|
|
609
871
|
},
|
|
610
872
|
api: {
|
|
611
873
|
address: `${apiAddress}:${port}`,
|
|
@@ -617,7 +879,10 @@ describe("Hub event tests", () => {
|
|
|
617
879
|
platform: os.platform(),
|
|
618
880
|
cpuCount: os.cpus().length,
|
|
619
881
|
memory: {
|
|
620
|
-
total:
|
|
882
|
+
total:
|
|
883
|
+
(os.totalmem / (1024 * 1024 * 1024)).toFixed(
|
|
884
|
+
2,
|
|
885
|
+
) + " GB",
|
|
621
886
|
free: expect.any(String),
|
|
622
887
|
used: expect.any(String),
|
|
623
888
|
},
|
|
@@ -629,6 +894,82 @@ describe("Hub event tests", () => {
|
|
|
629
894
|
expect(response).toBe(null);
|
|
630
895
|
expect(error).toBe("Unknown CLI command 'invalid command'");
|
|
631
896
|
});
|
|
897
|
+
|
|
898
|
+
describe("runCLIScript", () => {
|
|
899
|
+
test("shall used worker pool", async () => {
|
|
900
|
+
expect(cliScriptWorkerPool.workerType).toBe("thread"); // used node.js worker thread
|
|
901
|
+
|
|
902
|
+
const execSpy = jest.spyOn(cliScriptWorkerPool, "exec");
|
|
903
|
+
const runCommand = () =>
|
|
904
|
+
toPromise((resolve) => {
|
|
905
|
+
hubToCLISocket.emit(
|
|
906
|
+
"cliCommand",
|
|
907
|
+
{
|
|
908
|
+
command: "runCliScript",
|
|
909
|
+
scriptName: "sumScript",
|
|
910
|
+
scriptData: { x: 1, y: 2 },
|
|
911
|
+
},
|
|
912
|
+
(err, res) => {
|
|
913
|
+
resolve([err, res]);
|
|
914
|
+
},
|
|
915
|
+
);
|
|
916
|
+
});
|
|
917
|
+
|
|
918
|
+
execSpy.mockResolvedValueOnce("success");
|
|
919
|
+
await expect(runCommand()).resolves.toStrictEqual([
|
|
920
|
+
null,
|
|
921
|
+
"success",
|
|
922
|
+
]);
|
|
923
|
+
expect(execSpy.mock.calls.length).toBe(1);
|
|
924
|
+
expect(execSpy).toHaveBeenCalledWith("run", [
|
|
925
|
+
{
|
|
926
|
+
dbindex: 2,
|
|
927
|
+
subdomain,
|
|
928
|
+
url: `http://${apiAddress}:${port}`,
|
|
929
|
+
},
|
|
930
|
+
"sumScript",
|
|
931
|
+
{ x: 1, y: 2 },
|
|
932
|
+
]);
|
|
933
|
+
execSpy.mockReset();
|
|
934
|
+
|
|
935
|
+
execSpy.mockRejectedValueOnce("fail");
|
|
936
|
+
await expect(runCommand()).resolves.toStrictEqual([
|
|
937
|
+
"fail",
|
|
938
|
+
null,
|
|
939
|
+
]);
|
|
940
|
+
expect(execSpy.mock.calls.length).toBe(1);
|
|
941
|
+
expect(execSpy).toHaveBeenCalledWith("run", [
|
|
942
|
+
{
|
|
943
|
+
dbindex: 2,
|
|
944
|
+
subdomain,
|
|
945
|
+
url: `http://${apiAddress}:${port}`,
|
|
946
|
+
},
|
|
947
|
+
"sumScript",
|
|
948
|
+
{ x: 1, y: 2 },
|
|
949
|
+
]);
|
|
950
|
+
execSpy.mockReset();
|
|
951
|
+
|
|
952
|
+
// process beforeexit can not be reliably triggered or handled as expected within Jest's test environment, especially in worker thread scenario
|
|
953
|
+
// so we trigger the function directly
|
|
954
|
+
const terminateSpy = jest.spyOn(
|
|
955
|
+
cliScriptWorkerPool,
|
|
956
|
+
"terminate",
|
|
957
|
+
);
|
|
958
|
+
const workerpoolBeforeExit = process
|
|
959
|
+
.listeners("beforeexit")
|
|
960
|
+
.find(
|
|
961
|
+
(listener) =>
|
|
962
|
+
listener
|
|
963
|
+
.toString()
|
|
964
|
+
.toLowerCase()
|
|
965
|
+
.indexOf("cliscriptworkerpool") !== -1,
|
|
966
|
+
);
|
|
967
|
+
expect(isAsyncFunction(workerpoolBeforeExit)).toBeTruthy();
|
|
968
|
+
terminateSpy.mockReset();
|
|
969
|
+
workerpoolBeforeExit();
|
|
970
|
+
expect(terminateSpy.mock.calls.length).toBe(1);
|
|
971
|
+
});
|
|
972
|
+
});
|
|
632
973
|
});
|
|
633
974
|
});
|
|
634
975
|
|