2023-08-21 08:49:27 +00:00
|
|
|
// This file is part of the uutils coreutils package.
|
|
|
|
//
|
|
|
|
// For the full copyright and license information, please view the LICENSE
|
|
|
|
// file that was distributed with this source code.
|
2023-03-20 13:51:19 +00:00
|
|
|
use crate::common::util::TestScenario;
|
2021-04-26 20:14:59 +00:00
|
|
|
use regex::Regex;
|
|
|
|
use std::os::unix::process::ExitStatusExt;
|
|
|
|
use std::process::{Child, Command};
|
|
|
|
|
|
|
|
// A child process the tests will try to kill.
|
|
|
|
struct Target {
|
|
|
|
child: Child,
|
|
|
|
killed: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Target {
|
|
|
|
// Creates a target that will naturally die after some time if not killed
|
|
|
|
// fast enough.
|
|
|
|
// This timeout avoids hanging failing tests.
|
2022-01-30 13:59:31 +00:00
|
|
|
fn new() -> Self {
|
|
|
|
Self {
|
2021-04-26 20:14:59 +00:00
|
|
|
child: Command::new("sleep")
|
|
|
|
.arg("30")
|
|
|
|
.spawn()
|
|
|
|
.expect("cannot spawn target"),
|
|
|
|
killed: false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Waits for the target to complete and returns the signal it received if any.
|
|
|
|
fn wait_for_signal(&mut self) -> Option<i32> {
|
|
|
|
let sig = self.child.wait().expect("cannot wait on target").signal();
|
|
|
|
self.killed = true;
|
|
|
|
sig
|
|
|
|
}
|
|
|
|
|
|
|
|
fn pid(&self) -> u32 {
|
|
|
|
self.child.id()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for Target {
|
|
|
|
// Terminates this target to avoid littering test boxes with zombi processes
|
|
|
|
// when a test fails after creating a target but before killing it.
|
|
|
|
fn drop(&mut self) {
|
|
|
|
if !self.killed {
|
|
|
|
self.child.kill().expect("cannot kill target");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-10 16:38:14 +00:00
|
|
|
#[test]
|
|
|
|
fn test_invalid_arg() {
|
|
|
|
new_ucmd!().arg("--definitely-invalid").fails().code_is(1);
|
|
|
|
}
|
|
|
|
|
2021-04-26 20:14:59 +00:00
|
|
|
#[test]
|
|
|
|
fn test_kill_list_all_signals() {
|
|
|
|
// Check for a few signals. Do not try to be comprehensive.
|
|
|
|
new_ucmd!()
|
|
|
|
.arg("-l")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains("KILL")
|
|
|
|
.stdout_contains("TERM")
|
2024-04-13 14:40:30 +00:00
|
|
|
.stdout_contains("HUP")
|
|
|
|
.stdout_does_not_contain("EXIT");
|
2021-04-26 20:14:59 +00:00
|
|
|
}
|
|
|
|
|
2021-09-12 16:15:53 +00:00
|
|
|
#[test]
|
|
|
|
fn test_kill_list_final_new_line() {
|
2021-09-14 15:56:08 +00:00
|
|
|
let re = Regex::new("\\n$").unwrap();
|
|
|
|
assert!(re.is_match(new_ucmd!().arg("-l").succeeds().stdout_str()));
|
2021-09-12 16:15:53 +00:00
|
|
|
}
|
|
|
|
|
2021-04-26 20:14:59 +00:00
|
|
|
#[test]
|
|
|
|
fn test_kill_list_all_signals_as_table() {
|
|
|
|
// Check for a few signals. Do not try to be comprehensive.
|
|
|
|
new_ucmd!()
|
|
|
|
.arg("-t")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains("KILL")
|
|
|
|
.stdout_contains("TERM")
|
|
|
|
.stdout_contains("HUP");
|
|
|
|
}
|
|
|
|
|
2024-04-14 13:08:51 +00:00
|
|
|
#[test]
|
|
|
|
fn test_kill_table_starts_at_1() {
|
|
|
|
new_ucmd!()
|
|
|
|
.arg("-t")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_matches(&Regex::new("^\\s?1\\sHUP").unwrap());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_kill_table_lists_all_vertically() {
|
|
|
|
// Check for a few signals. Do not try to be comprehensive.
|
|
|
|
let command = new_ucmd!().arg("-t").succeeds();
|
|
|
|
let signals = command
|
|
|
|
.stdout_str()
|
|
|
|
.split('\n')
|
2024-06-30 14:27:08 +00:00
|
|
|
.filter_map(|line| line.trim().split(' ').nth(1))
|
2024-04-14 13:08:51 +00:00
|
|
|
.collect::<Vec<&str>>();
|
|
|
|
|
|
|
|
assert!(signals.contains(&"KILL"));
|
|
|
|
assert!(signals.contains(&"TERM"));
|
|
|
|
assert!(signals.contains(&"HUP"));
|
|
|
|
}
|
|
|
|
|
2021-04-26 20:14:59 +00:00
|
|
|
#[test]
|
|
|
|
fn test_kill_list_one_signal_from_name() {
|
|
|
|
// Use SIGKILL because it is 9 on all unixes.
|
|
|
|
new_ucmd!()
|
|
|
|
.arg("-l")
|
|
|
|
.arg("KILL")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_matches(&Regex::new("\\b9\\b").unwrap());
|
2024-04-14 17:46:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_kill_list_one_signal_ignore_case() {
|
|
|
|
// Use SIGKILL because it is 9 on all unixes.
|
|
|
|
new_ucmd!()
|
|
|
|
.arg("-l")
|
|
|
|
.arg("KiLl")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_matches(&Regex::new("\\b9\\b").unwrap());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_kill_list_unknown_must_match_input_case() {
|
|
|
|
new_ucmd!()
|
|
|
|
.arg("-l")
|
2024-04-30 15:26:32 +00:00
|
|
|
.arg("IaMnOtAsIgNaL")
|
2024-04-14 17:46:00 +00:00
|
|
|
.fails()
|
2024-04-30 15:26:32 +00:00
|
|
|
.stderr_contains("IaMnOtAsIgNaL");
|
2021-04-26 20:14:59 +00:00
|
|
|
}
|
|
|
|
|
2024-04-11 03:48:15 +00:00
|
|
|
#[test]
|
|
|
|
fn test_kill_list_all_vertically() {
|
|
|
|
// Check for a few signals. Do not try to be comprehensive.
|
|
|
|
let command = new_ucmd!().arg("-l").succeeds();
|
|
|
|
let signals = command.stdout_str().split('\n').collect::<Vec<&str>>();
|
|
|
|
assert!(signals.contains(&"KILL"));
|
|
|
|
assert!(signals.contains(&"TERM"));
|
|
|
|
assert!(signals.contains(&"HUP"));
|
|
|
|
}
|
|
|
|
|
2024-04-11 03:45:53 +00:00
|
|
|
#[test]
|
|
|
|
fn test_kill_list_two_signal_from_name() {
|
|
|
|
new_ucmd!()
|
|
|
|
.arg("-l")
|
|
|
|
.arg("INT")
|
|
|
|
.arg("KILL")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_matches(&Regex::new("\\d\n\\d").unwrap());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_kill_list_three_signal_first_unknown() {
|
|
|
|
new_ucmd!()
|
|
|
|
.arg("-l")
|
|
|
|
.arg("IAMNOTASIGNAL") // spell-checker:disable-line
|
|
|
|
.arg("INT")
|
|
|
|
.arg("KILL")
|
|
|
|
.fails()
|
|
|
|
.stderr_contains("unknown signal")
|
|
|
|
.stdout_matches(&Regex::new("\\d\n\\d").unwrap());
|
|
|
|
}
|
|
|
|
|
2021-04-26 20:14:59 +00:00
|
|
|
#[test]
|
|
|
|
fn test_kill_set_bad_signal_name() {
|
|
|
|
new_ucmd!()
|
|
|
|
.arg("-s")
|
2021-05-31 03:55:28 +00:00
|
|
|
.arg("IAMNOTASIGNAL") // spell-checker:disable-line
|
2021-04-26 20:14:59 +00:00
|
|
|
.fails()
|
|
|
|
.stderr_contains("unknown signal");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_kill_with_default_signal() {
|
|
|
|
let mut target = Target::new();
|
|
|
|
new_ucmd!().arg(format!("{}", target.pid())).succeeds();
|
|
|
|
assert_eq!(target.wait_for_signal(), Some(libc::SIGTERM));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_kill_with_signal_number_old_form() {
|
|
|
|
let mut target = Target::new();
|
|
|
|
new_ucmd!()
|
|
|
|
.arg("-9")
|
|
|
|
.arg(format!("{}", target.pid()))
|
|
|
|
.succeeds();
|
|
|
|
assert_eq!(target.wait_for_signal(), Some(9));
|
|
|
|
}
|
|
|
|
|
2021-09-11 20:37:55 +00:00
|
|
|
#[test]
|
|
|
|
fn test_kill_with_signal_name_old_form() {
|
|
|
|
let mut target = Target::new();
|
|
|
|
new_ucmd!()
|
|
|
|
.arg("-KILL")
|
|
|
|
.arg(format!("{}", target.pid()))
|
|
|
|
.succeeds();
|
|
|
|
assert_eq!(target.wait_for_signal(), Some(libc::SIGKILL));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_kill_with_signal_prefixed_name_old_form() {
|
|
|
|
let mut target = Target::new();
|
|
|
|
new_ucmd!()
|
|
|
|
.arg("-SIGKILL")
|
|
|
|
.arg(format!("{}", target.pid()))
|
|
|
|
.succeeds();
|
|
|
|
assert_eq!(target.wait_for_signal(), Some(libc::SIGKILL));
|
|
|
|
}
|
|
|
|
|
2021-04-26 20:14:59 +00:00
|
|
|
#[test]
|
|
|
|
fn test_kill_with_signal_number_new_form() {
|
|
|
|
let mut target = Target::new();
|
|
|
|
new_ucmd!()
|
|
|
|
.arg("-s")
|
|
|
|
.arg("9")
|
|
|
|
.arg(format!("{}", target.pid()))
|
|
|
|
.succeeds();
|
|
|
|
assert_eq!(target.wait_for_signal(), Some(9));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_kill_with_signal_name_new_form() {
|
|
|
|
let mut target = Target::new();
|
|
|
|
new_ucmd!()
|
|
|
|
.arg("-s")
|
|
|
|
.arg("KILL")
|
|
|
|
.arg(format!("{}", target.pid()))
|
|
|
|
.succeeds();
|
|
|
|
assert_eq!(target.wait_for_signal(), Some(libc::SIGKILL));
|
|
|
|
}
|
2021-09-11 20:37:55 +00:00
|
|
|
|
2024-04-14 18:13:17 +00:00
|
|
|
#[test]
|
|
|
|
fn test_kill_with_signal_name_new_form_ignore_case() {
|
|
|
|
let mut target = Target::new();
|
|
|
|
new_ucmd!()
|
|
|
|
.arg("-s")
|
|
|
|
.arg("KiLl")
|
|
|
|
.arg(format!("{}", target.pid()))
|
|
|
|
.succeeds();
|
|
|
|
assert_eq!(target.wait_for_signal(), Some(libc::SIGKILL));
|
|
|
|
}
|
|
|
|
|
2021-09-11 20:37:55 +00:00
|
|
|
#[test]
|
|
|
|
fn test_kill_with_signal_prefixed_name_new_form() {
|
|
|
|
let mut target = Target::new();
|
|
|
|
new_ucmd!()
|
|
|
|
.arg("-s")
|
|
|
|
.arg("SIGKILL")
|
|
|
|
.arg(format!("{}", target.pid()))
|
|
|
|
.succeeds();
|
|
|
|
assert_eq!(target.wait_for_signal(), Some(libc::SIGKILL));
|
|
|
|
}
|
2024-04-14 12:13:15 +00:00
|
|
|
|
2024-04-14 18:13:17 +00:00
|
|
|
#[test]
|
|
|
|
fn test_kill_with_signal_prefixed_name_new_form_ignore_case() {
|
|
|
|
let mut target = Target::new();
|
|
|
|
new_ucmd!()
|
|
|
|
.arg("-s")
|
|
|
|
.arg("SiGKiLl")
|
|
|
|
.arg(format!("{}", target.pid()))
|
|
|
|
.succeeds();
|
|
|
|
assert_eq!(target.wait_for_signal(), Some(libc::SIGKILL));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_kill_with_signal_name_new_form_unknown_must_match_input_case() {
|
|
|
|
let target = Target::new();
|
|
|
|
new_ucmd!()
|
|
|
|
.arg("-s")
|
2024-04-30 15:26:32 +00:00
|
|
|
.arg("IaMnOtAsIgNaL")
|
2024-04-14 18:13:17 +00:00
|
|
|
.arg(format!("{}", target.pid()))
|
|
|
|
.fails()
|
|
|
|
.stderr_contains("unknown signal")
|
2024-04-30 15:26:32 +00:00
|
|
|
.stderr_contains("IaMnOtAsIgNaL");
|
2024-04-14 18:13:17 +00:00
|
|
|
}
|
|
|
|
|
2024-04-14 12:13:15 +00:00
|
|
|
#[test]
|
|
|
|
fn test_kill_no_pid_provided() {
|
|
|
|
new_ucmd!()
|
|
|
|
.fails()
|
|
|
|
.stderr_contains("no process ID specified");
|
|
|
|
}
|
2024-04-27 15:33:45 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_kill_with_signal_exit_new_form() {
|
|
|
|
let target = Target::new();
|
|
|
|
new_ucmd!()
|
|
|
|
.arg("-s")
|
|
|
|
.arg("EXIT")
|
|
|
|
.arg(format!("{}", target.pid()))
|
|
|
|
.succeeds();
|
|
|
|
}
|