// Take a look at the license at the top of the repository in the LICENSE file. #[cfg(all(feature = "system", feature = "disk"))] fn should_skip() -> bool { if !sysinfo::IS_SUPPORTED_SYSTEM { return true; } let s = sysinfo::System::new_all(); // If we don't have any physical core present, it's very likely that we're inside a VM... s.physical_core_count().unwrap_or_default() == 0 } #[test] #[cfg(all(feature = "system", feature = "disk"))] fn test_disks() { if should_skip() { return; } let mut disks = sysinfo::Disks::new(); assert!(disks.list().is_empty()); disks.refresh(false); assert!(!disks.list().is_empty()); } #[test] #[cfg(all(feature = "system", feature = "disk"))] fn test_disk_refresh_kind() { use itertools::Itertools; use sysinfo::{DiskKind, DiskRefreshKind, Disks}; if should_skip() { return; } for fs in [ DiskRefreshKind::with_kind, DiskRefreshKind::without_kind, DiskRefreshKind::with_storage, DiskRefreshKind::without_storage, DiskRefreshKind::with_io_usage, DiskRefreshKind::without_io_usage, ] .iter() .powerset() { let mut refreshes = DiskRefreshKind::nothing(); for f in fs { refreshes = f(refreshes); } let assertions = |name: &'static str, disks: &Disks| { if refreshes.kind() { // This would ideally assert that *all* are refreshed, but we settle for a weaker // assertion because failures can't be distinguished from "not refreshed" values. #[cfg(not(any(target_os = "freebsd", target_os = "windows")))] assert!( disks .iter() .any(|disk| disk.kind() != DiskKind::Unknown(-1)), "{name}: disk.kind should be refreshed" ); } else { assert!( disks .iter() .all(|disk| disk.kind() == DiskKind::Unknown(-1)), "{name}: disk.kind should not be refreshed" ); } if refreshes.storage() { // These would ideally assert that *all* are refreshed, but we settle for a weaker // assertion because failures can't be distinguished from "not refreshed" values. assert!( disks .iter() .any(|disk| disk.available_space() != Default::default()), "{name}: disk.available_space should be refreshed" ); assert!( disks .iter() .any(|disk| disk.total_space() != Default::default()), "{name}: disk.total_space should be refreshed" ); // We can't assert anything about booleans, since false is indistinguishable from // not-refreshed } else { assert!( disks .iter() .all(|disk| disk.available_space() == Default::default()), "{name}: disk.available_space should not be refreshed" ); assert!( disks .iter() .all(|disk| disk.total_space() == Default::default()), "{name}: disk.total_space should not be refreshed" ); } if refreshes.io_usage() { // This would ideally assert that *all* are refreshed, but we settle for a weaker // assertion because failures can't be distinguished from "not refreshed" values. assert!( disks.iter().any(|disk| disk.usage() != Default::default()), "{name}: disk.usage should be refreshed" ); } else { assert!( disks.iter().all(|disk| disk.usage() == Default::default()), "{name}: disk.usage should not be refreshed" ); } }; // load and refresh with the desired details should work let disks = Disks::new_with_refreshed_list_specifics(refreshes); assertions("full", &disks); // load with minimal `DiskRefreshKind`, then refresh for added detail should also work! let mut disks = Disks::new_with_refreshed_list_specifics(DiskRefreshKind::nothing()); disks.refresh_specifics(false, refreshes); assertions("incremental", &disks); } } #[test] #[cfg(all(feature = "system", feature = "disk"))] fn test_disks_usage() { use std::fs::{remove_file, File}; use std::io::Write; use std::path::{Path, PathBuf}; use std::thread::sleep; use sysinfo::Disks; if should_skip() { return; } // The test always fails in CI on Linux. For some unknown reason, /proc/diskstats just doesn't // update, regardless of how long we wait. Until the root cause is discovered, skip the test // in CI. if cfg!(target_os = "linux") && std::env::var("CI").is_ok() { return; } let mut disks = Disks::new_with_refreshed_list(); let path = match std::env::var("CARGO_TARGET_DIR") { Ok(p) => Path::new(&p).join("data.tmp"), _ => PathBuf::from("target/data.tmp"), }; let mut file = File::create(&path).expect("failed to create temporary file"); // Write 10mb worth of data to the temp file. let data = vec![1u8; 10 * 1024 * 1024]; file.write_all(&data).unwrap(); // The sync_all call is important to ensure all the data is persisted to disk. Without // the call, this test is flaky. file.sync_all().unwrap(); // Wait a bit just in case sleep(std::time::Duration::from_millis(500)); disks.refresh(false); // Depending on the OS and how disks are configured, the disk usage may be the exact same // across multiple disks. To account for this, collect the disk usages and dedup. let mut disk_usages = disks.list().iter().map(|d| d.usage()).collect::<Vec<_>>(); disk_usages.dedup(); let mut written_bytes = 0; for disk_usage in disk_usages { written_bytes += disk_usage.written_bytes; } let _ = remove_file(path); // written_bytes should have increased by about 10mb, but this is not fully reliable in CI Linux. For now, // just verify the number is non-zero. assert!(written_bytes > 0); }