diff --git a/src/backend/wayland/backend/runtime_wake.rs b/src/backend/wayland/backend/runtime_wake.rs index 80e4df96..5a57c8ab 100644 --- a/src/backend/wayland/backend/runtime_wake.rs +++ b/src/backend/wayland/backend/runtime_wake.rs @@ -142,6 +142,8 @@ impl RuntimeWakeSource { } /// Reports whether a wake arrives within `timeout`, without draining it. + /// Any other readiness is an error, so a broken descriptor cannot pass for + /// silence in a test that expects no wake. #[cfg(test)] pub(crate) fn is_readable_within(&self, timeout: Duration) -> io::Result { let readable = poll_with_retry(Some(timeout), |timeout_ms| { @@ -149,8 +151,14 @@ impl RuntimeWakeSource { if poll_for_ms(&mut pollfds, timeout_ms)? == 0 { return Ok(None); } - Ok(Some(pollfds[0].revents().contains(PollFlags::IN))) + validate_poll_readiness( + pollfds[0].revents(), + "runtime wake", + TerminalReadinessPolicy::Reject, + ) + .map(Some) })?; + Ok(readable == Some(true)) } } @@ -194,6 +202,7 @@ mod tests { use std::time::{Duration, Instant}; use std::{fs, thread}; + use rustix::pipe; use rustix::process::Pid; use rustix::thread as rustix_thread; @@ -274,6 +283,15 @@ mod tests { assert!(!source.drain().unwrap()); } + #[test] + fn readiness_without_a_wake_is_an_error_rather_than_silence() { + let (read, write) = pipe::pipe().unwrap(); + drop(write); + let source = RuntimeWakeSource { fd: Arc::new(read) }; + + assert!(source.is_readable_within(Duration::ZERO).is_err()); + } + #[test] fn wait_readable_times_out_without_a_wake() { let source = RuntimeWakeSource::try_new().unwrap(); diff --git a/src/daemon/protocol_v2/tests.rs b/src/daemon/protocol_v2/tests.rs index 18231e3f..ae44eef4 100644 --- a/src/daemon/protocol_v2/tests.rs +++ b/src/daemon/protocol_v2/tests.rs @@ -10,11 +10,19 @@ use crate::{env_vars, test_env, test_temp}; use super::*; +/// Polls for input. Any other readiness fails the test, so a broken descriptor +/// cannot pass for silence. fn is_readable(fd: BorrowedFd<'_>, timeout: Duration) -> bool { let mut pollfds = [PollFd::from_borrowed_fd(fd, PollFlags::IN)]; let timeout = Timespec::try_from(timeout).unwrap(); - event::poll(&mut pollfds, Some(&timeout)).unwrap() == 1 - && pollfds[0].revents().contains(PollFlags::IN) + let ready = event::poll(&mut pollfds, Some(&timeout)).unwrap(); + let revents = pollfds[0].revents(); + assert!( + ready == 0 || revents == PollFlags::IN, + "unexpected readiness {:#x}", + revents.bits() + ); + ready == 1 } #[test]