Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -15,9 +15,13 @@ test("native CaseRun fixtures expose six deterministic API-owned states", () =>
|
||||
const running = readNativeRun(started!.runId);
|
||||
assert.equal(running?.status, "running");
|
||||
assert.equal(running?.terminal, false);
|
||||
for (let index = 0; index < 3; index += 1) readNativeRun(started!.runId);
|
||||
const completed = readNativeRun(started!.runId);
|
||||
assert.equal(completed?.status, "completed");
|
||||
assert.equal(completed?.terminal, true);
|
||||
assert.equal(completed?.workflowId, `harnessrl-caserun-${started!.runId}`);
|
||||
assert.equal(completed?.result.summary.artifactCount, 1);
|
||||
assert.equal(completed?.result.summary.artifacts[0].path, "native-result.json");
|
||||
assert.match(completed?.references.aggregate.sha256 ?? "", /^[a-f0-9]{64}$/);
|
||||
|
||||
const aggregate = readNativeAggregate(started!.runId);
|
||||
@@ -27,7 +31,8 @@ test("native CaseRun fixtures expose six deterministic API-owned states", () =>
|
||||
assert.equal(aggregate?.sha256, completed?.references.aggregate.sha256);
|
||||
|
||||
const events = readNativeEvents(started!.runId);
|
||||
assert.deepEqual(events?.events.map((event) => event.status), ["queued", "running", "completed"]);
|
||||
assert.deepEqual(events?.events.map((event) => event.stage), ["queued", "prepare", "prepared", "build-completed", "collect-completed", "completed"]);
|
||||
assert.equal(events?.events[0]?.createdAt, events?.events[0]?.at);
|
||||
assert.equal(events?.mode, "native-test");
|
||||
});
|
||||
|
||||
|
||||
@@ -23,7 +23,14 @@ const BASE_TIME = Date.parse("2026-07-17T00:00:00.000Z");
|
||||
const scenarios: Record<string, { title: string; steps: NativeStep[] }> = {
|
||||
"native-queued": { title: "原生排队中", steps: [{ status: "queued", stage: "queued", terminal: false }] },
|
||||
"native-running": { title: "原生运行中", steps: [{ status: "queued", stage: "queued", terminal: false }, { status: "running", stage: "agent-running", terminal: false }] },
|
||||
"native-completed": { title: "原生已完成", steps: [{ status: "queued", stage: "queued", terminal: false }, { status: "running", stage: "agent-running", terminal: false }, { status: "completed", stage: "completed", terminal: true }] },
|
||||
"native-completed": { title: "原生已完成", steps: [
|
||||
{ status: "queued", stage: "queued", terminal: false },
|
||||
{ status: "running", stage: "prepare", terminal: false },
|
||||
{ status: "running", stage: "prepared", terminal: false },
|
||||
{ status: "running", stage: "build-completed", terminal: false },
|
||||
{ status: "running", stage: "collect-completed", terminal: false },
|
||||
{ status: "completed", stage: "completed", terminal: true }
|
||||
] },
|
||||
"native-failed": { title: "原生失败", steps: [{ status: "queued", stage: "queued", terminal: false }, { status: "running", stage: "building", terminal: false }, { status: "failed", stage: "failed", terminal: true, blocker: { code: "native-build-failed", summary: "原生构建按确定性场景失败", layer: "build" } }] },
|
||||
"native-blocked": { title: "原生受阻", steps: [{ status: "queued", stage: "queued", terminal: false }, { status: "blocked", stage: "preparing", terminal: true, blocker: { code: "native-capability-blocked", summary: "原生能力按确定性场景受阻", layer: "hwpod" } }] },
|
||||
"native-canceled": { title: "原生已取消", steps: [{ status: "queued", stage: "queued", terminal: false }, { status: "running", stage: "agent-running", terminal: false }, { status: "canceled", stage: "canceled", terminal: true }] }
|
||||
@@ -38,15 +45,23 @@ function timestamp(index: number): string {
|
||||
|
||||
function aggregateResponse(run: NativeRunState) {
|
||||
const step = run.steps[run.cursor] ?? run.steps.at(-1)!;
|
||||
const artifact = {
|
||||
path: "native-result.json",
|
||||
bytes: 335,
|
||||
sha256: createHash("sha256").update(`${run.runId}:native-result.json`).digest("hex")
|
||||
};
|
||||
const summary = {
|
||||
mode: MODE,
|
||||
status: step.status,
|
||||
jobId: `job-${run.runId}`,
|
||||
artifactCount: step.status === "completed" ? 2 : 0
|
||||
artifacts: step.status === "completed" ? [artifact] : [],
|
||||
artifactCount: step.status === "completed" ? 1 : 0
|
||||
};
|
||||
const evidence = {
|
||||
mode: MODE,
|
||||
status: step.status,
|
||||
blocker: step.blocker ?? null,
|
||||
artifacts: step.status === "completed" ? [{ name: "firmware.bin" }, { name: "caserun.log" }] : []
|
||||
artifacts: step.status === "completed" ? [artifact] : []
|
||||
};
|
||||
const archivedRun = {
|
||||
runId: run.runId,
|
||||
@@ -54,7 +69,8 @@ function aggregateResponse(run: NativeRunState) {
|
||||
status: step.status,
|
||||
stage: step.stage,
|
||||
terminal: step.terminal,
|
||||
mode: MODE
|
||||
mode: MODE,
|
||||
hardwareRequired: false
|
||||
};
|
||||
const source = { runId: run.runId, caseId: run.caseId, status: step.status, summary, evidence, run: archivedRun };
|
||||
return {
|
||||
@@ -68,6 +84,7 @@ function aggregateResponse(run: NativeRunState) {
|
||||
terminal: step.terminal,
|
||||
sourceAuthority: { mode: MODE, sequence: "request-driven" },
|
||||
sha256: createHash("sha256").update(JSON.stringify(source)).digest("hex"),
|
||||
result: { run: archivedRun, summary, evidence },
|
||||
summary,
|
||||
evidence,
|
||||
run: archivedRun
|
||||
@@ -82,6 +99,8 @@ function runResponse(run: NativeRunState) {
|
||||
contractVersion: CONTRACT_VERSION,
|
||||
runId: run.runId,
|
||||
caseId: run.caseId,
|
||||
workflowId: `harnessrl-caserun-${run.runId}`,
|
||||
workflowRunId: `native-workflow-${run.runId}`,
|
||||
status: step.status,
|
||||
stage: step.stage,
|
||||
terminal: step.terminal,
|
||||
@@ -90,9 +109,10 @@ function runResponse(run: NativeRunState) {
|
||||
updatedAt: timestamp(run.cursor),
|
||||
facts: {
|
||||
jobId: `job-${run.runId}`,
|
||||
artifactCount: step.status === "completed" ? 2 : 0,
|
||||
artifactCount: step.status === "completed" ? 1 : 0,
|
||||
evidenceStatus: step.status
|
||||
},
|
||||
result: aggregateResponse(run).result,
|
||||
references: {
|
||||
status: { href: `/v1/caserun/runs/${run.runId}` },
|
||||
events: { href: `/v1/caserun/runs/${run.runId}/events`, count: run.cursor + 1 },
|
||||
@@ -142,7 +162,9 @@ export function readNativeEvents(runId: string) {
|
||||
if (!run) return null;
|
||||
const current = runResponse(run);
|
||||
const events = run.steps.slice(0, run.cursor + 1).map((step, index) => ({
|
||||
id: index + 1,
|
||||
at: timestamp(index),
|
||||
createdAt: timestamp(index),
|
||||
status: step.status,
|
||||
stage: step.stage,
|
||||
payload: { mode: MODE, terminal: step.terminal, blocker: step.blocker ?? null }
|
||||
|
||||
@@ -9,23 +9,29 @@ export default async function caserunNativeSmoke({ page, goto, wait, screenshot,
|
||||
await page.locator("#caserun-refresh").click();
|
||||
await wait(300);
|
||||
|
||||
const state = await page.locator("#caserun-status").evaluate((element) => element.textContent || "");
|
||||
const mode = (await page.locator("#caserun-mode").textContent())?.trim() || "";
|
||||
const terminal = (await page.locator("#caserun-terminal").textContent())?.trim() || "";
|
||||
const runId = (await page.locator("#caserun-run-id").textContent())?.trim() || "";
|
||||
const events = await page.locator("#caserun-event-text").textContent();
|
||||
const aggregateStatus = (await page.locator("#caserun-aggregate-status").textContent())?.trim() || "";
|
||||
const aggregateRunId = (await page.locator("#caserun-aggregate-run-id").textContent())?.trim() || "";
|
||||
const aggregateSha = (await page.locator("#caserun-aggregate-sha").textContent())?.trim() || "";
|
||||
const evidenceStatus = (await page.locator("#caserun-evidence-status").textContent())?.trim() || "";
|
||||
await page.getByRole("tab", { name: "产物" }).click();
|
||||
const artifactText = (await page.locator(".caserun-artifact-row").textContent()) || "";
|
||||
await page.getByRole("tab", { name: "编排" }).click();
|
||||
const workflowId = (await page.locator("#caserun-workflow-id").textContent())?.trim() || "";
|
||||
await page.getByRole("tab", { name: "结果" }).click();
|
||||
const conditions = {
|
||||
mode: mode.includes("native-test"),
|
||||
terminal: terminal === "是",
|
||||
aggregateStatus: aggregateStatus === "已完成",
|
||||
aggregateRunId: aggregateRunId === runId && runId.startsWith("native-completed-"),
|
||||
aggregateSha: /^[a-f0-9]{64}$/.test(aggregateSha),
|
||||
queuedEvent: events?.includes("queued") === true,
|
||||
runningEvent: events?.includes("running") === true,
|
||||
completedEvent: events?.includes("completed") === true
|
||||
evidenceStatus: evidenceStatus === "已完成",
|
||||
artifact: artifactText.includes("native-result.json") && artifactText.includes("335 B"),
|
||||
workflow: workflowId === `harnessrl-caserun-${runId}`,
|
||||
queuedEvent: events?.includes("进入队列") === true,
|
||||
buildEvent: events?.includes("构建完成") === true,
|
||||
completedEvent: events?.includes("运行完成") === true
|
||||
};
|
||||
const image = await screenshot("caserun-native-completed.png");
|
||||
recordStep("caserun-native-completed", { ok: Object.values(conditions).every(Boolean), conditions });
|
||||
|
||||
Reference in New Issue
Block a user