| // Take a look at the license at the top of the repository in the LICENSE file. |
| |
| use sysinfo::{Pid, PidExt, ProcessExt, SystemExt}; |
| |
| #[test] |
| fn test_process() { |
| let mut s = sysinfo::System::new(); |
| assert_eq!(s.processes().len(), 0); |
| s.refresh_processes(); |
| if !sysinfo::System::IS_SUPPORTED || cfg!(feature = "apple-sandbox") { |
| return; |
| } |
| assert!(!s.processes().is_empty()); |
| assert!(s |
| .processes() |
| .values() |
| .any(|p| !p.exe().to_str().unwrap_or("").is_empty())); |
| } |
| |
| #[test] |
| fn test_cwd() { |
| if !sysinfo::System::IS_SUPPORTED || cfg!(feature = "apple-sandbox") { |
| return; |
| } |
| let mut p = if cfg!(target_os = "windows") { |
| std::process::Command::new("waitfor") |
| .arg("/t") |
| .arg("3") |
| .arg("CwdSignal") |
| .stdout(std::process::Stdio::null()) |
| .spawn() |
| .unwrap() |
| } else { |
| std::process::Command::new("sleep") |
| .arg("3") |
| .stdout(std::process::Stdio::null()) |
| .spawn() |
| .unwrap() |
| }; |
| |
| let pid = Pid::from_u32(p.id() as _); |
| std::thread::sleep(std::time::Duration::from_secs(1)); |
| let mut s = sysinfo::System::new(); |
| s.refresh_processes(); |
| p.kill().expect("Unable to kill process."); |
| |
| let processes = s.processes(); |
| let p = processes.get(&pid); |
| |
| if let Some(p) = p { |
| assert_eq!(p.pid(), pid); |
| assert_eq!(p.cwd(), std::env::current_dir().unwrap()); |
| } else { |
| panic!("Process not found!"); |
| } |
| } |
| |
| #[test] |
| fn test_cmd() { |
| if !sysinfo::System::IS_SUPPORTED || cfg!(feature = "apple-sandbox") { |
| return; |
| } |
| let mut p = if cfg!(target_os = "windows") { |
| std::process::Command::new("waitfor") |
| .arg("/t") |
| .arg("3") |
| .arg("CmdSignal") |
| .stdout(std::process::Stdio::null()) |
| .spawn() |
| .unwrap() |
| } else { |
| std::process::Command::new("sleep") |
| .arg("3") |
| .stdout(std::process::Stdio::null()) |
| .spawn() |
| .unwrap() |
| }; |
| std::thread::sleep(std::time::Duration::from_millis(500)); |
| let mut s = sysinfo::System::new(); |
| assert!(s.processes().is_empty()); |
| s.refresh_processes(); |
| p.kill().expect("Unable to kill process."); |
| assert!(!s.processes().is_empty()); |
| if let Some(process) = s.process(Pid::from_u32(p.id() as _)) { |
| if cfg!(target_os = "windows") { |
| // Sometimes, we get the full path instead for some reasons... So just in case, |
| // we check for the command independently that from the arguments. |
| assert!(process.cmd()[0].contains("waitfor")); |
| assert_eq!(&process.cmd()[1..], &["/t", "3", "CmdSignal"]); |
| } else { |
| assert_eq!(process.cmd(), &["sleep", "3"]); |
| } |
| } else { |
| panic!("Process not found!"); |
| } |
| } |
| |
| #[test] |
| fn test_environ() { |
| if !sysinfo::System::IS_SUPPORTED || cfg!(feature = "apple-sandbox") { |
| return; |
| } |
| let mut p = if cfg!(target_os = "windows") { |
| std::process::Command::new("waitfor") |
| .arg("/t") |
| .arg("3") |
| .arg("EnvironSignal") |
| .stdout(std::process::Stdio::null()) |
| .env("FOO", "BAR") |
| .env("OTHER", "VALUE") |
| .spawn() |
| .unwrap() |
| } else { |
| std::process::Command::new("sleep") |
| .arg("3") |
| .stdout(std::process::Stdio::null()) |
| .env("FOO", "BAR") |
| .env("OTHER", "VALUE") |
| .spawn() |
| .unwrap() |
| }; |
| |
| let pid = Pid::from_u32(p.id() as _); |
| std::thread::sleep(std::time::Duration::from_secs(1)); |
| let mut s = sysinfo::System::new(); |
| s.refresh_processes(); |
| p.kill().expect("Unable to kill process."); |
| |
| let processes = s.processes(); |
| let p = processes.get(&pid); |
| |
| if let Some(p) = p { |
| assert_eq!(p.pid(), pid); |
| // FIXME: instead of ignoring the test on CI, try to find out what's wrong... |
| if std::env::var("APPLE_CI").is_err() { |
| assert!(p.environ().iter().any(|e| e == "FOO=BAR")); |
| assert!(p.environ().iter().any(|e| e == "OTHER=VALUE")); |
| } |
| } else { |
| panic!("Process not found!"); |
| } |
| } |
| |
| #[test] |
| fn test_process_refresh() { |
| let mut s = sysinfo::System::new(); |
| assert_eq!(s.processes().len(), 0); |
| |
| if !sysinfo::System::IS_SUPPORTED || cfg!(feature = "apple-sandbox") { |
| return; |
| } |
| s.refresh_process(sysinfo::get_current_pid().expect("failed to get current pid")); |
| assert!(s |
| .process(sysinfo::get_current_pid().expect("failed to get current pid")) |
| .is_some(),); |
| } |
| |
| #[test] |
| fn test_process_disk_usage() { |
| use std::fs; |
| use std::fs::File; |
| use std::io::prelude::*; |
| use sysinfo::{get_current_pid, ProcessExt, SystemExt}; |
| |
| if !sysinfo::System::IS_SUPPORTED || cfg!(feature = "apple-sandbox") { |
| return; |
| } |
| if std::env::var("FREEBSD_CI").is_ok() { |
| // For an unknown reason, when running this test on Cirrus CI, it fails. It works perfectly |
| // locally though... Dark magic... |
| return; |
| } |
| |
| fn inner() -> sysinfo::System { |
| { |
| let mut file = File::create("test.txt").expect("failed to create file"); |
| file.write_all(b"This is a test file\nwith test data.\n") |
| .expect("failed to write to file"); |
| } |
| fs::remove_file("test.txt").expect("failed to remove file"); |
| // Waiting a bit just in case... |
| std::thread::sleep(std::time::Duration::from_millis(250)); |
| let mut system = sysinfo::System::new(); |
| assert!(system.processes().is_empty()); |
| system.refresh_processes(); |
| assert!(!system.processes().is_empty()); |
| system |
| } |
| |
| let mut system = inner(); |
| let mut p = system |
| .process(get_current_pid().expect("Failed retrieving current pid.")) |
| .expect("failed to get process"); |
| |
| if cfg!(any(target_os = "macos", target_os = "ios")) && p.disk_usage().total_written_bytes == 0 |
| { |
| // For whatever reason, sometimes, mac doesn't work on the first time when running |
| // `cargo test`. Two solutions, either run with "cargo test -- --test-threads 1", or |
| // check twice... |
| system = inner(); |
| p = system |
| .process(get_current_pid().expect("Failed retrieving current pid.")) |
| .expect("failed to get process"); |
| } |
| |
| assert!( |
| p.disk_usage().total_written_bytes > 0, |
| "found {} total written bytes...", |
| p.disk_usage().total_written_bytes |
| ); |
| assert!( |
| p.disk_usage().written_bytes > 0, |
| "found {} written bytes...", |
| p.disk_usage().written_bytes |
| ); |
| } |
| |
| #[test] |
| fn cpu_usage_is_not_nan() { |
| let mut system = sysinfo::System::new(); |
| system.refresh_processes(); |
| |
| if !sysinfo::System::IS_SUPPORTED || cfg!(feature = "apple-sandbox") { |
| return; |
| } |
| |
| // We need `collect` otherwise we can't have mutable access to `system`. |
| #[allow(clippy::needless_collect)] |
| let first_pids = system |
| .processes() |
| .iter() |
| .take(10) |
| .map(|(&pid, _)| pid) |
| .collect::<Vec<_>>(); |
| let mut checked = 0; |
| |
| first_pids.into_iter().for_each(|pid| { |
| system.refresh_process(pid); |
| if let Some(p) = system.process(pid) { |
| assert!(!p.cpu_usage().is_nan()); |
| checked += 1; |
| } |
| }); |
| assert!(checked > 0); |
| } |
| |
| #[test] |
| fn test_process_times() { |
| use std::time::{SystemTime, UNIX_EPOCH}; |
| |
| if !sysinfo::System::IS_SUPPORTED || cfg!(feature = "apple-sandbox") { |
| return; |
| } |
| let mut p = if cfg!(target_os = "windows") { |
| std::process::Command::new("waitfor") |
| .arg("/t") |
| .arg("3") |
| .arg("ProcessTimes") |
| .stdout(std::process::Stdio::null()) |
| .spawn() |
| .unwrap() |
| } else { |
| std::process::Command::new("sleep") |
| .arg("3") |
| .stdout(std::process::Stdio::null()) |
| .spawn() |
| .unwrap() |
| }; |
| |
| let pid = Pid::from_u32(p.id() as _); |
| std::thread::sleep(std::time::Duration::from_secs(1)); |
| let mut s = sysinfo::System::new(); |
| s.refresh_processes(); |
| p.kill().expect("Unable to kill process."); |
| |
| if let Some(p) = s.process(pid) { |
| assert_eq!(p.pid(), pid); |
| assert!(p.run_time() >= 1); |
| assert!(p.run_time() <= 2); |
| assert!(p.start_time() > p.run_time()); |
| // On linux, for whatever reason, the uptime seems to be older than the boot time, leading |
| // to this weird `+ 3` to ensure the test is passing as it should... |
| assert!( |
| p.start_time() + 3 |
| > SystemTime::now() |
| .duration_since(UNIX_EPOCH) |
| .unwrap() |
| .as_secs(), |
| ); |
| assert!(p.start_time() >= s.boot_time()); |
| } else { |
| panic!("Process not found!"); |
| } |
| } |
| |
| // Checks that `refresh_processes` is removing dead processes. |
| #[test] |
| fn test_refresh_processes() { |
| if !sysinfo::System::IS_SUPPORTED || cfg!(feature = "apple-sandbox") { |
| return; |
| } |
| let mut p = if cfg!(target_os = "windows") { |
| std::process::Command::new("waitfor") |
| .arg("/t") |
| .arg("300") |
| .arg("RefreshProcesses") |
| .stdout(std::process::Stdio::null()) |
| .spawn() |
| .unwrap() |
| } else { |
| std::process::Command::new("sleep") |
| .arg("300") |
| .stdout(std::process::Stdio::null()) |
| .spawn() |
| .unwrap() |
| }; |
| |
| let pid = Pid::from_u32(p.id() as _); |
| std::thread::sleep(std::time::Duration::from_secs(1)); |
| |
| // Checks that the process is listed as it should. |
| let mut s = sysinfo::System::new(); |
| s.refresh_processes(); |
| assert!(s.process(pid).is_some()); |
| |
| // Check that the process name is not empty. |
| assert!(!s.process(pid).unwrap().name().is_empty()); |
| |
| p.kill().expect("Unable to kill process."); |
| // We need this, otherwise the process will still be around as a zombie on linux. |
| let _ = p.wait(); |
| // Let's give some time to the system to clean up... |
| std::thread::sleep(std::time::Duration::from_secs(1)); |
| |
| s.refresh_processes(); |
| // Checks that the process isn't listed anymore. |
| assert!(s.process(pid).is_none()); |
| } |
| |
| // Checks that `refresh_process` is NOT removing dead processes. |
| #[test] |
| fn test_refresh_process() { |
| if !sysinfo::System::IS_SUPPORTED || cfg!(feature = "apple-sandbox") { |
| return; |
| } |
| let mut p = if cfg!(target_os = "windows") { |
| std::process::Command::new("waitfor") |
| .arg("/t") |
| .arg("300") |
| .arg("RefreshProcess") |
| .stdout(std::process::Stdio::null()) |
| .spawn() |
| .unwrap() |
| } else { |
| std::process::Command::new("sleep") |
| .arg("300") |
| .stdout(std::process::Stdio::null()) |
| .spawn() |
| .unwrap() |
| }; |
| |
| let pid = Pid::from_u32(p.id() as _); |
| std::thread::sleep(std::time::Duration::from_secs(1)); |
| |
| // Checks that the process is listed as it should. |
| let mut s = sysinfo::System::new(); |
| s.refresh_process(pid); |
| assert!(s.process(pid).is_some()); |
| |
| // Check that the process name is not empty. |
| assert!(!s.process(pid).unwrap().name().is_empty()); |
| |
| p.kill().expect("Unable to kill process."); |
| // We need this, otherwise the process will still be around as a zombie on linux. |
| let _ = p.wait(); |
| // Let's give some time to the system to clean up... |
| std::thread::sleep(std::time::Duration::from_secs(1)); |
| |
| assert!(!s.refresh_process(pid)); |
| // Checks that the process is still listed. |
| assert!(s.process(pid).is_some()); |
| } |
| |
| #[test] |
| fn test_wait_child() { |
| if !sysinfo::System::IS_SUPPORTED || cfg!(feature = "apple-sandbox") { |
| return; |
| } |
| let p = if cfg!(target_os = "windows") { |
| std::process::Command::new("waitfor") |
| .arg("/t") |
| .arg("300") |
| .arg("RefreshProcess") |
| .stdout(std::process::Stdio::null()) |
| .spawn() |
| .unwrap() |
| } else { |
| std::process::Command::new("sleep") |
| .arg("300") |
| .stdout(std::process::Stdio::null()) |
| .spawn() |
| .unwrap() |
| }; |
| |
| let before = std::time::Instant::now(); |
| let pid = Pid::from_u32(p.id() as _); |
| |
| let mut s = sysinfo::System::new(); |
| s.refresh_process(pid); |
| let process = s.process(pid).unwrap(); |
| |
| // Kill the child process. |
| process.kill(); |
| // Wait for child process should work. |
| process.wait(); |
| |
| // Child process should not be present. |
| assert!(!s.refresh_process(pid)); |
| assert!(before.elapsed() < std::time::Duration::from_millis(1000)); |
| } |
| |
| #[test] |
| fn test_wait_non_child() { |
| if !sysinfo::System::IS_SUPPORTED || cfg!(feature = "apple-sandbox") { |
| return; |
| } |
| |
| // spawn non child process. |
| let p = if !cfg!(target_os = "linux") { |
| return; |
| } else { |
| std::process::Command::new("setsid") |
| .arg("-w") |
| .arg("sleep") |
| .arg("2") |
| .stdout(std::process::Stdio::null()) |
| .spawn() |
| .unwrap() |
| }; |
| let pid = Pid::from_u32(p.id()); |
| |
| let before = std::time::Instant::now(); |
| |
| let mut s = sysinfo::System::new(); |
| s.refresh_process(pid); |
| let process = s.process(pid).expect("Process not found!"); |
| |
| // Wait for a non child process. |
| process.wait(); |
| |
| // Child process should not be present. |
| assert!(!s.refresh_process(pid)); |
| |
| // should wait for 2s. |
| assert!(before.elapsed() > std::time::Duration::from_millis(2000)); |
| assert!(before.elapsed() < std::time::Duration::from_millis(3000)); |
| } |