biz-a-cli 2.3.1 → 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 +44 -65
- package/bin/hubEvent.js +72 -0
- package/bin/index.js +67 -55
- package/bin/proxy.js +14 -11
- 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 +31 -10
- package/proxyController.js +83 -0
- 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,105 @@
|
|
|
1
|
+
import dayjs from 'dayjs';
|
|
2
|
+
import weekOfYear from 'dayjs/plugin/weekOfYear.js';
|
|
3
|
+
import utc from 'dayjs/plugin/utc.js';
|
|
4
|
+
import timezone from 'dayjs/plugin/timezone.js';
|
|
5
|
+
import { checkSchedule } from './datalib.js';
|
|
6
|
+
|
|
7
|
+
dayjs.extend(weekOfYear);
|
|
8
|
+
dayjs.extend(utc);
|
|
9
|
+
dayjs.extend(timezone);
|
|
10
|
+
|
|
11
|
+
const DEFAULT_DATE_FORMAT = 'YYYY-M-D H:mm:ss';
|
|
12
|
+
|
|
13
|
+
function isOnTime(watchTime, nowDate) {
|
|
14
|
+
if (watchTime.hourly) {
|
|
15
|
+
if (!Array.isArray(watchTime.hourly)) return false
|
|
16
|
+
// return watchTime.time.hourly.includes(nowDate.format('H:mm'))
|
|
17
|
+
return watchTime.hourly.includes(nowDate.format('H:mm'))
|
|
18
|
+
// } else if (watchTime.time.everyMin) {
|
|
19
|
+
} else if (watchTime.minutely.everyMin) {
|
|
20
|
+
const getTime = (jam) => {
|
|
21
|
+
let arr = jam.split(':')
|
|
22
|
+
return nowDate.set('hour', arr[0]).set('minute', arr[1])
|
|
23
|
+
}
|
|
24
|
+
if (nowDate.isBefore(getTime(watchTime.minutely.from), 'minute')) return false
|
|
25
|
+
if (nowDate.isAfter(getTime(watchTime.minutely.to), 'minute')) return false
|
|
26
|
+
return (nowDate.minute() % watchTime.minutely.everyMin) == 0
|
|
27
|
+
}
|
|
28
|
+
return false
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function getMonthlyWatcher(watchTime, nowDate) {
|
|
32
|
+
if (!Array.isArray(watchTime.monthly)) return false
|
|
33
|
+
// if (!watchTime.monthly.includes(nowDate.date())) return false
|
|
34
|
+
const eom = watchTime.monthly.includes('eom')
|
|
35
|
+
if (!watchTime.monthly.includes(nowDate.date()) && !eom) return false
|
|
36
|
+
if (eom && (dayjs(nowDate).daysInMonth() !== nowDate.date())) return false
|
|
37
|
+
|
|
38
|
+
return isOnTime(watchTime, nowDate)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function getWeeklyWatcher(watchTime, nowDate) {
|
|
42
|
+
if (!Array.isArray(watchTime.weekly.days)) return false
|
|
43
|
+
if (!Array.isArray(watchTime.weekly.ordinal)) return false
|
|
44
|
+
let weekOfMonth = Math.ceil(nowDate.date() / 7)
|
|
45
|
+
if (!watchTime.weekly.ordinal.includes(weekOfMonth)) return false
|
|
46
|
+
if (!watchTime.weekly.days.includes(nowDate.day())) return false
|
|
47
|
+
return isOnTime(watchTime, nowDate)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function getDailyWatcher(watchTime, nowDate) {
|
|
51
|
+
// if (!watchTime.time) return false
|
|
52
|
+
if (!Array.isArray(watchTime.daily)) return false
|
|
53
|
+
if (!watchTime.daily.includes(nowDate.day())) return false
|
|
54
|
+
return isOnTime(watchTime, nowDate)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function checkPerWatchTime(watchTime, nowDate) {
|
|
58
|
+
if (!watchTime.minutely && !watchTime.hourly) return false
|
|
59
|
+
|
|
60
|
+
if (watchTime.daily) {
|
|
61
|
+
return getDailyWatcher(watchTime, nowDate);
|
|
62
|
+
} else if (watchTime.weekly) {
|
|
63
|
+
return getWeeklyWatcher(watchTime, nowDate);
|
|
64
|
+
} else if (watchTime.monthly) {
|
|
65
|
+
return getMonthlyWatcher(watchTime, nowDate);
|
|
66
|
+
}
|
|
67
|
+
return false
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function setTimeZoneDate(now, timezone) {
|
|
71
|
+
return dayjs(now, DEFAULT_DATE_FORMAT).tz(timezone);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// export function isItTime(watchTimes, now) {
|
|
75
|
+
// nowDate = [];
|
|
76
|
+
|
|
77
|
+
// return watchTimes.reduce((result, watchTime, index) => {
|
|
78
|
+
// // nowDate.push(dayjs(now, DEFAULT_DATE_FORMAT).tz(watchTime.timezone));
|
|
79
|
+
|
|
80
|
+
// nowDate.push(setTimeZoneDate(now, watchTime.timezone));
|
|
81
|
+
// // return result || (watchTime.active ? checkPerWatchTime(watchTime, index) : false)
|
|
82
|
+
// return result || (watchTime.active ? checkPerWatchTime(watchTime, nowDate[index]) : false)
|
|
83
|
+
// }, false)
|
|
84
|
+
// }
|
|
85
|
+
|
|
86
|
+
export function isItTime(watchTime, now) {
|
|
87
|
+
const timeZoneDate = setTimeZoneDate(now, watchTime.timezone);
|
|
88
|
+
return (watchTime.active ? checkPerWatchTime(watchTime, timeZoneDate) : false);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// export async function loopTimer(watchTimes, now, companyObjectId, needCheckSchedule) {
|
|
92
|
+
export function loopTimer(watchTimes, now, selectedConfig, needCheckSchedule) {
|
|
93
|
+
// const selectedConfig = await getSelectedConfig(companyObjectId);
|
|
94
|
+
if (selectedConfig) {
|
|
95
|
+
return watchTimes.map(watchTime => {
|
|
96
|
+
const isRightTime = isItTime(watchTime, now);
|
|
97
|
+
if (isRightTime && needCheckSchedule) {
|
|
98
|
+
checkSchedule(selectedConfig, watchTime, true);
|
|
99
|
+
}
|
|
100
|
+
return isRightTime;
|
|
101
|
+
});
|
|
102
|
+
} else {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
const {
|
|
2
|
+
historyRecordToJson,
|
|
3
|
+
watcherRecordToJson
|
|
4
|
+
} = await import('../scheduler/converter.js');
|
|
5
|
+
|
|
6
|
+
describe('converter test', () => {
|
|
7
|
+
test('convert history record to json', async () => {
|
|
8
|
+
const data = [{
|
|
9
|
+
history_id: 1,
|
|
10
|
+
timer_id: 2,
|
|
11
|
+
latest_run: '01.03.2024, 14:43:27.899'
|
|
12
|
+
}]
|
|
13
|
+
expect(historyRecordToJson(data)).toStrictEqual([{
|
|
14
|
+
_id: 1,
|
|
15
|
+
timerObjectId: 2,
|
|
16
|
+
latestRun: new Date('2024-01-03T07:43:27.899Z')
|
|
17
|
+
}]);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test('convert watcher record to json', async () => {
|
|
21
|
+
const data = [{
|
|
22
|
+
watcher_id: 1,
|
|
23
|
+
company_id: '62948492f7d559fba6f32196',
|
|
24
|
+
timer_id: 1,
|
|
25
|
+
timer_watcher_id: 1,
|
|
26
|
+
name: 'New Watcher 1',
|
|
27
|
+
active: true,
|
|
28
|
+
timezone: 'Asia/Jakarta',
|
|
29
|
+
templateName: 'cekUser.js',
|
|
30
|
+
seq: 0,
|
|
31
|
+
daily_days: '0,1,2,3,4,5,6',
|
|
32
|
+
weekly_ordinal: '',
|
|
33
|
+
weekly_days: '',
|
|
34
|
+
monthly_days: '',
|
|
35
|
+
minutely_everymin: 1,
|
|
36
|
+
minutely_time_from: '08:00',
|
|
37
|
+
minutely_time_to: '22:00',
|
|
38
|
+
hourly_hours: '',
|
|
39
|
+
scriptId: 1,
|
|
40
|
+
cli_script: 'abc'
|
|
41
|
+
}, {
|
|
42
|
+
watcher_id: 1,
|
|
43
|
+
company_id: '62948492f7d559fba6f32196',
|
|
44
|
+
timer_id: 2,
|
|
45
|
+
timer_watcher_id: 1,
|
|
46
|
+
name: 'New Watcher 2',
|
|
47
|
+
active: true,
|
|
48
|
+
timezone: 'Asia/Makassar',
|
|
49
|
+
templateName: 'cekUser2.js',
|
|
50
|
+
seq: 1,
|
|
51
|
+
daily_days: '',
|
|
52
|
+
weekly_ordinal: '',
|
|
53
|
+
weekly_days: '',
|
|
54
|
+
monthly_days: '2,3',
|
|
55
|
+
minutely_everymin: 0,
|
|
56
|
+
minutely_time_from: '',
|
|
57
|
+
minutely_time_to: '',
|
|
58
|
+
hourly_hours: '12:00,13:00',
|
|
59
|
+
scriptId: 2,
|
|
60
|
+
cli_script: 'def'
|
|
61
|
+
}]
|
|
62
|
+
|
|
63
|
+
expect(watcherRecordToJson(data)).toStrictEqual([{
|
|
64
|
+
_id: 1,
|
|
65
|
+
companyObjectId: '62948492f7d559fba6f32196',
|
|
66
|
+
timer: [{
|
|
67
|
+
_id: 1,
|
|
68
|
+
watcherObjectId: 1,
|
|
69
|
+
name: 'New Watcher 1',
|
|
70
|
+
active: true,
|
|
71
|
+
timezone: 'Asia/Jakarta',
|
|
72
|
+
templateName: 'cekUser.js',
|
|
73
|
+
seq: 0,
|
|
74
|
+
daily: [0, 1, 2, 3, 4, 5, 6],
|
|
75
|
+
minutely: {
|
|
76
|
+
everyMin: 1,
|
|
77
|
+
from: '08:00',
|
|
78
|
+
to: '22:00'
|
|
79
|
+
},
|
|
80
|
+
scriptId: 1,
|
|
81
|
+
script: '"abc"'
|
|
82
|
+
}, {
|
|
83
|
+
_id: 2,
|
|
84
|
+
watcherObjectId: 1,
|
|
85
|
+
name: 'New Watcher 2',
|
|
86
|
+
active: true,
|
|
87
|
+
timezone: 'Asia/Makassar',
|
|
88
|
+
templateName: 'cekUser2.js',
|
|
89
|
+
seq: 1,
|
|
90
|
+
monthly: [2, 3],
|
|
91
|
+
hourly: ['12:00', '13:00'],
|
|
92
|
+
scriptId: 2,
|
|
93
|
+
script: '"def"'
|
|
94
|
+
|
|
95
|
+
}]
|
|
96
|
+
}]);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
})
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { jest } from '@jest/globals'
|
|
2
|
+
|
|
3
|
+
const mockInsertHistory = jest.fn();
|
|
4
|
+
jest.unstable_mockModule("../scheduler/watcherController.js", () => ({
|
|
5
|
+
insertHistory: mockInsertHistory.mockResolvedValue('OK')
|
|
6
|
+
}))
|
|
7
|
+
|
|
8
|
+
// const mockModule = await import('../scheduler/datalib.js');
|
|
9
|
+
// const mockExtractFunctionScript = jest.fn();
|
|
10
|
+
// jest.unstable_mockModule("../scheduler/datalib.js", () => ({
|
|
11
|
+
// ...mockModule,
|
|
12
|
+
// extractFunctionScript: mockExtractFunctionScript
|
|
13
|
+
// }))
|
|
14
|
+
|
|
15
|
+
const {
|
|
16
|
+
scheduleSubscription,
|
|
17
|
+
getConfig,
|
|
18
|
+
getQueryDataObsParameters,
|
|
19
|
+
} = await import('../scheduler/datalib.js');
|
|
20
|
+
|
|
21
|
+
describe('data test', () => {
|
|
22
|
+
test('check schedule subscription no history', () => {
|
|
23
|
+
const config = {
|
|
24
|
+
_id: 'ffffffff2ae49fab9ea654e1',
|
|
25
|
+
API_URL: 'localhost'
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const data = [{ template: '7b2266756e6374696f6e73223a7b226f6e496e6974223a5b2277696e646f772e46756e6374696f6e222c5b22636f6e666967222c222064617461225d2c5b2220202020202020202020202020202020636f6e737420646f6974203d206173796e63202829203d3e207b222c222020202020202020202020202020202020202020636f6e7374207b20746170207d203d20617761697420696d706f7274282772786a732729222c222020202020202020202020202020202020202020636f6e7374207b20717565727944617461207d203d20617761697420696d706f727428272e2f646174616c69622e6a732729222c222020202020202020202020202020202020202020636f6e737420706172616d203d207b222c222020202020202020202020202020202020202020202020206c656e6774683a2031302c222c22202020202020202020202020202020202020202020202020636f6c756d6e733a205b222c22202020202020202020202020202020202020202020202020202020207b20646174613a202755534552532e555345524944272c206b65793a202775736572696427207d222c222020202020202020202020202020202020202020202020205d2c222c222020202020202020202020202020202020202020202020206462496e6465783a2031222c2220202020202020202020202020202020202020207d222c22202020202020202020202020202020202020202071756572794461746128706172616d2c20636f6e6669672c2074727565292e7069706528222c2220202020202020202020202020202020202020202020202074617028726573203d3e20636f6e736f6c652e6c6f672872657329292c222c222020202020202020202020202020202020202020292e73756273637269626528726573203d3e207b222c22202020202020202020202020202020202020202020202020636f6e736f6c652e6c6f67287265732c20277375627363726962652729222c2220202020202020202020202020202020202020207d29222c22202020202020202020202020202020207d222c2220202020202020202020202020202020646f69742829222c222020202020202020202020202020202072657475726e20276f6b20646172692063656b55736572273b225d5d7d7d' }]
|
|
29
|
+
const trigger = {
|
|
30
|
+
_id: 1,
|
|
31
|
+
name: 'New Watcher 1',
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
scheduleSubscription(config, data, trigger, false, true);
|
|
35
|
+
expect(mockInsertHistory).toBeCalledTimes(0);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test('check schedule subscription with history', () => {
|
|
39
|
+
const config = {
|
|
40
|
+
_id: 'ffffffff2ae49fab9ea654e1',
|
|
41
|
+
API_URL: 'localhost'
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const data = [{ template: '7b2266756e6374696f6e73223a7b226f6e496e6974223a5b2277696e646f772e46756e6374696f6e222c5b22636f6e666967222c222064617461225d2c5b2220202020202020202020202020202020636f6e737420646f6974203d206173796e63202829203d3e207b222c222020202020202020202020202020202020202020636f6e7374207b20746170207d203d20617761697420696d706f7274282772786a732729222c222020202020202020202020202020202020202020636f6e7374207b20717565727944617461207d203d20617761697420696d706f727428272e2f646174616c69622e6a732729222c222020202020202020202020202020202020202020636f6e737420706172616d203d207b222c222020202020202020202020202020202020202020202020206c656e6774683a2031302c222c22202020202020202020202020202020202020202020202020636f6c756d6e733a205b222c22202020202020202020202020202020202020202020202020202020207b20646174613a202755534552532e555345524944272c206b65793a202775736572696427207d222c222020202020202020202020202020202020202020202020205d2c222c222020202020202020202020202020202020202020202020206462496e6465783a2031222c2220202020202020202020202020202020202020207d222c22202020202020202020202020202020202020202071756572794461746128706172616d2c20636f6e6669672c2074727565292e7069706528222c2220202020202020202020202020202020202020202020202074617028726573203d3e20636f6e736f6c652e6c6f672872657329292c222c222020202020202020202020202020202020202020292e73756273637269626528726573203d3e207b222c22202020202020202020202020202020202020202020202020636f6e736f6c652e6c6f67287265732c20277375627363726962652729222c2220202020202020202020202020202020202020207d29222c22202020202020202020202020202020207d222c2220202020202020202020202020202020646f69742829222c222020202020202020202020202020202072657475726e20276f6b20646172692063656b55736572273b225d5d7d7d' }]
|
|
45
|
+
const trigger = {
|
|
46
|
+
_id: 1,
|
|
47
|
+
name: 'New Watcher 1',
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
scheduleSubscription(config, data, trigger, true, true);
|
|
51
|
+
expect(mockInsertHistory).toBeCalledTimes(1);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test('get config', () => {
|
|
55
|
+
const config = {
|
|
56
|
+
_id: 'ffffffff2ae49fab9ea654e1',
|
|
57
|
+
API_URL: 'localhost'
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
expect(getConfig(config)).toStrictEqual(config);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test('get config array', () => {
|
|
64
|
+
const config = [{
|
|
65
|
+
_id: 'ffffffff2ae49fab9ea654e1',
|
|
66
|
+
API_URL: 'localhost'
|
|
67
|
+
}]
|
|
68
|
+
|
|
69
|
+
expect(getConfig(config)).toStrictEqual(config[0]);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// test('get config array', () => {
|
|
73
|
+
// const trigger = {
|
|
74
|
+
// _id: 'abc'
|
|
75
|
+
// }
|
|
76
|
+
|
|
77
|
+
// expect(getQueryDataObsParameters(trigger)).toStrictEqual();
|
|
78
|
+
// });
|
|
79
|
+
})
|
|
80
|
+
|
|
@@ -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
|
+
})
|