90 lines
3.3 KiB
TypeScript
90 lines
3.3 KiB
TypeScript
// Ported from apps/server/test (CR-014 Step 14.5): the hourly cleanup job is
|
|
// now pruning on every save (Step 7.3, CR-014 §2).
|
|
import { content } from "@deadhead/content";
|
|
import { boardPeriodIndex, boardPeriodMs } from "@deadhead/sim";
|
|
import { describe, expect, it } from "vitest";
|
|
import { pruneSave } from "../../src/index";
|
|
import {
|
|
TEST_NOW,
|
|
useTestApp,
|
|
signUp,
|
|
call,
|
|
getState,
|
|
edit,
|
|
readSave,
|
|
testContract,
|
|
insertDispatch,
|
|
putBoard,
|
|
makeOwner,
|
|
} from "../support";
|
|
|
|
const testApp = useTestApp();
|
|
const RETENTION = content.config.boardRetentionPeriods;
|
|
const HOUR = 3_600_000;
|
|
|
|
describe("pruning old boards and trips on save", () => {
|
|
it("drops old boards and accepted contracts and keeps current ones", async () => {
|
|
const { app } = testApp();
|
|
const guest = await signUp(app);
|
|
const { shipId } = await makeOwner(app, guest.avatarId);
|
|
const period = boardPeriodMs(content.config);
|
|
const current = boardPeriodIndex(TEST_NOW, content.config);
|
|
const old = current - RETENTION - 1;
|
|
await putBoard(app, [testContract()], TEST_NOW - (current - old) * period);
|
|
await putBoard(app, [testContract()], TEST_NOW);
|
|
const record = await insertDispatch(app, {
|
|
shipId,
|
|
pilotId: guest.avatarId,
|
|
departAt: TEST_NOW,
|
|
});
|
|
await edit(app, (save) => {
|
|
save.acceptedContracts.push(
|
|
{ contractId: "old", periodIndex: old, dispatchId: record.id, acceptedAt: TEST_NOW },
|
|
{ contractId: "new", periodIndex: current, dispatchId: record.id, acceptedAt: TEST_NOW },
|
|
);
|
|
});
|
|
|
|
const save = await readSave(app);
|
|
pruneSave(save, TEST_NOW);
|
|
expect(save.contractBoards.map((b) => b.periodIndex)).toEqual([current]);
|
|
expect(save.acceptedContracts.map((a) => a.contractId)).toEqual(["new"]);
|
|
});
|
|
|
|
it("keeps boards inside the retention window", async () => {
|
|
const { app } = testApp();
|
|
await signUp(app);
|
|
await putBoard(app, [testContract()], TEST_NOW - RETENTION * boardPeriodMs(content.config));
|
|
const save = await readSave(app);
|
|
pruneSave(save, TEST_NOW);
|
|
expect(save.contractBoards).toHaveLength(1);
|
|
});
|
|
|
|
it("drops seen trips after the retention, keeps unseen ones and in-flight ones, and keeps goal progress", async () => {
|
|
const { app, clock } = testApp();
|
|
const guest = await signUp(app);
|
|
const { shipId } = await makeOwner(app, guest.avatarId);
|
|
const record = await insertDispatch(app, {
|
|
shipId,
|
|
pilotId: guest.avatarId,
|
|
departAt: clock.now,
|
|
});
|
|
clock.now = record.arrivalAt;
|
|
const landed = await getState(app);
|
|
expect(landed.summaries).toHaveLength(1);
|
|
const progressBefore = landed.goals;
|
|
|
|
// Unseen: kept however old.
|
|
clock.now += content.config.savedDispatchRetentionRealHours * HOUR + HOUR;
|
|
await getState(app);
|
|
expect((await readSave(app)).dispatches).toHaveLength(1);
|
|
|
|
// Seen and old: gone on the next save, with goal progress unchanged.
|
|
await call(app, guest, "POST", "/api/summaries/acknowledge", { dispatchIds: [record.id] });
|
|
clock.now += content.config.savedDispatchRetentionRealHours * HOUR + HOUR;
|
|
await call(app, guest, "POST", "/api/test/add-credits", { amount: 1 });
|
|
expect((await readSave(app)).dispatches).toEqual([]);
|
|
expect((await readSave(app)).stats.contractDeliveries).toBe(1);
|
|
expect((await getState(app)).goals).toEqual(progressBefore);
|
|
});
|
|
});
|