Skip to content

Commit 299feba

Browse files
authored
test: test posix_spawn() and add negative test cases (#2598)
* test: test posix_spawn() * chore: downgrade which to 5.0.0 due to MSRV limit * chore: use a homemade which * refactor: clippy fix * test: test posix_spawn() * refactor: CStr literal syntax is not supported * test: skip testing error cases under QEMU
1 parent 1c0f88f commit 299feba

File tree

1 file changed

+126
-2
lines changed

1 file changed

+126
-2
lines changed

test/test_spawn.rs

+126-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,115 @@
11
use super::FORK_MTX;
2+
use nix::errno::Errno;
23
use nix::spawn::{self, PosixSpawnAttr, PosixSpawnFileActions};
34
use nix::sys::signal;
45
use nix::sys::wait::{waitpid, WaitPidFlag, WaitStatus};
5-
use std::ffi::CString;
6+
use std::ffi::{CStr, CString};
7+
8+
/// Helper function to find a binary in the $PATH
9+
fn which(exe_name: &str) -> Option<std::path::PathBuf> {
10+
std::env::var_os("PATH").and_then(|paths| {
11+
std::env::split_paths(&paths)
12+
.filter_map(|dir| {
13+
let full_path = dir.join(exe_name);
14+
if full_path.is_file() {
15+
Some(full_path)
16+
} else {
17+
None
18+
}
19+
})
20+
.next()
21+
})
22+
}
623

724
#[test]
825
fn spawn_true() {
926
let _guard = FORK_MTX.lock();
1027

28+
let bin = which("true").unwrap();
29+
let args = &[
30+
CString::new("true").unwrap(),
31+
CString::new("story").unwrap(),
32+
];
33+
let vars: &[CString] = &[];
34+
let actions = PosixSpawnFileActions::init().unwrap();
35+
let attr = PosixSpawnAttr::init().unwrap();
36+
37+
let pid =
38+
spawn::posix_spawn(bin.as_path(), &actions, &attr, args, vars).unwrap();
39+
40+
let status = waitpid(pid, Some(WaitPidFlag::empty())).unwrap();
41+
42+
match status {
43+
WaitStatus::Exited(wpid, ret) => {
44+
assert_eq!(pid, wpid);
45+
assert_eq!(ret, 0);
46+
}
47+
_ => {
48+
panic!("Invalid WaitStatus");
49+
}
50+
};
51+
}
52+
53+
#[test]
54+
fn spawn_sleep() {
55+
let _guard = FORK_MTX.lock();
56+
57+
let bin = which("sleep").unwrap();
58+
let args = &[CString::new("sleep").unwrap(), CString::new("30").unwrap()];
59+
let vars: &[CString] = &[];
60+
let actions = PosixSpawnFileActions::init().unwrap();
61+
let attr = PosixSpawnAttr::init().unwrap();
62+
63+
let pid =
64+
spawn::posix_spawn(bin.as_path(), &actions, &attr, args, vars).unwrap();
65+
66+
let status =
67+
waitpid(pid, WaitPidFlag::from_bits(WaitPidFlag::WNOHANG.bits()))
68+
.unwrap();
69+
match status {
70+
WaitStatus::StillAlive => {}
71+
_ => {
72+
panic!("Invalid WaitStatus");
73+
}
74+
};
75+
76+
signal::kill(pid, signal::SIGTERM).unwrap();
77+
78+
let status = waitpid(pid, Some(WaitPidFlag::empty())).unwrap();
79+
match status {
80+
WaitStatus::Signaled(wpid, wsignal, _) => {
81+
assert_eq!(pid, wpid);
82+
assert_eq!(wsignal, signal::SIGTERM);
83+
}
84+
_ => {
85+
panic!("Invalid WaitStatus");
86+
}
87+
};
88+
}
89+
90+
#[test]
91+
// `posix_spawn(path_not_exist)` succeeds under QEMU, so ignore the test. No need
92+
// to investigate the root cause, this test still works in native environments, which
93+
// is sufficient to test the binding.
94+
#[cfg_attr(qemu, ignore)]
95+
fn spawn_cmd_does_not_exist() {
96+
let _guard = FORK_MTX.lock();
97+
98+
let args = &[CString::new("buzz").unwrap()];
99+
let envs: &[CString] = &[];
100+
let actions = PosixSpawnFileActions::init().unwrap();
101+
let attr = PosixSpawnAttr::init().unwrap();
102+
103+
let bin = "2b7433c4-523b-470c-abb5-d7ee9fd295d5-fdasf";
104+
let errno =
105+
spawn::posix_spawn(bin, &actions, &attr, args, envs).unwrap_err();
106+
assert_eq!(errno, Errno::ENOENT);
107+
}
108+
109+
#[test]
110+
fn spawnp_true() {
111+
let _guard = FORK_MTX.lock();
112+
11113
let bin = &CString::new("true").unwrap();
12114
let args = &[
13115
CString::new("true").unwrap(),
@@ -33,7 +135,7 @@ fn spawn_true() {
33135
}
34136

35137
#[test]
36-
fn spawn_sleep() {
138+
fn spawnp_sleep() {
37139
let _guard = FORK_MTX.lock();
38140

39141
let bin = &CString::new("sleep").unwrap();
@@ -67,3 +169,25 @@ fn spawn_sleep() {
67169
}
68170
};
69171
}
172+
173+
#[test]
174+
// `posix_spawnp(bin_not_exist)` succeeds under QEMU, so ignore the test. No need
175+
// to investigate the root cause, this test still works in native environments, which
176+
// is sufficient to test the binding.
177+
#[cfg_attr(qemu, ignore)]
178+
fn spawnp_cmd_does_not_exist() {
179+
let _guard = FORK_MTX.lock();
180+
181+
let args = &[CString::new("buzz").unwrap()];
182+
let envs: &[CString] = &[];
183+
let actions = PosixSpawnFileActions::init().unwrap();
184+
let attr = PosixSpawnAttr::init().unwrap();
185+
186+
let bin = CStr::from_bytes_with_nul(
187+
"2b7433c4-523b-470c-abb5-d7ee9fd295d5-fdasf\0".as_bytes(),
188+
)
189+
.unwrap();
190+
let errno =
191+
spawn::posix_spawnp(bin, &actions, &attr, args, envs).unwrap_err();
192+
assert_eq!(errno, Errno::ENOENT);
193+
}

0 commit comments

Comments
 (0)