Files
Edu/services/parent-bff/test/unit/orchestrator.test.ts
SpecialX 2229309a1e feat: initialize parent-bff service with full core features
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
2026-07-10 18:49:06 +08:00

121 lines
4.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, it, expect } from "vitest";
import { orchestrate } from "../../src/aggregation/orchestrator.js";
describe("Orchestrator", () => {
describe("全部成功", () => {
it("返回所有结果且 partial=false", async () => {
const result = await orchestrate({
a: Promise.resolve("value-a"),
b: Promise.resolve(42),
c: Promise.resolve({ key: "val" }),
});
expect(result.partial).toBe(false);
expect(result.failures).toHaveLength(0);
expect(result.results.a).toBe("value-a");
expect(result.results.b).toBe(42);
expect(result.results.c).toEqual({ key: "val" });
});
});
describe("部分失败降级(测试用例 5", () => {
it("data-ana 失败时该字段为 null其他字段正常", async () => {
const result = await orchestrate({
parent: Promise.resolve({ id: "parent-001", name: "王家长" }),
children: Promise.resolve([
{ id: "student-001", name: "李同学" },
]),
analytics: Promise.reject(new Error("data-ana connection refused")),
});
expect(result.partial).toBe(true);
expect(result.results.parent).toEqual({ id: "parent-001", name: "王家长" });
expect(result.results.children).toEqual([
{ id: "student-001", name: "李同学" },
]);
expect(result.results.analytics).toBeNull();
expect(result.failures).toHaveLength(1);
expect(result.failures[0]!.key).toBe("analytics");
});
it("多个失败都记录在 failures 中", async () => {
const result = await orchestrate({
ok: Promise.resolve("ok"),
fail1: Promise.reject(new Error("err1")),
fail2: Promise.reject(new Error("err2")),
});
expect(result.partial).toBe(true);
expect(result.failures).toHaveLength(2);
expect(result.failures.map((f) => f.key)).toContain("fail1");
expect(result.failures.map((f) => f.key)).toContain("fail2");
expect(result.results.ok).toBe("ok");
expect(result.results.fail1).toBeNull();
expect(result.results.fail2).toBeNull();
});
});
describe("全部失败", () => {
it("所有字段为 null 且 partial=true", async () => {
const result = await orchestrate({
a: Promise.reject(new Error("err-a")),
b: Promise.reject(new Error("err-b")),
});
expect(result.partial).toBe(true);
expect(result.results.a).toBeNull();
expect(result.results.b).toBeNull();
expect(result.failures).toHaveLength(2);
});
});
describe("空任务", () => {
it("返回空结果且 partial=false", async () => {
const result = await orchestrate({});
expect(result.partial).toBe(false);
expect(result.failures).toHaveLength(0);
expect(Object.keys(result.results)).toHaveLength(0);
});
});
describe("并行执行", () => {
it("任务并行执行而非串行", async () => {
const delay = (ms: number) => new Promise((r) => setTimeout(r, ms));
const start = Date.now();
await orchestrate({
a: delay(100).then(() => "a"),
b: delay(100).then(() => "b"),
c: delay(100).then(() => "c"),
});
const elapsed = Date.now() - start;
// 并行:总耗时约 100ms而非 300ms
expect(elapsed).toBeLessThan(250);
});
});
describe("failures 结构", () => {
it("failure 包含 key 和 error", async () => {
const error = new Error("test error");
const result = await orchestrate({
failing: Promise.reject(error),
});
expect(result.failures).toHaveLength(1);
expect(result.failures[0]!.key).toBe("failing");
expect(result.failures[0]!.error).toBe(error);
});
it("非 Error 类型的 rejection 也记录", async () => {
const result = await orchestrate({
failing: Promise.reject("string error"),
});
expect(result.failures).toHaveLength(1);
expect(result.failures[0]!.error).toBe("string error");
});
});
});