Files
openhuman/tests/cli_sigpipe.rs
T
fbcbd085ad fix(cli): restore SIGPIPE default on Unix (#3657)
Co-authored-by: shanu <shanu@tinyhumans.ai>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 12:18:54 -07:00

51 lines
2.0 KiB
Rust

#[cfg(unix)]
#[test]
fn help_output_closed_pipe_does_not_panic() {
use std::io::{BufRead, BufReader};
use std::os::unix::process::ExitStatusExt;
use std::process::{Command, Stdio};
let mut child = Command::new(env!("CARGO_BIN_EXE_openhuman-core"))
.arg("--help")
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.expect("spawn openhuman-core --help");
// Mirror the issue repro (`openhuman-core --help | head -n 1`): read a
// single line, then drop the read end mid-stream so the child's next write
// lands on a closed pipe. Closing before reading (as a naive test does)
// lets the child buffer its entire few-KB `--help` output in one successful
// write well under the 64 KB pipe buffer and exit cleanly, never exercising
// the broken-pipe path — a false green that passes even without the fix.
let stdout = child.stdout.take().expect("capture stdout");
let mut reader = BufReader::new(stdout);
let mut first_line = String::new();
reader
.read_line(&mut first_line)
.expect("read first help line");
drop(reader);
let output = child.wait_with_output().expect("wait for openhuman-core");
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
!stderr.contains("Broken pipe"),
"stderr must not include a broken-pipe panic: {stderr}"
);
assert!(
!stderr.contains("panicked"),
"stderr must not include a panic report: {stderr}"
);
// Acceptance criterion #1: a closed downstream reader must yield a clean
// exit — either the child finished before the pipe closed, or the restored
// default disposition let SIGPIPE terminate it. A normal-code crash (e.g.
// the panic exit code 101) is precisely the regression this guards against.
assert!(
output.status.success() || output.status.signal() == Some(libc::SIGPIPE),
"process must exit cleanly or via SIGPIPE, got {:?}",
output.status
);
}