mirror of
https://github.com/whyour/qinglong.git
synced 2026-10-17 07:20:51 +08:00
Translate UI, scheduler, validation, preload and maintenance messages dynamically, and propagate locale changes between workers. Harden update checks, downloads and terminal states, verify Debian pnpm, and ignore generated test artifacts.
77 lines
2.9 KiB
JavaScript
77 lines
2.9 KiB
JavaScript
const test = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const { format } = require('node:util');
|
|
const load = require('../helpers/load-security-module.cjs');
|
|
const { SchedulerReadiness } = require('../../back/shared/schedulerReadiness');
|
|
|
|
const { getTasks } = require('node-cron');
|
|
|
|
const legacySchedules = [
|
|
'* * * * *',
|
|
'*/5 * * * *',
|
|
'0 */10 * * * ?',
|
|
'0 */2 * * * ?',
|
|
'0 */5 * * * ?',
|
|
'0 0/30 * * * ?',
|
|
'0 0/5 * * * ?',
|
|
'0 0 12 ? * MON',
|
|
];
|
|
|
|
test('API accepts legacy question-mark schedules but rejects malformed cron', () => {
|
|
const { scheduleSchema } = load('back/validation/schedule.ts', {
|
|
'../config': { logPath: '/ql/data/log' },
|
|
});
|
|
for (const schedule of [...legacySchedules, '@once', '@boot']) {
|
|
assert.equal(scheduleSchema.validate(schedule).error, undefined, schedule);
|
|
}
|
|
for (const schedule of ['@bogus', '0 /5 * * * ?', '0 70 * * * ?', 'not a cron']) {
|
|
assert.ok(scheduleSchema.validate(schedule).error, schedule);
|
|
}
|
|
});
|
|
|
|
test('legacy main and extra schedules restore real jobs and healthy readiness', async (t) => {
|
|
const stacks = new Map();
|
|
t.after(() => {
|
|
for (const jobs of stacks.values()) for (const job of jobs) job.cancel();
|
|
});
|
|
const { addCron } = load('back/schedule/addCron.ts', {
|
|
'./data': { scheduleStacks: stacks },
|
|
'../shared/runCron': { runCron() {} },
|
|
'../loaders/logger': { info() {}, warn() {} },
|
|
'../shared/i18n': { t: (s) => s, tf: format },
|
|
});
|
|
const crons = legacySchedules.map((schedule, index) => ({
|
|
id: `legacy-${index}`, name: 'legacy', schedule, command: 'true',
|
|
extra_schedules: [{ schedule: '0 0/30 * * * ?' }],
|
|
}));
|
|
const register = (rows) => new Promise((resolve, reject) => {
|
|
addCron({ request: { replace: true, crons: rows } }, (error) =>
|
|
error ? reject(error) : resolve());
|
|
});
|
|
const readiness = new SchedulerReadiness(async () => {}, 60000);
|
|
t.after(() => clearTimeout(readiness.retry));
|
|
readiness.configure(() => register(crons));
|
|
assert.equal(await readiness.recover(), true);
|
|
assert.equal(await readiness.check(), true);
|
|
assert.equal(stacks.size, crons.length);
|
|
for (const jobs of stacks.values()) {
|
|
assert.equal(jobs.length, 2);
|
|
assert.ok(jobs.every((job) => typeof job.cancel === 'function'));
|
|
}
|
|
const nativeJobs = [...getTasks().values()];
|
|
assert.equal(nativeJobs.length, crons.length * 2);
|
|
assert.ok(nativeJobs.every((job) => job.getStatus() !== 'stopped'));
|
|
const previousJobs = [...stacks.values()].flat();
|
|
for (const schedule of ['@bogus', '0 /5 * * * ?', '0 70 * * * ?']) {
|
|
for (const invalid of [
|
|
{ ...crons[0], schedule },
|
|
{ ...crons[0], extra_schedules: [{ schedule }] },
|
|
]) {
|
|
await assert.rejects(register([invalid]), (error) => error.code === 3);
|
|
assert.deepEqual([...stacks.values()].flat(), previousJobs);
|
|
assert.deepEqual([...getTasks().values()], nativeJobs);
|
|
assert.ok(nativeJobs.every((job) => job.getStatus() !== 'stopped'));
|
|
}
|
|
}
|
|
});
|