mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-06 05:51:15 +08:00
fix(e2e): fail codex app server log errors
This commit is contained in:
@@ -7,20 +7,36 @@ const requestLog =
|
||||
let turnCount = 0;
|
||||
|
||||
function appendRequest(request) {
|
||||
fs.appendFileSync(requestLog, `${JSON.stringify(request)}\n`);
|
||||
try {
|
||||
fs.appendFileSync(requestLog, `${JSON.stringify(request)}\n`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
process.stderr.write(`fake Codex app-server request log write failed: ${message}\n`);
|
||||
if (request?.id != null) {
|
||||
sendError(request.id, `fake Codex app-server request log write failed: ${message}`);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function send(id, result) {
|
||||
process.stdout.write(`${JSON.stringify({ id, result })}\n`);
|
||||
}
|
||||
|
||||
function sendError(id, message) {
|
||||
process.stdout.write(`${JSON.stringify({ error: { message }, id })}\n`);
|
||||
}
|
||||
|
||||
const rl = readline.createInterface({ input: process.stdin });
|
||||
rl.on("line", (line) => {
|
||||
if (!line.trim()) {
|
||||
return;
|
||||
}
|
||||
const request = JSON.parse(line);
|
||||
appendRequest(request);
|
||||
if (!appendRequest(request)) {
|
||||
return;
|
||||
}
|
||||
const { id, method, params } = request;
|
||||
if (method === "initialize") {
|
||||
send(id, {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { type ChildProcessWithoutNullStreams, spawn, spawnSync } from "node:child_process";
|
||||
import { appendFileSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import path from "node:path";
|
||||
@@ -7,6 +7,9 @@ import { createJsonlRequestTailer } from "../../scripts/e2e/lib/codex-media-path
|
||||
import { readPositiveIntEnv } from "../../scripts/e2e/lib/codex-media-path/limits.mjs";
|
||||
|
||||
const tempRoots: string[] = [];
|
||||
const fakeAppServerPath = path.resolve(
|
||||
"scripts/e2e/lib/codex-media-path/fake-codex-app-server.mjs",
|
||||
);
|
||||
const writeConfigPath = path.resolve("scripts/e2e/lib/codex-media-path/write-config.mjs");
|
||||
|
||||
function makeTempRoot(): string {
|
||||
@@ -42,6 +45,42 @@ function runWriteConfig(root: string, env: Record<string, string> = {}) {
|
||||
});
|
||||
}
|
||||
|
||||
async function readStdoutLine(child: ChildProcessWithoutNullStreams): Promise<string> {
|
||||
return await new Promise<string>((resolve, reject) => {
|
||||
let stdout = "";
|
||||
const timeout = setTimeout(() => {
|
||||
reject(new Error(`timed out waiting for fake app-server response: ${stdout}`));
|
||||
}, 3_000);
|
||||
child.stdout.setEncoding("utf8");
|
||||
child.stdout.on("data", (chunk: string) => {
|
||||
stdout += chunk;
|
||||
const line = stdout.split("\n").find((entry) => entry.trim());
|
||||
if (line) {
|
||||
clearTimeout(timeout);
|
||||
resolve(line);
|
||||
}
|
||||
});
|
||||
child.once("error", (error) => {
|
||||
clearTimeout(timeout);
|
||||
reject(error);
|
||||
});
|
||||
child.once("exit", (code, signal) => {
|
||||
clearTimeout(timeout);
|
||||
reject(new Error(`fake app-server exited before response: code=${code} signal=${signal}`));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function stopChild(child: ChildProcessWithoutNullStreams): Promise<void> {
|
||||
if (child.exitCode !== null || child.signalCode !== null) {
|
||||
return;
|
||||
}
|
||||
await new Promise<void>((resolve) => {
|
||||
child.once("close", () => resolve());
|
||||
child.kill("SIGTERM");
|
||||
});
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
for (const root of tempRoots.splice(0)) {
|
||||
rmSync(root, { recursive: true, force: true });
|
||||
@@ -87,6 +126,40 @@ describe("codex media path limits", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("codex media path fake app-server", () => {
|
||||
it("returns a structured error when request logging fails", async () => {
|
||||
const requestLogDirectory = makeTempRoot();
|
||||
const child: ChildProcessWithoutNullStreams = spawn(process.execPath, [fakeAppServerPath], {
|
||||
env: {
|
||||
...process.env,
|
||||
OPENCLAW_CODEX_MEDIA_PATH_APP_SERVER_LOG: requestLogDirectory,
|
||||
},
|
||||
stdio: ["pipe", "pipe", "pipe"],
|
||||
});
|
||||
let stderr = "";
|
||||
child.stderr.setEncoding("utf8");
|
||||
child.stderr.on("data", (chunk: string) => {
|
||||
stderr += chunk;
|
||||
});
|
||||
|
||||
try {
|
||||
const responseLine = readStdoutLine(child);
|
||||
child.stdin.write(jsonl({ id: "request-1", method: "initialize" }));
|
||||
const response = JSON.parse(await responseLine);
|
||||
|
||||
expect(response).toMatchObject({
|
||||
error: {
|
||||
message: expect.stringContaining("fake Codex app-server request log write failed"),
|
||||
},
|
||||
id: "request-1",
|
||||
});
|
||||
expect(stderr).toContain("fake Codex app-server request log write failed");
|
||||
} finally {
|
||||
await stopChild(child);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("codex media path JSONL tailer", () => {
|
||||
it("keeps parsed app-server requests and reads only appended lines", () => {
|
||||
const logPath = path.join(makeTempRoot(), "app-server.jsonl");
|
||||
|
||||
Reference in New Issue
Block a user