Files
TREK/server/tests/unit/plugins/plugin-jobs.test.ts
2026-10-06 21:50:59 +02:00

68 lines
2.3 KiB
TypeScript

/**
* The host-side background-job scheduler (#plugins). Proves jobs are opt-in
* (jobs:run), invalid crons never run, the run callback receives the job id, a
* throwing job can't escape the tick, and stop() tears every task down.
*/
import { scheduleJobs, stopJobs } from '../../../src/nest/plugins/host/plugin-jobs';
import { describe, it, expect, vi, beforeEach } from 'vitest';
const h = vi.hoisted(() => ({ tasks: [] as Array<{ expr: string; fn: () => void; stopped: boolean; stop(): void }> }));
vi.mock('cron', () => ({
validateCronExpression: (expr: string) => ({
valid: typeof expr === 'string' && expr.trim() !== '' && expr !== 'not-a-cron',
}),
CronJob: {
from: ({ cronTime, onTick }: { cronTime: string; onTick: () => void }) => {
const t = {
expr: cronTime,
fn: onTick,
stopped: false,
stop() {
this.stopped = true;
},
};
h.tasks.push(t);
return t;
},
},
}));
describe('plugin background jobs (scheduler)', () => {
beforeEach(() => {
h.tasks.length = 0;
});
const jobs = [
{ id: 'nightly', schedule: '0 0 * * *' },
{ id: 'broken', schedule: 'not-a-cron' },
];
it('schedules nothing without the jobs:run grant (opt-in)', () => {
expect(scheduleJobs(new Set<string>(), jobs, () => {})).toEqual([]);
expect(h.tasks).toHaveLength(0);
});
it('schedules only valid-cron jobs when jobs:run is granted', () => {
const tasks = scheduleJobs(new Set(['jobs:run']), jobs, () => {});
expect(tasks).toHaveLength(1);
expect(h.tasks[0].expr).toBe('0 0 * * *'); // the invalid cron was skipped, never scheduled
});
it('fires the run callback with the job id and swallows a throwing job', () => {
const runs: string[] = [];
scheduleJobs(new Set(['jobs:run']), [{ id: 'a', schedule: '0 0 * * *' }], (id) => {
runs.push(id);
throw new Error('boom');
});
expect(() => h.tasks[0].fn()).not.toThrow(); // the tick wrapper contains the throw
expect(runs).toEqual(['a']);
});
it('stopJobs stops every task and is safe on undefined/empty', () => {
const tasks = scheduleJobs(new Set(['jobs:run']), [{ id: 'a', schedule: '0 0 * * *' }], () => {});
stopJobs(tasks);
expect(h.tasks[0].stopped).toBe(true);
expect(() => stopJobs(undefined)).not.toThrow();
});
});