import { describe, expect, it } from "@suaveplan/testing/runner"; import { cachedStorage } from "../../src/factory/factory.js"; import { KeysCapableFakeCache } from "../setup/fake-cache.js"; import { FakeStorage } from "../setup/fake-storage.js"; /** * Integration: two `CachedStorage` wrappers sharing one * `AbstractCache` instance with distinct namespaces. Neither wrapper * observes the other's entries on `get`, and `wrapperA.clear()` MUST * NOT evict `wrapperB`'s entries. * * Uses the `KeysCapableFakeCache` test helper because the canonical * `MemoryCache` from `@suaveplan/cache` does not expose `keys()`. The * test helper is a real `AbstractCache` subclass — not a * mock — so the integration exercises real iteration over real * cache entries. */ describe("integration: namespaced isolation on a shared cache", () => { it("distinct namespaces isolate entries on a shared cache", { timeout: 30000, }, async () => { const innerA = new FakeStorage(); const innerB = new FakeStorage(); const shared = new KeysCapableFakeCache(); const wrapperA = cachedStorage(innerA, { cache: shared, namespace: "a", }); const wrapperB = cachedStorage(innerB, { cache: shared, namespace: "b", }); innerA.seed("clip.mov", new Uint8Array([0xa])); innerB.seed("clip.mov", new Uint8Array([0xb])); // Wrapper A populates its entry under "a::clip.mov". await wrapperA.get("clip.mov"); expect(shared._peek("a::clip.mov")).toEqual(new Uint8Array([0xa])); expect(shared._peek("b::clip.mov")).toBeUndefined(); // Wrapper B observes a miss for the same logical key (different namespace). const fromB = await wrapperB.get("clip.mov"); expect(fromB).toEqual(new Uint8Array([0xb])); expect(wrapperB.getCacheStats().misses).toBe(1); expect(shared._peek("b::clip.mov")).toEqual(new Uint8Array([0xb])); }); it("clear on one wrapper does not evict the other's entries", { timeout: 30000, }, async () => { const innerA = new FakeStorage(); const innerB = new FakeStorage(); const shared = new KeysCapableFakeCache(); const wrapperA = cachedStorage(innerA, { cache: shared, namespace: "a", }); const wrapperB = cachedStorage(innerB, { cache: shared, namespace: "b", }); // Populate both. innerA.seed("x", new Uint8Array([0xa, 1])); innerA.seed("y", new Uint8Array([0xa, 2])); innerB.seed("z", new Uint8Array([0xb, 1])); await wrapperA.get("x"); await wrapperA.get("y"); await wrapperB.get("z"); expect(shared._peek("a::x")).toBeDefined(); expect(shared._peek("a::y")).toBeDefined(); expect(shared._peek("b::z")).toBeDefined(); // Wrapper A clears. await wrapperA.clear(); expect(shared._peek("a::x")).toBeUndefined(); expect(shared._peek("a::y")).toBeUndefined(); expect(shared._peek("b::z")).toEqual(new Uint8Array([0xb, 1])); }); });