import assert from "node:assert/strict"; import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import { test } from "bun:test"; import { createCloudApiServer } from "./server.ts"; test("cloud-api exposes web CaseRun cases, run status, events and aggregate", async () => { const root = await mkdtemp(path.join(os.tmpdir(), "hwlab-caserun-api-")); const stateRoot = path.join(root, "state"); const caseDir = path.join(root, "cases", "d601-f103-v2-compile"); await mkdir(caseDir, { recursive: true }); await writeFile(path.join(caseDir, "case.json"), JSON.stringify({ contractVersion: "hwpod-case-v1", caseId: "d601-f103-v2-compile", title: "D601 compile", mode: "compile-only", hwpodSpec: "hwpod-spec.yaml", subject: { repoLocalPath: "F:\\Work\\HWLAB-CASE-F103", commitId: "abc", subdir: "projects/01_baseline" } }), "utf8"); await writeFile(path.join(caseDir, "hwpod-spec.yaml"), sampleSpecYaml(), "utf8"); const seen: any[] = []; const accessController = { async ensureBootstrap() {}, async requireNavAccess() { return true; } }; const server = createCloudApiServer({ accessController, env: { PATH: process.env.PATH, HWLAB_CASERUN_CASE_REPO: root, HWLAB_CASERUN_STATE_DIR: stateRoot, HWLAB_ENVIRONMENT: "v03", HWLAB_CLOUD_API_PORT: "6667" }, caseRunExecutor: async (context: any, emit: any) => { seen.push(context.parsed); await emit("prepared", { runDir: context.parsed.runDir }); await emit("build-completed", { jobId: "job-test" }); return { summary: { status: "recorded", jobId: "job-test", artifactCount: 2, artifacts: [{ path: "atk_f103.hex" }, { path: "atk_f103.axf" }] }, evidence: { status: "recorded", keilJob: { jobId: "job-test", status: "completed" }, artifacts: [{ path: "atk_f103.hex" }, { path: "atk_f103.axf" }] }, run: { runId: context.parsed.runId, caseId: context.parsed.caseId } }; } }); await listen(server); try { const indexResponse = await fetch(`${serverUrl(server)}/v1`); const indexPayload = await indexResponse.json(); assert.equal(indexPayload.caserun.route, "/v1/caserun"); const casesResponse = await fetch(`${serverUrl(server)}/v1/caserun/cases`); const casesPayload = await casesResponse.json(); assert.equal(casesResponse.status, 200); assert.equal(casesPayload.count, 1); assert.equal(casesPayload.cases[0].caseId, "d601-f103-v2-compile"); const startResponse = await fetch(`${serverUrl(server)}/v1/caserun/runs`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ caseId: "d601-f103-v2-compile" }) }); const startPayload = await startResponse.json(); assert.equal(startResponse.status, 202); assert.ok(["queued", "running"].includes(startPayload.status)); assert.match(startPayload.runId, /^web-d601-f103-v2-compile-/u); assert.equal(startPayload.runtimeApiUrl, serverUrl(server)); const runPayload = await waitForRun(server, startPayload.runId, "completed"); assert.equal(runPayload.summary.jobId, "job-test"); assert.equal(seen[0].noCaseRepoRecord, true); assert.equal(seen[0].caseRepo, root); assert.equal(seen[0].apiUrl, "http://hwlab-cloud-api.hwlab-v03.svc.cluster.local:6667"); const eventsResponse = await fetch(`${serverUrl(server)}/v1/caserun/runs/${startPayload.runId}/events`); const eventsPayload = await eventsResponse.json(); assert.equal(eventsResponse.status, 200); assert.ok(eventsPayload.events.some((event: any) => event.stage === "build-completed")); const aggregateResponse = await fetch(`${serverUrl(server)}/v1/caserun/runs/${startPayload.runId}/aggregate`); const aggregatePayload = await aggregateResponse.json(); assert.equal(aggregateResponse.status, 200); assert.equal(aggregatePayload.summary.jobId, "job-test"); assert.match(aggregatePayload.sha256, /^[a-f0-9]{64}$/u); } finally { await close(server); await rm(root, { recursive: true, force: true }); } }); async function waitForRun(server: any, runId: string, status: string) { const deadline = Date.now() + 3000; let last: any = null; while (Date.now() < deadline) { const response = await fetch(`${serverUrl(server)}/v1/caserun/runs/${runId}`); last = await response.json(); if (last.status === status) return last; await new Promise((resolve) => setTimeout(resolve, 50)); } assert.fail(`run did not reach ${status}: ${JSON.stringify(last)}`); } async function listen(server: any) { await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve)); } async function close(server: any) { await new Promise((resolve, reject) => server.close((error: Error | undefined) => (error ? reject(error) : resolve(undefined)))); } function serverUrl(server: any) { return `http://127.0.0.1:${server.address().port}`; } function sampleSpecYaml() { return `apiVersion: hwlab.dev/v0alpha1 kind: Hwpod metadata: uid: D601-F103-V2 name: d601-f103-v2 spec: workspace: path: "F:\\\\Work\\\\HWLAB-CASE-F103" nodeBinding: nodeId: node-d601-f103-v2 `; }