68 lines
2.4 KiB
TypeScript
68 lines
2.4 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
vi.mock("~/utils/cache.server", () => {
|
|
const map = new Map<string, unknown>();
|
|
return {
|
|
cache: map,
|
|
cachified: vi.fn(),
|
|
clearCacheKey: vi.fn((key: string) => map.delete(key)),
|
|
clearCacheKeyPrefix: vi.fn((prefix: string) => {
|
|
for (const k of map.keys()) if (k.startsWith(prefix)) map.delete(k);
|
|
}),
|
|
__test_map: map,
|
|
};
|
|
});
|
|
|
|
vi.mock("~/shared-store.server", async () => {
|
|
const { MemoryAdapter, createSharedStore } = await import("@toolctrl/shared-store");
|
|
const adapter = new MemoryAdapter();
|
|
const store = createSharedStore({ namespace: "web-test", adapter });
|
|
return {
|
|
getSharedStore: () => store,
|
|
__setSharedStoreFactoryForTests: vi.fn(),
|
|
__resetSharedStoreForTests: vi.fn(),
|
|
};
|
|
});
|
|
|
|
import {
|
|
publishTenantInvalidation,
|
|
subscribeTenantCache,
|
|
__resetTenantCacheForTests,
|
|
} from "./tenant-cache.server";
|
|
import * as cacheServer from "~/utils/cache.server";
|
|
|
|
beforeEach(() => {
|
|
__resetTenantCacheForTests();
|
|
(cacheServer as unknown as { __test_map: Map<string, unknown> }).__test_map.clear();
|
|
vi.mocked(cacheServer.clearCacheKey).mockClear();
|
|
vi.mocked(cacheServer.clearCacheKeyPrefix).mockClear();
|
|
delete process.env.CACHE_INVALIDATION_ENABLED;
|
|
});
|
|
|
|
afterEach(() => {
|
|
__resetTenantCacheForTests();
|
|
});
|
|
|
|
describe("tenant cache (two-tier)", () => {
|
|
it("publishTenantInvalidation clears local cachified keys for tenant id", async () => {
|
|
await publishTenantInvalidation("tenant-7");
|
|
expect(vi.mocked(cacheServer.clearCacheKey)).toHaveBeenCalledWith("tenant:tenant-7");
|
|
expect(vi.mocked(cacheServer.clearCacheKey)).toHaveBeenCalledWith("tenantSimple:tenant-7");
|
|
expect(vi.mocked(cacheServer.clearCacheKey)).toHaveBeenCalledWith("tenantIdOrSlug:tenant-7");
|
|
});
|
|
|
|
it("remote invalidation purges all 3 cachified prefixes for the affected tenant", async () => {
|
|
await subscribeTenantCache();
|
|
await publishTenantInvalidation("tenant-9");
|
|
await new Promise((r) => setTimeout(r, 10));
|
|
// local + remote both fire clearCacheKey — assert tenant-9 keys were dropped
|
|
expect(vi.mocked(cacheServer.clearCacheKey).mock.calls.filter((c) => c[0] === "tenant:tenant-9").length).toBeGreaterThanOrEqual(1);
|
|
});
|
|
|
|
it("subscribeTenantCache is idempotent", async () => {
|
|
const a = await subscribeTenantCache();
|
|
const b = await subscribeTenantCache();
|
|
expect(a).toBe(b);
|
|
});
|
|
});
|