biz-a-cli 2.3.2 → 2.3.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/bin/hub.js +24 -60
- package/bin/hubEvent.js +72 -0
- package/bin/watcher.js +49 -0
- package/callbackController.js +19 -0
- package/constanta.js +8 -0
- package/envs/env.dev.js +10 -0
- package/envs/env.js +10 -0
- package/mailController.js +26 -0
- package/package.json +27 -7
- package/scheduler/configController.js +106 -0
- package/scheduler/converter.js +84 -0
- package/scheduler/datalib.js +200 -0
- package/scheduler/timer.js +83 -0
- package/scheduler/watcherController.js +105 -0
- package/scheduler/watcherlib.js +105 -0
- package/tests/converter.test.js +99 -0
- package/tests/data.test.js +80 -0
- package/tests/hub.test.js +87 -0
- package/tests/mailCtl.test.js +34 -0
- package/tests/timer.test.js +91 -0
- package/tests/watcher.test.js +350 -0
- package/tests/watcherCtl.test.js +128 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { Server } from 'socket.io';
|
|
2
|
+
import { createServer } from 'node:http'
|
|
3
|
+
import hubEvent from '../bin/hubEvent.js'
|
|
4
|
+
import { io as ioc } from "socket.io-client";
|
|
5
|
+
import { jest } from '@jest/globals';
|
|
6
|
+
import { of } from "rxjs";
|
|
7
|
+
import { Axios } from "axios-observable";
|
|
8
|
+
|
|
9
|
+
let socketsBySubdomain = {};
|
|
10
|
+
|
|
11
|
+
const createSocket2CLI = (socket) => {
|
|
12
|
+
return (subdomain, responseCb) => {
|
|
13
|
+
const responseCallback = (error) => { if (responseCb) responseCb(error) }
|
|
14
|
+
let subdomainStr = subdomain.toString();
|
|
15
|
+
|
|
16
|
+
socketsBySubdomain[subdomainStr] = socket;
|
|
17
|
+
socket.subdomain = subdomainStr;
|
|
18
|
+
// console.log(new Date() + ': ' + subdomainStr + ' registered successfully');
|
|
19
|
+
|
|
20
|
+
responseCallback(null);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const deleteSubdomain = (socket) => () => {
|
|
25
|
+
if (socket.subdomain) {
|
|
26
|
+
delete socketsBySubdomain[socket.subdomain];
|
|
27
|
+
console.log(new Date() + ': ' + socket.subdomain + ' unregistered');
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const toPromise = (cb) => new Promise((resolve, reject) => {
|
|
32
|
+
cb(resolve)
|
|
33
|
+
setTimeout(() => reject(new Error('timeout')), 1000)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
describe('cli req test', () => {
|
|
37
|
+
let io, port;
|
|
38
|
+
const startSocket = function startSocket(server) {
|
|
39
|
+
let io = new Server(server);
|
|
40
|
+
io.on('connection', (socket) => {
|
|
41
|
+
// console.log('socket client connect')
|
|
42
|
+
socket.on('createTunnel', createSocket2CLI(socket));
|
|
43
|
+
socket.on('disconnect', deleteSubdomain(socket));
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
return io;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
beforeAll((done) => {
|
|
50
|
+
const httpServer = createServer()
|
|
51
|
+
io = startSocket(httpServer)
|
|
52
|
+
|
|
53
|
+
httpServer.listen(async () => {
|
|
54
|
+
port = httpServer.address().port;
|
|
55
|
+
done()
|
|
56
|
+
})
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
afterAll(() => {
|
|
60
|
+
io.close();
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
test('request to cli', async () => {
|
|
64
|
+
jest.spyOn(Axios, 'request').mockReturnValue(of({ data: 'OK' }));
|
|
65
|
+
|
|
66
|
+
let socket;
|
|
67
|
+
try {
|
|
68
|
+
socket = ioc(`http://localhost:${port}`);
|
|
69
|
+
|
|
70
|
+
await hubEvent(socket, {
|
|
71
|
+
server: `http://localhost:${port}`,
|
|
72
|
+
subdomain: 'scy',
|
|
73
|
+
hostname: 'localhost',
|
|
74
|
+
port: 212,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const result = await toPromise(resolve => socketsBySubdomain['scy'].emit(
|
|
78
|
+
'cli-req', { d: 1, }, cb => resolve(cb)
|
|
79
|
+
))
|
|
80
|
+
|
|
81
|
+
expect(result).toStrictEqual('OK');
|
|
82
|
+
socket.disconnect();
|
|
83
|
+
} catch (error) {
|
|
84
|
+
console.log(error);
|
|
85
|
+
}
|
|
86
|
+
})
|
|
87
|
+
})
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
|
|
2
|
+
import { jest } from '@jest/globals'
|
|
3
|
+
|
|
4
|
+
const mockSendMail = jest.fn();
|
|
5
|
+
const mockCreateTransport = jest.fn();
|
|
6
|
+
mockCreateTransport.mockImplementation(() => ({
|
|
7
|
+
sendMail: mockSendMail
|
|
8
|
+
}))
|
|
9
|
+
|
|
10
|
+
jest.unstable_mockModule('nodemailer', () => ({
|
|
11
|
+
createTransport: (data) => mockCreateTransport(data)
|
|
12
|
+
}))
|
|
13
|
+
|
|
14
|
+
const { sendMailWatcher } = await import('../mailController.js');
|
|
15
|
+
|
|
16
|
+
describe('Mail Controller', () => {
|
|
17
|
+
let req;
|
|
18
|
+
|
|
19
|
+
test('transporter.sendmailWatcher is called', () => {
|
|
20
|
+
req = {
|
|
21
|
+
body: {
|
|
22
|
+
companyname: 'abc',
|
|
23
|
+
smtpConfig: {
|
|
24
|
+
smtp: 'test'
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
sendMailWatcher(req);
|
|
30
|
+
expect(mockSendMail).toBeCalledTimes(1);
|
|
31
|
+
expect(mockCreateTransport).toHaveBeenCalledWith({ smtp: 'test' });
|
|
32
|
+
|
|
33
|
+
})
|
|
34
|
+
})
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { jest } from '@jest/globals'
|
|
2
|
+
|
|
3
|
+
const mockCheckSchedule = jest.fn();
|
|
4
|
+
jest.unstable_mockModule("../scheduler/datalib.js", () => ({
|
|
5
|
+
checkSchedule: mockCheckSchedule.mockResolvedValue('OK'),
|
|
6
|
+
queryData: jest.fn().mockResolvedValue('OK'),
|
|
7
|
+
crudData: jest.fn().mockResolvedValue('OK'),
|
|
8
|
+
genId: jest.fn().mockResolvedValue('OK'),
|
|
9
|
+
delay: jest.fn().mockResolvedValue('OK')
|
|
10
|
+
}))
|
|
11
|
+
|
|
12
|
+
const {
|
|
13
|
+
SCHEDULE_INTERVAL,
|
|
14
|
+
getSelectedData,
|
|
15
|
+
increaseInterval,
|
|
16
|
+
runHistory
|
|
17
|
+
} = await import('../scheduler/timer.js');
|
|
18
|
+
const { ObjectId } = await import('mongodb');
|
|
19
|
+
|
|
20
|
+
describe('timer and mitigation test', () => {
|
|
21
|
+
test('increase interval', async () => {
|
|
22
|
+
const nextTime = increaseInterval('2024-02-16T10:30:10.593Z');
|
|
23
|
+
expect(new Date(nextTime).toISOString()).toStrictEqual('2024-02-16T10:31:10.593Z');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test('get selected data from array', async () => {
|
|
27
|
+
const SELECTED_HISTORY = {
|
|
28
|
+
_id: new ObjectId('65c34df55e7c9d9448804738'),
|
|
29
|
+
timerObjectId: new ObjectId('65c34bd774ae2595b5efb5a9'),
|
|
30
|
+
latestRun: '2024-02-03T10:30:10.593Z'
|
|
31
|
+
};
|
|
32
|
+
const HISTORIES = [
|
|
33
|
+
{
|
|
34
|
+
_id: new ObjectId('65c34df55e7c9d9448804737'),
|
|
35
|
+
timerObjectId: new ObjectId('65c34bd774ae2595b5efb5a8'),
|
|
36
|
+
latestRun: '2024-02-16T10:30:10.593Z'
|
|
37
|
+
},
|
|
38
|
+
SELECTED_HISTORY,
|
|
39
|
+
{
|
|
40
|
+
_id: new ObjectId('65c3613d5e7c9d94489a32d2'),
|
|
41
|
+
timerObjectId: new ObjectId('65c35aa937be3a626388ba6e'),
|
|
42
|
+
latestRun: '2024-02-04T11:00:26.783Z'
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
expect(getSelectedData(HISTORIES, 'timerObjectId', '65c34bd774ae2595b5efb5a9')).toStrictEqual(SELECTED_HISTORY);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test('run history', async () => {
|
|
49
|
+
function decreaseInterval(now) {
|
|
50
|
+
const subtractInterval = new Date(now).getMilliseconds() - (3 * SCHEDULE_INTERVAL);
|
|
51
|
+
return new Date(now).setMilliseconds(subtractInterval);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const NOW = new Date('2024-02-29T07:00:00.000Z');
|
|
55
|
+
const HISTORIES = [
|
|
56
|
+
{
|
|
57
|
+
_id: new ObjectId('65c34df55e7c9d9448804737'),
|
|
58
|
+
timerObjectId: new ObjectId('65c34bd774ae2595b5efb5a8'),
|
|
59
|
+
latestRun: new Date(decreaseInterval(NOW)).toISOString()
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
const CONFIGS = [{
|
|
63
|
+
companyObjectId: new ObjectId('62948492f7d559fba6f32196')
|
|
64
|
+
}]
|
|
65
|
+
const WATCHERS = [
|
|
66
|
+
{
|
|
67
|
+
_id: new ObjectId('65c34bd674ae2595b5efb5a7'),
|
|
68
|
+
companyObjectId: new ObjectId('62948492f7d559fba6f32196'),
|
|
69
|
+
timer: [
|
|
70
|
+
{
|
|
71
|
+
_id: new ObjectId('65c34bd774ae2595b5efb5a8'),
|
|
72
|
+
name: 'New Watcher 1',
|
|
73
|
+
active: true,
|
|
74
|
+
timezone: 'Asia/Jakarta',
|
|
75
|
+
templateName: 'cekUser.js',
|
|
76
|
+
daily: [
|
|
77
|
+
0, 1, 2, 3,
|
|
78
|
+
4, 5, 6
|
|
79
|
+
],
|
|
80
|
+
minutely: { everyMin: 1, from: '09:00', to: '18:00' },
|
|
81
|
+
watcherObjectId: new ObjectId('65c34bd674ae2595b5efb5a7'),
|
|
82
|
+
seq: 0,
|
|
83
|
+
}
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
await runHistory(HISTORIES, CONFIGS, WATCHERS, new Date('2024-02-29T07:00:00.000Z'));
|
|
89
|
+
expect(mockCheckSchedule).toBeCalledTimes(3);
|
|
90
|
+
});
|
|
91
|
+
})
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
import { isItTime, loopTimer } from "../scheduler/watcherlib.js"
|
|
2
|
+
|
|
3
|
+
describe('isItTime', () => {
|
|
4
|
+
// Note: 2023-11-6 is Monday
|
|
5
|
+
|
|
6
|
+
test('1 daily 1 day 1 hourly', () => {
|
|
7
|
+
let dataWatcher = {
|
|
8
|
+
active: true,
|
|
9
|
+
daily: [1],
|
|
10
|
+
hourly: ['10:15']
|
|
11
|
+
}
|
|
12
|
+
expect(isItTime(dataWatcher, '2023-11-5 10:15:59')).toBe(false)
|
|
13
|
+
expect(isItTime(dataWatcher, '2023-11-7 10:15:59')).toBe(false)
|
|
14
|
+
expect(isItTime(dataWatcher, '2023-11-6 10:15:59')).toBe(true)
|
|
15
|
+
expect(isItTime(dataWatcher, '2023-11-6 10:15:01')).toBe(true)
|
|
16
|
+
expect(isItTime(dataWatcher, '2023-11-6 10:14:59')).toBe(false)
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test('1 daily 1 day 2 hourly', () => {
|
|
20
|
+
let dataWatcher = {
|
|
21
|
+
active: true,
|
|
22
|
+
daily: [1],
|
|
23
|
+
hourly: ['10:15', '1:05']
|
|
24
|
+
}
|
|
25
|
+
expect(isItTime(dataWatcher, '2023-11-6 1:05:01')).toBe(true)
|
|
26
|
+
expect(isItTime(dataWatcher, '2023-11-6 1:04:01')).toBe(false)
|
|
27
|
+
expect(isItTime(dataWatcher, '2023-11-5 1:05:01')).toBe(false)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
test('1 daily 3 days 2 hourly', () => {
|
|
31
|
+
let dataWatcher = {
|
|
32
|
+
active: true,
|
|
33
|
+
daily: [1, 3, 5],
|
|
34
|
+
hourly: ['9:05', '17:05']
|
|
35
|
+
}
|
|
36
|
+
expect(isItTime(dataWatcher, '2023-11-6 9:05:01')).toBe(true)
|
|
37
|
+
expect(isItTime(dataWatcher, '2023-11-6 9:04:59')).toBe(false)
|
|
38
|
+
expect(isItTime(dataWatcher, '2023-11-6 9:06:01')).toBe(false)
|
|
39
|
+
expect(isItTime(dataWatcher, '2023-11-6 17:05:01')).toBe(true)
|
|
40
|
+
expect(isItTime(dataWatcher, '2023-11-6 17:04:59')).toBe(false)
|
|
41
|
+
expect(isItTime(dataWatcher, '2023-11-6 17:06:01')).toBe(false)
|
|
42
|
+
|
|
43
|
+
expect(isItTime(dataWatcher, '2023-11-8 9:05:01')).toBe(true)
|
|
44
|
+
expect(isItTime(dataWatcher, '2023-11-8 9:04:59')).toBe(false)
|
|
45
|
+
expect(isItTime(dataWatcher, '2023-11-8 9:06:01')).toBe(false)
|
|
46
|
+
expect(isItTime(dataWatcher, '2023-11-8 17:05:59')).toBe(true)
|
|
47
|
+
expect(isItTime(dataWatcher, '2023-11-8 17:04:59')).toBe(false)
|
|
48
|
+
expect(isItTime(dataWatcher, '2023-11-8 17:06:01')).toBe(false)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
expect(isItTime(dataWatcher, '2023-11-10 9:05:01')).toBe(true)
|
|
52
|
+
expect(isItTime(dataWatcher, '2023-11-10 17:05:01')).toBe(true)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
expect(isItTime(dataWatcher, '2023-11-5 17:05:01')).toBe(false)
|
|
56
|
+
expect(isItTime(dataWatcher, '2023-11-7 17:05:01')).toBe(false)
|
|
57
|
+
expect(isItTime(dataWatcher, '2023-11-9 17:05:01')).toBe(false)
|
|
58
|
+
expect(isItTime(dataWatcher, '2023-11-11 17:05:01')).toBe(false)
|
|
59
|
+
|
|
60
|
+
expect(isItTime(dataWatcher, '2023-11-13 17:05:01')).toBe(true)
|
|
61
|
+
expect(isItTime(dataWatcher, '2023-11-14 17:05:01')).toBe(false)
|
|
62
|
+
expect(isItTime(dataWatcher, '2023-11-15 17:05:01')).toBe(true)
|
|
63
|
+
expect(isItTime(dataWatcher, '2023-11-16 17:05:01')).toBe(false)
|
|
64
|
+
expect(isItTime(dataWatcher, '2023-11-17 17:05:01')).toBe(true)
|
|
65
|
+
expect(isItTime(dataWatcher, '2023-11-18 17:05:01')).toBe(false)
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
test('1 daily 1 days 1 hourly data incomplete', () => {
|
|
69
|
+
let dataWatcher = {
|
|
70
|
+
active: true,
|
|
71
|
+
daily: [1],
|
|
72
|
+
hourly: '9:05'
|
|
73
|
+
}
|
|
74
|
+
expect(isItTime(dataWatcher, '2023-11-6 9:05:01')).toBe(false)
|
|
75
|
+
dataWatcher.hourly = ['9:05']
|
|
76
|
+
expect(isItTime(dataWatcher, '2023-11-6 9:05:01')).toBe(true)
|
|
77
|
+
|
|
78
|
+
// dataWatcher[0].time = {}
|
|
79
|
+
// expect(isItTime(dataWatcher, '2023-11-6 9:05:01')).toBe(false)
|
|
80
|
+
// dataWatcher[0].time = { hourly: ['9:05'] }
|
|
81
|
+
// dataWatcher[0].hourly = ['9:05'];
|
|
82
|
+
// expect(isItTime(dataWatcher, '2023-11-6 9:05:01')).toBe(true)
|
|
83
|
+
|
|
84
|
+
dataWatcher.daily = 1
|
|
85
|
+
expect(isItTime(dataWatcher, '2023-11-6 9:05:01')).toBe(false)
|
|
86
|
+
dataWatcher.daily = [1]
|
|
87
|
+
expect(isItTime(dataWatcher, '2023-11-6 9:05:01')).toBe(true)
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
test('1 daily 1 day everyMin', () => {
|
|
91
|
+
let dataWatcher = {
|
|
92
|
+
active: true,
|
|
93
|
+
daily: [2],
|
|
94
|
+
minutely: {
|
|
95
|
+
everyMin: 5,
|
|
96
|
+
from: '9:00',
|
|
97
|
+
to: '17:00'
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
expect(isItTime(dataWatcher, '2023-11-7 9:00:01')).toBe(true)
|
|
101
|
+
expect(isItTime(dataWatcher, '2023-11-7 9:05:01')).toBe(true)
|
|
102
|
+
expect(isItTime(dataWatcher, '2023-11-7 17:00:01')).toBe(true)
|
|
103
|
+
expect(isItTime(dataWatcher, '2023-11-7 16:55:59')).toBe(true)
|
|
104
|
+
expect(isItTime(dataWatcher, '2023-11-7 8:59:59')).toBe(false)
|
|
105
|
+
expect(isItTime(dataWatcher, '2023-11-7 9:01:59')).toBe(false)
|
|
106
|
+
expect(isItTime(dataWatcher, '2023-11-7 9:04:59')).toBe(false)
|
|
107
|
+
expect(isItTime(dataWatcher, '2023-11-7 9:06:01')).toBe(false)
|
|
108
|
+
expect(isItTime(dataWatcher, '2023-11-7 17:01:00')).toBe(false)
|
|
109
|
+
|
|
110
|
+
dataWatcher.minutely.everyMin = 7
|
|
111
|
+
expect(isItTime(dataWatcher, '2023-11-7 9:00:00')).toBe(true)
|
|
112
|
+
expect(isItTime(dataWatcher, '2023-11-7 9:07:01')).toBe(true)
|
|
113
|
+
expect(isItTime(dataWatcher, '2023-11-7 9:14:59')).toBe(true)
|
|
114
|
+
expect(isItTime(dataWatcher, '2023-11-7 9:21:32')).toBe(true)
|
|
115
|
+
expect(isItTime(dataWatcher, '2023-11-7 9:28:32')).toBe(true)
|
|
116
|
+
expect(isItTime(dataWatcher, '2023-11-7 9:35:32')).toBe(true)
|
|
117
|
+
expect(isItTime(dataWatcher, '2023-11-7 9:42:32')).toBe(true)
|
|
118
|
+
expect(isItTime(dataWatcher, '2023-11-7 9:49:32')).toBe(true)
|
|
119
|
+
expect(isItTime(dataWatcher, '2023-11-7 9:56:32')).toBe(true)
|
|
120
|
+
expect(isItTime(dataWatcher, '2023-11-7 10:00:32')).toBe(true)
|
|
121
|
+
expect(isItTime(dataWatcher, '2023-11-7 10:07:32')).toBe(true)
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
test('1 weekly 1 day', () => {
|
|
125
|
+
let dataWatcher = {
|
|
126
|
+
active: true,
|
|
127
|
+
weekly: {
|
|
128
|
+
ordinal: [1],
|
|
129
|
+
days: [2]
|
|
130
|
+
},
|
|
131
|
+
hourly: ['9:01']
|
|
132
|
+
} //every first Tuesday at 9:01
|
|
133
|
+
|
|
134
|
+
expect(isItTime(dataWatcher, '2023-11-7 9:01:01')).toBe(true)
|
|
135
|
+
expect(isItTime(dataWatcher, '2023-11-14 9:01:01')).toBe(false)
|
|
136
|
+
|
|
137
|
+
dataWatcher.weekly.ordinal = [1, 3]
|
|
138
|
+
expect(isItTime(dataWatcher, '2023-11-21 9:01:01')).toBe(true)
|
|
139
|
+
expect(isItTime(dataWatcher, '2023-11-28 9:01:01')).toBe(false)
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
test('1 weekly 3 day', () => {
|
|
143
|
+
let dataWatcher = {
|
|
144
|
+
active: true,
|
|
145
|
+
weekly: {
|
|
146
|
+
ordinal: [1],
|
|
147
|
+
days: [1, 3, 5]
|
|
148
|
+
},
|
|
149
|
+
hourly: ['9:01']
|
|
150
|
+
} //every first Mon, Wed, Fri at 9:01
|
|
151
|
+
|
|
152
|
+
expect(isItTime(dataWatcher, '2023-11-1 9:01:01')).toBe(true)
|
|
153
|
+
expect(isItTime(dataWatcher, '2023-11-3 9:01:01')).toBe(true)
|
|
154
|
+
expect(isItTime(dataWatcher, '2023-11-6 9:01:01')).toBe(true)
|
|
155
|
+
expect(isItTime(dataWatcher, '2023-11-8 9:01:01')).toBe(false)
|
|
156
|
+
expect(isItTime(dataWatcher, '2023-11-10 9:01:01')).toBe(false)
|
|
157
|
+
expect(isItTime(dataWatcher, '2023-11-2 9:01:01')).toBe(false)
|
|
158
|
+
|
|
159
|
+
dataWatcher.weekly.ordinal = [1, 3]
|
|
160
|
+
expect(isItTime(dataWatcher, '2023-11-15 9:01:01')).toBe(true)
|
|
161
|
+
expect(isItTime(dataWatcher, '2023-11-17 9:01:01')).toBe(true)
|
|
162
|
+
expect(isItTime(dataWatcher, '2023-11-20 9:01:01')).toBe(true)
|
|
163
|
+
expect(isItTime(dataWatcher, '2023-11-22 9:01:01')).toBe(false)
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
test('weekly incorrect data', () => {
|
|
167
|
+
let dataWatcher = {
|
|
168
|
+
active: true,
|
|
169
|
+
weekly: {
|
|
170
|
+
ordinal: [1],
|
|
171
|
+
days: 1
|
|
172
|
+
},
|
|
173
|
+
hourly: ['9:01']
|
|
174
|
+
}
|
|
175
|
+
expect(isItTime(dataWatcher, '2023-11-1 9:01:01')).toBe(false)
|
|
176
|
+
|
|
177
|
+
dataWatcher.weekly.days = [1]
|
|
178
|
+
dataWatcher.weekly.ordinal = 1
|
|
179
|
+
expect(isItTime(dataWatcher, '2023-11-1 9:01:01')).toBe(false)
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
test('1 monthly', () => {
|
|
183
|
+
let dataWatcher = {
|
|
184
|
+
active: true,
|
|
185
|
+
monthly: [2],
|
|
186
|
+
minutely: {
|
|
187
|
+
everyMin: 10,
|
|
188
|
+
from: '9:00',
|
|
189
|
+
to: '17:00'
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
expect(isItTime(dataWatcher, '2023-11-2 9:00:01')).toBe(true)
|
|
193
|
+
expect(isItTime(dataWatcher, '2023-11-2 9:10:01')).toBe(true)
|
|
194
|
+
expect(isItTime(dataWatcher, '2023-11-2 16:50:01')).toBe(true)
|
|
195
|
+
expect(isItTime(dataWatcher, '2023-11-3 16:50:01')).toBe(false)
|
|
196
|
+
|
|
197
|
+
dataWatcher.monthly.push(15)
|
|
198
|
+
expect(isItTime(dataWatcher, '2023-11-15 16:50:01')).toBe(true)
|
|
199
|
+
expect(isItTime(dataWatcher, '2023-11-16 16:50:01')).toBe(false)
|
|
200
|
+
expect(isItTime(dataWatcher, '2023-11-14 16:50:01')).toBe(false)
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
test('eom monthly', () => {
|
|
204
|
+
let dataWatcher = {
|
|
205
|
+
active: true,
|
|
206
|
+
monthly: ['eom'],
|
|
207
|
+
minutely: {
|
|
208
|
+
everyMin: 10,
|
|
209
|
+
from: '9:00',
|
|
210
|
+
to: '17:00'
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
expect(isItTime(dataWatcher, '2023-11-2 9:00:01')).toBe(false)
|
|
214
|
+
expect(isItTime(dataWatcher, '2023-11-2 9:10:01')).toBe(false)
|
|
215
|
+
expect(isItTime(dataWatcher, '2023-11-2 16:50:01')).toBe(false)
|
|
216
|
+
expect(isItTime(dataWatcher, '2023-11-3 16:50:01')).toBe(false)
|
|
217
|
+
|
|
218
|
+
expect(isItTime(dataWatcher, '2023-11-30 9:00:01')).toBe(true)
|
|
219
|
+
expect(isItTime(dataWatcher, '2023-11-30 9:10:01')).toBe(true)
|
|
220
|
+
expect(isItTime(dataWatcher, '2023-11-30 16:50:01')).toBe(true)
|
|
221
|
+
|
|
222
|
+
expect(isItTime(dataWatcher, '2023-11-29 16:50:01')).toBe(false)
|
|
223
|
+
expect(isItTime(dataWatcher, '2023-12-1 16:50:01')).toBe(false)
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
test('1 monthly incorrect data', () => {
|
|
227
|
+
let dataWatcher = {
|
|
228
|
+
active: true,
|
|
229
|
+
monthly: 2,
|
|
230
|
+
minutely: {
|
|
231
|
+
everyMin: 10,
|
|
232
|
+
from: '9:00',
|
|
233
|
+
to: '17:00'
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
expect(isItTime(dataWatcher, '2023-11-15 16:50:01')).toBe(false)
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
test('1 monthly from to overlap', () => {
|
|
240
|
+
let dataWatcher = {
|
|
241
|
+
active: true,
|
|
242
|
+
monthly: [2],
|
|
243
|
+
minutely: {
|
|
244
|
+
everyMin: 10,
|
|
245
|
+
from: '09:00',
|
|
246
|
+
to: '08:00'
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
expect(isItTime(dataWatcher, '2023-11-2 9:00:01')).toBe(false);
|
|
250
|
+
expect(isItTime(dataWatcher, '2023-11-2 9:00:00')).toBe(false);
|
|
251
|
+
expect(isItTime(dataWatcher, '2023-11-2 8:59:59')).toBe(false);
|
|
252
|
+
expect(isItTime(dataWatcher, '2023-11-2 8:00:01')).toBe(false);
|
|
253
|
+
expect(isItTime(dataWatcher, '2023-11-2 8:00:00')).toBe(false);
|
|
254
|
+
expect(isItTime(dataWatcher, '2023-11-2 7:59:59')).toBe(false);
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
test('1 monthly from to overlap different day', () => {
|
|
258
|
+
let dataWatcher = {
|
|
259
|
+
active: true,
|
|
260
|
+
monthly: [2],
|
|
261
|
+
minutely: {
|
|
262
|
+
everyMin: 10,
|
|
263
|
+
from: '22:00',
|
|
264
|
+
to: '02:00'
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
expect(isItTime(dataWatcher, '2023-11-2 22:00:01')).toBe(false);
|
|
268
|
+
expect(isItTime(dataWatcher, '2023-11-2 22:00:00')).toBe(false);
|
|
269
|
+
expect(isItTime(dataWatcher, '2023-11-2 21:59:59')).toBe(false);
|
|
270
|
+
expect(isItTime(dataWatcher, '2023-11-2 2:00:01')).toBe(false);
|
|
271
|
+
expect(isItTime(dataWatcher, '2023-11-2 2:00:00')).toBe(false);
|
|
272
|
+
expect(isItTime(dataWatcher, '2023-11-2 1:59:59')).toBe(false);
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
test('watcher not active', () => {
|
|
276
|
+
let dataWatcher = {
|
|
277
|
+
active: false,
|
|
278
|
+
daily: [1],
|
|
279
|
+
hourly: ['10:15']
|
|
280
|
+
}
|
|
281
|
+
expect(isItTime(dataWatcher, '2023-11-5 10:15:59')).toBe(false)
|
|
282
|
+
expect(isItTime(dataWatcher, '2023-11-7 10:15:59')).toBe(false)
|
|
283
|
+
expect(isItTime(dataWatcher, '2023-11-6 10:15:59')).toBe(false)
|
|
284
|
+
expect(isItTime(dataWatcher, '2023-11-6 10:15:01')).toBe(false)
|
|
285
|
+
expect(isItTime(dataWatcher, '2023-11-6 10:14:59')).toBe(false)
|
|
286
|
+
})
|
|
287
|
+
|
|
288
|
+
test('Mix daily weekly monthly', () => {
|
|
289
|
+
let dataWatchers = [
|
|
290
|
+
{ //every sunday at 10:00
|
|
291
|
+
active: true,
|
|
292
|
+
daily: [0],
|
|
293
|
+
// time: { hourly: ['10:00'] }
|
|
294
|
+
hourly: ['10:00']
|
|
295
|
+
},
|
|
296
|
+
{ //or every first Monday at 9:00
|
|
297
|
+
active: true,
|
|
298
|
+
weekly: { ordinal: [1], days: [1] },
|
|
299
|
+
// time: { hourly: ['9:00'] }
|
|
300
|
+
hourly: ['9:00']
|
|
301
|
+
},
|
|
302
|
+
{ //or every 15th at 11:00
|
|
303
|
+
active: true,
|
|
304
|
+
monthly: [15],
|
|
305
|
+
// time: { hourly: ['11:00'] }
|
|
306
|
+
hourly: ['11:00']
|
|
307
|
+
}
|
|
308
|
+
]
|
|
309
|
+
|
|
310
|
+
let dummyConfig = { companyObjectId: '62948492f7d559fba6f32196' };
|
|
311
|
+
|
|
312
|
+
expect(loopTimer(dataWatchers, '2023-11-5 10:00:01', dummyConfig)).toStrictEqual([true, false, false])
|
|
313
|
+
expect(loopTimer(dataWatchers, '2023-11-12 10:00:01', dummyConfig)).toStrictEqual([true, false, false])
|
|
314
|
+
expect(loopTimer(dataWatchers, '2023-11-19 10:00:01', dummyConfig)).toStrictEqual([true, false, false])
|
|
315
|
+
expect(loopTimer(dataWatchers, '2023-11-26 10:00:01', dummyConfig)).toStrictEqual([true, false, false])
|
|
316
|
+
expect(loopTimer(dataWatchers, '2023-11-6 9:00:01', dummyConfig)).toStrictEqual([false, true, false])
|
|
317
|
+
expect(loopTimer(dataWatchers, '2023-11-15 11:00:01', dummyConfig)).toStrictEqual([false, false, true])
|
|
318
|
+
expect(loopTimer(dataWatchers, '2023-11-16 11:00:01', dummyConfig)).toStrictEqual([false, false, false])
|
|
319
|
+
expect(loopTimer(dataWatchers, '2023-11-13 9:00:01', dummyConfig)).toStrictEqual([false, false, false])
|
|
320
|
+
expect(loopTimer(dataWatchers, '2023-11-5 9:59:01', dummyConfig)).toStrictEqual([false, false, false])
|
|
321
|
+
})
|
|
322
|
+
|
|
323
|
+
test('watcher has timezone (UTC + 8) (UTC + 9)', () => {
|
|
324
|
+
let dataWatcher = [{
|
|
325
|
+
active: true,
|
|
326
|
+
timezone: 'Asia/Makassar',
|
|
327
|
+
daily: [1],
|
|
328
|
+
hourly: ['10:15']
|
|
329
|
+
}, {
|
|
330
|
+
active: true,
|
|
331
|
+
timezone: 'Asia/Jayapura',
|
|
332
|
+
daily: [1],
|
|
333
|
+
hourly: ['10:15']
|
|
334
|
+
}]
|
|
335
|
+
|
|
336
|
+
let dummyConfig = { companyObjectId: '62948492f7d559fba6f32196' };
|
|
337
|
+
|
|
338
|
+
expect(loopTimer(dataWatcher, '2023-11-5 8:15:59', dummyConfig)).toStrictEqual([false, false])
|
|
339
|
+
expect(loopTimer(dataWatcher, '2023-11-7 8:15:59', dummyConfig)).toStrictEqual([false, false])
|
|
340
|
+
expect(loopTimer(dataWatcher, '2023-11-6 8:15:59', dummyConfig)).toStrictEqual([false, true])
|
|
341
|
+
expect(loopTimer(dataWatcher, '2023-11-6 8:15:01', dummyConfig)).toStrictEqual([false, true])
|
|
342
|
+
expect(loopTimer(dataWatcher, '2023-11-6 8:14:59', dummyConfig)).toStrictEqual([false, false])
|
|
343
|
+
|
|
344
|
+
expect(loopTimer(dataWatcher, '2023-11-5 9:15:59', dummyConfig)).toStrictEqual([false, false])
|
|
345
|
+
expect(loopTimer(dataWatcher, '2023-11-7 9:15:59', dummyConfig)).toStrictEqual([false, false])
|
|
346
|
+
expect(loopTimer(dataWatcher, '2023-11-6 9:15:59', dummyConfig)).toStrictEqual([true, false])
|
|
347
|
+
expect(loopTimer(dataWatcher, '2023-11-6 9:15:01', dummyConfig)).toStrictEqual([true, false])
|
|
348
|
+
expect(loopTimer(dataWatcher, '2023-11-6 9:14:59', dummyConfig)).toStrictEqual([false, false])
|
|
349
|
+
})
|
|
350
|
+
})
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { jest } from '@jest/globals';
|
|
2
|
+
import { of } from "rxjs";
|
|
3
|
+
|
|
4
|
+
let mockQueryData = jest.fn();
|
|
5
|
+
let mockCrudData = jest.fn().mockImplementation(param => of(param));
|
|
6
|
+
|
|
7
|
+
jest.unstable_mockModule('../scheduler/datalib.js', () => ({
|
|
8
|
+
// queryData: jest.fn().mockReturnValue(of([{ history_id: '10' }])),
|
|
9
|
+
queryData: mockQueryData,
|
|
10
|
+
genId: jest.fn().mockReturnValue(of(20)),
|
|
11
|
+
crudData: mockCrudData
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
const {
|
|
15
|
+
getWatcherParameters,
|
|
16
|
+
getInsertHistoryParameters,
|
|
17
|
+
getHistoryParameters,
|
|
18
|
+
getHistoryField,
|
|
19
|
+
formatDate2API,
|
|
20
|
+
insertHistory
|
|
21
|
+
} = await import("../scheduler/watcherController.js");
|
|
22
|
+
|
|
23
|
+
describe('Get Watcher Parameters', () => {
|
|
24
|
+
test('get parameters', () => {
|
|
25
|
+
expect(getWatcherParameters()).toStrictEqual({
|
|
26
|
+
// filter: [{ junction: '', column: 'ID', operator: '=', value1: `'${watcherFilter?.companyObjectId}'` }],
|
|
27
|
+
columns: [
|
|
28
|
+
{ data: "SYS$WATCHER.ID", key: 'watcher_id' },
|
|
29
|
+
{ data: "SYS$WATCHER.COMPANY_OBJ_ID", key: 'company_id' },
|
|
30
|
+
{ data: "SYS$WATCHER.ID.WATCHER_ID.SYS$TIMER.ID", key: 'timer_id' },
|
|
31
|
+
{ data: "SYS$WATCHER.ID.WATCHER_ID.SYS$TIMER.WATCHER_ID", key: 'timer_watcher_id' },
|
|
32
|
+
{ data: "SYS$WATCHER.ID.WATCHER_ID.SYS$TIMER.NAME", key: 'name' },
|
|
33
|
+
{ data: "SYS$WATCHER.ID.WATCHER_ID.SYS$TIMER.ACTIVE", key: 'active' },
|
|
34
|
+
{ data: "SYS$WATCHER.ID.WATCHER_ID.SYS$TIMER.TIME_ZONE", key: 'timezone' },
|
|
35
|
+
{ data: "SYS$WATCHER.ID.WATCHER_ID.SYS$TIMER.SCRIPT_NAME", key: 'templateName' },
|
|
36
|
+
{ data: "SYS$WATCHER.ID.WATCHER_ID.SYS$TIMER.SEQ", key: 'seq' },
|
|
37
|
+
{ data: "SYS$WATCHER.ID.WATCHER_ID.SYS$TIMER.SCRIPT_ID", key: 'scriptId' },
|
|
38
|
+
{ data: "SYS$TIMER.ID.TIMER_ID.SYS$DAILY.DAYS", key: 'daily_days' },
|
|
39
|
+
{ data: "SYS$TIMER.ID.TIMER_ID.SYS$WEEKLY.ORDINAL", key: 'weekly_ordinal' },
|
|
40
|
+
{ data: "SYS$TIMER.ID.TIMER_ID.SYS$WEEKLY.DAYS", key: 'weekly_days' },
|
|
41
|
+
{ data: "SYS$TIMER.ID.TIMER_ID.SYS$MONTHLY.DAYS", key: 'monthly_days' },
|
|
42
|
+
{ data: "SYS$TIMER.ID.TIMER_ID.SYS$MINUTELY.EVERYMIN", key: 'minutely_everymin' },
|
|
43
|
+
{ data: "SYS$TIMER.ID.TIMER_ID.SYS$MINUTELY.TIME_FROM", key: 'minutely_time_from' },
|
|
44
|
+
{ data: "SYS$TIMER.ID.TIMER_ID.SYS$MINUTELY.TIME_TO", key: 'minutely_time_to' },
|
|
45
|
+
{ data: "SYS$TIMER.ID.TIMER_ID.SYS$HOURLY.HOURS", key: 'hourly_hours' },
|
|
46
|
+
{ data: "SYS$TIMER.SCRIPT_ID.ID.SYS$CLI_SCRIPT.SCRIPT", key: 'cli_script' }
|
|
47
|
+
]
|
|
48
|
+
});
|
|
49
|
+
})
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
describe('Get Insert History Parameters', () => {
|
|
53
|
+
test('get parameters', () => {
|
|
54
|
+
expect(getInsertHistoryParameters('abc')).toStrictEqual({
|
|
55
|
+
filter: [{
|
|
56
|
+
junction: '',
|
|
57
|
+
column: 'TIMER_ID',
|
|
58
|
+
operator: '=',
|
|
59
|
+
value1: "'abc'"
|
|
60
|
+
}],
|
|
61
|
+
columns: [
|
|
62
|
+
{ data: "HISTORY.ID", key: 'history_id' },
|
|
63
|
+
]
|
|
64
|
+
})
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
describe('Format Date to API', () => {
|
|
69
|
+
test('date conversion', () => {
|
|
70
|
+
expect(formatDate2API('2024-03-06T14:37:16.610Z')).toStrictEqual('2024-03-06 14:37:16.610');
|
|
71
|
+
})
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
describe('Get History Field', () => {
|
|
75
|
+
test('get field', () => {
|
|
76
|
+
expect(getHistoryField('345', 12, '2024-03-06T14:37:16.610Z')).toStrictEqual({
|
|
77
|
+
SYS$HISTORY: {
|
|
78
|
+
ID: 12,
|
|
79
|
+
TIMER_ID: parseInt('345'),
|
|
80
|
+
LATEST_RUN: '2024-03-06 14:37:16.610'
|
|
81
|
+
}
|
|
82
|
+
})
|
|
83
|
+
})
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
describe('Get History Parameters', () => {
|
|
87
|
+
test('get parameters', () => {
|
|
88
|
+
expect(getHistoryParameters()).toStrictEqual({
|
|
89
|
+
columns: [
|
|
90
|
+
{ data: "SYS$HISTORY.ID", key: 'history_id' },
|
|
91
|
+
{ data: "SYS$HISTORY.TIMER_ID", key: 'timer_id' },
|
|
92
|
+
{ data: "SYS$HISTORY.LATEST_RUN", key: 'latest_run' }
|
|
93
|
+
]
|
|
94
|
+
})
|
|
95
|
+
})
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
describe('Insert History', () => {
|
|
99
|
+
test('has history', () => {
|
|
100
|
+
mockQueryData.mockReturnValue(of([{ history_id: '10' }]));
|
|
101
|
+
|
|
102
|
+
insertHistory({}, '1', '2024-03-06T14:37:16.610Z');
|
|
103
|
+
expect(mockCrudData).toHaveBeenCalledWith(
|
|
104
|
+
{
|
|
105
|
+
"SYS$HISTORY": {
|
|
106
|
+
"ID": 10,
|
|
107
|
+
"LATEST_RUN": "2024-03-06 14:37:16.610",
|
|
108
|
+
"TIMER_ID": 1
|
|
109
|
+
}
|
|
110
|
+
}, {}, "put", "orm");
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
test('no history', () => {
|
|
114
|
+
jest.clearAllMocks();
|
|
115
|
+
mockQueryData.mockReturnValue(of([]));
|
|
116
|
+
|
|
117
|
+
insertHistory({}, '1', '2024-03-06T14:37:16.610Z');
|
|
118
|
+
expect(mockCrudData).toHaveBeenCalledWith(
|
|
119
|
+
{
|
|
120
|
+
"SYS$HISTORY": {
|
|
121
|
+
"ID": 20,
|
|
122
|
+
"LATEST_RUN": "2024-03-06 14:37:16.610",
|
|
123
|
+
"TIMER_ID": 1
|
|
124
|
+
}
|
|
125
|
+
}, {}, "put", "orm");
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
})
|