import { BadRequestException } from '@nestjs/common'; import * as path from 'node:path'; import { assertBackupCron, assertGuiBackupPath, resolveGuiBackupPath, } from './backup-schedule-rules'; describe('backup-schedule-rules', () => { const originalRoot = process.env.BACKUP_ROOT; beforeEach(() => { process.env.BACKUP_ROOT = path.resolve('/data/backups'); }); afterAll(() => { process.env.BACKUP_ROOT = originalRoot; }); it('keeps a GUI path under the backup root', () => { expect(resolveGuiBackupPath('nightly')).toBe( path.resolve('/data/backups/nightly'), ); expect(() => assertGuiBackupPath('nightly')).not.toThrow(); }); it('refuses a GUI path that leaves the backup root', () => { expect(() => assertGuiBackupPath('../../app/public')).toThrow( BadRequestException, ); expect(() => assertGuiBackupPath('/etc')).toThrow(BadRequestException); expect(() => assertGuiBackupPath('/data/backups-evil')).toThrow( BadRequestException, ); }); it('accepts a daily schedule', () => { expect(() => assertBackupCron('0 3 * * *')).not.toThrow(); }); it('refuses a schedule that runs more than hourly or has seconds', () => { expect(() => assertBackupCron('* * * * *')).toThrow(BadRequestException); expect(() => assertBackupCron('*/10 * * * *')).toThrow(BadRequestException); expect(() => assertBackupCron('* * * * * *')).toThrow(BadRequestException); }); it('refuses an invalid expression', () => { expect(() => assertBackupCron('every day')).toThrow(BadRequestException); }); });