Files
rustfs/ecstore/src/utils/os/mod.rs
T

339 lines
10 KiB
Rust

#[cfg(target_os = "linux")]
mod linux;
#[cfg(all(unix, not(target_os = "linux")))]
mod unix;
#[cfg(target_os = "windows")]
mod windows;
#[cfg(target_os = "linux")]
pub use linux::{get_drive_stats, get_info, same_disk};
// pub use linux::same_disk;
#[cfg(all(unix, not(target_os = "linux")))]
pub use unix::{get_drive_stats, get_info, same_disk};
#[cfg(target_os = "windows")]
pub use windows::{get_drive_stats, get_info, same_disk};
#[derive(Debug, Default, PartialEq)]
pub struct IOStats {
pub read_ios: u64,
pub read_merges: u64,
pub read_sectors: u64,
pub read_ticks: u64,
pub write_ios: u64,
pub write_merges: u64,
pub write_sectors: u64,
pub write_ticks: u64,
pub current_ios: u64,
pub total_ticks: u64,
pub req_ticks: u64,
pub discard_ios: u64,
pub discard_merges: u64,
pub discard_sectors: u64,
pub discard_ticks: u64,
pub flush_ios: u64,
pub flush_ticks: u64,
}
#[cfg(test)]
mod tests {
use super::*;
use std::path::PathBuf;
#[test]
fn test_get_info_valid_path() {
let temp_dir = tempfile::tempdir().unwrap();
let info = get_info(temp_dir.path()).unwrap();
println!("Disk Info: {:?}", info);
assert!(info.total > 0);
assert!(info.free > 0);
assert!(info.used > 0);
assert!(info.files > 0);
assert!(info.ffree > 0);
assert!(!info.fstype.is_empty());
}
#[test]
fn test_get_info_invalid_path() {
let invalid_path = PathBuf::from("/invalid/path");
let result = get_info(&invalid_path);
assert!(result.is_err());
}
#[test]
fn test_same_disk_same_path() {
let temp_dir = tempfile::tempdir().unwrap();
let path = temp_dir.path().to_str().unwrap();
let result = same_disk(path, path).unwrap();
assert!(result);
}
#[test]
fn test_same_disk_different_paths() {
let temp_dir1 = tempfile::tempdir().unwrap();
let temp_dir2 = tempfile::tempdir().unwrap();
let path1 = temp_dir1.path().to_str().unwrap();
let path2 = temp_dir2.path().to_str().unwrap();
let result = same_disk(path1, path2).unwrap();
// Note: On many systems, temporary directories are on the same disk
// This test mainly verifies the function works without error
// The actual result depends on the system configuration
println!("Same disk result for temp dirs: {}", result);
// Just verify the function executes successfully
assert!(result == true || result == false);
}
#[test]
fn test_get_drive_stats_default() {
let stats = get_drive_stats(0, 0).unwrap();
assert_eq!(stats, IOStats::default());
}
#[test]
fn test_iostats_default_values() {
// Test that IOStats default values are all zero
let stats = IOStats::default();
assert_eq!(stats.read_ios, 0);
assert_eq!(stats.read_merges, 0);
assert_eq!(stats.read_sectors, 0);
assert_eq!(stats.read_ticks, 0);
assert_eq!(stats.write_ios, 0);
assert_eq!(stats.write_merges, 0);
assert_eq!(stats.write_sectors, 0);
assert_eq!(stats.write_ticks, 0);
assert_eq!(stats.current_ios, 0);
assert_eq!(stats.total_ticks, 0);
assert_eq!(stats.req_ticks, 0);
assert_eq!(stats.discard_ios, 0);
assert_eq!(stats.discard_merges, 0);
assert_eq!(stats.discard_sectors, 0);
assert_eq!(stats.discard_ticks, 0);
assert_eq!(stats.flush_ios, 0);
assert_eq!(stats.flush_ticks, 0);
}
#[test]
fn test_iostats_equality() {
// Test IOStats equality comparison
let stats1 = IOStats::default();
let stats2 = IOStats::default();
assert_eq!(stats1, stats2);
let stats3 = IOStats {
read_ios: 100,
write_ios: 50,
..Default::default()
};
let stats4 = IOStats {
read_ios: 100,
write_ios: 50,
..Default::default()
};
assert_eq!(stats3, stats4);
// Test inequality
assert_ne!(stats1, stats3);
}
#[test]
fn test_iostats_debug_format() {
// Test Debug trait implementation
let stats = IOStats {
read_ios: 123,
write_ios: 456,
total_ticks: 789,
..Default::default()
};
let debug_str = format!("{:?}", stats);
assert!(debug_str.contains("read_ios: 123"));
assert!(debug_str.contains("write_ios: 456"));
assert!(debug_str.contains("total_ticks: 789"));
}
#[test]
fn test_iostats_partial_eq() {
// Test PartialEq trait implementation with various field combinations
let base_stats = IOStats {
read_ios: 10,
write_ios: 20,
read_sectors: 100,
write_sectors: 200,
..Default::default()
};
let same_stats = IOStats {
read_ios: 10,
write_ios: 20,
read_sectors: 100,
write_sectors: 200,
..Default::default()
};
let different_read = IOStats {
read_ios: 11, // Different
write_ios: 20,
read_sectors: 100,
write_sectors: 200,
..Default::default()
};
assert_eq!(base_stats, same_stats);
assert_ne!(base_stats, different_read);
}
#[test]
fn test_get_info_path_edge_cases() {
// Test with root directory (should work on most systems)
#[cfg(unix)]
{
let result = get_info(std::path::Path::new("/"));
assert!(result.is_ok(), "Root directory should be accessible");
if let Ok(info) = result {
assert!(info.total > 0, "Root filesystem should have non-zero total space");
assert!(!info.fstype.is_empty(), "Root filesystem should have a type");
}
}
#[cfg(windows)]
{
let result = get_info(std::path::Path::new("C:\\"));
// On Windows, C:\ might not always exist, so we don't assert success
if let Ok(info) = result {
assert!(info.total > 0);
assert!(!info.fstype.is_empty());
}
}
}
#[test]
fn test_get_info_nonexistent_path() {
// Test with various types of invalid paths
let invalid_paths = [
"/this/path/definitely/does/not/exist/anywhere",
"/dev/null/invalid", // /dev/null is a file, not a directory
"", // Empty path
];
for invalid_path in &invalid_paths {
let result = get_info(std::path::Path::new(invalid_path));
assert!(result.is_err(), "Invalid path should return error: {}", invalid_path);
}
}
#[test]
fn test_same_disk_edge_cases() {
// Test with same path (should always be true)
let temp_dir = tempfile::tempdir().unwrap();
let path_str = temp_dir.path().to_str().unwrap();
let result = same_disk(path_str, path_str);
assert!(result.is_ok());
assert!(result.unwrap(), "Same path should be on same disk");
// Test with parent and child directories (should be on same disk)
let child_dir = temp_dir.path().join("child");
std::fs::create_dir(&child_dir).unwrap();
let child_path = child_dir.to_str().unwrap();
let result = same_disk(path_str, child_path);
assert!(result.is_ok());
assert!(result.unwrap(), "Parent and child should be on same disk");
}
#[test]
fn test_same_disk_invalid_paths() {
// Test with invalid paths
let temp_dir = tempfile::tempdir().unwrap();
let valid_path = temp_dir.path().to_str().unwrap();
let invalid_path = "/this/path/does/not/exist";
let result1 = same_disk(valid_path, invalid_path);
assert!(result1.is_err(), "Should fail with one invalid path");
let result2 = same_disk(invalid_path, valid_path);
assert!(result2.is_err(), "Should fail with one invalid path");
let result3 = same_disk(invalid_path, invalid_path);
assert!(result3.is_err(), "Should fail with both invalid paths");
}
#[test]
fn test_iostats_field_ranges() {
// Test that IOStats can handle large values
let large_stats = IOStats {
read_ios: u64::MAX,
write_ios: u64::MAX,
read_sectors: u64::MAX,
write_sectors: u64::MAX,
total_ticks: u64::MAX,
..Default::default()
};
// Should be able to create and compare
let another_large = IOStats {
read_ios: u64::MAX,
write_ios: u64::MAX,
read_sectors: u64::MAX,
write_sectors: u64::MAX,
total_ticks: u64::MAX,
..Default::default()
};
assert_eq!(large_stats, another_large);
}
#[test]
fn test_get_drive_stats_error_handling() {
// Test with potentially invalid major/minor numbers
// Note: This might succeed on some systems, so we just ensure it doesn't panic
let result1 = get_drive_stats(999, 999);
// Don't assert success/failure as it's platform-dependent
let _ = result1;
let result2 = get_drive_stats(u32::MAX, u32::MAX);
let _ = result2;
}
#[cfg(unix)]
#[test]
fn test_unix_specific_paths() {
// Test Unix-specific paths
let unix_paths = ["/tmp", "/var", "/usr"];
for path in &unix_paths {
if std::path::Path::new(path).exists() {
let result = get_info(std::path::Path::new(path));
if result.is_ok() {
let info = result.unwrap();
assert!(info.total > 0, "Path {} should have non-zero total space", path);
}
}
}
}
#[test]
fn test_iostats_clone_and_copy() {
// Test that IOStats implements Clone (if it does)
let original = IOStats {
read_ios: 42,
write_ios: 84,
..Default::default()
};
// Test Debug formatting with non-default values
let debug_output = format!("{:?}", original);
assert!(debug_output.contains("42"));
assert!(debug_output.contains("84"));
}
}