Skip to content

Commit 103777b

Browse files
authored
Merge pull request #8798 from naoNao89/test/cat-stdbuf-broken-pipe
tests(cat,stdbuf): Add broken-pipe robustness tests (#4627)
2 parents 5d2ac30 + e092d75 commit 103777b

File tree

2 files changed

+55
-0
lines changed

2 files changed

+55
-0
lines changed

tests/by-util/test_cat.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,32 @@ use uutests::util::TestScenario;
1818
use uutests::util::vec_of_size;
1919
use uutests::util_name;
2020

21+
#[cfg(unix)]
22+
// Verify cat handles a broken pipe on stdout without hanging or crashing and exits nonzero
23+
#[test]
24+
fn test_cat_broken_pipe_nonzero_and_message() {
25+
use std::fs::File;
26+
use std::os::unix::io::FromRawFd;
27+
use uutests::new_ucmd;
28+
29+
unsafe {
30+
let mut fds: [libc::c_int; 2] = [0, 0];
31+
assert_eq!(libc::pipe(fds.as_mut_ptr()), 0, "Failed to create pipe");
32+
// Close the read end to simulate a broken pipe on stdout
33+
let read_end = File::from_raw_fd(fds[0]);
34+
// Explicitly drop the read-end so writers see EPIPE instead of blocking on a full pipe
35+
std::mem::drop(read_end);
36+
let write_end = File::from_raw_fd(fds[1]);
37+
38+
let content = (0..10000).map(|_| "x").collect::<String>();
39+
// On Unix, SIGPIPE should lead to a non-zero exit; ensure process exits and fails
40+
new_ucmd!()
41+
.set_stdout(write_end)
42+
.pipe_in(content.as_bytes())
43+
.fails();
44+
}
45+
}
46+
2147
#[test]
2248
fn test_output_simple() {
2349
new_ucmd!()

tests/by-util/test_stdbuf.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ fn invalid_input() {
1515
new_ucmd!().arg("-/").fails_with_code(125);
1616
}
1717

18+
#[cfg(not(feature = "feat_external_libstdbuf"))]
1819
#[test]
1920
fn test_permission() {
2021
new_ucmd!()
@@ -24,6 +25,23 @@ fn test_permission() {
2425
.stderr_contains("Permission denied");
2526
}
2627

28+
// TODO: Tests below are brittle when feat_external_libstdbuf is enabled and libstdbuf is not installed.
29+
// Align stdbuf with GNU search order to enable deterministic testing without installation:
30+
// 1) search for libstdbuf next to the stdbuf binary, 2) then in LIBSTDBUF_DIR, 3) then system locations.
31+
// After implementing this, rework tests to provide a temporary symlink rather than depending on system state.
32+
33+
#[cfg(feature = "feat_external_libstdbuf")]
34+
#[test]
35+
fn test_permission_external_missing_lib() {
36+
// When built with external libstdbuf, running stdbuf fails early if lib is not installed
37+
new_ucmd!()
38+
.arg("-o1")
39+
.arg(".")
40+
.fails_with_code(1)
41+
.stderr_contains("External libstdbuf not found");
42+
}
43+
44+
#[cfg(not(feature = "feat_external_libstdbuf"))]
2745
#[test]
2846
fn test_no_such() {
2947
new_ucmd!()
@@ -33,6 +51,17 @@ fn test_no_such() {
3351
.stderr_contains("No such file or directory");
3452
}
3553

54+
#[cfg(feature = "feat_external_libstdbuf")]
55+
#[test]
56+
fn test_no_such_external_missing_lib() {
57+
// With external lib mode and missing installation, stdbuf fails before spawning the command
58+
new_ucmd!()
59+
.arg("-o1")
60+
.arg("no_such")
61+
.fails_with_code(1)
62+
.stderr_contains("External libstdbuf not found");
63+
}
64+
3665
// Disabled on x86_64-unknown-linux-musl because the cross-rs Docker image for this target
3766
// does not provide musl-compiled system utilities (like head), leading to dynamic linker errors
3867
// when preloading musl-compiled libstdbuf.so into glibc-compiled binaries. Same thing for FreeBSD.

0 commit comments

Comments
 (0)