From c9201556798217b2ebbcba98df1a78ba32f0ca50 Mon Sep 17 00:00:00 2001 From: Rahul Date: Mon, 2 Nov 2026 15:20:45 +0530 Subject: [PATCH] test(cli): a child that exits before draining stdin breaks the write, not the test The FreeBSD run of run_reads_commands_from_a_file_or_stdin hit a race: the CLI exits with code 2 on the usage-error cases before the helper finishes writing its standard input, so write_all fails with BrokenPipe and the unwrap panicked at apps/effectcraft-cli/tests/it/cli.rs:139:61. Ignore exactly BrokenPipe while writing the piped standard input and assert on any other error kind, so an early exit keeps feeding the assertions below instead of failing the harness. Fixes #2794 Co-authored-by: rahul05ranjan <11793455+rahul05ranjan@users.noreply.github.com> --- apps/effectcraft-cli/tests/it/cli.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/effectcraft-cli/tests/it/cli.rs b/apps/effectcraft-cli/tests/it/cli.rs index e9a96dd7e..74314e307 100644 --- a/apps/effectcraft-cli/tests/it/cli.rs +++ b/apps/effectcraft-cli/tests/it/cli.rs @@ -136,7 +136,14 @@ fn run_reads_arguments_from_a_file() { /// Run with `stdin` piped in; returns (exit code, stdout, stderr). fn run_with_stdin(args: &[&str], stdin: &str) -> (i32, String, String) { let mut child = bin().args(args).stdin(Stdio::piped()).stdout(Stdio::piped()).stderr(Stdio::piped()).spawn().unwrap(); - child.stdin.take().unwrap().write_all(stdin.as_bytes()).unwrap(); + // The child may exit before it has read all of standard input (the usage-error cases below + // exit with code 2 without draining stdin), so a broken pipe while writing is that early + // exit, not a failure of this helper; the assertions on the returned output still hold. + let mut stdin_pipe = child.stdin.take().unwrap(); + if let Err(err) = stdin_pipe.write_all(stdin.as_bytes()) { + assert_eq!(err.kind(), std::io::ErrorKind::BrokenPipe, "writing the child's standard input: {err}"); + } + drop(stdin_pipe); let out = child.wait_with_output().unwrap(); (out.status.code().unwrap_or(-1), String::from_utf8_lossy(&out.stdout).into_owned(), String::from_utf8_lossy(&out.stderr).into_owned()) }