biz-a-cli 2.3.57 → 2.3.59
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/acert/cert.pem +30 -0
- package/acert/key.pem +27 -0
- package/acert/root.pem +29 -0
- package/bin/app.js +182 -283
- package/bin/debug.log +8 -0
- package/bin/deployEvent.js +105 -0
- package/bin/directHubEvent.js +46 -25
- package/bin/hub.js +5 -6
- package/bin/hubEvent.js +5 -2
- package/bin/script.js +125 -0
- package/bin/uploadApp.js +1 -1
- package/debug.log +2 -0
- package/log/debug.log +280 -0
- package/log/error.log +281 -0
- package/log/exception.log +101 -0
- package/log/info.log +279 -0
- package/package.json +8 -5
- package/tests/app.test.js +92 -28
- package/tests/debug.log +4 -0
- package/tests/deployment.test.js +351 -0
- package/tests/hub.test.js +8 -7
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "biz-a-cli",
|
|
3
3
|
"nameDev": "biz-a-cli-dev",
|
|
4
|
-
"version": "2.3.
|
|
4
|
+
"version": "2.3.59",
|
|
5
5
|
"versionDev": "0.0.34",
|
|
6
6
|
"description": "",
|
|
7
7
|
"main": "bin/index.js",
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
},
|
|
13
13
|
"scripts": {
|
|
14
14
|
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js --watch a",
|
|
15
|
-
"
|
|
15
|
+
"testOnce": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
|
|
16
16
|
"dev": "node --watch server.js",
|
|
17
|
-
"hub": "node --experimental-vm-modules bin/hub.js"
|
|
17
|
+
"hub": "set NODE_ENV=production && node --experimental-vm-modules bin/hub.js"
|
|
18
18
|
},
|
|
19
19
|
"author": "Imamatek",
|
|
20
20
|
"license": "ISC",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"socket.io-client": "^4.7.5",
|
|
42
42
|
"socket.io-stream": "^0.9.1",
|
|
43
43
|
"tar": "^7.4.0",
|
|
44
|
-
"uglify-js": "^3.
|
|
44
|
+
"uglify-js": "^3.19.3",
|
|
45
45
|
"web-push": "^3.6.7",
|
|
46
46
|
"winston": "^3.13.0",
|
|
47
47
|
"yargs": "^17.7.2"
|
|
@@ -55,6 +55,9 @@
|
|
|
55
55
|
"<rootDir>/tests/**",
|
|
56
56
|
"!<rootDir>/tests/mockData",
|
|
57
57
|
"!<rootDir>/tests/mockData/**"
|
|
58
|
-
]
|
|
58
|
+
],
|
|
59
|
+
"testPathIgnorePatterns": ["<rootDir>/node_modules", "<rootDir>/tests/mockData"],
|
|
60
|
+
"watchPathIgnorePatterns": ["<rootDir>/node_modules", "<rootDir>/tests/mockData"],
|
|
61
|
+
"coveragePathIgnorePatterns": ["<rootDir>/node_modules", "<rootDir>/tests/mockData", "<rootDir>/tests/mockData/**"]
|
|
59
62
|
}
|
|
60
63
|
}
|
package/tests/app.test.js
CHANGED
|
@@ -47,14 +47,12 @@ describe('Biz-A Apps CLI', ()=>{
|
|
|
47
47
|
|
|
48
48
|
describe('Add App', ()=>{
|
|
49
49
|
const mockDataFolder = './tests/mockData/'
|
|
50
|
-
const appName = 'mockApp'
|
|
51
|
-
const appFolderName = mockDataFolder + appName+ '/';
|
|
52
50
|
|
|
53
|
-
function mockValidTemplates(scriptList){
|
|
54
|
-
fs.rmSync(
|
|
55
|
-
fs.mkdirSync(
|
|
51
|
+
function mockValidTemplates(appName, scriptList){
|
|
52
|
+
fs.rmSync(mockDataFolder+'/'+appName, {force: true, recursive: true})
|
|
53
|
+
fs.mkdirSync(mockDataFolder+'/'+appName, {recursive: true})
|
|
56
54
|
for (const [key, value] of Object.entries(scriptList)){
|
|
57
|
-
fs.writeFileSync(
|
|
55
|
+
fs.writeFileSync(mockDataFolder+'/'+appName + '/' + key, value.act)
|
|
58
56
|
}
|
|
59
57
|
}
|
|
60
58
|
|
|
@@ -70,7 +68,7 @@ describe('Biz-A Apps CLI', ()=>{
|
|
|
70
68
|
axios.post.mockResolvedValue({data: {success: true}, status: 200})
|
|
71
69
|
}
|
|
72
70
|
|
|
73
|
-
|
|
71
|
+
beforeAll(()=>{
|
|
74
72
|
fs.rmSync(mockDataFolder, {recursive: true, force: true})
|
|
75
73
|
})
|
|
76
74
|
|
|
@@ -79,7 +77,7 @@ describe('Biz-A Apps CLI', ()=>{
|
|
|
79
77
|
})
|
|
80
78
|
|
|
81
79
|
const stressTestCount = 10;
|
|
82
|
-
it.each(Array(stressTestCount).fill().map((v,i)=>i+1))(`shall compress and encrypt app scripts (stress test %p of ${stressTestCount})`, async ()=>{
|
|
80
|
+
it.each(Array(stressTestCount).fill().map((v,i)=>i+1))(`shall compress and encrypt app scripts (stress test %p of ${stressTestCount})`, async (testNo)=>{
|
|
83
81
|
const mockScripts = {
|
|
84
82
|
'a.js' : {
|
|
85
83
|
act: 'get = function () {return {modelA: {}}}',
|
|
@@ -154,11 +152,12 @@ describe('Biz-A Apps CLI', ()=>{
|
|
|
154
152
|
}
|
|
155
153
|
}
|
|
156
154
|
|
|
157
|
-
|
|
155
|
+
const appName = 'compressStressTest' + testNo
|
|
156
|
+
mockValidTemplates(appName, mockScripts)
|
|
158
157
|
mockIssuerKeyResponse()
|
|
159
158
|
const mockAESKey = Buffer.from('hAnHadaJXJaq/9fCFMNmjkrB61CBPXJid6vbtXgG8Ug=', 'base64')
|
|
160
159
|
|
|
161
|
-
await runCommand('add', '-s', 'https://a.b.c', '-p', '1205', '-i', '2', '-d',
|
|
160
|
+
await runCommand('add', '-s', 'https://a.b.c', '-p', '1205', '-i', '2', '-d', mockDataFolder + '/' + appName)
|
|
162
161
|
|
|
163
162
|
expect(axios.get.mock.calls).toHaveLength(1)
|
|
164
163
|
const getArgs = axios.get.mock.calls[0]
|
|
@@ -233,6 +232,8 @@ describe('Biz-A Apps CLI', ()=>{
|
|
|
233
232
|
|
|
234
233
|
expect(logSpy.mock.calls[0][0]).toContain(`Finished packing ${Object.keys(mockScripts).length} files into "./upload/${appName.toLowerCase()}.tgz"`)
|
|
235
234
|
expect(logSpy.mock.calls[1][0]).toContain(`Finished uploading "./upload/${appName.toLocaleLowerCase()}.tgz"`)
|
|
235
|
+
|
|
236
|
+
// fs.rmSync(mockDataFolder + '/' + appName, {recursive: true, force: true})
|
|
236
237
|
})
|
|
237
238
|
|
|
238
239
|
/* it('Invalid script syntax', async ()=>{
|
|
@@ -290,57 +291,61 @@ describe('Biz-A Apps CLI', ()=>{
|
|
|
290
291
|
'Invalid script syntax',
|
|
291
292
|
{act: 'get = function () {return {modelA: {}}'}, // missing close closure at the end',
|
|
292
293
|
()=>{
|
|
293
|
-
expect(logSpy.mock.calls.length).toBe(
|
|
294
|
+
expect(logSpy.mock.calls.length).toBe(5)
|
|
294
295
|
expect(logSpy.mock.calls[0][0]).toBe('===================\nA.JS\n===================')
|
|
296
|
+
expect(logSpy.mock.calls[1][0]).toBe('Running script with VM') // node sandbox (VN) error as console.log
|
|
297
|
+
expect(logSpy.mock.calls[2][0]).toStrictEqual('a.js:1:38: SyntaxError: Unexpected token: eof, expected: punc «}»')
|
|
298
|
+
expect(logSpy.mock.calls[3][0]).toStrictEqual('Running script with Import function')
|
|
299
|
+
expect(logSpy.mock.calls[4][0]).toStrictEqual('===================\nEOF A.JS\n===================')
|
|
295
300
|
|
|
296
301
|
expect(errorSpy.mock.calls.length).toBe(1)
|
|
297
|
-
|
|
298
|
-
expect(errorSpy.mock.calls[0][0]).toStrictEqual('a.js:1:38: SyntaxError: Unexpected token: eof, expected: punc «}»')
|
|
302
|
+
expect(errorSpy.mock.calls[0][0]).toBe('a.js : SyntaxError: Unexpected end of input')
|
|
299
303
|
}
|
|
300
304
|
],
|
|
301
305
|
[
|
|
302
306
|
'Failed to compile script with node sandbox and ES6 Import',
|
|
303
307
|
{act: 'get = function () {return {modelA: {}}}\n modul.expor = get;\n'}, // wrong "module.export"
|
|
304
308
|
()=>{
|
|
305
|
-
expect(logSpy.mock.calls.length).toBe(
|
|
309
|
+
expect(logSpy.mock.calls.length).toBe(6)
|
|
306
310
|
expect(logSpy.mock.calls[0][0]).toBe('===================\nA.JS\n===================')
|
|
307
|
-
expect(logSpy.mock.calls[1][0]).toBe('
|
|
308
|
-
expect(logSpy.mock.calls[2][0]).toBe('
|
|
311
|
+
expect(logSpy.mock.calls[1][0]).toBe('Running script with VM') // node sandbox (VN) error as console.log
|
|
312
|
+
expect(logSpy.mock.calls[2][0]).toBe('Minify : \nget=function(){return{modelA:{}}};modul.expor=get;')
|
|
309
313
|
expect(logSpy.mock.calls[3][0]).toBe("a.js : ReferenceError: modul is not defined")
|
|
310
314
|
expect(logSpy.mock.calls[4][0]).toBe('Running script with Import function')
|
|
315
|
+
expect(logSpy.mock.calls[5][0]).toStrictEqual('===================\nEOF A.JS\n===================')
|
|
311
316
|
|
|
312
317
|
expect(errorSpy.mock.calls.length).toBe(1)
|
|
313
|
-
|
|
314
|
-
expect(errorSpy.mock.calls[0][0]).toStrictEqual('a.js : ReferenceError: modul is not defined')// ES6 import error
|
|
318
|
+
expect(errorSpy.mock.calls[0][0]).toStrictEqual('a.js : Error: Invalid data URI')// ES6 import error
|
|
315
319
|
}
|
|
316
320
|
],
|
|
317
321
|
[
|
|
318
322
|
'Shall not allow empty script',
|
|
319
323
|
{act: 'get = function () {}'}, // empty script
|
|
320
324
|
()=>{
|
|
321
|
-
expect(logSpy.mock.calls.length).toBe(
|
|
325
|
+
expect(logSpy.mock.calls.length).toBe(5)
|
|
322
326
|
expect(logSpy.mock.calls[0][0]).toBe('===================\nA.JS\n===================')
|
|
323
|
-
expect(logSpy.mock.calls[1][0]).toBe('
|
|
324
|
-
expect(logSpy.mock.calls[2][0]).toBe('
|
|
327
|
+
expect(logSpy.mock.calls[1][0]).toBe('Running script with VM') // node sandbox (VN) error as console.log
|
|
328
|
+
expect(logSpy.mock.calls[2][0]).toBe('Minify : \nget=function(){};')
|
|
325
329
|
expect(logSpy.mock.calls[3][0]).toBe('Running script with Import function')
|
|
330
|
+
expect(logSpy.mock.calls[4][0]).toStrictEqual('===================\nEOF A.JS\n===================')
|
|
326
331
|
|
|
327
332
|
expect(errorSpy.mock.calls.length).toBe(1)
|
|
328
|
-
// expect(errorSpy.mock.calls[0][0]).toStrictEqual({e: 'a.js : Failed to compile template script.\nPlease make sure the script is correct and not returning empty result'})
|
|
329
333
|
expect(errorSpy.mock.calls[0][0]).toStrictEqual('a.js : Failed to compile template script.\nPlease make sure the script is correct and not returning empty result')
|
|
330
334
|
}
|
|
331
335
|
],
|
|
332
336
|
]
|
|
333
337
|
it.each(errorHandlingTestCases)('%p', async (name, scripts, expectedFn)=>{
|
|
334
|
-
|
|
338
|
+
const appName = 'errorHandlingTest' + errorHandlingTestCases.findIndex(testCase => testCase[0] === name)
|
|
339
|
+
mockValidTemplates(appName, {'a.js' : scripts})
|
|
335
340
|
mockIssuerKeyResponse()
|
|
336
|
-
await runCommand('add', '-s', 'https://a.b.c', '-p', '1205', '-i', '2', '-d',
|
|
341
|
+
await runCommand('add', '-s', 'https://a.b.c', '-p', '1205', '-i', '2', '-d', mockDataFolder + '/' + appName, "-v")
|
|
337
342
|
expectedFn()
|
|
338
343
|
})
|
|
339
344
|
|
|
340
|
-
it('Shall not allow
|
|
341
|
-
mockValidTemplates({})
|
|
345
|
+
it('Shall not allow app without script template', async ()=>{
|
|
346
|
+
mockValidTemplates(expect.getState().currentTestName, {})
|
|
342
347
|
mockIssuerKeyResponse()
|
|
343
|
-
await runCommand('add', '-s', 'https://a.b.c', '-p', '1205', '-i', '2', '-d',
|
|
348
|
+
await runCommand('add', '-s', 'https://a.b.c', '-p', '1205', '-i', '2', '-d', mockDataFolder + '/' + expect.getState().currentTestName, "-v")
|
|
344
349
|
|
|
345
350
|
expect(logSpy.mock.calls.length).toBe(0)
|
|
346
351
|
|
|
@@ -350,7 +355,7 @@ describe('Biz-A Apps CLI', ()=>{
|
|
|
350
355
|
|
|
351
356
|
it('Shall recommend command', async ()=>{
|
|
352
357
|
const exitSpy = jest.spyOn(process, 'exit').mockImplementation(()=>{})
|
|
353
|
-
await runCommand('Add', '-s', 'https://a.b.c', '-p', '1205', '-i', '2', '-d',
|
|
358
|
+
await runCommand('Add', '-s', 'https://a.b.c', '-p', '1205', '-i', '2', '-d', mockDataFolder + '/NotExistFolder', "-v")
|
|
354
359
|
expect(logSpy.mock.calls.length).toBe(0)
|
|
355
360
|
expect(exitSpy).toHaveBeenCalledWith(1) // exit code = 1
|
|
356
361
|
expect(errorSpy.mock.calls[errorSpy.mock.calls.length-1][0]).toBe('Did you mean add?')
|
|
@@ -419,4 +424,63 @@ describe('Biz-A Apps CLI', ()=>{
|
|
|
419
424
|
})
|
|
420
425
|
})
|
|
421
426
|
|
|
427
|
+
it('Shall have options', async ()=>{
|
|
428
|
+
jest.spyOn(process, 'exit').mockImplementation()
|
|
429
|
+
const appModule = await import('../bin/app.js')
|
|
430
|
+
expect(appModule.options).toStrictEqual({
|
|
431
|
+
"s" : {
|
|
432
|
+
alias: "server",
|
|
433
|
+
describe: `API or Server URL (ex: ${env.BIZA_SERVER_LINK} or http://192.168.1.1 or https://finaapi.imamatek.com)`,
|
|
434
|
+
type: "string",
|
|
435
|
+
demandOption: true,
|
|
436
|
+
default: 'http://localhost'
|
|
437
|
+
},
|
|
438
|
+
"i" : {
|
|
439
|
+
alias: "dbIndex",
|
|
440
|
+
default: 2,
|
|
441
|
+
describe: "database index",
|
|
442
|
+
type: "number",
|
|
443
|
+
demandOption: false
|
|
444
|
+
},
|
|
445
|
+
"sub": {
|
|
446
|
+
alias: "subdomain",
|
|
447
|
+
describe: "Subdomain",
|
|
448
|
+
type: "string",
|
|
449
|
+
demandOption: false
|
|
450
|
+
},
|
|
451
|
+
"p": {
|
|
452
|
+
alias: "apiPort",
|
|
453
|
+
default : 212,
|
|
454
|
+
describe: "FINA API Port",
|
|
455
|
+
type: "number",
|
|
456
|
+
demandOption: false,
|
|
457
|
+
}
|
|
458
|
+
})
|
|
459
|
+
expect(appModule.addCommandOptions).toStrictEqual({
|
|
460
|
+
'd': {
|
|
461
|
+
alias: "workingDir",
|
|
462
|
+
describe: "Path to templates directory",
|
|
463
|
+
type: "string",
|
|
464
|
+
demandOption: false,
|
|
465
|
+
default: process.cwd(),
|
|
466
|
+
},
|
|
467
|
+
'v': {
|
|
468
|
+
alias: "verbose",
|
|
469
|
+
describe: "Print info to console",
|
|
470
|
+
type: "boolean",
|
|
471
|
+
demandOption: false,
|
|
472
|
+
default: false,
|
|
473
|
+
}
|
|
474
|
+
})
|
|
475
|
+
expect(appModule.removeCommandOptions).toStrictEqual({
|
|
476
|
+
'n': {
|
|
477
|
+
alias: "appName",
|
|
478
|
+
describe: "Application name",
|
|
479
|
+
type: "string",
|
|
480
|
+
demandOption: true,
|
|
481
|
+
default: ""
|
|
482
|
+
}
|
|
483
|
+
})
|
|
484
|
+
})
|
|
485
|
+
|
|
422
486
|
})
|
package/tests/debug.log
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
[0605/214850.720:ERROR:registration_protocol_win.cc(108)] CreateFile: The system cannot find the file specified. (0x2)
|
|
2
|
+
[0605/214852.995:ERROR:registration_protocol_win.cc(108)] CreateFile: The system cannot find the file specified. (0x2)
|
|
3
|
+
[0605/220241.422:ERROR:registration_protocol_win.cc(108)] CreateFile: The system cannot find the file specified. (0x2)
|
|
4
|
+
[0605/220243.465:ERROR:registration_protocol_win.cc(108)] CreateFile: The system cannot find the file specified. (0x2)
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import { Server as ioServer } from 'socket.io';
|
|
2
|
+
import { getAppData, onScriptChangeFromVsCode, onScriptChangeFromHubServer} from '../bin/deployEvent.js'
|
|
3
|
+
import { io as ioClient, Socket, Manager } from "socket.io-client";
|
|
4
|
+
import { expect, jest } from '@jest/globals';
|
|
5
|
+
import axios from "axios";
|
|
6
|
+
import { directHubEvent, getSocketCORSOrigin, CLIENT_ROOM } from '../bin/directHubEvent.js'
|
|
7
|
+
import { createDecipheriv } from 'node:crypto'
|
|
8
|
+
import { hubEvent } from '../bin/hubEvent.js';
|
|
9
|
+
|
|
10
|
+
describe('Deployment', () => {
|
|
11
|
+
|
|
12
|
+
const hostname = '127.0.0.1'
|
|
13
|
+
const port = 7778
|
|
14
|
+
const dbindex = 2
|
|
15
|
+
const subdomain = 'deploy'
|
|
16
|
+
|
|
17
|
+
const toPromise = (cb) => new Promise((resolve, reject) => {
|
|
18
|
+
cb(resolve)
|
|
19
|
+
setTimeout(() => reject(new Error('timeout')), 1000)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
function freeSocketClient(sock){
|
|
23
|
+
if (sock) {
|
|
24
|
+
if (sock.connected) {
|
|
25
|
+
sock.off()
|
|
26
|
+
sock.disconnect()
|
|
27
|
+
}
|
|
28
|
+
sock.destroy()
|
|
29
|
+
sock = undefined
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
beforeEach(()=>{
|
|
34
|
+
jest.restoreAllMocks()
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
afterEach(()=>{
|
|
38
|
+
jest.restoreAllMocks()
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('shall allow origins', ()=>{
|
|
42
|
+
expect(getSocketCORSOrigin(hostname)).toStrictEqual([
|
|
43
|
+
'https://biz-a.id',
|
|
44
|
+
'https://test.biz-a.id',
|
|
45
|
+
/\.biz-a\.id$/,
|
|
46
|
+
'vscode-file://vscode-app',
|
|
47
|
+
/\.vscode-cdn\.net$/,
|
|
48
|
+
`http://${hostname}:4200`,
|
|
49
|
+
'http://localhost:4200'
|
|
50
|
+
])
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('shall get app list from database', async ()=>{
|
|
54
|
+
// Failed : check for error message
|
|
55
|
+
const requestSpy = jest.spyOn(axios, 'request').mockResolvedValueOnce({
|
|
56
|
+
status: 200,
|
|
57
|
+
statusText: 'Success',
|
|
58
|
+
data: {"recordsTotal": 2}
|
|
59
|
+
})
|
|
60
|
+
let result = await getAppData({hostname, port, dbindex, secure: true})
|
|
61
|
+
expect(requestSpy).toHaveBeenCalledWith({
|
|
62
|
+
timeout: 30*1000,
|
|
63
|
+
baseURL: `https://${hostname}:${port}`,
|
|
64
|
+
url: 'fina/rest/TOrmMethod/%22list%22',
|
|
65
|
+
method: "POST",
|
|
66
|
+
"data" : {"dbIndex":2, "object":{"columns":[
|
|
67
|
+
{"title":"app","data":"SYS$APPS.APPNAME"},
|
|
68
|
+
{"title":"metadata","data":"SYS$APPS.METADATA"}
|
|
69
|
+
]}}
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
expect(result.error).toBe('"undefined" is not valid JSON')
|
|
73
|
+
expect(result.apps).toStrictEqual([])
|
|
74
|
+
|
|
75
|
+
// Success : check for apps data
|
|
76
|
+
const expectedAppData = [
|
|
77
|
+
{'SYS$APPS.APPNAME': 'firstApp', "SYS$APPS.METADATA": {acquirer: {data: '', signature: ''}, menu: ''}},
|
|
78
|
+
{'SYS$APPS.APPNAME': 'secondApp', "SYS$APPS.METADATA": {acquirer: {data: '', signature: ''}, menu: ''}},
|
|
79
|
+
]
|
|
80
|
+
|
|
81
|
+
requestSpy.mockResolvedValueOnce({
|
|
82
|
+
status: 200,
|
|
83
|
+
statusText: 'Success',
|
|
84
|
+
data: {
|
|
85
|
+
"recordsTotal": 2,
|
|
86
|
+
data: JSON.stringify(expectedAppData)
|
|
87
|
+
}
|
|
88
|
+
})
|
|
89
|
+
result = await getAppData({hostname, port, dbindex})
|
|
90
|
+
expect(result.error).toBe(null)
|
|
91
|
+
expect(result.apps).toStrictEqual(expectedAppData)
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
it('shall log connect and disconnect', async ()=>{
|
|
95
|
+
const logSpy = jest.spyOn(console, 'log').mockImplementation()
|
|
96
|
+
let vsCodeToCLISock
|
|
97
|
+
let serverSideSock
|
|
98
|
+
const socketServer = new ioServer(1234)// mocking of CLI socket server
|
|
99
|
+
directHubEvent(socketServer, {subdomain, hostname, port: 1234, secure: false, dbindex, server: 'mockServer'})
|
|
100
|
+
try {
|
|
101
|
+
vsCodeToCLISock = await toPromise((resolve)=>{
|
|
102
|
+
const sock = ioClient(`http://${hostname}:${1234}`, {reconnection: false, query: {isDeploy: true}}).on('connect', async ()=>{
|
|
103
|
+
serverSideSock = (await socketServer.fetchSockets()).find(s=>s.id==sock.id)
|
|
104
|
+
resolve(sock)
|
|
105
|
+
})
|
|
106
|
+
})
|
|
107
|
+
expect(logSpy).toHaveBeenCalledTimes(1)
|
|
108
|
+
expect(logSpy).toHaveBeenCalledWith('<Deployer> ' + vsCodeToCLISock.id, 'connected')
|
|
109
|
+
|
|
110
|
+
logSpy.mockReset()
|
|
111
|
+
serverSideSock.disconnect()
|
|
112
|
+
expect(logSpy).toHaveBeenCalledTimes(1)
|
|
113
|
+
expect(logSpy).toHaveBeenCalledWith('<Deployer> ' + vsCodeToCLISock.id, 'disconnected. Reason : server namespace disconnect')
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
socketServer.close()
|
|
117
|
+
freeSocketClient(vsCodeToCLISock)
|
|
118
|
+
logSpy.mockRestore()
|
|
119
|
+
}
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
describe('from vs code', ()=>{
|
|
123
|
+
|
|
124
|
+
let cliSocketServer // mocking of CLI socket server
|
|
125
|
+
|
|
126
|
+
beforeAll(()=>{
|
|
127
|
+
cliSocketServer = new ioServer(port)// mocking of CLI socket server
|
|
128
|
+
directHubEvent(cliSocketServer, {subdomain, hostname, port, secure: false, dbindex, server: 'mockServer'})
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
afterAll(async ()=>{
|
|
132
|
+
if (cliSocketServer) {
|
|
133
|
+
(await cliSocketServer.of('').sockets).forEach((sock)=>{sock.removeAllListeners()})
|
|
134
|
+
await cliSocketServer.close()
|
|
135
|
+
}
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
it('shall have "appList" listener', async ()=>{
|
|
139
|
+
let vsCodeToCLISock
|
|
140
|
+
try {
|
|
141
|
+
jest.spyOn(console, 'log').mockImplementation()
|
|
142
|
+
jest.spyOn(axios, 'request').mockResolvedValueOnce({
|
|
143
|
+
status: 200,
|
|
144
|
+
statusText: 'Success',
|
|
145
|
+
data: {
|
|
146
|
+
"recordsTotal": 2,
|
|
147
|
+
data: JSON.stringify([
|
|
148
|
+
{'SYS$APPS.APPNAME': 'firstApp', "SYS$APPS.METADATA": {acquirer: {data: '', signature: ''}, menu: ''}},
|
|
149
|
+
{'SYS$APPS.APPNAME': 'secondApp', "SYS$APPS.METADATA": {acquirer: {data: '', signature: ''}, menu: ''}},
|
|
150
|
+
])
|
|
151
|
+
}
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
vsCodeToCLISock = await toPromise((resolve)=>{
|
|
155
|
+
const sock = ioClient(`http://${hostname}:${port}`, {query: {isDeploy:true}}).on('connect', ()=>{resolve(sock)})
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
const [error, apps] = await toPromise(resolve => {vsCodeToCLISock.emit('appList', {}, (err, data)=>{resolve([err, data])})});
|
|
159
|
+
expect(error).toBe(null);
|
|
160
|
+
expect(apps).toStrictEqual(['firstApp', 'secondApp']);
|
|
161
|
+
}
|
|
162
|
+
finally {
|
|
163
|
+
freeSocketClient(vsCodeToCLISock)
|
|
164
|
+
}
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
it('shall prepare deploy script', async ()=>{
|
|
168
|
+
let vsCodeToCLISock
|
|
169
|
+
let serverSideSock
|
|
170
|
+
let emitSpy
|
|
171
|
+
let broadcastSpy
|
|
172
|
+
let result
|
|
173
|
+
try {
|
|
174
|
+
jest.spyOn(console, 'log').mockImplementation()
|
|
175
|
+
|
|
176
|
+
vsCodeToCLISock = await toPromise((resolve)=>{
|
|
177
|
+
const sock = ioClient(`http://${hostname}:${port}`).on('connect', async ()=>{
|
|
178
|
+
serverSideSock = (await cliSocketServer.fetchSockets()).find((s)=>s.id==sock.id)
|
|
179
|
+
|
|
180
|
+
// if using socket.broadcast.emit()
|
|
181
|
+
// const mockedBroadcast = serverSideSock.newBroadcastOperator()
|
|
182
|
+
// broadcastSpy = jest.fn().mockReturnValue(mockedBroadcast) // mock it to return same broadcast object
|
|
183
|
+
// serverSideSock.newBroadcastOperator = broadcastSpy
|
|
184
|
+
|
|
185
|
+
// if using socket.to(roomName).emit()
|
|
186
|
+
const mockedBroadcast = serverSideSock.to(CLIENT_ROOM)
|
|
187
|
+
broadcastSpy = jest.spyOn(serverSideSock, 'to').mockReturnValue(mockedBroadcast) // mock it to return same broadcast object
|
|
188
|
+
|
|
189
|
+
emitSpy = jest.spyOn(mockedBroadcast, 'emit').mockImplementation()
|
|
190
|
+
|
|
191
|
+
resolve(sock)
|
|
192
|
+
})
|
|
193
|
+
})
|
|
194
|
+
const mockAESKey = Buffer.from('hAnHadaJXJaq/9fCFMNmjkrB61CBPXJid6vbtXgG8Ug=', 'base64')
|
|
195
|
+
const requestSpy = jest.spyOn(axios, 'request').mockResolvedValue({status: 200, statusText: 'Success', data: mockAESKey})
|
|
196
|
+
const deployData = {appName: 'app', fileName: 'filename.js', script: "put script here for testing"}
|
|
197
|
+
|
|
198
|
+
// Failed of empty script
|
|
199
|
+
emitSpy.mockReset()
|
|
200
|
+
result = await onScriptChangeFromVsCode(
|
|
201
|
+
serverSideSock,
|
|
202
|
+
'https://mock.server.com',
|
|
203
|
+
[{'SYS$APPS.APPNAME': 'app', "SYS$APPS.METADATA": JSON.stringify({acquirer: {data: '', signature: ''}, menu: ''})}],
|
|
204
|
+
{...deployData, ...{script: ""}}
|
|
205
|
+
)
|
|
206
|
+
expect(result.error).toBe("filename.js : Failed to compile template script.\nPlease make sure the script is correct and not returning empty result")
|
|
207
|
+
expect(result.script).toBeUndefined()
|
|
208
|
+
expect(requestSpy).not.toHaveBeenCalled()
|
|
209
|
+
expect(emitSpy).not.toHaveBeenCalled()
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
// Failed of invalid script syntax
|
|
213
|
+
emitSpy.mockReset()
|
|
214
|
+
result = await onScriptChangeFromVsCode(
|
|
215
|
+
serverSideSock,
|
|
216
|
+
'https://mock.server.com',
|
|
217
|
+
[{'SYS$APPS.APPNAME': 'app', "SYS$APPS.METADATA": JSON.stringify({acquirer: {data: '', signature: ''}, menu: ''})}],
|
|
218
|
+
{...deployData, ...{script: "invalidScript"}}
|
|
219
|
+
)
|
|
220
|
+
expect(result.error).toBe("filename.js : ReferenceError: invalidScript is not defined")
|
|
221
|
+
expect(result.script).toBeUndefined()
|
|
222
|
+
expect(requestSpy).not.toHaveBeenCalled()
|
|
223
|
+
expect(emitSpy).not.toHaveBeenCalled()
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
// Success : prepare script for BizA Client
|
|
227
|
+
emitSpy.mockReset()
|
|
228
|
+
const validScript = "get = function () {return {tableName: ''}}"
|
|
229
|
+
result = await onScriptChangeFromVsCode(
|
|
230
|
+
serverSideSock,
|
|
231
|
+
'https://mock.server.com',
|
|
232
|
+
[{'SYS$APPS.APPNAME': 'app', "SYS$APPS.METADATA": JSON.stringify({acquirer: {data: '', signature: ''}, menu: ''})}],
|
|
233
|
+
{...deployData, ...{script: validScript}}
|
|
234
|
+
)
|
|
235
|
+
expect(requestSpy).toHaveBeenCalledWith({
|
|
236
|
+
timeout: 30*1000,
|
|
237
|
+
baseURL: 'https://mock.server.com',
|
|
238
|
+
url: 'api/acquirerKey',
|
|
239
|
+
method: "POST",
|
|
240
|
+
data : {"metadata": JSON.stringify({data: '', signature: ''})}
|
|
241
|
+
})
|
|
242
|
+
expect(result.error).toBe(null)
|
|
243
|
+
|
|
244
|
+
const cipherText = Buffer.from(result.script, 'base64')
|
|
245
|
+
const decipher = createDecipheriv('aes-256-cbc', mockAESKey, cipherText.subarray(0, 16))
|
|
246
|
+
const decryptedScript = Buffer.concat([decipher.update(cipherText.subarray(16)), decipher.final()]).toString()
|
|
247
|
+
expect(decryptedScript).toBe('{"tableName":""}')
|
|
248
|
+
|
|
249
|
+
expect(emitSpy).toHaveBeenCalledTimes(1)
|
|
250
|
+
expect(emitSpy).toHaveBeenCalledWith('scriptDeploy', {appName: 'app', fileName: 'filename.js', script: result.script})
|
|
251
|
+
}
|
|
252
|
+
finally {
|
|
253
|
+
freeSocketClient(vsCodeToCLISock)
|
|
254
|
+
if (broadcastSpy) broadcastSpy.mockRestore()
|
|
255
|
+
}
|
|
256
|
+
})
|
|
257
|
+
|
|
258
|
+
it('shall have "scriptChange" listener', async ()=>{
|
|
259
|
+
let vsCodeToCLISock;
|
|
260
|
+
try {
|
|
261
|
+
jest.spyOn(console, 'log').mockImplementation()
|
|
262
|
+
vsCodeToCLISock = await toPromise((resolve)=>{
|
|
263
|
+
const sock = ioClient(`http://${hostname}:${port}`, {query: {isDeploy:true}}).on('connect', ()=>{resolve(sock)})
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
const requestSpy = jest.spyOn(axios, 'request');
|
|
267
|
+
requestSpy.mockResolvedValueOnce({
|
|
268
|
+
status: 200,
|
|
269
|
+
statusText: 'Success',
|
|
270
|
+
data: {
|
|
271
|
+
"recordsTotal": 2,
|
|
272
|
+
data: JSON.stringify([
|
|
273
|
+
{'SYS$APPS.APPNAME': 'firstApp', "SYS$APPS.METADATA": {acquirer: {data: '', signature: ''}, menu: ''}},
|
|
274
|
+
{'SYS$APPS.APPNAME': 'secondApp', "SYS$APPS.METADATA": {acquirer: {data: '', signature: ''}, menu: ''}},
|
|
275
|
+
])
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
const [error, script] = await toPromise(resolve => {vsCodeToCLISock.emit('scriptChange', {appName: 'firstApp', fileName: 'filename.js', script: ""}, (err, data)=>{resolve([err, data])})});
|
|
280
|
+
expect(error).toBe("filename.js : Failed to compile template script.\nPlease make sure the script is correct and not returning empty result");
|
|
281
|
+
expect(script).toBeNull();
|
|
282
|
+
}
|
|
283
|
+
finally {
|
|
284
|
+
freeSocketClient(vsCodeToCLISock);
|
|
285
|
+
};
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
describe('from Hub Server', ()=>{
|
|
291
|
+
|
|
292
|
+
it('shall prepare deploy script', async ()=>{
|
|
293
|
+
let result;
|
|
294
|
+
|
|
295
|
+
const mockAESKey = Buffer.from('hAnHadaJXJaq/9fCFMNmjkrB61CBPXJid6vbtXgG8Ug=', 'base64')
|
|
296
|
+
const requestSpy = jest.spyOn(axios, 'request').mockResolvedValue({status: 200, statusText: 'Success', data: mockAESKey})
|
|
297
|
+
const deployData = {appName: 'app', fileName: 'filename.js', script: "put script here for testing"}
|
|
298
|
+
|
|
299
|
+
// Failed of empty script
|
|
300
|
+
result = await onScriptChangeFromHubServer(
|
|
301
|
+
'https://mock.server.com',
|
|
302
|
+
[{'SYS$APPS.APPNAME': 'app', "SYS$APPS.METADATA": JSON.stringify({acquirer: {data: '', signature: ''}, menu: ''})}],
|
|
303
|
+
{...deployData, ...{script: ""}}
|
|
304
|
+
)
|
|
305
|
+
expect(result.error).toBe("filename.js : Failed to compile template script.\nPlease make sure the script is correct and not returning empty result")
|
|
306
|
+
expect(result.script).toBeUndefined()
|
|
307
|
+
expect(requestSpy).not.toHaveBeenCalled()
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
// Failed of invalid script syntax
|
|
311
|
+
result = await onScriptChangeFromHubServer(
|
|
312
|
+
'https://mock.server.com',
|
|
313
|
+
[{'SYS$APPS.APPNAME': 'app', "SYS$APPS.METADATA": JSON.stringify({acquirer: {data: '', signature: ''}, menu: ''})}],
|
|
314
|
+
{...deployData, ...{script: "invalidScript"}}
|
|
315
|
+
)
|
|
316
|
+
expect(result.error).toBe("filename.js : ReferenceError: invalidScript is not defined")
|
|
317
|
+
expect(result.script).toBeUndefined()
|
|
318
|
+
expect(requestSpy).not.toHaveBeenCalled()
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
// Success : prepare script for BizA Client
|
|
322
|
+
const validScript = "get = function () {return {tableName: ''}}"
|
|
323
|
+
result = await onScriptChangeFromHubServer(
|
|
324
|
+
'https://mock.server.com',
|
|
325
|
+
[{'SYS$APPS.APPNAME': 'app', "SYS$APPS.METADATA": JSON.stringify({acquirer: {data: '', signature: ''}, menu: ''})}],
|
|
326
|
+
{...deployData, ...{script: validScript}}
|
|
327
|
+
)
|
|
328
|
+
expect(requestSpy).toHaveBeenCalledWith({
|
|
329
|
+
timeout: 30*1000,
|
|
330
|
+
baseURL: 'https://mock.server.com',
|
|
331
|
+
url: 'api/acquirerKey',
|
|
332
|
+
method: "POST",
|
|
333
|
+
data : {"metadata": JSON.stringify({data: '', signature: ''})}
|
|
334
|
+
})
|
|
335
|
+
expect(result.error).toBe(null)
|
|
336
|
+
|
|
337
|
+
const cipherText = Buffer.from(result.script, 'base64')
|
|
338
|
+
const decipher = createDecipheriv('aes-256-cbc', mockAESKey, cipherText.subarray(0, 16))
|
|
339
|
+
const decryptedScript = Buffer.concat([decipher.update(cipherText.subarray(16)), decipher.final()]).toString()
|
|
340
|
+
expect(decryptedScript).toBe('{"tableName":""}')
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
it('shall have "scriptChange Listener"', ()=>{
|
|
344
|
+
const sock = new Socket(new Manager('', {autoConnect: false}), '');
|
|
345
|
+
hubEvent(sock, {subdomain, hostname, port, secure: false, dbindex, server: 'mockServer'}, ()=>{});
|
|
346
|
+
expect(sock.listeners('scriptChange').length).toBe(1);
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
})
|
package/tests/hub.test.js
CHANGED
|
@@ -236,13 +236,14 @@ describe('Hub event tests', () => {
|
|
|
236
236
|
cliSocketServer = new ioServer(9999)// mocking of CLI socket server
|
|
237
237
|
directHubEvent(cliSocketServer, {subdomain, hostname: apiAddress, port, secure: false})
|
|
238
238
|
|
|
239
|
-
clientToCliSocket = ioClient('http://localhost:9999')
|
|
239
|
+
clientToCliSocket = ioClient('http://localhost:9999', {query: {isClient:true}})
|
|
240
240
|
})
|
|
241
241
|
|
|
242
|
-
afterAll(()=>{
|
|
242
|
+
afterAll(async ()=>{
|
|
243
243
|
freeSocketClient(clientToCliSocket)
|
|
244
244
|
if (cliSocketServer) {
|
|
245
|
-
cliSocketServer.
|
|
245
|
+
await cliSocketServer.of('').sockets.forEach((sock)=>sock.removeAllListeners())
|
|
246
|
+
await cliSocketServer.close()
|
|
246
247
|
}
|
|
247
248
|
})
|
|
248
249
|
|
|
@@ -259,7 +260,7 @@ describe('Hub event tests', () => {
|
|
|
259
260
|
clientToCliSocket.emit(
|
|
260
261
|
'apiRequest'
|
|
261
262
|
, {subDomain: subdomain, method: 'POST', path: '/test', headers: {'req-header': 'aa'}, body: 'body of request', responseType: 'json'}
|
|
262
|
-
, (
|
|
263
|
+
, (err, res)=>{resolve([err, res])}
|
|
263
264
|
)
|
|
264
265
|
})
|
|
265
266
|
|
|
@@ -300,7 +301,7 @@ describe('Hub event tests', () => {
|
|
|
300
301
|
clientToCliSocket.emit(
|
|
301
302
|
'apiRequest'
|
|
302
303
|
, {subDomain: subdomain, method: 'POST', path: '/test', headers: {'req-header': 'aa'}, body: 'body of request', responseType: 'arraybuffer'}
|
|
303
|
-
, (
|
|
304
|
+
, (err, res)=>{resolve([err, res])}
|
|
304
305
|
)
|
|
305
306
|
})
|
|
306
307
|
|
|
@@ -326,7 +327,7 @@ describe('Hub event tests', () => {
|
|
|
326
327
|
clientToCliSocket.emit(
|
|
327
328
|
'apiRequest'
|
|
328
329
|
, {subDomain: 'wrong subdomain', method: 'POST', path: '/test', headers: {'req-header': 'aa'}, body: 'body of request'}
|
|
329
|
-
, (
|
|
330
|
+
, (err, res)=>{resolve([err, res])}
|
|
330
331
|
)
|
|
331
332
|
})
|
|
332
333
|
|
|
@@ -376,7 +377,7 @@ describe('Hub event tests', () => {
|
|
|
376
377
|
hubToCLISocket.emit(
|
|
377
378
|
'apiRequest'
|
|
378
379
|
, {subDomain: subdomain, method: 'POST', path: '/test', headers: {'req-header': 'aa'}, body: reqData, responseType: 'json'}
|
|
379
|
-
, (
|
|
380
|
+
, (err, res)=>{resolve([err, res])}
|
|
380
381
|
)
|
|
381
382
|
})
|
|
382
383
|
return {error, response}
|