Start empty when the cache directory holds another account's cache (closes #104)
check / check (push) Successful in 30s
check / check (push) Successful in 30s
When metadata.json in the cache directory was written for a different, non-zero user ID than the client's, Library.open deletes it and mldata/ and loads an empty store, so the first refresh enumerates from 0 and none of the other account's collections, files, keys or ML results are served. Only reachable with --cache-dir or an explicit cacheDirectory. Model: opus-5-5
This commit is contained in:
@@ -13,6 +13,8 @@
|
||||
* 2. `Library` wiring: after each refresh the library fetches ML data through
|
||||
* the metadata pool for every known file not yet cached, is incremental on
|
||||
* later refreshes, and refetches a file whose `updationTime` advanced.
|
||||
* Opening a cache directory written by another account starts empty,
|
||||
* its ML data included (issue #104).
|
||||
*
|
||||
* Embedding values are chosen to be exactly representable as float32 so the
|
||||
* round-trip through `clip.f32` compares equal.
|
||||
@@ -498,4 +500,63 @@ describe("Library ML-data fetch on refresh", () => {
|
||||
await lib.close();
|
||||
}
|
||||
});
|
||||
|
||||
it("starts empty when the cache directory holds another account's cache", async () => {
|
||||
// Account A fills the cache directory: metadata and ML data.
|
||||
const clientA = new MLMockClient();
|
||||
clientA.collectionsQueue.push({
|
||||
collections: [collection(1, 100)],
|
||||
deleted: [],
|
||||
cursor: 100,
|
||||
});
|
||||
clientA.filesFor(1, {
|
||||
files: [file(1001, 1, 90)],
|
||||
deleted: [],
|
||||
cursor: 90,
|
||||
});
|
||||
clientA.mlByFile.set(1001, payload([0.5, 0.25, 0.75]));
|
||||
const libA = await Library.open({
|
||||
client: clientA,
|
||||
cacheDirectory,
|
||||
refreshIntervalSeconds: 3600,
|
||||
});
|
||||
try {
|
||||
await vi.waitFor(
|
||||
() => expect(libA.status().lastMLFetchAt).toBeGreaterThan(0),
|
||||
{ timeout: 2000, interval: 5 },
|
||||
);
|
||||
} finally {
|
||||
await libA.close();
|
||||
}
|
||||
|
||||
// Account B opens the same directory.
|
||||
const clientB = new MLMockClient();
|
||||
clientB.userID = USER_ID + 1;
|
||||
const sinceTimes: number[] = [];
|
||||
const realCollectionsSince = clientB.collectionsSince.bind(clientB);
|
||||
clientB.collectionsSince = async (args) => {
|
||||
sinceTimes.push(args.sinceTime);
|
||||
return realCollectionsSince(args);
|
||||
};
|
||||
const libB = await Library.open({
|
||||
client: clientB,
|
||||
cacheDirectory,
|
||||
refreshIntervalSeconds: 3600,
|
||||
});
|
||||
try {
|
||||
expect(sinceTimes[0]).toBe(0);
|
||||
expect(libB.status().userID).toBe(USER_ID + 1);
|
||||
expect(libB.listCollections()).toEqual([]);
|
||||
expect(libB.getFile(1, 1001)).toBeUndefined();
|
||||
expect(await libB.mldata.forFile({ fileID: 1001 })).toBeUndefined();
|
||||
expect(
|
||||
libB.mldata.searchByEmbedding({ embedding: [0.5, 0.25, 0.75] }),
|
||||
).toEqual([]);
|
||||
expect(
|
||||
existsSync(join(cacheDirectory, "mldata", "1001.json")),
|
||||
).toBe(false);
|
||||
} finally {
|
||||
await libB.close();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user