Files
wehub-resource-sync a789495a98
FreeBSD Smoke / FreeBSD Smoke (x86_64) (push) Has been cancelled
CI / Quality Guardrails (push) Has been cancelled
CI / Build & Test (macos-latest) (push) Has been cancelled
CI / Build & Test (ubuntu-latest) (push) Has been cancelled
CI / Build & Test (windows-latest) (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / PowerShell Syntax (push) Has been cancelled
CI / Windows Cross-Target Check (Linux) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:10:34 +08:00

158 lines
5.2 KiB
Rust

use super::*;
#[test]
fn desired_nofile_soft_limit_only_raises_when_possible() {
assert_eq!(desired_nofile_soft_limit(1024, 524_288, 8192), Some(8192));
assert_eq!(desired_nofile_soft_limit(8192, 524_288, 8192), None);
assert_eq!(desired_nofile_soft_limit(1024, 4096, 8192), Some(4096));
}
#[cfg(unix)]
#[test]
fn spawn_detached_creates_new_session() {
use tempfile::NamedTempFile;
let output = NamedTempFile::new().expect("temp file");
let output_path = output.path().to_string_lossy().to_string();
let parent_sid = unsafe { libc::getsid(0) };
let mut cmd = std::process::Command::new("sh");
cmd.arg("-c")
.arg("ps -o sid= -p $$ > \"$JCODE_TEST_OUTPUT\"")
.env("JCODE_TEST_OUTPUT", &output_path)
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null());
let mut child = super::spawn_detached(&mut cmd).expect("spawn detached child");
let status = child.wait().expect("wait for child");
assert!(status.success(), "child should exit successfully");
let child_sid = std::fs::read_to_string(&output_path)
.expect("read child sid")
.trim()
.parse::<u32>()
.expect("parse child sid");
assert_eq!(
child_sid,
child.id(),
"detached child should lead its own session"
);
assert_ne!(
child_sid as i32, parent_sid,
"detached child should not share parent session"
);
}
#[cfg(windows)]
#[test]
fn is_process_running_reports_exited_children_as_stopped() {
use std::process::{Command, Stdio};
use std::time::Duration;
let mut cmd = Command::new("cmd.exe");
cmd.args(["/C", "ping -n 3 127.0.0.1 >NUL"])
.stdout(Stdio::null())
.stderr(Stdio::null());
let mut child = cmd.spawn().expect("spawn child");
let pid = child.id();
assert!(
super::is_process_running(pid),
"child should initially be running"
);
let status = child.wait().expect("wait for child");
assert!(status.success(), "child should exit successfully");
std::thread::sleep(Duration::from_millis(100));
assert!(
!super::is_process_running(pid),
"exited child should not be reported as running"
);
}
#[cfg(windows)]
#[test]
fn signal_detached_process_group_terminates_descendant_tree() {
use std::process::{Command, Stdio};
use std::time::{Duration, Instant};
let temp = tempfile::tempdir().expect("temp dir");
let ready_path = temp.path().join("child-ready.txt");
let survived_path = temp.path().join("child-survived.txt");
let child_script_path = temp.path().join("child.cmd");
let parent_script_path = temp.path().join("parent.cmd");
let child_script = concat!(
"@echo off\r\n",
"echo ready>\"%~dp0child-ready.txt\"\r\n",
"ping -n 6 127.0.0.1 >NUL\r\n",
"echo survived>\"%~dp0child-survived.txt\"\r\n"
);
let parent_script = concat!(
"@echo off\r\n",
"start \"\" /B cmd.exe /D /C \"\"%~dp0child.cmd\"\"\r\n",
"ping -n 30 127.0.0.1 >NUL\r\n"
);
std::fs::write(&child_script_path, child_script).expect("write child command script");
std::fs::write(&parent_script_path, parent_script).expect("write parent command script");
let mut cmd = Command::new("cmd.exe");
cmd.args(["/D", "/C"])
.arg(&parent_script_path)
.stdout(Stdio::null())
.stderr(Stdio::null());
let mut parent = super::spawn_detached(&mut cmd).expect("spawn detached process tree");
let parent_pid = parent.id();
let deadline = Instant::now() + Duration::from_secs(10);
while !ready_path.exists() && Instant::now() < deadline {
std::thread::sleep(Duration::from_millis(50));
}
assert!(ready_path.exists(), "descendant should report ready");
assert!(super::is_process_running(parent_pid));
super::signal_detached_process_group(parent_pid, 0).expect("terminate process tree");
let deadline = Instant::now() + Duration::from_secs(10);
while super::is_process_running(parent_pid) && Instant::now() < deadline {
std::thread::sleep(Duration::from_millis(50));
}
let _ = parent.wait();
assert!(!super::is_process_running(parent_pid), "parent should stop");
std::thread::sleep(Duration::from_secs(6));
assert!(
!survived_path.exists(),
"descendant should not survive termination of the detached process tree"
);
}
#[cfg(windows)]
#[test]
fn spawn_replacement_process_returns_without_waiting_for_child_exit() {
use std::process::{Command, Stdio};
use std::time::{Duration, Instant};
let mut cmd = Command::new("cmd.exe");
cmd.args(["/C", "ping -n 4 127.0.0.1 >NUL"])
.stdout(Stdio::null())
.stderr(Stdio::null());
let start = Instant::now();
let mut child = super::spawn_replacement_process(&mut cmd)
.expect("spawn replacement process should succeed");
let elapsed = start.elapsed();
assert!(
elapsed < Duration::from_secs(1),
"replacement spawn should not block, took {:?}",
elapsed
);
assert!(
child.try_wait().expect("poll child status").is_none(),
"replacement child should still be running immediately after spawn"
);
child.kill().ok();
let _ = child.wait();
}