mirror of
https://github.com/openclaw/openclaw.git
synced 2026-10-03 09:39:25 +00:00
fix(e2e): prevent wizard FIFO startup races (#158605)
* fix(e2e): prevent wizard FIFO startup races Anchor the FIFO before reader startup, close the inherited anchor in the child, and restore a write-only parent descriptor. This prevents a fast reader exit from stranding open while preserving EOF and EPIPE behavior. * test(e2e): bound wizard EOF regression process
This commit is contained in:
parent
5b3cb698b6
commit
50df80460a
2 changed files with 46 additions and 2 deletions
|
|
@ -164,9 +164,15 @@ run_wizard_cmd() {
|
|||
local log_path="$OPENCLAW_E2E_LOG_DIR/${case_name}.log"
|
||||
WIZARD_LOG_PATH="$log_path"
|
||||
export WIZARD_LOG_PATH
|
||||
# Run under script to keep an interactive TTY for clack prompts.
|
||||
openclaw_e2e_run_script_with_pty "$command" "$log_path" <"$input_fifo" >/dev/null 2>&1 &
|
||||
# Anchor the FIFO before forking so a fast-exiting reader cannot strand open().
|
||||
if ! exec 3<>"$input_fifo"; then
|
||||
cleanup_wizard_case
|
||||
return 1
|
||||
fi
|
||||
# Open stdin before dropping the inherited anchor; only the driver keeps a writer.
|
||||
openclaw_e2e_run_script_with_pty "$command" "$log_path" <"$input_fifo" 3>&- >/dev/null 2>&1 &
|
||||
wizard_pid=$!
|
||||
# Restore write-only semantics so an exited wizard still produces EPIPE.
|
||||
if ! exec 3>"$input_fifo"; then
|
||||
cleanup_wizard_case
|
||||
return 1
|
||||
|
|
|
|||
|
|
@ -336,6 +336,44 @@ run_wizard_cmd failing-wizard fake-state "node fake-wizard" send_noop false
|
|||
}
|
||||
});
|
||||
|
||||
it("delivers wizard input and EOF without retaining an inherited writer", async () => {
|
||||
const tempRoot = tempDirs.make("openclaw-onboard-fifo-eof-");
|
||||
const fixturePath = path.join(tempRoot, "wizard-eof.sh");
|
||||
await writeFile(
|
||||
fixturePath,
|
||||
`#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
export OPENCLAW_ONBOARD_SCENARIO_SOURCE_ONLY=1
|
||||
export OPENCLAW_ONBOARD_E2E_TMPDIR=${JSON.stringify(tempRoot)}
|
||||
OPENCLAW_ENTRY=node
|
||||
openclaw_test_state_create() { :; }
|
||||
source scripts/e2e/lib/onboard/scenario.sh
|
||||
|
||||
openclaw_e2e_run_script_with_pty() { cat >"$2"; }
|
||||
send_and_close() {
|
||||
printf 'wizard input\\n' >&3
|
||||
exec 3>&-
|
||||
}
|
||||
run_wizard_cmd eof-wizard fake-state cat send_and_close false
|
||||
printf 'recorded input:'
|
||||
cat "$WIZARD_LOG_PATH"
|
||||
test -z "$(find "$ONBOARD_TMP_DIR" -name '*.fifo.*')"
|
||||
cleanup_onboard_artifacts
|
||||
test ! -e "$ONBOARD_TMP_DIR"
|
||||
`,
|
||||
);
|
||||
|
||||
const result = spawnSync("bash", [fixturePath], {
|
||||
cwd: process.cwd(),
|
||||
encoding: "utf8",
|
||||
timeout: 10_000,
|
||||
});
|
||||
|
||||
expect(result.error).toBeUndefined();
|
||||
expect(result.status, `${result.stdout}\n${result.stderr}`).toBe(0);
|
||||
expect(result.stdout).toContain("recorded input:wizard input\n");
|
||||
});
|
||||
|
||||
it("does not wait for a skills prompt after the ready state renders", async () => {
|
||||
const tempRoot = tempDirs.make("openclaw-onboard-skills-ready-");
|
||||
const fixturePath = path.join(tempRoot, "skills-ready.sh");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue