sysinfo/
system.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3// Once https://github.com/rust-lang/rfcs/blob/master/text/1422-pub-restricted.md
4// feature gets stabilized, we can move common parts in here.
5
6#[cfg(test)]
7mod tests {
8    use crate::{ProcessExt, System, SystemExt};
9
10    #[test]
11    fn test_refresh_system() {
12        let mut sys = System::new();
13        sys.refresh_system();
14        // We don't want to test on unsupported systems.
15        if System::IS_SUPPORTED {
16            assert!(sys.total_memory() != 0);
17            assert!(sys.free_memory() != 0);
18        }
19        assert!(sys.total_memory() >= sys.free_memory());
20        assert!(sys.total_swap() >= sys.free_swap());
21    }
22
23    #[test]
24    fn test_refresh_process() {
25        let mut sys = System::new();
26        assert!(sys.processes().is_empty(), "no process should be listed!");
27        // We don't want to test on unsupported systems.
28
29        #[cfg(not(feature = "apple-sandbox"))]
30        if System::IS_SUPPORTED {
31            assert!(
32                sys.refresh_process(crate::get_current_pid().expect("failed to get current pid")),
33                "process not listed",
34            );
35            // Ensure that the process was really added to the list!
36            assert!(sys
37                .process(crate::get_current_pid().expect("failed to get current pid"))
38                .is_some());
39        }
40    }
41
42    #[test]
43    fn test_get_process() {
44        let mut sys = System::new();
45        sys.refresh_processes();
46        let current_pid = match crate::get_current_pid() {
47            Ok(pid) => pid,
48            _ => {
49                if !System::IS_SUPPORTED {
50                    return;
51                }
52                panic!("get_current_pid should work!");
53            }
54        };
55        if let Some(p) = sys.process(current_pid) {
56            assert!(p.memory() > 0);
57        } else {
58            #[cfg(not(feature = "apple-sandbox"))]
59            assert!(!System::IS_SUPPORTED);
60        }
61    }
62
63    #[test]
64    fn check_if_send_and_sync() {
65        trait Foo {
66            fn foo(&self) {}
67        }
68        impl<T> Foo for T where T: Send {}
69
70        trait Bar {
71            fn bar(&self) {}
72        }
73
74        impl<T> Bar for T where T: Sync {}
75
76        let mut sys = System::new();
77        sys.refresh_processes();
78        let current_pid = match crate::get_current_pid() {
79            Ok(pid) => pid,
80            _ => {
81                if !System::IS_SUPPORTED {
82                    return;
83                }
84                panic!("get_current_pid should work!");
85            }
86        };
87        if let Some(p) = sys.process(current_pid) {
88            p.foo(); // If this doesn't compile, it'll simply mean that the Process type
89                     // doesn't implement the Send trait.
90            p.bar(); // If this doesn't compile, it'll simply mean that the Process type
91                     // doesn't implement the Sync trait.
92        } else {
93            #[cfg(not(feature = "apple-sandbox"))]
94            assert!(!System::IS_SUPPORTED);
95        }
96    }
97
98    #[test]
99    fn check_hostname_has_no_nuls() {
100        let sys = System::new();
101
102        if let Some(hostname) = sys.host_name() {
103            assert!(!hostname.contains('\u{0}'))
104        }
105    }
106
107    #[test]
108    fn check_uptime() {
109        let sys = System::new();
110        let uptime = sys.uptime();
111        if System::IS_SUPPORTED {
112            std::thread::sleep(std::time::Duration::from_millis(1000));
113            let new_uptime = sys.uptime();
114            assert!(uptime < new_uptime);
115        }
116    }
117
118    // This test is used to ensure that the CPU usage computation isn't completely going off
119    // when refreshing it too frequently (ie, multiple times in a row in a very small interval).
120    #[test]
121    #[ignore] // This test MUST be run on its own to prevent wrong CPU usage measurements.
122    fn test_consecutive_cpu_usage_update() {
123        use crate::{PidExt, ProcessExt, ProcessRefreshKind, System, SystemExt};
124        use std::sync::atomic::{AtomicBool, Ordering};
125        use std::sync::Arc;
126        use std::time::Duration;
127
128        if !System::IS_SUPPORTED {
129            return;
130        }
131
132        let mut sys = System::new_all();
133        assert!(!sys.cpus().is_empty());
134        sys.refresh_processes_specifics(ProcessRefreshKind::new().with_cpu());
135
136        let stop = Arc::new(AtomicBool::new(false));
137        // Spawning a few threads to ensure that it will actually have an impact on the CPU usage.
138        for it in 0..sys.cpus().len() / 2 + 1 {
139            let stop_c = Arc::clone(&stop);
140            std::thread::spawn(move || {
141                while !stop_c.load(Ordering::Relaxed) {
142                    if it != 0 {
143                        // The first thread runs at 100% to be sure it'll be noticeable.
144                        std::thread::sleep(Duration::from_millis(1));
145                    }
146                }
147            });
148        }
149
150        let mut pids = sys
151            .processes()
152            .iter()
153            .map(|(pid, _)| *pid)
154            .take(2)
155            .collect::<Vec<_>>();
156        let pid = std::process::id();
157        pids.push(PidExt::from_u32(pid));
158        assert_eq!(pids.len(), 3);
159
160        for it in 0..3 {
161            std::thread::sleep(
162                crate::System::MINIMUM_CPU_UPDATE_INTERVAL + Duration::from_millis(1),
163            );
164            for pid in &pids {
165                sys.refresh_process_specifics(*pid, ProcessRefreshKind::new().with_cpu());
166            }
167            // To ensure that Linux doesn't give too high numbers.
168            assert!(
169                sys.process(pids[2]).unwrap().cpu_usage() < sys.cpus().len() as f32 * 100.,
170                "using ALL CPU: failed at iteration {}",
171                it
172            );
173            // To ensure it's not 0 either.
174            assert!(
175                sys.process(pids[2]).unwrap().cpu_usage() > 0.,
176                "using NO CPU: failed at iteration {}",
177                it
178            );
179        }
180        stop.store(false, Ordering::Relaxed);
181    }
182}