#![cfg(feature = "heavy-tests")]
use std::time::Duration;
use tokio::process::Command;
#[cfg(unix)]
#[tokio::test]
async fn test_unix_process_group_cleanup() {
use std::process::Stdio;
let mut cmd = Command::new("sh");
cmd.arg("-c")
.arg("sleep 30 & sleep 30 & wait")
.stdout(Stdio::null())
.stderr(Stdio::null())
.stdin(Stdio::null());
unsafe {
cmd.pre_exec(|| {
use nix::unistd::{setpgid, Pid};
setpgid(Pid::from_raw(0), Pid::from_raw(0)).map_err(std::io::Error::other)?;
Ok(())
});
}
let mut child = cmd.spawn().expect("Failed to spawn test process");
let pid = child.id().expect("Failed to get PID");
let pid_string = pid.to_string();
tokio::time::sleep(Duration::from_millis(500)).await;
let check_output = std::process::Command::new("ps")
.args(["-o", "pid,pgid", "-p", &pid_string])
.output()
.expect("Failed to check process group");
assert!(
check_output.status.success(),
"Process should be running before termination"
);
use nix::sys::signal::{killpg, Signal};
use nix::unistd::Pid;
killpg(Pid::from_raw(pid as i32), Signal::SIGTERM).expect("Failed to kill process group");
let _ = child.wait().await;
let mut terminated = false;
for _ in 0..10 {
tokio::time::sleep(Duration::from_millis(200)).await;
let check_output = std::process::Command::new("ps")
.args(["-p", &pid_string])
.output()
.expect("Failed to check process");
if !check_output.status.success() {
terminated = true;
break;
}
}
assert!(terminated, "Process should be terminated after killpg");
}
#[cfg(windows)]
#[tokio::test]
async fn test_windows_job_object_cleanup() {
println!("Windows job object test not yet implemented");
}
#[cfg(unix)]
#[tokio::test]
async fn test_process_group_isolation() {
use std::process::Stdio;
use tokio::process::Command;
let parent_pgid = unsafe { libc::getpgid(0) };
let mut cmd = Command::new("sh");
cmd.arg("-c")
.arg("echo $PPID")
.stdout(Stdio::piped())
.stderr(Stdio::null());
unsafe {
cmd.pre_exec(|| {
use nix::unistd::{setpgid, Pid};
setpgid(Pid::from_raw(0), Pid::from_raw(0)).map_err(std::io::Error::other)?;
Ok(())
});
}
let child = cmd.spawn().expect("Failed to spawn test process");
let child_pid = child.id().expect("Failed to get child PID");
let child_pgid = unsafe { libc::getpgid(child_pid as i32) };
assert_ne!(
parent_pgid, child_pgid,
"Child should be in a different process group"
);
let _ = child.wait_with_output().await;
}