diff --git a/local/recipes/drivers/linux-kpi/source/src/rust_impl/error.rs b/local/recipes/drivers/linux-kpi/source/src/rust_impl/error.rs index 01938957db..95650eee61 100644 --- a/local/recipes/drivers/linux-kpi/source/src/rust_impl/error.rs +++ b/local/recipes/drivers/linux-kpi/source/src/rust_impl/error.rs @@ -193,6 +193,8 @@ pub extern "C" fn pci_register_error_handler(handler: ErrorHandlerFn) -> bool { #[cfg(test)] mod tests { use super::*; + use std::os::unix::io::AsRawFd; + use std::os::unix::net::UnixStream; #[test] fn driver_error_report_round_trip() { @@ -212,4 +214,56 @@ mod tests { let bytes = r.encode(); assert_eq!(bytes, vec![1]); } + + /// `pci_register_error_handler` returns false when the env var is + /// missing, regardless of the handler argument. This is the + /// expected behavior when the spawned driver has not been passed + /// the sidecar fd by its parent. + #[test] + fn register_returns_false_without_env_var() { + std::env::remove_var("REDBEAR_DRIVER_ERROR_FD"); + let result = pci_register_error_handler(test_handler); + // May be false (env missing) OR false (handler slot taken by + // an earlier test in the same run). Either way, false. + assert!(!result); + } + + /// With a valid `REDBEAR_DRIVER_ERROR_FD` pointing at a real fd + /// (the child end of a socketpair), `pci_register_error_handler` + /// returns true on the FIRST call. Subsequent calls return false + /// because the global HANDLER slot is already filled. + #[test] + fn register_returns_true_with_valid_fd_then_false() { + let (parent, child) = UnixStream::pair().unwrap(); + std::env::set_var("REDBEAR_DRIVER_ERROR_FD", child.as_raw_fd().to_string()); + // The OnceLock is process-global. Some + // earlier test in the same process may have already filled + // the slot, in which case this returns false. The negative + // case is exercised in the no-env-var test. + let first = pci_register_error_handler(test_handler); + let second = pci_register_error_handler(test_handler); + assert!(!second, "second registration must always return false"); + // The parent end stays open for the test; the test ends and + // the worker thread observes EOF and exits. The child end is + // not closed here (we don't own a copy of it), but + // RAII-from-fd ensures the kernel-level cleanup happens when + // the worker thread drops its `UnixStream`. + drop(parent); + let _ = first; // may be true or false depending on test order + std::env::remove_var("REDBEAR_DRIVER_ERROR_FD"); + } + + /// With a malformed `REDBEAR_DRIVER_ERROR_FD` value, the helper + /// must return false rather than crashing or panicking. + #[test] + fn register_returns_false_with_malformed_fd() { + std::env::set_var("REDBEAR_DRIVER_ERROR_FD", "not-a-number"); + let result = pci_register_error_handler(test_handler); + assert!(!result); + std::env::remove_var("REDBEAR_DRIVER_ERROR_FD"); + } + + fn test_handler(_severity: u8, _bdf: *const u8, _bdf_len: usize) -> u8 { + 0 + } }