mirror of
https://github.com/uutils/procps.git
synced 2026-06-10 16:14:00 -07:00
420 lines
10 KiB
Rust
420 lines
10 KiB
Rust
// This file is part of the uutils procps package.
|
|
//
|
|
// For the full copyright and license information, please view the LICENSE
|
|
// file that was distributed with this source code.
|
|
|
|
#[cfg(target_os = "linux")]
|
|
use regex::Regex;
|
|
use uutests::new_ucmd;
|
|
|
|
#[cfg(target_os = "linux")]
|
|
use uucore::process::geteuid;
|
|
|
|
#[test]
|
|
#[cfg(target_os = "linux")]
|
|
fn test_select_all_processes() {
|
|
let expected_headers = ["PID", "TTY", "TIME", "CMD"];
|
|
|
|
let args_sets = vec![vec!["-A"], vec!["-e"], vec!["-A", "-e"]];
|
|
for args in args_sets {
|
|
let result = new_ucmd!().args(&args).succeeds();
|
|
let lines: Vec<&str> = result.stdout_str().lines().collect();
|
|
|
|
assert!(
|
|
lines.len() >= 2,
|
|
"expected at least a header and one process row"
|
|
);
|
|
|
|
let headers: Vec<&str> = lines[0].split_whitespace().collect();
|
|
assert_eq!(
|
|
headers, expected_headers,
|
|
"unexpected header for args: {:?}",
|
|
args
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_invalid_arg() {
|
|
new_ucmd!().arg("--definitely-invalid").fails().code_is(1);
|
|
}
|
|
|
|
/// Helper function to check that ps output has the correct headers in the correct order
|
|
#[cfg(target_os = "linux")]
|
|
fn check_header(flag: &str, expected_headers: &[&str]) {
|
|
let result = new_ucmd!().arg(flag).succeeds();
|
|
let lines: Vec<&str> = result.stdout_str().lines().collect();
|
|
let headers: Vec<&str> = lines[0].split_whitespace().collect();
|
|
|
|
assert_eq!(headers, expected_headers);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(target_os = "linux")]
|
|
fn test_full_format_listing() {
|
|
check_header(
|
|
"-f",
|
|
&["UID", "PID", "PPID", "C", "STIME", "TTY", "TIME", "CMD"],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(target_os = "linux")]
|
|
fn test_extra_full_format() {
|
|
check_header(
|
|
"-F",
|
|
&[
|
|
"UID", "PID", "PPID", "C", "SZ", "RSS", "PSR", "STIME", "TTY", "TIME", "CMD",
|
|
],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(target_os = "linux")]
|
|
fn test_job_format() {
|
|
check_header("-j", &["PID", "PGID", "SID", "TTY", "TIME", "CMD"]);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(target_os = "linux")]
|
|
fn test_long_format() {
|
|
check_header(
|
|
"-l",
|
|
&[
|
|
"F", "S", "UID", "PID", "PPID", "C", "PRI", "NI", "ADDR", "SZ", "WCHAN", "TTY", "TIME",
|
|
"CMD",
|
|
],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(target_os = "linux")]
|
|
fn test_long_format_with_y() {
|
|
check_header(
|
|
"-ly",
|
|
&[
|
|
"S", "UID", "PID", "PPID", "C", "PRI", "NI", "RSS", "SZ", "WCHAN", "TTY", "TIME", "CMD",
|
|
],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(target_os = "linux")]
|
|
fn test_psr_format() {
|
|
check_header("-P", &["PID", "PSR", "TTY", "TIME", "CMD"]);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(target_os = "linux")]
|
|
fn test_signal_format() {
|
|
check_header(
|
|
"-s",
|
|
&[
|
|
"UID", "PID", "PENDING", "BLOCKED", "IGNORED", "CAUGHT", "STAT", "TTY", "TIME",
|
|
"COMMAND",
|
|
],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(target_os = "linux")]
|
|
fn test_user_format() {
|
|
check_header(
|
|
"-u",
|
|
&[
|
|
"USER", "PID", "%CPU", "%MEM", "VSZ", "RSS", "TTY", "STAT", "START", "TIME", "COMMAND",
|
|
],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(target_os = "linux")]
|
|
fn test_virtual_memory_format() {
|
|
check_header(
|
|
"-v",
|
|
&[
|
|
"PID", "TTY", "STAT", "TIME", "MAJFL", "TRS", "DRS", "RSS", "%MEM", "COMMAND",
|
|
],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(target_os = "linux")]
|
|
fn test_register_format() {
|
|
check_header(
|
|
"-X",
|
|
&[
|
|
"PID", "STACKP", "ESP", "EIP", "TMOUT", "ALARM", "STAT", "TTY", "TIME", "COMMAND",
|
|
],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(target_os = "linux")]
|
|
fn test_x_format() {
|
|
check_header("-x", &["PID", "TTY", "STAT", "TIME", "COMMAND"]);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(target_os = "linux")]
|
|
fn test_code_mapping() {
|
|
new_ucmd!()
|
|
.args(&["-o", "cmd=CCMD"])
|
|
.succeeds()
|
|
.stdout_contains("CCMD");
|
|
|
|
new_ucmd!().args(&["-o", "cmd= "]).succeeds();
|
|
|
|
new_ucmd!().args(&["-o", "ccmd=CCMD"]).fails().code_is(1);
|
|
|
|
new_ucmd!()
|
|
.args(&["-o", "cmd=CMD1", "-o", "cmd=CMD2"])
|
|
.succeeds()
|
|
.stdout_contains("CMD1")
|
|
.stdout_contains("CMD2");
|
|
|
|
new_ucmd!()
|
|
.args(&["-o", "cmd=CMD1,cmd=CMD2"])
|
|
.succeeds()
|
|
.stdout_contains("CMD1")
|
|
.stdout_contains("CMD2");
|
|
|
|
new_ucmd!()
|
|
.args(&["-o", "ucmd=CMD1", "-o", "ucmd=CMD2"])
|
|
.succeeds()
|
|
.stdout_contains("CMD1")
|
|
.stdout_contains("CMD2");
|
|
|
|
new_ucmd!()
|
|
.args(&["-o", "ucmd=CMD1,ucmd=CMD2"])
|
|
.succeeds()
|
|
.stdout_contains("CMD1")
|
|
.stdout_contains("CMD2");
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(target_os = "linux")]
|
|
fn test_no_headers_flags() {
|
|
let regex = Regex::new("^ *PID +").unwrap();
|
|
for flag in &["--no-headers", "--no-heading"] {
|
|
new_ucmd!()
|
|
.arg(flag)
|
|
.succeeds()
|
|
.stdout_does_not_match(®ex);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(target_os = "linux")]
|
|
fn test_deselect() {
|
|
// Inverse of all processes should be empty
|
|
new_ucmd!()
|
|
.args(&["--deselect", "-A", "--no-headers"])
|
|
.fails()
|
|
.code_is(1)
|
|
.no_output();
|
|
|
|
// PID 1 should be present in inverse of default filter criteria
|
|
new_ucmd!()
|
|
.args(&["--deselect"])
|
|
.succeeds()
|
|
.stdout_matches(&Regex::new("\n *1 ").unwrap());
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(target_os = "linux")]
|
|
fn test_command_name_selection() {
|
|
// Test that test runner process can be located with -C flag
|
|
let our_pid = std::process::id();
|
|
let our_comm = std::fs::read_to_string(format!("/proc/{}/comm", our_pid))
|
|
.unwrap()
|
|
.trim()
|
|
.to_string();
|
|
new_ucmd!()
|
|
.args(&["-C", &our_comm, "--no-headers", "-o", "pid"])
|
|
.succeeds()
|
|
.stdout_contains(our_pid.to_string());
|
|
|
|
// Test nonexistent command
|
|
new_ucmd!()
|
|
.args(&["-C", "non_existent_command", "--no-headers"])
|
|
.fails()
|
|
.code_is(1)
|
|
.no_output();
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(target_os = "linux")]
|
|
fn test_pid_and_quick_pid_selection() {
|
|
let our_pid = std::process::id();
|
|
// Test that only pid 1 and pid of the test runner is present
|
|
let test = |pid_args: &[&str]| {
|
|
let match_regex = Regex::new(&format!("^ *1 *\n *{our_pid} *\n$")).unwrap();
|
|
let mut args = vec!["--no-headers", "-o", "pid"];
|
|
args.extend_from_slice(pid_args);
|
|
new_ucmd!()
|
|
.args(&args)
|
|
.succeeds()
|
|
.stdout_matches(&match_regex);
|
|
};
|
|
|
|
for flag in ["-p", "--pid", "-q", "--quick-pid"] {
|
|
test(&[flag, &format!("1 {our_pid}")]);
|
|
test(&[flag, &format!("1,{our_pid}")]);
|
|
test(&[flag, "1", flag, &our_pid.to_string()]);
|
|
|
|
// Test nonexistent PID
|
|
new_ucmd!()
|
|
.args(&[flag, "0", "--no-headers"])
|
|
.fails()
|
|
.code_is(1)
|
|
.no_output();
|
|
|
|
// Test invalid PID
|
|
new_ucmd!()
|
|
.args(&[flag, "invalid"])
|
|
.fails()
|
|
.stderr_contains("invalid number");
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(target_os = "linux")]
|
|
fn test_ppid_selection() {
|
|
new_ucmd!()
|
|
.args(&["--ppid", "1"])
|
|
.succeeds()
|
|
.stdout_does_not_match(&Regex::new(".*\n *1 +.*").unwrap());
|
|
|
|
// Test nonexistent PPID
|
|
new_ucmd!()
|
|
.args(&["--ppid", "999999", "--no-headers"])
|
|
.fails()
|
|
.code_is(1)
|
|
.no_output();
|
|
|
|
// Test invalid PPID
|
|
new_ucmd!()
|
|
.args(&["--ppid", "invalid"])
|
|
.fails()
|
|
.stderr_contains("invalid number");
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(target_os = "linux")]
|
|
fn test_sid_selection() {
|
|
new_ucmd!()
|
|
.args(&["--sid", "1"])
|
|
.succeeds()
|
|
.stdout_matches(&Regex::new(".*\n *1 +.*").unwrap());
|
|
|
|
// Test nonexistent SID
|
|
new_ucmd!()
|
|
.args(&["--sid", "999999", "--no-headers"])
|
|
.fails()
|
|
.code_is(1)
|
|
.no_output();
|
|
|
|
// Test invalid SID
|
|
new_ucmd!()
|
|
.args(&["--sid", "invalid"])
|
|
.fails()
|
|
.stderr_contains("invalid number");
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(target_os = "linux")]
|
|
fn test_effective_user_selection() {
|
|
let regex = Regex::new("^( *0 +root *\n)+").unwrap();
|
|
|
|
for user_param in ["root", "0"] {
|
|
new_ucmd!()
|
|
.args(&["--user", user_param, "--no-headers", "-o", "euid,euser"])
|
|
.succeeds()
|
|
.stdout_matches(®ex);
|
|
}
|
|
|
|
new_ucmd!()
|
|
.args(&["--user", "nonexistent_user"])
|
|
.fails()
|
|
.stderr_contains("invalid user name");
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(target_os = "linux")]
|
|
fn test_real_user_selection() {
|
|
let regex = Regex::new("^( *0 +root *\n)+").unwrap();
|
|
|
|
for user_param in ["root", "0"] {
|
|
new_ucmd!()
|
|
.args(&["--User", user_param, "--no-headers", "-o", "ruid,ruser"])
|
|
.succeeds()
|
|
.stdout_matches(®ex);
|
|
}
|
|
|
|
new_ucmd!()
|
|
.args(&["--User", "nonexistent_user"])
|
|
.fails()
|
|
.stderr_contains("invalid user name");
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(target_os = "linux")]
|
|
fn test_effective_group_selection() {
|
|
let regex = Regex::new("^( *0 +root *\n)+").unwrap();
|
|
|
|
for group_param in ["root", "0"] {
|
|
new_ucmd!()
|
|
.args(&["--group", group_param, "--no-headers", "-o", "egid,egroup"])
|
|
.succeeds()
|
|
.stdout_matches(®ex);
|
|
}
|
|
|
|
new_ucmd!()
|
|
.args(&["--group", "nonexistent_group"])
|
|
.fails()
|
|
.stderr_contains("invalid group name");
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(target_os = "linux")]
|
|
fn test_real_group_selection() {
|
|
let regex = Regex::new("^( *0 +root *\n)+").unwrap();
|
|
|
|
for group_param in ["root", "0"] {
|
|
new_ucmd!()
|
|
.args(&["--Group", group_param, "--no-headers", "-o", "rgid,rgroup"])
|
|
.succeeds()
|
|
.stdout_matches(®ex);
|
|
}
|
|
|
|
new_ucmd!()
|
|
.args(&["--Group", "nonexistent_group"])
|
|
.fails()
|
|
.stderr_contains("invalid group name");
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(target_os = "linux")]
|
|
fn test_combined_selection_criteria() {
|
|
let pids: Vec<u32> = new_ucmd!()
|
|
.args(&[
|
|
"--pid",
|
|
"1",
|
|
"--user",
|
|
&geteuid().to_string(),
|
|
"--no-headers",
|
|
"-o",
|
|
"pid",
|
|
])
|
|
.succeeds()
|
|
.stdout_str()
|
|
.lines()
|
|
.filter_map(|line| line.trim().parse::<u32>().ok())
|
|
.collect();
|
|
|
|
// Should include PID 1 and processes owned by current user
|
|
assert!(pids.contains(&1));
|
|
assert!(pids.len() > 1);
|
|
}
|