#![cfg(unix)]
#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
use std::process::Stdio;
use std::time::Duration;
use embacle::process::run_cli_command;
use tokio::fs;
use tokio::process::Command;
use tokio::time::{sleep, timeout};
const CHILD_SLEEP_SECS: &str = "120";
const REAP_DEADLINE: Duration = Duration::from_secs(10);
async fn is_alive(pid: &str) -> bool {
Command::new("kill")
.args(["-0", pid])
.stderr(Stdio::null())
.status()
.await
.unwrap()
.success()
}
#[tokio::test(flavor = "multi_thread")]
async fn dropping_the_call_kills_the_child() {
let dir = tempfile::tempdir().unwrap();
let pid_file = dir.path().join("child.pid");
let mut cmd = Command::new("sh");
cmd.arg("-c").arg(format!(
"echo $$ > '{}'; exec sleep {CHILD_SLEEP_SECS}",
pid_file.display()
));
let dropped = timeout(
Duration::from_secs(2),
run_cli_command(&mut cmd, Duration::from_secs(300), 0),
)
.await;
assert!(dropped.is_err(), "the child should still be sleeping");
let pid = fs::read_to_string(&pid_file).await.unwrap();
let pid = pid.trim();
assert!(!pid.is_empty(), "the child never recorded its pid");
let waited = timeout(REAP_DEADLINE, async {
while is_alive(pid).await {
sleep(Duration::from_millis(100)).await;
}
})
.await;
assert!(
waited.is_ok(),
"child {pid} outlived the dropped call by {REAP_DEADLINE:?}"
);
}