pub fn notify_ready() -> std::io::Result<()> {
#[cfg(target_os = "linux")]
{
sd_notify::notify(false, &[sd_notify::NotifyState::Ready])?;
}
Ok(())
}
pub fn notify_status(message: &str) -> std::io::Result<()> {
#[cfg(target_os = "linux")]
{
sd_notify::notify(false, &[sd_notify::NotifyState::Status(message)])?;
}
#[cfg(not(target_os = "linux"))]
let _ = message;
Ok(())
}
pub fn notify_stopping() -> std::io::Result<()> {
#[cfg(target_os = "linux")]
{
sd_notify::notify(false, &[sd_notify::NotifyState::Stopping])?;
}
Ok(())
}
#[must_use]
pub fn is_under_systemd() -> bool {
#[cfg(target_os = "linux")]
{
std::env::var_os("NOTIFY_SOCKET").is_some()
}
#[cfg(not(target_os = "linux"))]
{
false
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::lifecycle::test_support::NotifySocketGuard;
#[test]
fn notify_ready_is_ok_without_notify_socket() {
let _guard = NotifySocketGuard::unset();
assert!(
notify_ready().is_ok(),
"notify_ready must not error when NOTIFY_SOCKET is absent"
);
}
#[test]
fn notify_status_is_ok_without_notify_socket() {
let _guard = NotifySocketGuard::unset();
assert!(
notify_status("test status message").is_ok(),
"notify_status must not error when NOTIFY_SOCKET is absent"
);
}
#[test]
fn notify_stopping_is_ok_without_notify_socket() {
let _guard = NotifySocketGuard::unset();
assert!(
notify_stopping().is_ok(),
"notify_stopping must not error when NOTIFY_SOCKET is absent"
);
}
#[test]
fn is_under_systemd_returns_false_without_notify_socket() {
let _guard = NotifySocketGuard::unset();
assert!(
!is_under_systemd(),
"is_under_systemd must return false when NOTIFY_SOCKET is absent"
);
}
#[test]
#[cfg(not(target_os = "linux"))]
fn is_under_systemd_is_always_false_on_non_linux() {
let _guard = NotifySocketGuard::set("/run/systemd/notify");
assert!(
!is_under_systemd(),
"is_under_systemd must always be false on non-Linux platforms \
even when NOTIFY_SOCKET is set"
);
}
#[test]
#[cfg(target_os = "linux")]
fn is_under_systemd_returns_true_when_notify_socket_set() {
let _guard = NotifySocketGuard::set("/run/systemd/notify");
assert!(
is_under_systemd(),
"is_under_systemd must return true when NOTIFY_SOCKET is set"
);
}
#[test]
#[cfg(target_os = "linux")]
fn notify_ready_errors_on_stale_notify_socket() {
let dir = tempfile::tempdir().expect("tempdir allocation failed");
let nonexistent = dir.path().join("notify.sock");
debug_assert!(!nonexistent.exists(), "notify.sock must not pre-exist");
let socket_path = nonexistent
.to_str()
.expect("tempdir path must be valid UTF-8");
let _guard = NotifySocketGuard::set(socket_path);
let result = notify_ready();
assert!(
result.is_err(),
"notify_ready must return Err when NOTIFY_SOCKET points to a non-existent socket"
);
}
}