Files
pikasTech-HWLAB/tools/hwlab-cli/caserun.test.ts
T
2026-06-06 10:11:46 +08:00

89 lines
5.4 KiB
TypeScript

import assert from "node:assert/strict";
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { test } from "bun:test";
import { runHwlabCli } from "../src/hwlab-cli-lib.ts";
import { artifactsFromKeilStatusForTest, extractKeilJobId, jobStatusCommandForTest } from "../src/hwlab-caserun-lib.ts";
test("hwlab-cli case prepare copies a case hwpod-spec into isolated run state", async () => {
const root = await mkdtempCaseRoot();
const caseRepo = path.join(root, "hwlab-case-registry");
const cwd = path.join(root, "hwlab");
const caseDir = path.join(caseRepo, "cases", "d601-f103-v2-compile");
try {
await mkdir(path.join(caseRepo, ".git"), { recursive: true });
await writeFile(path.join(caseRepo, ".git", "HEAD"), "ref: refs/heads/main\n", "utf8");
await mkdir(caseDir, { recursive: true });
await mkdir(cwd, { recursive: true });
await writeFile(path.join(caseDir, "case.json"), JSON.stringify({ contractVersion: "hwpod-case-v1", caseId: "d601-f103-v2-compile", hwpodSpec: "hwpod-spec.yaml", subject: { repo: "git@github.com:pikasTech/D601-HWLAB.git", ref: "main", subdir: "projects/01_baseline" } }, null, 2), "utf8");
await writeFile(path.join(caseDir, "hwpod-spec.yaml"), "kind: Hwpod\nspec:\n nodeBinding:\n nodeId: node-d601-f103-v2\n workspace:\n path: F:\\\\Work\\\\D601-HWLAB\n targetDevice:\n board: D601-F103-V2\n debugProbe:\n type: daplink\n ioProbe:\n uart:\n port: COM9\n", "utf8");
const result = await runHwlabCli(["case", "prepare", "d601-f103-v2-compile", "--case-repo", caseRepo, "--run-id", "run-test"], { cwd, now: () => "2026-06-05T00:00:00.000Z" });
assert.equal(result.exitCode, 0);
assert.equal(result.payload.action, "case.prepare.prepare");
assert.equal(result.payload.runId, "run-test");
assert.equal(result.payload.caseRepo, caseRepo);
assert.equal(result.payload.compileOnly, true);
assert.match(await readFile(path.join(cwd, ".state", "hwlab-cli", "caserun", "run-test", ".hwlab", "hwpod-spec.yaml"), "utf8"), /node-d601-f103-v2/u);
} finally {
await rm(root, { recursive: true, force: true });
}
});
test("case prepare uses the new registry by default and refuses the removed hwpod-cases path", async () => {
const root = await mkdtempCaseRoot();
const cwd = path.join(root, "hwlab");
const newRepo = path.join(root, "hwlab-case-registry");
const removedRepo = path.join(root, "hwpod-cases");
const caseId = "d601-f103-v2-compile";
try {
await createCaseRepo(newRepo, caseId);
await createCaseRepo(removedRepo, caseId);
await mkdir(cwd, { recursive: true });
const defaultResult = await runHwlabCli(["case", "prepare", caseId, "--run-id", "run-default"], { cwd, now: () => "2026-06-05T00:00:00.000Z" });
assert.equal(defaultResult.exitCode, 0);
assert.equal(defaultResult.payload.caseRepo, newRepo);
const removedResult = await runHwlabCli(["case", "prepare", caseId, "--case-repo", removedRepo], { cwd, now: () => "2026-06-05T00:00:00.000Z" });
assert.equal(removedResult.exitCode, 1);
assert.equal(removedResult.payload.error.code, "removed_case_repo_path");
assert.equal(removedResult.payload.error.details.standardCaseRepo, "/root/hwlab-case-registry");
} finally {
await rm(root, { recursive: true, force: true });
}
});
test("case run extracts Keil async job ids from hwpod-node output", () => {
const jobId = extractKeilJobId({ body: { results: [{ stdout: JSON.stringify({ ok: true, job_id: "20260605_203835_798515c0" }) }] } });
assert.equal(jobId, "20260605_203835_798515c0");
const nestedJobId = extractKeilJobId({ body: { results: [{ output: { stdout: JSON.stringify({ accepted: true, job_id: "20260605_210457_bdf3292a" }) } }] } });
assert.equal(nestedJobId, "20260605_210457_bdf3292a");
});
test("case run uses cmd.run command plus argv for Keil job-status", () => {
const command = jobStatusCommandForTest("py -3", "C:\\Users\\liang\\.agents\\skills\\keil\\keil-cli.py", "job-1");
assert.deepEqual(command, { command: "py", argv: ["-3", "C:\\Users\\liang\\.agents\\skills\\keil\\keil-cli.py", "job-status", "job-1"] });
});
test("case run exposes Keil hex and axf artifacts in evidence summary", () => {
assert.deepEqual(artifactsFromKeilStatusForTest({ result: { hex_file: "F:\\out.hex", axf_file: "F:\\out.axf" } }), ["F:\\out.hex", "F:\\out.axf"]);
});
async function mkdtempCaseRoot() {
return await import("node:fs/promises").then(({ mkdtemp }) => mkdtemp(path.join(os.tmpdir(), "hwlab-caserun-")));
}
async function createCaseRepo(caseRepo: string, caseId: string) {
const caseDir = path.join(caseRepo, "cases", caseId);
await mkdir(path.join(caseRepo, ".git"), { recursive: true });
await writeFile(path.join(caseRepo, ".git", "HEAD"), "ref: refs/heads/main\n", "utf8");
await mkdir(caseDir, { recursive: true });
await writeFile(path.join(caseDir, "case.json"), JSON.stringify({ contractVersion: "hwpod-case-v1", caseId, hwpodSpec: "hwpod-spec.yaml", subject: { repo: "git@github.com:pikasTech/D601-HWLAB.git", ref: "main", subdir: "projects/01_baseline" } }, null, 2), "utf8");
await writeFile(path.join(caseDir, "hwpod-spec.yaml"), "kind: Hwpod\nspec:\n nodeBinding:\n nodeId: node-d601-f103-v2\n workspace:\n path: F:\\\\Work\\\\D601-HWLAB\n targetDevice:\n board: D601-F103-V2\n debugProbe:\n type: daplink\n ioProbe:\n uart:\n port: COM9\n", "utf8");
}