import { describe, expect, test } from "bun:test"; import { CommandChecker } from "../../../../../src/server/checker/runner/command/runner"; import type { CheckerContext } from "../../../../../src/server/checker/runner/types"; import type { ResolvedCommandTarget } from "../../../../../src/server/checker/types"; const checker = new CommandChecker(); function makeTarget( command: Partial, overrides?: Partial, ): ResolvedCommandTarget { return { type: "command", name: "test-cmd", group: "default", command: { exec: "echo", args: ["hello"], cwd: "/tmp", env: {}, maxOutputBytes: 1024 * 1024, ...command, }, intervalMs: 60000, timeoutMs: 5000, ...overrides, }; } function makeCtx(timeoutMs = 5000): CheckerContext { const controller = new AbortController(); setTimeout(() => controller.abort(), timeoutMs); return { signal: controller.signal }; } describe("CommandChecker", () => { test("exitCode=0 成功", async () => { const result = await checker.execute(makeTarget({ exec: "true", args: [] }), makeCtx()); expect(result.matched).toBe(true); expect(result.statusDetail).toBe("exitCode=0"); expect(result.failure).toBeNull(); }); test("exitCode=1 不匹配默认 [0]", async () => { const result = await checker.execute(makeTarget({ exec: "false", args: [] }), makeCtx()); expect(result.matched).toBe(false); expect(result.statusDetail).toBe("exitCode=1"); expect(result.failure!.phase).toBe("exitCode"); }); test("exitCode=1 匹配自定义 [1]", async () => { const result = await checker.execute(makeTarget({ exec: "false", args: [] }, { expect: { exitCode: [1] } }), makeCtx()); expect(result.matched).toBe(true); expect(result.statusDetail).toBe("exitCode=1"); }); test("命令不存在返回 spawn 错误", async () => { const result = await checker.execute(makeTarget({ exec: "/nonexistent/command/xyz" }), makeCtx()); expect(result.matched).toBe(false); expect(result.failure!.phase).toBe("exitCode"); expect(result.failure!.message).toBeTruthy(); }); test("超时返回错误", async () => { const result = await checker.execute(makeTarget({ exec: "sleep", args: ["10"] }, { timeoutMs: 100 }), makeCtx(100)); expect(result.matched).toBe(false); expect(result.failure!.message).toContain("超时"); }); test("stdout 输出捕获", async () => { const result = await checker.execute(makeTarget({ exec: "echo", args: ["hello world"] }), makeCtx()); expect(result.matched).toBe(true); }); test("stdout 匹配 expect", async () => { const result = await checker.execute(makeTarget({ exec: "echo", args: ["hello"] }, { expect: { stdout: [{ contains: "hello" }] } }), makeCtx()); expect(result.matched).toBe(true); }); test("stdout 不匹配 expect", async () => { const result = await checker.execute(makeTarget({ exec: "echo", args: ["hello"] }, { expect: { stdout: [{ contains: "nonexistent" }] } }), makeCtx()); expect(result.matched).toBe(false); expect(result.failure!.phase).toBe("stdout"); }); test("stderr 匹配 expect", async () => { const result = await checker.execute(makeTarget({ exec: "bash", args: ["-c", "echo error >&2"] }, { expect: { stderr: [{ contains: "error" }] } }), makeCtx()); expect(result.matched).toBe(true); }); test("输出超过 maxOutputBytes", async () => { const result = await checker.execute(makeTarget({ exec: "bash", args: ["-c", "yes | head -1000"], maxOutputBytes: 10 }), makeCtx()); expect(result.matched).toBe(false); expect(result.failure!.message).toContain("超过限制"); }); test("durationMs 非空", async () => { const result = await checker.execute(makeTarget({ exec: "true", args: [] }), makeCtx()); expect(result.durationMs).not.toBeNull(); expect(result.durationMs!).toBeGreaterThanOrEqual(0); }); test("不使用 shell,通配符不被展开", async () => { const result = await checker.execute(makeTarget({ exec: "echo", args: ["*"] }, { expect: { stdout: [{ contains: "*" }] } }), makeCtx()); expect(result.matched).toBe(true); }); test("serialize 返回命令摘要和 config JSON", () => { const target = makeTarget({ exec: "echo", args: ["hello"] }); const s = checker.serialize(target); expect(s.target).toBe("exec echo hello"); const config = JSON.parse(s.config); expect(config.exec).toBe("echo"); expect(config.args).toEqual(["hello"]); }); });