Files
Autonomous-Bug-Explorer/tests/server/scheduler.test.ts

152 lines
4.6 KiB
TypeScript

/**
* Tests for SchedulerService: cron parsing, schedule registration, skip when session active.
*/
import Database from 'better-sqlite3';
import { runMigrations } from '../../src/db/migrations';
import { ScheduleRepository } from '../../src/db/ScheduleRepository';
import { SchedulerService } from '../../src/server/scheduler/SchedulerService';
import { SessionStore } from '../../src/server/SessionStore';
function makeDb(): Database.Database {
const db = new Database(':memory:');
db.pragma('foreign_keys = ON');
runMigrations(db);
return db;
}
describe('SchedulerService', () => {
let db: Database.Database;
let repo: ScheduleRepository;
let store: SessionStore;
let scheduler: SchedulerService;
beforeEach(() => {
db = makeDb();
repo = new ScheduleRepository(db);
store = new SessionStore('./reports');
scheduler = new SchedulerService(repo, store);
});
afterEach(() => {
scheduler.stop();
db.close();
});
it('starts without error when no schedules exist', () => {
expect(() => scheduler.start()).not.toThrow();
});
it('registers a valid cron job', () => {
repo.create({
id: 'sched_1',
name: 'Daily check',
url: 'http://example.com',
configJson: '{}',
cronExpression: '0 2 * * *',
enabled: true,
});
expect(() => scheduler.register(repo.findById('sched_1')!)).not.toThrow();
});
it('skips invalid cron expressions', () => {
repo.create({
id: 'sched_bad',
name: 'Bad',
url: 'http://x.com',
configJson: '{}',
cronExpression: 'not-valid-cron',
enabled: true,
});
expect(() => scheduler.register(repo.findById('sched_bad')!)).not.toThrow();
});
it('unregisters a schedule job', () => {
repo.create({
id: 'sched_2',
name: 'Test',
url: 'http://example.com',
configJson: '{}',
cronExpression: '0 * * * *',
enabled: true,
});
scheduler.register(repo.findById('sched_2')!);
expect(() => scheduler.unregister('sched_2')).not.toThrow();
});
it('computeNextRunAt returns a future timestamp for valid cron', () => {
const nextRun = SchedulerService.computeNextRunAt('0 2 * * *');
expect(nextRun).not.toBeNull();
expect(nextRun!).toBeGreaterThan(Date.now());
});
it('computeNextRunAt returns null for invalid cron', () => {
expect(SchedulerService.computeNextRunAt('not-valid')).toBeNull();
});
it('does not register job for disabled schedule', () => {
repo.create({
id: 'sched_3',
name: 'Disabled',
url: 'http://example.com',
configJson: '{}',
cronExpression: '0 * * * *',
enabled: false,
});
// Should not throw and job should not be registered
expect(() => scheduler.register(repo.findById('sched_3')!)).not.toThrow();
// Unregistering a non-existing job is also safe
expect(() => scheduler.unregister('sched_3')).not.toThrow();
});
});
describe('ScheduleRepository', () => {
let db: Database.Database;
let repo: ScheduleRepository;
beforeEach(() => {
db = makeDb();
repo = new ScheduleRepository(db);
});
afterEach(() => db.close());
it('creates and retrieves a schedule', () => {
repo.create({
id: 's1',
name: 'Daily',
url: 'http://test.com',
configJson: '{"maxStates":10}',
cronExpression: '0 2 * * *',
});
const record = repo.findById('s1');
expect(record).toBeDefined();
expect(record!.name).toBe('Daily');
expect(record!.enabled).toBe(true);
});
it('findAll returns all schedules', () => {
repo.create({ id: 's1', name: 'A', url: 'http://a.com', configJson: '{}', cronExpression: '0 * * * *' });
repo.create({ id: 's2', name: 'B', url: 'http://b.com', configJson: '{}', cronExpression: '0 2 * * *' });
expect(repo.findAll()).toHaveLength(2);
});
it('findAll(true) returns only enabled schedules', () => {
repo.create({ id: 's1', name: 'Enabled', url: 'http://a.com', configJson: '{}', cronExpression: '0 * * * *', enabled: true });
repo.create({ id: 's2', name: 'Disabled', url: 'http://b.com', configJson: '{}', cronExpression: '0 * * * *', enabled: false });
expect(repo.findAll(true)).toHaveLength(1);
});
it('updates enabled field', () => {
repo.create({ id: 's1', name: 'A', url: 'http://a.com', configJson: '{}', cronExpression: '0 * * * *' });
repo.update('s1', { enabled: false });
expect(repo.findById('s1')!.enabled).toBe(false);
});
it('deletes a schedule', () => {
repo.create({ id: 's1', name: 'A', url: 'http://a.com', configJson: '{}', cronExpression: '0 * * * *' });
repo.delete('s1');
expect(repo.findById('s1')).toBeUndefined();
});
});