From e550e3d72e2a5c3283cbc36b896afcbc575fd295 Mon Sep 17 00:00:00 2001 From: Dorian Peron Date: Thu, 6 Feb 2025 11:29:29 +0100 Subject: [PATCH] test(tee): Add test for broken pipe behavior with -p --- tests/by-util/test_tee.rs | 44 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/tests/by-util/test_tee.rs b/tests/by-util/test_tee.rs index 4f2437ace..84a0b12c3 100644 --- a/tests/by-util/test_tee.rs +++ b/tests/by-util/test_tee.rs @@ -165,6 +165,7 @@ mod linux_only { use std::fmt::Write; use std::fs::File; use std::process::{Output, Stdio}; + use std::time::Duration; fn make_broken_pipe() -> File { use libc::c_int; @@ -183,6 +184,22 @@ mod linux_only { unsafe { File::from_raw_fd(fds[1]) } } + fn make_hanging_read() -> File { + use libc::c_int; + use std::os::unix::io::FromRawFd; + + let mut fds: [c_int; 2] = [0, 0]; + assert!( + (unsafe { libc::pipe(std::ptr::from_mut::(&mut fds[0])) } == 0), + "Failed to create pipe" + ); + + // PURPOSELY leak the write end of the pipe, so the read end hangs. + + // Return the read end of the pipe + unsafe { File::from_raw_fd(fds[0]) } + } + fn run_tee(proc: &mut UCommand) -> (String, Output) { let content = (1..=100_000).fold(String::new(), |mut output, x| { let _ = writeln!(output, "{x}"); @@ -535,4 +552,31 @@ mod linux_only { expect_failure(&output, "No space left"); expect_short(file_out_a, &at, content.as_str()); } + + #[test] + fn test_pipe_mode_broken_pipe_only() { + new_ucmd!() + .timeout(Duration::from_secs(1)) + .arg("-p") + .set_stdin(make_hanging_read()) + .set_stdout(make_broken_pipe()) + .succeeds(); + } + + #[test] + fn test_pipe_mode_broken_pipe_file() { + let (at, mut ucmd) = at_and_ucmd!(); + + let file_out_a = "tee_file_out_a"; + + let proc = ucmd + .arg("-p") + .arg(file_out_a) + .set_stdout(make_broken_pipe()); + + let (content, output) = run_tee(proc); + + expect_success(&output); + expect_correct(file_out_a, &at, content.as_str()); + } }