mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-19 05:26:47 +00:00
08dac57577
The plugin host's job scheduler now uses the cron package (the one @nestjs/schedule wraps), so node-cron and @types/node-cron leave the dependency tree entirely. Verified against both real libraries that the accepted cron grammar is identical — no plugin's declared schedule tightens — and pinned that with an unmocked compat test.
51 lines
2.2 KiB
TypeScript
51 lines
2.2 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 { 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;
|
|
},
|
|
},
|
|
}));
|
|
|
|
import { scheduleJobs, stopJobs } from '../../../src/nest/plugins/host/plugin-jobs';
|
|
|
|
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();
|
|
});
|
|
});
|