lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

commit ae8d5a18416000c96498f460866ae3b1b45ab104
parent 15d8850412224d48073d20e09ae26bd96efeb4a4
Author: triesap <tyson@radroots.org>
Date:   Sun, 16 Aug 2026 06:06:57 +0000

service-host: qualify stable support paths

Diffstat:
Mcrates/service_host/src/lifecycle/shutdown.rs | 25+++++++++++++++++--------
Mcrates/service_host/src/lifecycle/signal.rs | 10+++++++++-
Mcrates/service_host/src/lifecycle/task.rs | 12+++++++++++-
Mcrates/service_host/src/status/reason.rs | 19+++++++++++++++++++
Mcrates/service_host/src/time.rs | 13+++++++++++++
5 files changed, 69 insertions(+), 10 deletions(-)

diff --git a/crates/service_host/src/lifecycle/shutdown.rs b/crates/service_host/src/lifecycle/shutdown.rs @@ -409,6 +409,7 @@ mod tests { .unwrap(); let (mut handler, phases) = handler(None); let mut shutdown = GracefulShutdown::new(Duration::from_secs(30)).unwrap(); + assert_eq!(shutdown.grace(), Duration::from_secs(30)); let first = shutdown .run(&clock(), &mut supervisor, &mut handler, pending()) @@ -520,6 +521,7 @@ mod tests { ); assert!(!failure.to_string().contains("sensitive")); assert!(!format!("{failure:?}").contains("sensitive shutdown detail")); + assert!(failure.source().is_some()); } #[tokio::test] @@ -553,9 +555,11 @@ mod tests { #[test] fn zero_grace_fails_closed() { + let error = GracefulShutdown::new(Duration::ZERO).err().unwrap(); + assert_eq!(error, ShutdownConfigError::ZeroGrace); assert_eq!( - GracefulShutdown::new(Duration::ZERO).err(), - Some(ShutdownConfigError::ZeroGrace) + error.to_string(), + "shutdown grace must be greater than zero" ); } @@ -569,14 +573,19 @@ mod tests { let (mut handler, phases) = handler(None); let mut shutdown = GracefulShutdown::new(Duration::from_nanos(1)).unwrap(); + let error = shutdown + .run(&overflow_clock, &mut supervisor, &mut handler, pending()) + .await + .unwrap_err(); + assert_eq!( + error, + ShutdownStartError::Deadline(MonotonicClockError::DeadlineOverflow) + ); assert_eq!( - shutdown - .run(&overflow_clock, &mut supervisor, &mut handler, pending()) - .await, - Err(ShutdownStartError::Deadline( - MonotonicClockError::DeadlineOverflow - )) + error.to_string(), + "shutdown grace deadline could not be represented" ); + assert!(error.source().is_some()); assert!(phases.lock().unwrap().is_empty()); assert!(!cancellation.is_cancelled()); assert!(shutdown.phase_failure().is_none()); diff --git a/crates/service_host/src/lifecycle/signal.rs b/crates/service_host/src/lifecycle/signal.rs @@ -206,6 +206,10 @@ mod tests { let mut before_first = ProcessSignalAdapter::new(InjectedSignals::new([])); let error = before_first.next_action().await.unwrap_err(); assert_eq!(error.stage(), ProcessSignalStage::FirstCancellation); + assert_eq!( + error.to_string(), + "process signal source closed before the expected event" + ); assert_eq!(before_first.stage(), ProcessSignalStage::FirstCancellation); let mut before_force = @@ -225,8 +229,12 @@ mod tests { #[test] fn normalized_names_are_stable_and_platform_bounded() { assert_eq!(ProcessSignal::Interrupt.as_str(), "interrupt"); + assert_eq!(ProcessSignal::Interrupt.to_string(), "interrupt"); #[cfg(unix)] - assert_eq!(ProcessSignal::Terminate.as_str(), "terminate"); + { + assert_eq!(ProcessSignal::Terminate.as_str(), "terminate"); + assert_eq!(ProcessSignal::Terminate.to_string(), "terminate"); + } let adapter = ProcessSignalAdapter::new(InjectedSignals::new([ProcessSignal::Interrupt])); assert_eq!(adapter.into_inner().events.len(), 1); diff --git a/crates/service_host/src/lifecycle/task.rs b/crates/service_host/src/lifecycle/task.rs @@ -165,7 +165,9 @@ mod tests { #[test] fn task_names_are_bounded_stable_and_secret_safe() { for valid in ["a", "admin_listener", "outbox_worker_01"] { - assert_eq!(TaskName::new(valid).unwrap().as_str(), valid); + let name = TaskName::new(valid).unwrap(); + assert_eq!(name.as_str(), valid); + assert_eq!(name.to_string(), valid); } assert!(TaskName::new("a".repeat(TASK_NAME_MAX_BYTES)).is_ok()); for invalid in [ @@ -188,6 +190,14 @@ mod tests { TaskName::new("a".repeat(4 * 1024 * 1024)), Err(TaskMetadataError::InvalidTaskName) ); + assert_eq!( + TaskMetadataError::InvalidTaskName.to_string(), + "supervised task name is invalid" + ); + assert_eq!( + TaskMetadataError::InvalidShutdownPhaseAssignment.to_string(), + "supervised task shutdown phase does not match its classification" + ); } #[test] diff --git a/crates/service_host/src/status/reason.rs b/crates/service_host/src/status/reason.rs @@ -276,6 +276,25 @@ mod tests { } #[test] + fn owned_text_traits_empty_state_and_deserializer_expectations_are_bound() { + let owned = ReasonCode::from_string("owned_reason".to_owned()).expect("owned reason"); + assert_eq!(owned.to_string(), "owned_reason"); + assert_eq!( + "parsed_reason".parse::<ReasonCode>().unwrap().as_str(), + "parsed_reason" + ); + assert_eq!( + ReasonCode::from_string("Invalid".to_owned()), + Err(StatusContractError::InvalidReasonCode) + ); + + assert!(ReasonCodes::empty().is_empty()); + assert!(!ReasonCodes::new([owned]).unwrap().is_empty()); + assert!(serde_json::from_str::<ReasonCode>("42").is_err()); + assert!(serde_json::from_str::<ReasonCodes>(r#"{"reason":"owned_reason"}"#).is_err()); + } + + #[test] fn collections_sort_deduplicate_bound_and_serialize_canonically() { let reasons = ReasonCodes::new([ ReasonCode::new("z_reason").unwrap(), diff --git a/crates/service_host/src/time.rs b/crates/service_host/src/time.rs @@ -251,5 +251,18 @@ mod tests { let second = monotonic.now_monotonic(); assert!(second >= first); assert!(monotonic.deadline_after(Duration::from_secs(1)).is_ok()); + + let default_monotonic = SystemMonotonicClock::default(); + assert!( + default_monotonic.now_monotonic().duration_since_origin() <= Duration::from_secs(1) + ); + assert_eq!( + WallClockError::BeforeUnixEpoch.to_string(), + "wall clock is before the Unix epoch" + ); + assert_eq!( + MonotonicClockError::DeadlineOverflow.to_string(), + "monotonic deadline overflows" + ); } }