Fix two intermittently failing library tests (closes #90)
check / check (push) Successful in 28s
check / check (push) Successful in 28s
Library.close() now returns a promise that resolves once the work it started has finished: an in-flight refresh with its cache write, the ML data fetch, and running precache sweeps. The interval test could see a refresh's new state, close, and remove the directory while the write was still running. Every library test and CLI command now awaits close(), and tests hold each of the three writes open to prove close() waits for it. The precache test waited for its stub source to be called, but the cache records a file only after checking it on disk, so status() could lag. It now waits for both fills to report "done". Model: opus-5-5
This commit is contained in:
@@ -402,16 +402,64 @@ describe("Precache through Library.open", () => {
|
||||
}
|
||||
|
||||
it("starts both precaches from open() and reports them in status()", async () => {
|
||||
const thumbFetched = new Set<number>();
|
||||
const origFetched = new Set<number>();
|
||||
const source: ContentSource = {
|
||||
original: async ({ file: f, destination }) => {
|
||||
origFetched.add(f.id);
|
||||
original: async ({ destination }) => {
|
||||
await writeFile(destination, Buffer.alloc(10, 1));
|
||||
return { bytesWritten: 10 };
|
||||
},
|
||||
thumbnail: async ({ file: f, destination }) => {
|
||||
thumbFetched.add(f.id);
|
||||
thumbnail: async ({ destination }) => {
|
||||
await writeFile(destination, Buffer.alloc(10, 1));
|
||||
return { bytesWritten: 10 };
|
||||
},
|
||||
};
|
||||
// Each fill reports "done" once the cache has recorded its files. The
|
||||
// source returning is not enough: the cache records a file only after
|
||||
// it has checked it on disk.
|
||||
const finished = new Set<string>();
|
||||
let bothFinished!: () => void;
|
||||
const precached = new Promise<void>((r) => (bothFinished = r));
|
||||
const lib = await Library.open({
|
||||
client: new MockClient(),
|
||||
cacheDirectory: join(root, "cache"),
|
||||
contentSource: source,
|
||||
refreshIntervalSeconds: 3600,
|
||||
onProgress: (e) => {
|
||||
if (
|
||||
e.status === "done" &&
|
||||
(e.operation === "precacheThumbnails" ||
|
||||
e.operation === "precacheOriginals")
|
||||
) {
|
||||
finished.add(e.operation);
|
||||
if (finished.size === 2) bothFinished();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// Every file's thumbnail is precached; the favorite (file 3) and the
|
||||
// week's files (1, 2) all have their originals precached.
|
||||
await precached;
|
||||
const status = lib.status();
|
||||
expect(status.thumbnailsTotal).toBe(3);
|
||||
expect(status.thumbnailsCached).toBe(3);
|
||||
expect(status.originalsPinned).toBe(3);
|
||||
expect(status.originalsCached).toBe(3);
|
||||
await lib.close();
|
||||
});
|
||||
|
||||
it("close() resolves only after a running precache fetch has written its file", async () => {
|
||||
// Every thumbnail fetch waits until the test releases it.
|
||||
let release!: () => void;
|
||||
const held = new Promise<void>((r) => (release = r));
|
||||
let fetchStarted!: (destination: string) => void;
|
||||
const started = new Promise<string>((r) => (fetchStarted = r));
|
||||
const source: ContentSource = {
|
||||
original: async ({ destination }) => {
|
||||
await writeFile(destination, Buffer.alloc(10, 1));
|
||||
return { bytesWritten: 10 };
|
||||
},
|
||||
thumbnail: async ({ destination }) => {
|
||||
fetchStarted(destination);
|
||||
await held;
|
||||
await writeFile(destination, Buffer.alloc(10, 1));
|
||||
return { bytesWritten: 10 };
|
||||
},
|
||||
@@ -421,16 +469,24 @@ describe("Precache through Library.open", () => {
|
||||
cacheDirectory: join(root, "cache"),
|
||||
contentSource: source,
|
||||
refreshIntervalSeconds: 3600,
|
||||
precacheOriginals: false,
|
||||
});
|
||||
try {
|
||||
const destination = await started;
|
||||
|
||||
// Every file's thumbnail is precached; the favorite (file 3) and the
|
||||
// week's files (1, 2) all have their originals precached.
|
||||
await until(() => thumbFetched.size === 3 && origFetched.size === 3);
|
||||
const status = lib.status();
|
||||
expect(status.thumbnailsTotal).toBe(3);
|
||||
expect(status.thumbnailsCached).toBe(3);
|
||||
expect(status.originalsPinned).toBe(3);
|
||||
expect(status.originalsCached).toBe(3);
|
||||
lib.close();
|
||||
let closed = false;
|
||||
const closing = lib.close().then(() => {
|
||||
closed = true;
|
||||
});
|
||||
await new Promise((r) => setTimeout(r, 20));
|
||||
expect(closed).toBe(false);
|
||||
|
||||
release();
|
||||
await closing;
|
||||
expect(existsSync(destination)).toBe(true);
|
||||
} finally {
|
||||
release();
|
||||
await lib.close();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user