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"); }); }); });