Compare commits

..
1 Commits
Author SHA1 Message Date
sneak 4f41e21abf Fix two intermittently failing library tests (closes #90)
check / check (push) Successful in 15s
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 now awaits close(), and a new test
holds a cache write 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
2026-09-23 01:47:45 +00:00
3 changed files with 8 additions and 94 deletions
+8 -8
View File
@@ -194,7 +194,7 @@ export const collectionsCommand = async (
}
return 0;
} finally {
await lib.close();
lib.close();
}
};
@@ -235,7 +235,7 @@ export const filesCommand = async (
}
return 0;
} finally {
await lib.close();
lib.close();
}
};
@@ -272,7 +272,7 @@ export const getCommand = async (
ctx.stderr.write(`${result.bytes} bytes -> ${outPath}\n`);
return 0;
} finally {
await lib.close();
lib.close();
}
};
@@ -309,7 +309,7 @@ export const getThumbCommand = async (
ctx.stderr.write(`${result.bytes} bytes -> ${outPath}\n`);
return 0;
} finally {
await lib.close();
lib.close();
}
};
@@ -329,7 +329,7 @@ export const backupMetadataCommand = async (
});
return 0;
} finally {
await lib.close();
lib.close();
}
};
@@ -376,7 +376,7 @@ export const backupCommand = async (
return result.failed > 0 ? 1 : 0;
} finally {
await lib.close();
lib.close();
}
};
@@ -411,7 +411,7 @@ export const listMissingThumbnailsCommand = async (
}
return 0;
} finally {
await lib.close();
lib.close();
}
};
@@ -481,6 +481,6 @@ export const fixMissingThumbnailsCommand = async (
return results.some((r) => r.status === "failed") ? 1 : 0;
} finally {
await lib.close();
lib.close();
}
};
-47
View File
@@ -446,51 +446,4 @@ describe("Library ML-data fetch on refresh", () => {
await lib.close();
}
});
it("close() resolves only after a running ML data fetch has stored its payloads", async () => {
const client = new MLMockClient();
client.collectionsQueue.push({
collections: [collection(1, 100)],
deleted: [],
cursor: 100,
});
client.filesFor(1, {
files: [file(1001, 1, 90)],
deleted: [],
cursor: 90,
});
client.mlByFile.set(1001, payload([0.5, 0.25, 0.75]));
// Hold the ML data fetch open until the test releases it.
let release!: () => void;
const held = new Promise<void>((r) => (release = r));
let fetchStarted!: () => void;
const started = new Promise<void>((r) => (fetchStarted = r));
const realFetch = client.fetchMLData.bind(client);
client.fetchMLData = async (args) => {
fetchStarted();
await held;
return realFetch(args);
};
const lib = await Library.open({
client,
cacheDirectory,
refreshIntervalSeconds: 3600,
});
await started;
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(join(cacheDirectory, "mldata", "1001.json"))).toBe(
true,
);
});
});
-39
View File
@@ -445,43 +445,4 @@ describe("Precache through Library.open", () => {
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 };
},
};
const lib = await Library.open({
client: new MockClient(),
cacheDirectory: join(root, "cache"),
contentSource: source,
refreshIntervalSeconds: 3600,
precacheOriginals: false,
});
const destination = await started;
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);
});
});