use std::process::Command;
use super::{ServiceError, ServiceManager};
const UNIT_NAME: &str = "greggd";
#[derive(Debug, Clone)]
pub struct SystemdManager {
unit: String,
}
impl SystemdManager {
#[must_use]
pub fn new() -> Self {
Self {
unit: UNIT_NAME.to_owned(),
}
}
#[must_use]
pub fn with_unit(unit: impl Into<String>) -> Self {
Self { unit: unit.into() }
}
fn run_systemctl(&self, action: &str) -> Result<(), ServiceError> {
let output = Command::new("systemctl")
.args([action, &self.unit])
.output()
.map_err(|e| ServiceError::ExecFailed {
command: format!("systemctl {action} {}", self.unit),
source: e,
})?;
if output.status.success() {
Ok(())
} else {
let stderr = String::from_utf8_lossy(&output.stderr).into_owned();
Err(ServiceError::CommandFailed {
command: format!("systemctl {action} {}", self.unit),
exit_status: output.status.code(),
stderr,
})
}
}
fn check_active(&self) -> Result<bool, ServiceError> {
let output = Command::new("systemctl")
.args(["is-active", &self.unit])
.output()
.map_err(|e| ServiceError::ExecFailed {
command: format!("systemctl is-active {}", self.unit),
source: e,
})?;
let stdout = String::from_utf8_lossy(&output.stdout);
let active = output.status.success() && stdout.trim() == "active";
Ok(active)
}
}
impl Default for SystemdManager {
fn default() -> Self {
Self::new()
}
}
impl ServiceManager for SystemdManager {
fn start(&self) -> Result<(), ServiceError> {
self.run_systemctl("start")
}
fn stop(&self) -> Result<(), ServiceError> {
self.run_systemctl("stop")
}
fn restart(&self) -> Result<(), ServiceError> {
self.run_systemctl("restart")
}
fn is_active(&self) -> Result<bool, ServiceError> {
self.check_active()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn systemd_manager_construction() {
let manager = SystemdManager::new();
assert_eq!(manager.unit, "greggd");
let custom = SystemdManager::with_unit("greggd-test");
assert_eq!(custom.unit, "greggd-test");
}
#[test]
fn systemd_manager_clone() {
let manager = SystemdManager::new();
let cloned = manager.clone();
assert_eq!(manager.unit, cloned.unit);
}
#[test]
fn systemd_manager_debug() {
let manager = SystemdManager::new();
let debug = format!("{manager:?}");
assert!(debug.contains("SystemdManager"));
}
#[test]
fn systemd_command_uses_fixed_arg_arrays() {
let manager = SystemdManager::with_unit("test-unit");
assert_eq!(manager.unit, "test-unit");
}
#[test]
fn systemd_check_active_uses_fixed_args() {
let manager = SystemdManager::with_unit("my-service");
assert_eq!(manager.unit, "my-service");
}
}