Repository navigation
Expand file tree
/
Copy pathcreate-cache.redis.test.ts
More file actions
63 lines (52 loc) · 2.75 KB
/
Copy pathcreate-cache.redis.test.ts
File metadata and controls
63 lines (52 loc) · 2.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import { describe, it, expect, afterEach } from "vitest";
import { createCacheFactory, type CacheHandle } from "./create-cache.js";
import { RedisCache } from "./redis-cache.js";
// Same disclosure as store/postgres-case-store.test.ts: gated on REDIS_URL,
// skipped (not failed) when absent. create-cache.test.ts's own doc comment
// explains why the real-`ioredis` path (redisUrl set) was previously
// exercised nowhere at all — not even gated-and-skipped — "covered by
// typechecking and code review rather than an automated test." This file is
// that automated test: it proves createCacheFactory's connection-lifecycle
// wiring (lazyConnect, the `ready` handler, close()) actually works against
// a real Redis, not just that RedisCache's own logic is correct against
// redis-cache.test.ts's FakeRedis.
const REDIS_URL = process.env.REDIS_URL;
describe.skipIf(!REDIS_URL)("createCacheFactory with a real Redis (integration — requires REDIS_URL)", () => {
let handle: CacheHandle;
afterEach(async () => {
await handle?.close();
});
it("returns a RedisCache, not the in-memory fallback, once redisUrl is set", () => {
handle = createCacheFactory({ redisUrl: REDIS_URL, ttlMs: 60_000 });
const cache = handle.factory<string>(`ci-test-${Date.now()}`);
expect(cache).toBeInstanceOf(RedisCache);
});
it("actually round-trips through Redis — a second getOrLoad for the same key hits the cache, not the loader", async () => {
handle = createCacheFactory({ redisUrl: REDIS_URL, ttlMs: 60_000 });
const cache = handle.factory<string>(`ci-test-${Date.now()}`);
let calls = 0;
const load = async () => {
calls++;
return "real-redis-value";
};
expect(await cache.getOrLoad("k", load)).toBe("real-redis-value");
expect(await cache.getOrLoad("k", load)).toBe("real-redis-value");
expect(calls).toBe(1); // second call was served from Redis, not re-loaded
});
it("delete() actually clears the key in Redis, not just in this process", async () => {
handle = createCacheFactory({ redisUrl: REDIS_URL, ttlMs: 60_000 });
const cache = handle.factory<string>(`ci-test-${Date.now()}`);
let calls = 0;
const load = async () => {
calls++;
return `v${calls}`;
};
expect(await cache.getOrLoad("k", load)).toBe("v1");
await cache.delete("k");
expect(await cache.getOrLoad("k", load)).toBe("v2"); // reloaded — the old entry is really gone
});
it("close() disconnects cleanly without throwing", async () => {
handle = createCacheFactory({ redisUrl: REDIS_URL, ttlMs: 60_000 });
await expect(handle.close()).resolves.toBeUndefined();
});
});