mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-28 09:02:12 +08:00
fix: restore legacy cron schedules and shell diagnostics (#3078)
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
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 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 ['?', '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': { 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) => job.nextInvocation()));
|
||||
}
|
||||
const previousJobs = [...stacks.values()].flat();
|
||||
for (const schedule of ['?', '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.ok(previousJobs.every((job) => job.nextInvocation()));
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const { spawnSync } = require('node:child_process');
|
||||
|
||||
test('shell translations print leading dashes, placeholders and newlines', () => {
|
||||
const result = spawnSync('bash', ['-c', String.raw`
|
||||
source shell/share.sh
|
||||
t '---> 服务诊断信息'
|
||||
t '---> 最近的系统日志: %s' '/tmp/test.log'
|
||||
t 'first\nsecond'
|
||||
`], { encoding: 'utf8', env: { ...process.env, QL_DIR: process.cwd() } });
|
||||
assert.equal(result.status, 0, result.stderr);
|
||||
assert.equal(result.stderr, '');
|
||||
assert.equal(result.stdout,
|
||||
'---> 服务诊断信息\n---> 最近的系统日志: /tmp/test.log\nfirst\nsecond\n');
|
||||
});
|
||||
Reference in New Issue
Block a user