All files / services/scheduler-service/src/__tests__ scheduler.test.js

0% Statements 0/66
0% Branches 0/15
0% Functions 0/15
0% Lines 0/60

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119                                                                                                                                                                                                                                             
const CrawlerSchedule = require('../models/CrawlerSchedule');
 
const mockSchedule = {
  organizationId: 'org-123',
  configId: '507f1f77bcf86cd799439011',
  name: 'Test schedule',
  cronExpression: '0 */6 * * *',
  timezone: 'UTC',
};
 
describe('CrawlerSchedule Model', () => {
  it('should create a valid schedule', () => {
    const schedule = new CrawlerSchedule(mockSchedule);
    expect(schedule.organizationId).toBe('org-123');
    expect(schedule.cronExpression).toBe('0 */6 * * *');
    expect(schedule.isActive).toBe(true);
    expect(schedule.runCount).toBe(0);
  });
 
  it('should reject missing organizationId', () => {
    const schedule = new CrawlerSchedule({ configId: 'abc', cronExpression: '0 * * * *' });
    const error = schedule.validateSync();
    expect(error.errors.organizationId).toBeDefined();
  });
 
  it('should reject missing cronExpression', () => {
    const schedule = new CrawlerSchedule({ organizationId: 'org-1', configId: 'abc' });
    const error = schedule.validateSync();
    expect(error.errors.cronExpression).toBeDefined();
  });
 
  it('should reject invalid lastRunStatus', () => {
    const schedule = new CrawlerSchedule({
      ...mockSchedule,
      lastRunStatus: 'invalid',
    });
    const error = schedule.validateSync();
    expect(error).toBeDefined();
    expect(error.errors['lastRunStatus']).toBeDefined();
  });
 
  it('should accept valid lastRunStatus values', () => {
    const success = new CrawlerSchedule({ ...mockSchedule, lastRunStatus: 'success' });
    const failed = new CrawlerSchedule({ ...mockSchedule, lastRunStatus: 'failed' });
    const pending = new CrawlerSchedule({ ...mockSchedule, lastRunStatus: 'pending' });
    expect(success.validateSync()).toBeUndefined();
    expect(failed.validateSync()).toBeUndefined();
    expect(pending.validateSync()).toBeUndefined();
  });
 
  it('should default isActive to true', () => {
    const schedule = new CrawlerSchedule(mockSchedule);
    expect(schedule.isActive).toBe(true);
  });
 
  it('should default runCount to 0', () => {
    const schedule = new CrawlerSchedule(mockSchedule);
    expect(schedule.runCount).toBe(0);
  });
 
  it('should default timezone to UTC', () => {
    const schedule = new CrawlerSchedule(mockSchedule);
    expect(schedule.timezone).toBe('UTC');
  });
});
 
function isValidCron(expr) {
  if (!expr || typeof expr !== 'string') return false;
  const parts = expr.trim().split(/\s+/);
  if (parts.length !== 5) return false;
  const cronRegex = /^(\*|\d+(-\d+)?)(\/\d+)?$/;
  const rangeChecks = [
    { min: 0, max: 59 },
    { min: 0, max: 23 },
    { min: 1, max: 31 },
    { min: 1, max: 12 },
    { min: 0, max: 7 },
  ];
  for (let i = 0; i < parts.length; i++) {
    if (parts[i] === '*') continue;
    const fields = parts[i].split(',');
    for (const field of fields) {
      if (!cronRegex.test(field)) return false;
      const num = parseInt(field, 10);
      if (!isNaN(num) && (num < rangeChecks[i].min || num > rangeChecks[i].max)) return false;
    }
  }
  return true;
}
 
describe('Cron Expression Validation', () => {
  it('should accept valid cron expressions', () => {
    const valid = [
      '0 */6 * * *',
      '0 0 * * *',
      '*/15 * * * *',
      '0 0 1 1 *',
      '30 4 * * 1-5',
      '* * * * *',
    ];
    valid.forEach((expr) => {
      expect(isValidCron(expr)).toBe(true);
    });
  });
 
  it('should reject invalid cron expressions', () => {
    const invalid = [
      'not-a-cron',
      '0 * * *',
      '* * * * * *',
      '',
      null,
    ];
    invalid.forEach((expr) => {
      expect(isValidCron(expr)).toBe(false);
    });
  });
});