use std::sync::Arc;
use std::time::Duration;
use folk_plugin_process::config::{ProcessDef, RestartPolicy};
use folk_plugin_process::supervisor::{ProcessStatus, ProcessSupervisor};
use tokio::sync::watch;
#[tokio::test]
async fn supervisor_restarts_on_failure() {
let def = ProcessDef {
name: "test".into(),
command: "false".into(),
restart: RestartPolicy::OnFailure,
max_restarts: 2,
restart_delay: Duration::from_millis(10),
};
let (_sd_tx, sd_rx) = watch::channel(false);
let sup = Arc::new(ProcessSupervisor::new(def));
let sup_clone = sup.clone();
tokio::spawn(async move {
sup_clone.run(sd_rx).await;
});
tokio::time::sleep(Duration::from_millis(200)).await;
let status = sup.status().await;
assert!(
matches!(status, ProcessStatus::Failed { .. }),
"expected Failed, got {:?}",
status
);
}
#[tokio::test]
async fn supervisor_stops_on_shutdown() {
let def = ProcessDef {
name: "sleeper".into(),
command: "sleep 60".into(),
restart: RestartPolicy::Always,
max_restarts: 5,
restart_delay: Duration::from_millis(10),
};
let (sd_tx, sd_rx) = watch::channel(false);
let sup = Arc::new(ProcessSupervisor::new(def));
let sup_clone = sup.clone();
let handle = tokio::spawn(async move {
sup_clone.run(sd_rx).await;
});
tokio::time::sleep(Duration::from_millis(100)).await;
sd_tx.send(true).unwrap();
let _ = tokio::time::timeout(Duration::from_secs(10), handle).await;
let status = sup.status().await;
assert_eq!(status, ProcessStatus::Stopped);
}
#[tokio::test]
async fn supervisor_never_restart_exits_cleanly() {
let def = ProcessDef {
name: "once".into(),
command: "true".into(),
restart: RestartPolicy::Never,
max_restarts: 5,
restart_delay: Duration::from_millis(10),
};
let (_sd_tx, sd_rx) = watch::channel(false);
let sup = Arc::new(ProcessSupervisor::new(def));
let sup_clone = sup.clone();
let handle = tokio::spawn(async move {
sup_clone.run(sd_rx).await;
});
let _ = tokio::time::timeout(Duration::from_secs(5), handle).await;
let status = sup.status().await;
assert!(matches!(status, ProcessStatus::Failed { .. }));
}