Test: lib.backup() rejects only once its workers have stopped when onProgress throws
check / check (push) Waiting to run
check / check (push) Waiting to run
With a content pool of eight, all eight downloads wait at once. Photo 103's is answered 404 and the line reporting it throws while the other seven still wait. When lib.backup() rejects, the other seven originals must be in place and the lock gone, so nothing is written after the backup has ended. Today the backup rejects as soon as that one worker throws, before the others have written anything. Model: opus-5-5
This commit is contained in:
@@ -396,6 +396,69 @@ describe("lib.backup()", () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// A throw from `onProgress` fails the backup: `lib.backup()` rejects with
|
||||||
|
// it. It rejects only once it has finished with every original it was
|
||||||
|
// working on, so nothing is written into the backup after it has ended
|
||||||
|
// and removed its lock. Here, with a content pool of eight, all eight
|
||||||
|
// downloads wait at once. Photo 103's is let go first and answered 404,
|
||||||
|
// and the line reporting that failure throws while the other seven wait.
|
||||||
|
it("when onProgress throws, rejects only once the originals it was working on are in place", async () => {
|
||||||
|
const dir = mkdtempSync(join(root, "backup-"));
|
||||||
|
const holding = holdingServer(103);
|
||||||
|
const lib = await openLibrary(
|
||||||
|
dir,
|
||||||
|
holding.fetch,
|
||||||
|
new RequestPools({ contentConcurrency: 8 }),
|
||||||
|
);
|
||||||
|
const lines: string[] = [];
|
||||||
|
try {
|
||||||
|
const backup = lib.backup({
|
||||||
|
onProgress: (line) => {
|
||||||
|
lines.push(line);
|
||||||
|
if (line.startsWith("FAILED")) {
|
||||||
|
throw new Error("the progress output is closed");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// The photos whose originals are in place, and whether the lock
|
||||||
|
// is there, at the moment `lib.backup()` rejects.
|
||||||
|
let storedWhenRejected: number[] = [];
|
||||||
|
let lockedWhenRejected = true;
|
||||||
|
const rejection = backup.catch((err: unknown) => {
|
||||||
|
storedWhenRejected = PHOTO_IDS.filter((id) =>
|
||||||
|
existsSync(savedAt(dir, id)),
|
||||||
|
);
|
||||||
|
lockedWhenRejected = existsSync(join(dir, "backup.lock"));
|
||||||
|
return err;
|
||||||
|
});
|
||||||
|
|
||||||
|
await vi.waitFor(() => expect(holding.held).toHaveLength(8), {
|
||||||
|
interval: 5,
|
||||||
|
timeout: 5000,
|
||||||
|
});
|
||||||
|
const at103 = holding.held.findIndex((h) => h.id === 103);
|
||||||
|
holding.held.splice(at103, 1)[0]!.release();
|
||||||
|
await vi.waitFor(
|
||||||
|
() =>
|
||||||
|
expect(
|
||||||
|
lines.some((line) => line.startsWith("FAILED")),
|
||||||
|
).toBe(true),
|
||||||
|
{ interval: 5, timeout: 5000 },
|
||||||
|
);
|
||||||
|
for (const download of holding.held) download.release();
|
||||||
|
|
||||||
|
expect(await rejection).toEqual(
|
||||||
|
new Error("the progress output is closed"),
|
||||||
|
);
|
||||||
|
expect(storedWhenRejected).toEqual(
|
||||||
|
PHOTO_IDS.filter((id) => id !== 103),
|
||||||
|
);
|
||||||
|
expect(lockedWhenRejected).toBe(false);
|
||||||
|
} finally {
|
||||||
|
await lib.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Working on several originals at once changes only how long a backup
|
// Working on several originals at once changes only how long a backup
|
||||||
// takes. The same two runs, with a content pool of one, which backs up
|
// takes. The same two runs, with a content pool of one, which backs up
|
||||||
// one original at a time, and with the default pools, end the same way:
|
// one original at a time, and with the default pools, end the same way:
|
||||||
|
|||||||
Reference in New Issue
Block a user