feat: migrate device pod cli to rest authority
This commit is contained in:
@@ -173,6 +173,61 @@ test("device pod executor dispatches internal jobs through cloud-api gateway ada
|
||||
}
|
||||
});
|
||||
|
||||
test("device-pod executor maps v0.1 CLI options to device-host-cli argv", async () => {
|
||||
let dispatchedBody = null;
|
||||
const cloudApi = createServer(async (request, response) => {
|
||||
dispatchedBody = await requestJson(request);
|
||||
response.writeHead(200, { "content-type": "application/json; charset=utf-8" });
|
||||
response.end(JSON.stringify({
|
||||
ok: true,
|
||||
result: {
|
||||
status: "completed",
|
||||
dispatch: { shellExecuted: true, dispatchStatus: "succeeded", stdout: "ok", exitCode: 0 },
|
||||
auditId: "aud_options",
|
||||
evidenceId: "ev_options"
|
||||
}
|
||||
}));
|
||||
});
|
||||
await new Promise((resolve) => cloudApi.listen(0, "127.0.0.1", resolve));
|
||||
const cloudPort = cloudApi.address().port;
|
||||
const service = await startDevicePod("device-pod-test", {
|
||||
HWLAB_CLOUD_API_INTERNAL_URL: `http://127.0.0.1:${cloudPort}`
|
||||
});
|
||||
|
||||
try {
|
||||
const jobResponse = await fetch(`http://127.0.0.1:${service.port}/v1/device-pods/device-pod-test/jobs`, {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json", "x-hwlab-internal-service": "hwlab-cloud-api" },
|
||||
body: JSON.stringify({
|
||||
jobId: "job_options_test",
|
||||
intent: "debug.download",
|
||||
args: { action: "start", captureUart: "uart/1", captureDurationMs: 8000, port: "COM4", baudRate: 921600 },
|
||||
profileHash: "sha256:profile",
|
||||
profile: {
|
||||
devicePodId: "device-pod-test",
|
||||
target: { id: "target-test" },
|
||||
route: { gatewaySessionId: "gws_test", resourceId: "res_test", capabilityId: "cap_test", hostCli: "node tools/device-host-cli.mjs" }
|
||||
}
|
||||
})
|
||||
});
|
||||
assert.equal(jobResponse.status, 202);
|
||||
await waitForJobStatus(service.port, "device-pod-test", "job_options_test", "completed");
|
||||
const command = dispatchedBody.params.input.command;
|
||||
const encoded = command.match(/"([A-Za-z0-9+/=]+)"$/u)[1];
|
||||
const decoded = JSON.parse(Buffer.from(encoded, "base64").toString("utf8"));
|
||||
assert.deepEqual(decoded.args, [
|
||||
"debug-probe", "download", "start",
|
||||
"--capture-uart", "uart/1",
|
||||
"--capture-duration-ms", "8000",
|
||||
"--port", "COM4",
|
||||
"--baud-rate", "921600"
|
||||
]);
|
||||
} finally {
|
||||
await service.stop();
|
||||
await new Promise((resolve, reject) => cloudApi.close((error) => (error ? reject(error) : resolve())));
|
||||
}
|
||||
});
|
||||
|
||||
async function startDevicePod(devicePodId, extraEnv = {}) {
|
||||
const port = await freePort();
|
||||
const child = spawn(bunCommand, ["run", "cmd/hwlab-device-pod/main.ts"], {
|
||||
|
||||
@@ -399,20 +399,38 @@ function deviceHostArgs(intent, args = {}) {
|
||||
}
|
||||
if (intent === "workspace.rg") {
|
||||
const pattern = textOr(args.pattern ?? args.query, "");
|
||||
return pattern ? ["workspace", "rg", pattern, textOr(args.path, ".")] : null;
|
||||
return pattern ? ["workspace", "rg", pattern, textOr(args.path, "."), ...hostOptionArgs(args, ["glob", "g", "filesWithMatches", "l", "ignoreCase", "i", "maxCount"])] : null;
|
||||
}
|
||||
if (intent === "workspace.apply-patch") return ["workspace", "apply-patch", textOr(args.base, "."), "--patch-b64", patchBase64(args)];
|
||||
if (intent === "workspace.build") return ["workspace", "build", textOr(args.action, "start")];
|
||||
if (intent === "workspace.build") return ["workspace", "build", textOr(args.action, "start"), ...hostOptionArgs(args, ["target", "timeoutMs"]), ...jobIdArgs(args)];
|
||||
if (intent === "debug.status") return ["debug-probe", "status"];
|
||||
if (intent === "debug.chip-id") return ["debug-probe", "chip-id"];
|
||||
if (intent === "debug.download") return ["debug-probe", "download", textOr(args.action, "start")];
|
||||
if (intent === "debug.download") return ["debug-probe", "download", textOr(args.action, "start"), ...hostOptionArgs(args, ["target", "timeoutMs", "captureUart", "captureDurationMs", "durationMs", "port", "baudRate"]), ...jobIdArgs(args)];
|
||||
if (intent === "debug.reset") return ["debug-probe", "reset"];
|
||||
if (intent === "io.ports") return ["io-probe", textOr(args.uartId, "uart/1"), "ports"];
|
||||
if (intent === "io.uart.read") return ["io-probe", textOr(args.uartId, "uart/1"), "read", "--duration-ms", String(numberOr(args.durationMs ?? args["duration-ms"], 1000))];
|
||||
if (intent === "io.uart.write") return ["io-probe", textOr(args.uartId, "uart/1"), "write", ...(args.hex ? ["--hex"] : []), textOr(args.message ?? args.text ?? args.data, "")];
|
||||
if (intent === "io.uart.read") return ["io-probe", textOr(args.uartId, "uart/1"), "read", "--duration-ms", String(numberOr(args.durationMs ?? args["duration-ms"], 1000)), ...hostOptionArgs(args, ["port", "baudRate"])] ;
|
||||
if (intent === "io.uart.read-after-launch-flash") return ["io-probe", textOr(args.uartId, "uart/1"), "read-after-launch-flash", ...hostOptionArgs(args, ["durationMs", "port", "baudRate", "flashBase", "skipHardwareReset", "connectMode", "timeoutMs"])] ;
|
||||
if (intent === "io.uart.write") return ["io-probe", textOr(args.uartId, "uart/1"), "write", ...(args.hex ? ["--hex"] : []), ...hostOptionArgs(args, ["port", "baudRate"]), textOr(args.message ?? args.text ?? args.data, "")];
|
||||
return null;
|
||||
}
|
||||
|
||||
function jobIdArgs(args = {}) {
|
||||
const jobId = textOr(args.jobId, "");
|
||||
return jobId ? [jobId] : [];
|
||||
}
|
||||
|
||||
function hostOptionArgs(args = {}, keys = []) {
|
||||
const out = [];
|
||||
for (const key of keys) {
|
||||
const value = args[key];
|
||||
if (value === undefined || value === null || value === "" || value === false) continue;
|
||||
const name = `--${key.replace(/[A-Z]/gu, (match) => `-${match.toLowerCase()}`)}`;
|
||||
if (value === true) out.push(name);
|
||||
else out.push(name, String(value));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function patchBase64(args = {}) {
|
||||
if (typeof args.patchB64 === "string") return args.patchB64;
|
||||
if (typeof args["patch-b64"] === "string") return args["patch-b64"];
|
||||
|
||||
Reference in New Issue
Block a user