181 lines
4.5 KiB
TypeScript
181 lines
4.5 KiB
TypeScript
import assert from "node:assert/strict";
|
||
import { mkdtemp, realpath, writeFile } from "node:fs/promises";
|
||
import { tmpdir } from "node:os";
|
||
import { join } from "node:path";
|
||
import test from "node:test";
|
||
|
||
import { runClawCommandForTesting } from "../src/lib/execution/backends/claw-runner.ts";
|
||
|
||
async function createTempScript(source: string) {
|
||
const dir = await mkdtemp(join(tmpdir(), "claw-runner-"));
|
||
const scriptPath = join(dir, "claw-script.mjs");
|
||
await writeFile(scriptPath, source, "utf8");
|
||
return { dir, scriptPath };
|
||
}
|
||
|
||
test("Claw runner 把 completed JSON 响应映射成 completed,并把 payload 写入 stdin", async () => {
|
||
const workspace = await mkdtemp(join(tmpdir(), "claw-runner-cwd-"));
|
||
const expectedWorkspace = await realpath(workspace);
|
||
const { scriptPath } = await createTempScript(`
|
||
import { readFile } from "node:fs/promises";
|
||
|
||
let stdin = "";
|
||
process.stdin.setEncoding("utf8");
|
||
for await (const chunk of process.stdin) {
|
||
stdin += chunk;
|
||
}
|
||
|
||
const payload = JSON.parse(stdin);
|
||
process.stdout.write(JSON.stringify({
|
||
status: "completed",
|
||
output: JSON.stringify({
|
||
body: payload.body,
|
||
cwd: process.cwd(),
|
||
command: payload.command,
|
||
}),
|
||
}));
|
||
`);
|
||
|
||
const result = await runClawCommandForTesting({
|
||
config: {
|
||
enabled: true,
|
||
command: process.execPath,
|
||
args: [scriptPath],
|
||
cwd: workspace,
|
||
timeoutMs: 1000,
|
||
},
|
||
payload: {
|
||
body: "继续执行",
|
||
command: "claw",
|
||
},
|
||
});
|
||
|
||
assert.equal(result.status, "completed");
|
||
if (result.status !== "completed") {
|
||
assert.fail("expected completed");
|
||
}
|
||
|
||
const output = JSON.parse(result.output) as {
|
||
body: string;
|
||
cwd: string;
|
||
command: string;
|
||
};
|
||
|
||
assert.equal(output.body, "继续执行");
|
||
assert.equal(output.cwd, expectedWorkspace);
|
||
assert.equal(output.command, "claw");
|
||
});
|
||
|
||
test("Claw runner 把 failed JSON 响应映射成 failed", async () => {
|
||
const { scriptPath } = await createTempScript(`
|
||
let stdin = "";
|
||
process.stdin.setEncoding("utf8");
|
||
for await (const chunk of process.stdin) {
|
||
stdin += chunk;
|
||
}
|
||
|
||
const payload = JSON.parse(stdin);
|
||
process.stdout.write(JSON.stringify({
|
||
status: "failed",
|
||
error: "bad-request:" + payload.body,
|
||
}));
|
||
`);
|
||
|
||
const result = await runClawCommandForTesting({
|
||
config: {
|
||
enabled: true,
|
||
command: process.execPath,
|
||
args: [scriptPath],
|
||
timeoutMs: 1000,
|
||
},
|
||
payload: {
|
||
body: "格式不对",
|
||
},
|
||
});
|
||
|
||
assert.equal(result.status, "failed");
|
||
if (result.status !== "failed") {
|
||
assert.fail("expected failed");
|
||
}
|
||
|
||
assert.equal(result.error, "bad-request:格式不对");
|
||
});
|
||
|
||
test("Claw runner 把无效 JSON 响应映射成 INVALID_CLAW_RESPONSE", async () => {
|
||
const { scriptPath } = await createTempScript(`
|
||
process.stdout.write("not-json");
|
||
`);
|
||
|
||
const result = await runClawCommandForTesting({
|
||
config: {
|
||
enabled: true,
|
||
command: process.execPath,
|
||
args: [scriptPath],
|
||
timeoutMs: 1000,
|
||
},
|
||
payload: {
|
||
body: "anything",
|
||
},
|
||
});
|
||
|
||
assert.equal(result.status, "failed");
|
||
if (result.status !== "failed") {
|
||
assert.fail("expected failed");
|
||
}
|
||
|
||
assert.match(result.error, /INVALID_CLAW_RESPONSE/);
|
||
});
|
||
|
||
test("Claw runner 把非零退出码映射成 stderr 或退出码错误", async () => {
|
||
const { scriptPath } = await createTempScript(`
|
||
process.stderr.write("claw crashed");
|
||
process.exit(2);
|
||
`);
|
||
|
||
const result = await runClawCommandForTesting({
|
||
config: {
|
||
enabled: true,
|
||
command: process.execPath,
|
||
args: [scriptPath],
|
||
timeoutMs: 1000,
|
||
},
|
||
payload: {
|
||
body: "anything",
|
||
},
|
||
});
|
||
|
||
assert.equal(result.status, "failed");
|
||
if (result.status !== "failed") {
|
||
assert.fail("expected failed");
|
||
}
|
||
|
||
assert.match(result.error, /claw crashed/);
|
||
});
|
||
|
||
test("Claw runner 超时后返回 CLAW_TIMEOUT", async () => {
|
||
const { scriptPath } = await createTempScript(`
|
||
setTimeout(() => {
|
||
process.stdout.write(JSON.stringify({ status: "completed", output: "late" }));
|
||
}, 500);
|
||
`);
|
||
|
||
const result = await runClawCommandForTesting({
|
||
config: {
|
||
enabled: true,
|
||
command: process.execPath,
|
||
args: [scriptPath],
|
||
timeoutMs: 50,
|
||
},
|
||
payload: {
|
||
body: "slow",
|
||
},
|
||
});
|
||
|
||
assert.equal(result.status, "failed");
|
||
if (result.status !== "failed") {
|
||
assert.fail("expected failed");
|
||
}
|
||
|
||
assert.match(result.error, /CLAW_TIMEOUT/);
|
||
});
|