fix: accept submission completion state in worker API parser
This commit is contained in:
@@ -33,6 +33,7 @@ import {
|
|||||||
parseWorkerLaunchOptionsResponse,
|
parseWorkerLaunchOptionsResponse,
|
||||||
parseWorkerSummary,
|
parseWorkerSummary,
|
||||||
} from "./workers.ts";
|
} from "./workers.ts";
|
||||||
|
import { loadJson } from "./http.ts";
|
||||||
|
|
||||||
const worker = {
|
const worker = {
|
||||||
runtime_id: "runtime-a",
|
runtime_id: "runtime-a",
|
||||||
@@ -111,6 +112,92 @@ Deno.test("Worker summary parser enforces observation freshness", () => {
|
|||||||
assertEquals(observedStopped.state, "stopped");
|
assertEquals(observedStopped.state, "stopped");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const workerStates = [
|
||||||
|
{ kind: "idle" },
|
||||||
|
{ kind: "busy", state: { kind: "run", state: "running" } },
|
||||||
|
{ kind: "busy", state: { kind: "run", state: "pausing" } },
|
||||||
|
{ kind: "busy", state: { kind: "run", state: "paused" } },
|
||||||
|
{ kind: "busy", state: { kind: "run", state: "cancelling" } },
|
||||||
|
{ kind: "busy", state: { kind: "maintenance", state: "compacting" } },
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
Deno.test("Worker summary parser preserves the optional submission completion fence in every state", () => {
|
||||||
|
for (const state of workerStates) {
|
||||||
|
for (const completion of [
|
||||||
|
{},
|
||||||
|
{ last_finished_submission_request_id: null },
|
||||||
|
{ last_finished_submission_request_id: "completed-submit" },
|
||||||
|
]) {
|
||||||
|
const snapshot = { last_command_id: 7, ...completion, state };
|
||||||
|
const parsed = parseWorkerSummary({
|
||||||
|
...worker,
|
||||||
|
resource_key: "W-1",
|
||||||
|
availability: "observed",
|
||||||
|
worker_state: snapshot,
|
||||||
|
});
|
||||||
|
assertEquals(parsed.worker_state, snapshot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Deno.test("Worker summary parser validates submission completion fences without accepting unknown fields", () => {
|
||||||
|
for (const state of workerStates) {
|
||||||
|
for (const invalid of [0, false, {}, [], "x".repeat(65_537)]) {
|
||||||
|
assertThrows(
|
||||||
|
() => parseWorkerSummary({
|
||||||
|
...worker,
|
||||||
|
resource_key: "W-1",
|
||||||
|
availability: "observed",
|
||||||
|
worker_state: {
|
||||||
|
last_command_id: 7,
|
||||||
|
last_finished_submission_request_id: invalid,
|
||||||
|
state,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
Error,
|
||||||
|
"worker_state.last_finished_submission_request_id",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
assertThrows(
|
||||||
|
() => parseWorkerSummary({
|
||||||
|
...worker,
|
||||||
|
resource_key: "W-1",
|
||||||
|
availability: "observed",
|
||||||
|
worker_state: {
|
||||||
|
last_command_id: 7,
|
||||||
|
last_finished_submission_request_id: "completed-submit",
|
||||||
|
state,
|
||||||
|
unexpected: true,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
Error,
|
||||||
|
"unknown field unexpected",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Deno.test("Console Worker API loading accepts a completed submission snapshot", async () => {
|
||||||
|
const snapshot = {
|
||||||
|
last_command_id: 0,
|
||||||
|
last_finished_submission_request_id: "completed-submit",
|
||||||
|
state: { kind: "idle" },
|
||||||
|
};
|
||||||
|
const result = await loadJson(
|
||||||
|
() => Promise.resolve(Response.json({
|
||||||
|
...worker,
|
||||||
|
resource_key: "W-1",
|
||||||
|
availability: "observed",
|
||||||
|
worker_state: snapshot,
|
||||||
|
})),
|
||||||
|
"/api/w/workspace-a/workers/W-1",
|
||||||
|
undefined,
|
||||||
|
parseWorkerSummary,
|
||||||
|
{ diagnosticLabel: "Worker API", maxResponseBytes: 8 * 1024 * 1024 },
|
||||||
|
);
|
||||||
|
assertEquals(result.error, null);
|
||||||
|
assertEquals(result.data?.worker_state, snapshot);
|
||||||
|
});
|
||||||
|
|
||||||
Deno.test("Worker summary parser preserves attachment-effective External permissions", () => {
|
Deno.test("Worker summary parser preserves attachment-effective External permissions", () => {
|
||||||
const attachment = {
|
const attachment = {
|
||||||
alias: "sessions",
|
alias: "sessions",
|
||||||
|
|||||||
@@ -262,7 +262,16 @@ function workerStateSnapshot(
|
|||||||
label: string,
|
label: string,
|
||||||
): WorkerStateSnapshot {
|
): WorkerStateSnapshot {
|
||||||
const snapshot = record(value, label);
|
const snapshot = record(value, label);
|
||||||
exact(snapshot, ["last_command_id", "state"], label);
|
exact(
|
||||||
|
snapshot,
|
||||||
|
["last_command_id", "last_finished_submission_request_id", "state"],
|
||||||
|
label,
|
||||||
|
);
|
||||||
|
const lastFinishedSubmissionRequestId = optional(
|
||||||
|
snapshot.last_finished_submission_request_id,
|
||||||
|
`${label}.last_finished_submission_request_id`,
|
||||||
|
string,
|
||||||
|
);
|
||||||
const state = record(snapshot.state, `${label}.state`);
|
const state = record(snapshot.state, `${label}.state`);
|
||||||
const kind = string(state.kind, `${label}.state.kind`);
|
const kind = string(state.kind, `${label}.state.kind`);
|
||||||
if (kind === "idle") {
|
if (kind === "idle") {
|
||||||
@@ -272,6 +281,7 @@ function workerStateSnapshot(
|
|||||||
snapshot.last_command_id,
|
snapshot.last_command_id,
|
||||||
`${label}.last_command_id`,
|
`${label}.last_command_id`,
|
||||||
),
|
),
|
||||||
|
last_finished_submission_request_id: lastFinishedSubmissionRequestId,
|
||||||
state: { kind: "idle" },
|
state: { kind: "idle" },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -291,6 +301,7 @@ function workerStateSnapshot(
|
|||||||
snapshot.last_command_id,
|
snapshot.last_command_id,
|
||||||
`${label}.last_command_id`,
|
`${label}.last_command_id`,
|
||||||
),
|
),
|
||||||
|
last_finished_submission_request_id: lastFinishedSubmissionRequestId,
|
||||||
state: {
|
state: {
|
||||||
kind: "busy",
|
kind: "busy",
|
||||||
state: busyKind === "run"
|
state: busyKind === "run"
|
||||||
|
|||||||
Reference in New Issue
Block a user