Files
smartmigration/test/test.run.checkpoint.ts

73 lines
2.5 KiB
TypeScript
Raw Permalink Normal View History

import { tap, expect } from '@git.zone/tstest/tapbundle';
import { makeTestDb } from './helpers/services.js';
import type * as smartdata from '@push.rocks/smartdata';
import { SmartMigration, SmartMigrationError } from '../ts/index.js';
let db: smartdata.SmartdataDb;
let cleanup: () => Promise<void>;
tap.test('setup: connect shared db', async () => {
const r = await makeTestDb('checkpoint');
db = r.db;
cleanup = r.cleanup;
});
tap.test('checkpoint: resumable step writes and re-reads progress across runs', async () => {
// First runner: simulate a crash after writing the first half of the work.
const m1 = new SmartMigration({ targetVersion: '1.1.0', db, ledgerName: 'resume' });
let crashed = false;
m1.step('big-job').from('1.0.0').to('1.1.0').resumable().up(async (ctx) => {
const seen = (await ctx.checkpoint!.read<number>('processed')) ?? 0;
// Pretend we processed items 0..4 and then crash.
for (let i = seen; i < 5; i++) {
await ctx.checkpoint!.write('processed', i + 1);
}
crashed = true;
throw new Error('simulated crash mid-step');
});
let caught: SmartMigrationError | undefined;
try {
await m1.run();
} catch (err) {
caught = err as SmartMigrationError;
}
expect(caught).toBeInstanceOf(SmartMigrationError);
expect(crashed).toBeTrue();
// Second runner: should see the checkpoint and resume from item 5.
const m2 = new SmartMigration({ targetVersion: '1.1.0', db, ledgerName: 'resume' });
let resumedFrom: number | undefined;
let finalCount: number | undefined;
m2.step('big-job').from('1.0.0').to('1.1.0').resumable().up(async (ctx) => {
resumedFrom = (await ctx.checkpoint!.read<number>('processed')) ?? 0;
// Process items 5..9.
let n = resumedFrom;
while (n < 10) {
n++;
await ctx.checkpoint!.write('processed', n);
}
finalCount = n;
});
const r = await m2.run();
expect(resumedFrom).toEqual(5);
expect(finalCount).toEqual(10);
expect(r.currentVersionAfter).toEqual('1.1.0');
});
tap.test('checkpoint: ctx.checkpoint is undefined for non-resumable steps', async () => {
const m = new SmartMigration({ targetVersion: '1.1.0', db, ledgerName: 'noresume' });
let observed: boolean | undefined;
m.step('plain').from('1.0.0').to('1.1.0').up(async (ctx) => {
observed = ctx.checkpoint === undefined;
});
await m.run();
expect(observed).toBeTrue();
});
tap.test('cleanup: close shared db', async () => {
await cleanup();
});
export default tap.start();