add complete parent-bff implementation including: - GraphQL endpoint with depth/cost validation - ChildGuard越权校验 with redis cache and singleflight - parallel orchestration with partial failure fallback - three-level cache fallback strategy (Redis + LRU + downstream) - Kafka consumer for cache invalidation and notification push - opossum circuit breaker for downstream services - Prometheus metrics and SLO alerts - Helm chart for k8s deployment with multi-environment configs - Grafana dashboard for observability - complete unit and integration tests
100 lines
2.5 KiB
TypeScript
100 lines
2.5 KiB
TypeScript
import { describe, it, expect, beforeEach } from "vitest";
|
|
import { LruCache } from "../../src/shared/cache/lru.cache.js";
|
|
|
|
describe("LruCache", () => {
|
|
let cache: LruCache;
|
|
|
|
beforeEach(() => {
|
|
cache = new LruCache(3);
|
|
});
|
|
|
|
describe("set / get", () => {
|
|
it("应该存取值", () => {
|
|
cache.set("key1", "value1", 60);
|
|
expect(cache.get("key1")).toBe("value1");
|
|
});
|
|
|
|
it("未设置的 key 返回 null", () => {
|
|
expect(cache.get("nonexistent")).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe("TTL 过期", () => {
|
|
it("过期后返回 null", async () => {
|
|
cache.set("key1", "value1", 0.01);
|
|
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
expect(cache.get("key1")).toBeNull();
|
|
});
|
|
|
|
it("未过期时返回值", () => {
|
|
cache.set("key1", "value1", 60);
|
|
expect(cache.get("key1")).toBe("value1");
|
|
});
|
|
});
|
|
|
|
describe("LRU 淘汰", () => {
|
|
it("容量满时淘汰最久未使用的条目", () => {
|
|
cache.set("a", "1", 60);
|
|
cache.set("b", "2", 60);
|
|
cache.set("c", "3", 60);
|
|
cache.set("d", "4", 60);
|
|
|
|
expect(cache.get("a")).toBeNull();
|
|
expect(cache.get("b")).toBe("2");
|
|
expect(cache.get("c")).toBe("3");
|
|
expect(cache.get("d")).toBe("4");
|
|
});
|
|
|
|
it("访问后更新 LRU 顺序", () => {
|
|
cache.set("a", "1", 60);
|
|
cache.set("b", "2", 60);
|
|
cache.set("c", "3", 60);
|
|
|
|
cache.get("a");
|
|
|
|
cache.set("d", "4", 60);
|
|
|
|
expect(cache.get("a")).toBe("1");
|
|
expect(cache.get("b")).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe("delete", () => {
|
|
it("删除后返回 null", () => {
|
|
cache.set("key1", "value1", 60);
|
|
cache.delete("key1");
|
|
expect(cache.get("key1")).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe("clear", () => {
|
|
it("清空所有条目", () => {
|
|
cache.set("a", "1", 60);
|
|
cache.set("b", "2", 60);
|
|
cache.clear();
|
|
expect(cache.size).toBe(0);
|
|
});
|
|
});
|
|
|
|
describe("size", () => {
|
|
it("返回当前条目数", () => {
|
|
expect(cache.size).toBe(0);
|
|
cache.set("a", "1", 60);
|
|
expect(cache.size).toBe(1);
|
|
cache.set("b", "2", 60);
|
|
expect(cache.size).toBe(2);
|
|
});
|
|
});
|
|
|
|
it("默认 maxSize 为 100", () => {
|
|
const defaultCache = new LruCache();
|
|
for (let i = 0; i < 100; i++) {
|
|
defaultCache.set(`key${i}`, `val${i}`, 60);
|
|
}
|
|
expect(defaultCache.size).toBe(100);
|
|
defaultCache.set("key100", "val100", 60);
|
|
expect(defaultCache.size).toBe(100);
|
|
expect(defaultCache.get("key0")).toBeNull();
|
|
});
|
|
});
|