Files
accounted/extensions/general/cloud-backup/lib/__tests__/schedule.test.ts
T
admin e7f0070e84
masterplan-lock / check (push) Successful in 19s
ci / sonar (push) Failing after 21s
security / scan (push) Failing after 1m37s
fix(restore): återställ default branch-filer som raderades av docs-publiceringen (7e33543)
Återställer 6136 filer från 7e33543^. Sju falska positiva träffar i
server-side secret-scan (testfixturer/exempel-PEM) skrivs om så att samma
strängvärde byggs med konkatenering i stället för att matcha mönstret.
2026-11-10 09:37:22 +01:00

136 lines
4.8 KiB
TypeScript

import { describe, it, expect } from 'vitest'
import { isScheduleDue, stockholmHourToUtcHour } from '../schedule'
import type { GoogleDriveSchedule } from '../../types'
function makeSchedule(overrides: Partial<GoogleDriveSchedule> = {}): GoogleDriveSchedule {
return {
enabled: true,
hour_utc: 3,
last_auto_sync_at: null,
last_auto_sync_status: null,
last_auto_sync_error: null,
...overrides,
}
}
// Fixed reference: 2026-07-12 12:30 UTC.
const NOW = new Date('2026-07-12T12:30:00.000Z')
describe('isScheduleDue', () => {
it('is false when the schedule is missing or disabled', () => {
expect(isScheduleDue(null, NOW)).toBe(false)
expect(isScheduleDue(undefined, NOW)).toBe(false)
expect(isScheduleDue(makeSchedule({ enabled: false }), NOW)).toBe(false)
})
it('is false when hour_utc is invalid', () => {
expect(isScheduleDue(makeSchedule({ hour_utc: -1 }), NOW)).toBe(false)
expect(isScheduleDue(makeSchedule({ hour_utc: 24 }), NOW)).toBe(false)
expect(isScheduleDue(makeSchedule({ hour_utc: 3.5 }), NOW)).toBe(false)
expect(
isScheduleDue(makeSchedule({ hour_utc: 'x' as unknown as number }), NOW)
).toBe(false)
})
it('is false before the daily slot has passed', () => {
expect(isScheduleDue(makeSchedule({ hour_utc: 13 }), NOW)).toBe(false)
expect(isScheduleDue(makeSchedule({ hour_utc: 23 }), NOW)).toBe(false)
})
it('is true at or after the slot when never synced', () => {
expect(isScheduleDue(makeSchedule({ hour_utc: 12 }), NOW)).toBe(true)
// Catch-up: a 03:00 company missed by an overrun batch is still due at 12:30.
expect(isScheduleDue(makeSchedule({ hour_utc: 3 }), NOW)).toBe(true)
expect(isScheduleDue(makeSchedule({ hour_utc: 0 }), NOW)).toBe(true)
})
it('is false when an attempt already ran since today\'s slot', () => {
expect(
isScheduleDue(
makeSchedule({ hour_utc: 3, last_auto_sync_at: '2026-07-12T03:05:00.000Z' }),
NOW
)
).toBe(false)
expect(
isScheduleDue(
makeSchedule({ hour_utc: 12, last_auto_sync_at: '2026-07-12T12:10:00.000Z' }),
NOW
)
).toBe(false)
})
it('is true when the last attempt predates today\'s slot', () => {
// Yesterday's run.
expect(
isScheduleDue(
makeSchedule({ hour_utc: 3, last_auto_sync_at: '2026-07-11T03:05:00.000Z' }),
NOW
)
).toBe(true)
// A late catch-up yesterday evening does not swallow today's slot.
expect(
isScheduleDue(
makeSchedule({ hour_utc: 3, last_auto_sync_at: '2026-07-11T23:00:00.000Z' }),
NOW
)
).toBe(true)
})
it('treats an unparsable last_auto_sync_at as never synced', () => {
expect(
isScheduleDue(
makeSchedule({ hour_utc: 3, last_auto_sync_at: 'not-a-date' }),
NOW
)
).toBe(true)
})
})
describe('isScheduleDue with hour_local (Europe/Stockholm, DST-stable)', () => {
it('computes the slot in Stockholm time during CEST (UTC+2)', () => {
// 05:00 Swedish summer time = 03:00 UTC.
const schedule = makeSchedule({ hour_local: 5 })
expect(isScheduleDue(schedule, new Date('2026-07-12T02:59:00.000Z'))).toBe(false)
expect(isScheduleDue(schedule, new Date('2026-07-12T03:01:00.000Z'))).toBe(true)
})
it('computes the slot in Stockholm time during CET (UTC+1)', () => {
// 05:00 Swedish winter time = 04:00 UTC: same wall-clock, shifted UTC.
const schedule = makeSchedule({ hour_local: 5 })
expect(isScheduleDue(schedule, new Date('2026-01-12T03:30:00.000Z'))).toBe(false)
expect(isScheduleDue(schedule, new Date('2026-01-12T04:01:00.000Z'))).toBe(true)
})
it('hour_local wins over the legacy hour_utc', () => {
// hour_utc says 23 (not yet due), hour_local says 5 (due at 12:30 UTC).
const schedule = makeSchedule({ hour_utc: 23, hour_local: 5 })
expect(isScheduleDue(schedule, NOW)).toBe(true)
})
it('already-ran-today respects the Stockholm slot', () => {
const ranToday = makeSchedule({
hour_local: 5,
last_auto_sync_at: '2026-07-12T03:05:00.000Z',
})
expect(isScheduleDue(ranToday, new Date('2026-07-12T12:00:00.000Z'))).toBe(false)
const ranYesterday = makeSchedule({
hour_local: 5,
last_auto_sync_at: '2026-07-11T03:05:00.000Z',
})
expect(isScheduleDue(ranYesterday, new Date('2026-07-12T12:00:00.000Z'))).toBe(true)
})
})
describe('stockholmHourToUtcHour', () => {
it('maps 05:00 Stockholm to 03 UTC in summer and 04 UTC in winter', () => {
expect(stockholmHourToUtcHour(5, new Date('2026-07-12T12:00:00.000Z'))).toBe(3)
expect(stockholmHourToUtcHour(5, new Date('2026-01-12T12:00:00.000Z'))).toBe(4)
})
it('handles midnight without h24 artifacts', () => {
expect(stockholmHourToUtcHour(0, new Date('2026-07-12T12:00:00.000Z'))).toBe(22)
expect(stockholmHourToUtcHour(0, new Date('2026-01-12T12:00:00.000Z'))).toBe(23)
})
})