procutils-killall 0.2.0

Kill processes by name
Documentation
//! Snapshot tests for `killall`. Signal-delivery to live processes is
//! out of scope (the test harness runs against fake /proc trees with
//! no real processes); these tests cover argument parsing, the signal
//! list, and the "no process found" path.

use procutils_testutil::{Builder, ProcRoot, ProcessFixture};
use std::process::{Command, Output};

const BIN: &str = env!("CARGO_BIN_EXE_killall");

fn empty_proc() -> ProcRoot {
    let init = ProcessFixture {
        ppid: 0,
        ..ProcessFixture::new(1, "init")
    };
    Builder::new()
        .process(init)
        .finish()
        .expect("build fixture")
}

#[track_caller]
fn run_status(root: &ProcRoot, args: &[&str]) -> Output {
    let mounts = procutils_testutil::proc_only(root.path());
    procutils_testutil::run(BIN, &mounts, args).expect("spawn unshare")
}

#[test]
fn list_signals_short_flag() {
    let out = Command::new(BIN).arg("-l").output().expect("spawn killall");
    assert!(out.status.success());
    insta::assert_snapshot!(String::from_utf8_lossy(&out.stdout));
}

#[test]
fn list_signals_long_flag() {
    let short = Command::new(BIN).arg("-l").output().expect("spawn killall");
    let long = Command::new(BIN)
        .arg("--list")
        .output()
        .expect("spawn killall");
    assert_eq!(short.stdout, long.stdout);
}

#[test]
fn unknown_signal_exits_2() {
    let out = Command::new(BIN)
        .args(["-s", "NOPE", "anything"])
        .output()
        .expect("spawn killall");
    assert_eq!(out.status.code(), Some(2));
    assert!(
        String::from_utf8_lossy(&out.stderr).contains("unknown signal"),
        "stderr: {}",
        String::from_utf8_lossy(&out.stderr)
    );
}

#[test]
fn no_args_exits_2() {
    let out = Command::new(BIN).output().expect("spawn killall");
    assert_eq!(out.status.code(), Some(2));
}

#[test]
fn no_match_prints_diagnostic_and_exits_1() {
    if !procutils_testutil::unshare_supported() {
        return;
    }
    let out = run_status(&empty_proc(), &["never-matches"]);
    assert_eq!(out.status.code(), Some(1));
    let stderr = String::from_utf8_lossy(&out.stderr);
    assert!(
        stderr.contains("never-matches: no process found"),
        "stderr: {stderr}"
    );
}

#[test]
fn no_match_under_quiet_is_silent() {
    if !procutils_testutil::unshare_supported() {
        return;
    }
    let out = run_status(&empty_proc(), &["-q", "never-matches"]);
    assert_eq!(out.status.code(), Some(1));
    assert!(out.stderr.is_empty(), "stderr: {:?}", out.stderr);
}

#[test]
fn dash_signal_shorthand_matches_dash_s() {
    if !procutils_testutil::unshare_supported() {
        return;
    }
    let a = run_status(&empty_proc(), &["-HUP", "never-matches"]);
    let b = run_status(&empty_proc(), &["-s", "HUP", "never-matches"]);
    // Both should fail identically with "no process found".
    assert_eq!(a.status.code(), b.status.code());
    assert_eq!(a.stderr, b.stderr);
}