mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-06 05:51:15 +08:00
fix(e2e): fail pty transcript log errors
This commit is contained in:
@@ -39,6 +39,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Release/CI/E2E: abort stalled Kitchen Sink RPC readiness probes as soon as the gateway exits so proof failures return promptly.
|
||||
- Release/CI/E2E: keep Parallels JSON-mode progress on stderr so macOS, Linux, Windows, and aggregate update smoke summaries stay parseable on stdout.
|
||||
- Release/CI/E2E: fail Crabbox sparse-sync runs clearly when their temporary full checkout disappears while the child process is running, instead of pretending the child's deleted cwd can be repaired.
|
||||
- Release/CI/E2E: fail PTY-backed E2E commands when transcript logs cannot be written instead of letting missing proof capture crash around a live child process.
|
||||
|
||||
## 2026.6.1
|
||||
|
||||
|
||||
@@ -13,6 +13,16 @@ if (!logPath || !command) {
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
let exiting = false;
|
||||
let forwardedSignal = null;
|
||||
let forceKillTimer = null;
|
||||
let logFailed = false;
|
||||
const outputLimitMarker = `\n[run-with-pty output truncated after ${OUTPUT_MAX_BYTES} bytes]\n`;
|
||||
const outputState = {
|
||||
bytes: 0,
|
||||
truncated: false,
|
||||
};
|
||||
|
||||
const log = fs.createWriteStream(logPath, { flags: "w" });
|
||||
const pty = spawn(command, args, {
|
||||
name: process.env.TERM || "xterm-256color",
|
||||
@@ -22,14 +32,23 @@ const pty = spawn(command, args, {
|
||||
env: process.env,
|
||||
});
|
||||
|
||||
let exiting = false;
|
||||
let forwardedSignal = null;
|
||||
let forceKillTimer = null;
|
||||
const outputLimitMarker = `\n[run-with-pty output truncated after ${OUTPUT_MAX_BYTES} bytes]\n`;
|
||||
const outputState = {
|
||||
bytes: 0,
|
||||
truncated: false,
|
||||
};
|
||||
log.on("error", (error) => {
|
||||
if (logFailed) {
|
||||
return;
|
||||
}
|
||||
logFailed = true;
|
||||
console.error(`run-with-pty transcript log failed: ${error.message}`);
|
||||
if (exiting) {
|
||||
process.exit(1);
|
||||
}
|
||||
if (!exiting) {
|
||||
pty.kill("SIGTERM");
|
||||
forceKillTimer ??= setTimeout(() => {
|
||||
pty.kill("SIGKILL");
|
||||
}, FORCE_KILL_MS);
|
||||
forceKillTimer.unref?.();
|
||||
}
|
||||
});
|
||||
|
||||
function writeCappedOutput(data) {
|
||||
if (outputState.truncated) {
|
||||
@@ -39,18 +58,24 @@ function writeCappedOutput(data) {
|
||||
const remainingBytes = OUTPUT_MAX_BYTES - outputState.bytes;
|
||||
if (buffer.byteLength <= remainingBytes) {
|
||||
outputState.bytes += buffer.byteLength;
|
||||
log.write(buffer);
|
||||
if (!logFailed) {
|
||||
log.write(buffer);
|
||||
}
|
||||
process.stdout.write(buffer);
|
||||
return;
|
||||
}
|
||||
if (remainingBytes > 0) {
|
||||
const head = buffer.subarray(0, remainingBytes);
|
||||
log.write(head);
|
||||
if (!logFailed) {
|
||||
log.write(head);
|
||||
}
|
||||
process.stdout.write(head);
|
||||
}
|
||||
outputState.bytes = OUTPUT_MAX_BYTES;
|
||||
outputState.truncated = true;
|
||||
log.write(outputLimitMarker);
|
||||
if (!logFailed) {
|
||||
log.write(outputLimitMarker);
|
||||
}
|
||||
process.stdout.write(outputLimitMarker);
|
||||
}
|
||||
|
||||
@@ -61,6 +86,9 @@ pty.onData((data) => {
|
||||
pty.onExit(({ exitCode, signal }) => {
|
||||
exiting = true;
|
||||
clearTimeout(forceKillTimer);
|
||||
if (logFailed) {
|
||||
process.exit(1);
|
||||
}
|
||||
log.end(() => {
|
||||
if (forwardedSignal) {
|
||||
process.exit(signalExitCode(forwardedSignal));
|
||||
|
||||
@@ -105,6 +105,23 @@ describe("run-with-pty", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("fails when the transcript log cannot be written", async () => {
|
||||
const tempRoot = await mkdtemp(path.join(os.tmpdir(), "openclaw-run-with-pty-"));
|
||||
try {
|
||||
const result = await runPtyProbe(
|
||||
tempRoot,
|
||||
{},
|
||||
[process.execPath, "-e", "console.log('ready')"],
|
||||
"",
|
||||
);
|
||||
|
||||
expect(result.code).toBe(1);
|
||||
expect(result.stderr).toContain("run-with-pty transcript log failed:");
|
||||
} finally {
|
||||
await rm(tempRoot, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
posixIt("escalates forwarded termination signals for PTY commands that ignore them", async () => {
|
||||
const tempRoot = await mkdtemp(path.join(os.tmpdir(), "openclaw-run-with-pty-"));
|
||||
const logPath = path.join(tempRoot, "pty.log");
|
||||
|
||||
Reference in New Issue
Block a user