forked from EduCraft/curriculum-project-hub
test(hub): integration 测试套件(13 tests,真 prisma+真 cph)
三层 integration,对齐 unit 层: - trigger.test.ts: @bot→run→lock→release→card 全链路;权限拒绝(READ 不能 triggerAgent ADR-0004);竞态 busy(ADR-0002);未绑定 chat 忽略 (ADR-0001);无 @bot 忽略 —— 5 tests - lock.test.ts: acquire/release 回环;排他性(同 project 二次 acquire 抛); WellFormed(终止 run 持锁即抛);release 幂等;isTerminal 对齐 spec —— 5 tests - cph.test.ts: 真 cph binary 跑 TH-141 examples 的 check(exit 0)+ build student PDF(exit 0)+ 空目录 check(非 0)—— 3 tests helpers: resetDb(truncate CASCADE)、mockFeishuRuntime(记录 sentTexts/ sentCards)、MockProvider(fixed stop 响应)、seedProject(project→user→grant) prisma migrate dev init 生成初始 migration 并应用到 cph_hub_test 库。 vitest config 改 fileParallelism=false(integration 共享一 DB,串行避免 truncate/insert 竞态)。 vitest run 35/35(22 unit + 13 integration)通过;tsc rc=0。
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
import { describe, it, expect, beforeEach } from "vitest";
|
||||
import { mkdtemp, rm, writeFile, mkdir } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { ToolRegistry } from "../../src/agent/tools.js";
|
||||
import { cphCheckTool, cphBuildTool } from "../../src/agent/cph.js";
|
||||
|
||||
const EXAMPLES_DIR = join(process.cwd(), "..", "examples", "TH-141");
|
||||
|
||||
describe("cph subprocess tools (integration, real cph binary)", () => {
|
||||
let ws: string;
|
||||
let tools: ToolRegistry;
|
||||
|
||||
beforeEach(async () => {
|
||||
// Use the real TH-141 example as the workspace.
|
||||
ws = EXAMPLES_DIR;
|
||||
tools = new ToolRegistry();
|
||||
tools.register(cphCheckTool());
|
||||
tools.register(cphBuildTool());
|
||||
});
|
||||
|
||||
it("cph_check runs on the TH-141 example and returns diagnostics", async () => {
|
||||
const ctx = { runId: "r", projectId: "p", boundChatId: "c", workspaceDir: ws };
|
||||
const out = await tools.execute("cph_check", {}, ctx);
|
||||
const result = JSON.parse(out) as { exitCode: number; stdout: string; stderr: string };
|
||||
|
||||
// cph check exits 0 on a legal lesson (no error diagnostics, ADR-0010).
|
||||
// If the example has warnings, exit is still 0.
|
||||
expect(result.exitCode).toBe(0);
|
||||
}, 30000);
|
||||
|
||||
it("cph_build renders the student target PDF", async () => {
|
||||
const ctx = { runId: "r", projectId: "p", boundChatId: "c", workspaceDir: ws };
|
||||
const out = await tools.execute("cph_build", { target: "student", output: "build/test-student.pdf" }, ctx);
|
||||
const result = JSON.parse(out) as { exitCode: number; stdout: string; stderr: string; output: string };
|
||||
|
||||
expect(result.exitCode).toBe(0);
|
||||
}, 30000);
|
||||
|
||||
it("cph_check on a temp dir with no engineering file returns non-zero", async () => {
|
||||
const empty = await mkdtemp(join(tmpdir(), "hub-cph-empty-"));
|
||||
try {
|
||||
const ctx = { runId: "r", projectId: "p", boundChatId: "c", workspaceDir: empty };
|
||||
const out = await tools.execute("cph_check", {}, ctx);
|
||||
const result = JSON.parse(out) as { exitCode: number };
|
||||
expect(result.exitCode).not.toBe(0);
|
||||
} finally {
|
||||
await rm(empty, { recursive: true, force: true });
|
||||
}
|
||||
}, 15000);
|
||||
});
|
||||
Reference in New Issue
Block a user