Skip to content

Commit d22bc1e

Browse files
authored
Write some more tests. (#1378)
Write some more tests for `pidfd_*`, `clock_gettime`, and `getrandom`. This turned up that the accessors on `WaitStatus` that return signal numbers should return `i32` instead of `u32`.
1 parent 69d42c8 commit d22bc1e

File tree

6 files changed

+227
-14
lines changed

6 files changed

+227
-14
lines changed

CHANGES.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ the functions in the [`rustix::thread::futex`] module instead.
3333

3434
[`rustix::process::waitpid`]: https://docs.rs/rustix/1.0.0/rustix/process/fn.waitpid.html
3535

36+
[`terminating_signal`] and other functions in [`rustix::process::WaitStatus`] changed
37+
from returning `u32` to returning `i32`, for better compatibility with the new
38+
[`Signal`] type.
39+
40+
[`terminating_signal`]: https://docs.rs/rustix/1.0.0/rustix/process/struct.WaitStatus.html#method.terminating_signal
41+
[`rustix::process::WaitStatus`]: https://docs.rs/rustix/1.0.0/rustix/process/struct.WaitStatus.html
42+
[`Signal`]: https://docs.rs/rustix/1.0.0/rustix/process/struct.Signal.html
43+
3644
The `SLAVE` flag in [`rustix::mount::MountPropagationFlags`] is renamed to
3745
[`DOWNSTREAM`].
3846

src/process/wait.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ impl WaitStatus {
115115
/// Returns the number of the signal that stopped the process, if the
116116
/// process was stopped by a signal.
117117
#[inline]
118-
pub fn stopping_signal(self) -> Option<u32> {
118+
pub fn stopping_signal(self) -> Option<i32> {
119119
if self.stopped() {
120120
Some(backend::process::wait::WSTOPSIG(self.0 as _) as _)
121121
} else {
@@ -137,7 +137,7 @@ impl WaitStatus {
137137
/// Returns the number of the signal that terminated the process, if the
138138
/// process was terminated by a signal.
139139
#[inline]
140-
pub fn terminating_signal(self) -> Option<u32> {
140+
pub fn terminating_signal(self) -> Option<i32> {
141141
if self.signaled() {
142142
Some(backend::process::wait::WTERMSIG(self.0 as _) as _)
143143
} else {
@@ -215,7 +215,7 @@ impl WaitIdStatus {
215215
/// process was stopped by a signal.
216216
#[inline]
217217
#[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "netbsd")))]
218-
pub fn stopping_signal(&self) -> Option<u32> {
218+
pub fn stopping_signal(&self) -> Option<i32> {
219219
if self.stopped() {
220220
Some(self.si_status() as _)
221221
} else {
@@ -227,7 +227,7 @@ impl WaitIdStatus {
227227
/// process was trapped by a signal.
228228
#[inline]
229229
#[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "netbsd")))]
230-
pub fn trapping_signal(&self) -> Option<u32> {
230+
pub fn trapping_signal(&self) -> Option<i32> {
231231
if self.trapped() {
232232
Some(self.si_status() as _)
233233
} else {
@@ -251,7 +251,7 @@ impl WaitIdStatus {
251251
/// process was terminated by a signal.
252252
#[inline]
253253
#[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "netbsd")))]
254-
pub fn terminating_signal(&self) -> Option<u32> {
254+
pub fn terminating_signal(&self) -> Option<i32> {
255255
if self.killed() || self.dumped() {
256256
Some(self.si_status() as _)
257257
} else {

tests/process/pidfd.rs

Lines changed: 162 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Tests for the `pidfd` type.
22
3-
use libc::{kill, SIGSTOP};
3+
use libc::{kill, SIGCONT, SIGINT, SIGSTOP};
44
#[cfg(feature = "event")]
55
use rustix::event;
66
use rustix::fd::AsFd as _;
@@ -24,7 +24,7 @@ fn test_pidfd_waitid() {
2424
Ok(pidfd) => pidfd,
2525
Err(io::Errno::NOSYS) => {
2626
// The kernel does not support pidfds.
27-
unsafe { kill(child.id() as _, SIGSTOP) };
27+
unsafe { kill(child.id() as _, SIGINT) };
2828
return;
2929
}
3030
Err(e) => panic!("failed to open pidfd: {}", e),
@@ -40,8 +40,154 @@ fn test_pidfd_waitid() {
4040
.expect("failed to wait")
4141
.unwrap();
4242

43-
// TODO
44-
let _ = status;
43+
assert!(status.stopped());
44+
assert!(!status.exited());
45+
assert!(!status.killed());
46+
assert!(!status.trapped());
47+
assert!(!status.dumped());
48+
assert!(!status.continued());
49+
50+
assert_eq!(
51+
status.stopping_signal(),
52+
Some(process::Signal::STOP.as_raw())
53+
);
54+
assert_eq!(status.trapping_signal(), None);
55+
assert_eq!(status.exit_status(), None);
56+
assert_eq!(status.terminating_signal(), None);
57+
58+
unsafe { kill(child.id() as _, SIGCONT) };
59+
60+
let status = process::waitid(
61+
process::WaitId::PidFd(pidfd.as_fd()),
62+
process::WaitIdOptions::CONTINUED,
63+
)
64+
.expect("failed to wait")
65+
.unwrap();
66+
67+
assert!(!status.stopped());
68+
assert!(!status.exited());
69+
assert!(!status.killed());
70+
assert!(!status.trapped());
71+
assert!(!status.dumped());
72+
assert!(status.continued());
73+
74+
assert_eq!(status.stopping_signal(), None);
75+
assert_eq!(status.trapping_signal(), None);
76+
assert_eq!(status.exit_status(), None);
77+
assert_eq!(status.terminating_signal(), None);
78+
79+
unsafe { kill(child.id() as _, SIGINT) };
80+
81+
let status = process::waitid(
82+
process::WaitId::PidFd(pidfd.as_fd()),
83+
process::WaitIdOptions::EXITED,
84+
)
85+
.expect("failed to wait")
86+
.unwrap();
87+
88+
assert!(!status.stopped());
89+
assert!(!status.exited());
90+
assert!(status.killed());
91+
assert!(!status.trapped());
92+
assert!(!status.dumped());
93+
assert!(!status.continued());
94+
95+
assert_eq!(status.stopping_signal(), None);
96+
assert_eq!(status.trapping_signal(), None);
97+
assert_eq!(status.exit_status(), None);
98+
assert_eq!(status.terminating_signal(), Some(SIGINT));
99+
}
100+
101+
// Similar to `test_pidfd_waitid`, but use `pidfd_send_signal` to send the
102+
// signals.
103+
#[test]
104+
#[serial]
105+
fn test_pidfd_send_signal() {
106+
// Create a new process.
107+
let child = Command::new("yes")
108+
.stdout(std::process::Stdio::null())
109+
.stderr(std::process::Stdio::null())
110+
.spawn()
111+
.expect("failed to execute child");
112+
113+
// Create a pidfd for the child process.
114+
let pid = process::Pid::from_child(&child);
115+
let pidfd = match process::pidfd_open(pid, process::PidfdFlags::empty()) {
116+
Ok(pidfd) => pidfd,
117+
Err(io::Errno::NOSYS) => {
118+
// The kernel does not support pidfds.
119+
process::kill_process(process::Pid::from_child(&child), process::Signal::INT).unwrap();
120+
return;
121+
}
122+
Err(e) => panic!("failed to open pidfd: {}", e),
123+
};
124+
125+
// Wait for the child process to stop.
126+
process::pidfd_send_signal(&pidfd, process::Signal::STOP).unwrap();
127+
128+
let status = process::waitid(
129+
process::WaitId::PidFd(pidfd.as_fd()),
130+
process::WaitIdOptions::STOPPED,
131+
)
132+
.expect("failed to wait")
133+
.unwrap();
134+
135+
assert!(status.stopped());
136+
assert!(!status.exited());
137+
assert!(!status.killed());
138+
assert!(!status.trapped());
139+
assert!(!status.dumped());
140+
assert!(!status.continued());
141+
142+
assert_eq!(
143+
status.stopping_signal(),
144+
Some(process::Signal::STOP.as_raw())
145+
);
146+
assert_eq!(status.trapping_signal(), None);
147+
assert_eq!(status.exit_status(), None);
148+
assert_eq!(status.terminating_signal(), None);
149+
150+
process::pidfd_send_signal(&pidfd, process::Signal::CONT).unwrap();
151+
152+
let status = process::waitid(
153+
process::WaitId::PidFd(pidfd.as_fd()),
154+
process::WaitIdOptions::CONTINUED,
155+
)
156+
.expect("failed to wait")
157+
.unwrap();
158+
159+
assert!(!status.stopped());
160+
assert!(!status.exited());
161+
assert!(!status.killed());
162+
assert!(!status.trapped());
163+
assert!(!status.dumped());
164+
assert!(status.continued());
165+
166+
assert_eq!(status.stopping_signal(), None);
167+
assert_eq!(status.trapping_signal(), None);
168+
assert_eq!(status.exit_status(), None);
169+
assert_eq!(status.terminating_signal(), None);
170+
171+
process::pidfd_send_signal(&pidfd, process::Signal::INT).unwrap();
172+
173+
let status = process::waitid(
174+
process::WaitId::PidFd(pidfd.as_fd()),
175+
process::WaitIdOptions::EXITED,
176+
)
177+
.expect("failed to wait")
178+
.unwrap();
179+
180+
assert!(!status.stopped());
181+
assert!(!status.exited());
182+
assert!(status.killed());
183+
assert!(!status.trapped());
184+
assert!(!status.dumped());
185+
assert!(!status.continued());
186+
187+
assert_eq!(status.stopping_signal(), None);
188+
assert_eq!(status.trapping_signal(), None);
189+
assert_eq!(status.exit_status(), None);
190+
assert_eq!(status.terminating_signal(), Some(SIGINT));
45191
}
46192

47193
#[cfg(feature = "event")]
@@ -62,6 +208,7 @@ fn test_pidfd_poll() {
62208
Ok(pidfd) => pidfd,
63209
Err(io::Errno::NOSYS) | Err(io::Errno::INVAL) => {
64210
// The kernel does not support non-blocking pidfds.
211+
process::kill_process(process::Pid::from_child(&child), process::Signal::INT).unwrap();
65212
return;
66213
}
67214
Err(e) => panic!("failed to open pidfd: {}", e),
@@ -89,6 +236,15 @@ fn test_pidfd_poll() {
89236
.expect("failed to wait")
90237
.unwrap();
91238

92-
// TODO
93-
let _ = status;
239+
assert!(!status.stopped());
240+
assert!(status.exited());
241+
assert!(!status.killed());
242+
assert!(!status.trapped());
243+
assert!(!status.dumped());
244+
assert!(!status.continued());
245+
246+
assert_eq!(status.stopping_signal(), None);
247+
assert_eq!(status.trapping_signal(), None);
248+
assert_eq!(status.exit_status(), Some(0));
249+
assert_eq!(status.terminating_signal(), None);
94250
}

tests/rand/getrandom.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ use rustix::rand::{getrandom, GetRandomFlags};
44
#[test]
55
fn test_getrandom() {
66
let mut buf = [0_u8; 256];
7-
let _ = getrandom(&mut buf, GetRandomFlags::empty());
7+
let len = getrandom(&mut buf, GetRandomFlags::empty()).unwrap();
8+
assert!(len <= buf.len());
89
}
910

1011
#[test]

tests/time/monotonic.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,31 @@ fn test_monotonic_clock_with_sleep_1ms() {
4343
assert!(b.tv_sec >= a.tv_sec);
4444
assert!(b.tv_sec != a.tv_sec || b.tv_nsec > a.tv_nsec);
4545
}
46+
47+
#[test]
48+
fn test_monotonic_clock_vs_libc() {
49+
let mut before = unsafe { core::mem::zeroed::<libc::timespec>() };
50+
let r = unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut before) };
51+
assert_eq!(r, 0);
52+
53+
let a = clock_gettime(ClockId::Monotonic);
54+
55+
// Test that the timespec is valid.
56+
assert!(a.tv_nsec < 1_000_000_000);
57+
58+
let mut after = unsafe { core::mem::zeroed::<libc::timespec>() };
59+
let r = unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut after) };
60+
assert_eq!(r, 0);
61+
62+
let before = Timespec {
63+
tv_sec: before.tv_sec.try_into().unwrap(),
64+
tv_nsec: before.tv_nsec.try_into().unwrap(),
65+
};
66+
let after = Timespec {
67+
tv_sec: after.tv_sec.try_into().unwrap(),
68+
tv_nsec: after.tv_nsec.try_into().unwrap(),
69+
};
70+
71+
assert!(before <= a);
72+
assert!(a <= after);
73+
}

tests/time/wall.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,29 @@
1-
use rustix::time::{clock_gettime, ClockId};
1+
use rustix::time::{clock_gettime, ClockId, Timespec};
22

33
#[test]
44
fn test_wall_clock() {
5+
let mut before = unsafe { core::mem::zeroed::<libc::timespec>() };
6+
let r = unsafe { libc::clock_gettime(libc::CLOCK_REALTIME, &mut before) };
7+
assert_eq!(r, 0);
8+
59
let a = clock_gettime(ClockId::Realtime);
610

7-
// Test that the timespec is valid; there's not much else we can say.
11+
// Test that the timespec is valid.
812
assert!(a.tv_nsec < 1_000_000_000);
13+
14+
let mut after = unsafe { core::mem::zeroed::<libc::timespec>() };
15+
let r = unsafe { libc::clock_gettime(libc::CLOCK_REALTIME, &mut after) };
16+
assert_eq!(r, 0);
17+
18+
let before = Timespec {
19+
tv_sec: before.tv_sec.try_into().unwrap(),
20+
tv_nsec: before.tv_nsec.try_into().unwrap(),
21+
};
22+
let after = Timespec {
23+
tv_sec: after.tv_sec.try_into().unwrap(),
24+
tv_nsec: after.tv_nsec.try_into().unwrap(),
25+
};
26+
27+
assert!(before <= a);
28+
assert!(a <= after);
929
}

0 commit comments

Comments
 (0)