ic-host-process 0.71.0

Native process observations, admitted execution and Git provenance
Documentation
use super::*;
use std::ffi::OsStr;

#[test]
fn relinquishing_a_running_child_never_kills_it_on_drop() {
    let _fixture = Fixture::new();
    let mut command = command("exec sleep 30");
    let mut child = OwnedChild::spawn(&mut command, CleanupPolicy::KillAndWait).unwrap();
    let pid = child.id();
    assert!(child.relinquish().unwrap().is_none());
    assert!(child.poll_exit().is_err());
    drop(child);
    let pid = Pid::from_raw(i32::try_from(pid).unwrap()).unwrap();
    assert!(
        waitid(
            WaitId::Pid(pid),
            WaitIdOptions::EXITED | WaitIdOptions::NOHANG
        )
        .unwrap()
        .is_none()
    );
    kill_process_group(pid, Signal::KILL).unwrap();
    waitid(WaitId::Pid(pid), WaitIdOptions::EXITED).unwrap();
}

#[test]
fn relinquishing_an_exited_child_reaps_without_killing_its_group() {
    let fixture = Fixture::new();
    let marker = fixture.path().join("alive");
    let mut cmd = command("(sleep 0.1; printf alive > \"$MARKER\") & exit 7");
    cmd.env("MARKER", &marker);
    let mut child = OwnedChild::spawn(&mut cmd, CleanupPolicy::KillAndWait).unwrap();
    until(|| child.poll_exit().unwrap().is_some());
    assert_eq!(child.relinquish().unwrap().unwrap().code(), Some(7));
    assert_reaped(child.id());
    drop(child);
    until(|| std::fs::read(&marker).is_ok_and(|bytes| bytes == b"alive"));
}

#[test]
fn graceful_cleanup_preserves_the_final_unreaped_observation() {
    let _fixture = Fixture::new();
    let mut child = OwnedChild::spawn(&mut command("exit 7"), CleanupPolicy::KillAndWait).unwrap();
    until(|| child.poll_exit().unwrap().is_some());
    let pid = child.id();
    #[cfg(target_os = "linux")]
    assert!(crate::observation::basic_process(pid).is_some());
    let status = child
        .terminate_with_grace(Duration::from_millis(500))
        .unwrap();
    assert_eq!(status.code(), Some(7));
    assert_reaped(pid);
}

#[test]
fn graceful_cleanup_kills_a_group_that_ignores_term() {
    let _fixture = Fixture::new();
    let mut cmd = command("trap '' TERM; printf ready; while :; do sleep 1; done");
    cmd.stdout(Stdio::piped());
    let mut child = OwnedChild::spawn(&mut cmd, CleanupPolicy::KillAndWait).unwrap();
    let mut stdout = child.take_stdout().unwrap();
    let mut ready = [0; 5];
    stdout.read_exact(&mut ready).unwrap();
    let started = Instant::now();
    assert!(
        !child
            .terminate_with_grace(Duration::from_millis(25))
            .unwrap()
            .success()
    );
    assert!(started.elapsed() >= Duration::from_millis(25));
    assert_reaped(child.id());
}

#[test]
fn launch_gate_preserves_stdin_environment_and_exact_argument_bytes() {
    let _fixture = Fixture::new();
    let args = [
        "-c",
        "read value; printf '%s|%s|%s' \"$value\" \"$1\" \"$SELECTED\"",
        "fixture",
        "literal $() and spaces",
    ]
    .map(Into::into);
    let (mut cmd, mut gate) =
        gated_command(OsStr::new("/bin/sh"), &args, OsStr::new("profiler-fixture")).unwrap();
    cmd.env("SELECTED", "kept")
        .stdin(Stdio::piped())
        .stdout(Stdio::piped());
    let mut child = OwnedChild::spawn(&mut cmd, CleanupPolicy::KillAndWait).unwrap();
    let mut stdin = child.take_stdin().unwrap();
    stdin.write_all(b"input\n").unwrap();
    drop(stdin);
    std::thread::sleep(Duration::from_millis(20));
    assert!(child.poll_exit().unwrap().is_none());
    gate.write_all(b"start\n").unwrap();
    drop(gate);
    let mut result = Vec::new();
    child
        .take_stdout()
        .unwrap()
        .read_to_end(&mut result)
        .unwrap();
    assert!(child.wait().unwrap().success());
    assert_eq!(result, b"input|literal $() and spaces|kept");
}

#[test]
fn closing_the_gate_refuses_workload_execution() {
    let fixture = Fixture::new();
    let marker = fixture.path().join("must-not-exist");
    let args = ["-c".into(), "touch \"$MARKER\"".into()];
    let (mut cmd, gate) =
        gated_command(OsStr::new("/bin/sh"), &args, OsStr::new("gate-fixture")).unwrap();
    cmd.env("MARKER", &marker);
    let mut child = OwnedChild::spawn(&mut cmd, CleanupPolicy::KillAndWait).unwrap();
    drop(gate);
    assert_eq!(child.wait().unwrap().code(), Some(125));
    assert!(!marker.exists());
}