52 lines
3.2 KiB
TypeScript
52 lines
3.2 KiB
TypeScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { HistoryScheduler, type HistoryCaptureStore } from './scheduler.js';
|
|
|
|
function fixture(enabledAt='2026-10-30T13:00:00+08:00') {
|
|
const captures:string[]=[],missed:string[]=[],failed:string[]=[];
|
|
let activates=0;
|
|
const store:HistoryCaptureStore={
|
|
activate:async()=>{activates++;return{enabledAt};},dailyBatches:async()=>[],
|
|
capture:async(month)=>{captures.push(month);return'captured';},
|
|
recordOutcome:async(month,status)=>{(status==='FAILED'?failed:missed).push(month);},
|
|
};
|
|
return {store,captures,missed,failed,activates:()=>activates};
|
|
}
|
|
test('scheduler captures only in daily 23:55 minute and activation is persisted once',async()=>{
|
|
const f=fixture();let date=new Date('2026-10-31T23:54:59+08:00');
|
|
const scheduler=new HistoryScheduler(f.store,()=>date,()=>{});
|
|
await scheduler.tick();assert.deepEqual(f.captures,[]);
|
|
date=new Date('2026-10-31T23:55:00+08:00');await scheduler.tick();assert.deepEqual(f.captures,['2026-10-31']);assert.equal(f.activates(),1);
|
|
});
|
|
test('restart records missed eligible days without backfilling old live data or pre-activation periods',async()=>{
|
|
const f=fixture();const scheduler=new HistoryScheduler(f.store,()=>new Date('2026-11-02T08:00:00+08:00'),()=>{});
|
|
await scheduler.tick();assert.deepEqual(f.captures,[]);assert.deepEqual(f.missed,['2026-10-30','2026-10-31','2026-11-01']);
|
|
const late=fixture('2026-10-31T23:55:10+08:00');await new HistoryScheduler(late.store,()=>new Date('2026-10-31T23:55:20+08:00'),()=>{}).tick();
|
|
assert.deepEqual(late.captures,[]);assert.deepEqual(late.missed,[]);
|
|
});
|
|
test('completed days skip capture and existing failures are preserved after the window',async()=>{
|
|
const f=fixture();f.store.dailyBatches=async()=>[{day:'2026-10-30',status:'COMPLETE'}];
|
|
f.store.capture=async()=>{throw new Error('source unavailable');};
|
|
await new HistoryScheduler(f.store,()=>new Date('2026-10-31T23:55:20+08:00'),()=>{}).tick();
|
|
assert.deepEqual(f.missed,[]);assert.deepEqual(f.failed,['2026-10-31']);
|
|
f.store.dailyBatches=async()=>[{day:'2026-10-30',status:'COMPLETE'},{day:'2026-10-31',status:'FAILED'}];
|
|
await new HistoryScheduler(f.store,()=>new Date('2026-10-31T23:56:00+08:00'),()=>{}).tick();
|
|
assert.deepEqual(f.failed,['2026-10-31']);assert.deepEqual(f.missed,[]);
|
|
});
|
|
test('concurrent ticks and repeated start do not register duplicate jobs',async()=>{
|
|
const f=fixture();let release!:()=>void;
|
|
f.store.capture=async()=>{f.captures.push('2026-10-31');await new Promise<void>(r=>{release=r;});return'captured';};
|
|
const scheduler=new HistoryScheduler(f.store,()=>new Date('2026-10-31T23:55:20+08:00'),()=>{});
|
|
const stop=scheduler.start();scheduler.start();
|
|
await new Promise<void>(r=>setImmediate(r));await scheduler.tick();assert.equal(f.captures.length,1);
|
|
stop();release();await new Promise<void>(r=>setImmediate(r));
|
|
});
|
|
|
|
test('consecutive dates in one month and across month boundary capture independently',async()=>{
|
|
const f=fixture();
|
|
for(const day of ['2026-10-30','2026-10-31','2026-11-01']) {
|
|
await new HistoryScheduler(f.store,()=>new Date(`${day}T23:55:00+08:00`),()=>{}).tick();
|
|
}
|
|
assert.deepEqual(f.captures,['2026-10-30','2026-10-31','2026-11-01']);
|
|
});
|