test(ecstore): assert the error conversions, and stop the census over-reporting (#6241)

This commit is contained in:
Zhengchao An
2026-08-19 11:01:20 +08:00
committed by GitHub
parent 7b5389d2f9
commit 728efcec89
5 changed files with 121 additions and 32 deletions
+23 -4
View File
@@ -853,13 +853,32 @@ mod tests {
#[test]
fn test_error_conversions() {
// Test From implementations
// A plain io::Error carries no typed payload to recover, so it lands in
// `Io` rather than being guessed at from its kind — `NotFound` here must
// not silently become `FileNotFound`, which quorum aggregation counts as
// a different error (rustfs/backlog#1836).
let io_error = std::io::Error::new(std::io::ErrorKind::NotFound, "test");
let _disk_error: DiskError = io_error.into();
let disk_error: DiskError = io_error.into();
match &disk_error {
DiskError::Io(inner) => assert_eq!(inner.kind(), std::io::ErrorKind::NotFound),
other => panic!("a plain io::Error must stay typed as Io, got {other:?}"),
}
let json_str = r#"{"invalid": json}"#; // Invalid JSON
// A typed DiskError boxed through io::Error round-trips back to itself
// instead of degrading to `Io`.
let boxed: std::io::Error = std::io::Error::other(DiskError::VolumeNotFound);
assert_eq!(DiskError::from(boxed), DiskError::VolumeNotFound);
// serde_json errors have no dedicated variant and fold into `other`,
// keeping the original message.
let json_str = r#"{"invalid": json}"#;
let json_error = serde_json::from_str::<serde_json::Value>(json_str).unwrap_err();
let _disk_error: DiskError = json_error.into();
let json_message = json_error.to_string();
let disk_error: DiskError = json_error.into();
assert!(
disk_error.to_string().contains(&json_message),
"the json error message must survive the conversion: {disk_error}"
);
}
#[test]
+35 -20
View File
@@ -436,30 +436,45 @@ mod tests {
assert_eq!(unknown_profile.sequential_boost_multiplier, 1.0);
}
#[cfg(target_os = "linux")]
// What platform probing returns depends on the machine, so these pin the two
// rules that do not: the override wins over probing, and probing that is
// switched off reports Unknown rather than guessing (rustfs/backlog#1836).
#[test]
fn test_linux_storage_detection_exists() {
// This test just verifies the detection function exists and doesn't panic
// The actual result depends on the system it's running on
let result = detect_storage_media(true, "");
// We should get some result (not panic)
match result {
StorageMedia::Nvme | StorageMedia::Ssd | StorageMedia::Hdd | StorageMedia::Unknown => {
// All valid results
}
fn storage_media_override_wins_over_platform_detection() {
for (override_value, expected) in [
("nvme", StorageMedia::Nvme),
("ssd", StorageMedia::Ssd),
("hdd", StorageMedia::Hdd),
] {
assert_eq!(detect_storage_media(true, override_value), expected);
assert_eq!(
detect_storage_media(false, override_value),
expected,
"an override must be honoured even with detection disabled"
);
}
}
#[cfg(target_os = "macos")]
#[test]
fn test_macos_storage_detection_exists() {
// This test just verifies the detection function exists and doesn't panic
let result = detect_storage_media(true, "");
// We should get some result (not panic)
match result {
StorageMedia::Nvme | StorageMedia::Ssd | StorageMedia::Hdd | StorageMedia::Unknown => {
// All valid results
}
}
fn disabled_detection_reports_unknown_instead_of_guessing() {
assert_eq!(detect_storage_media(false, ""), StorageMedia::Unknown);
assert_eq!(
detect_storage_media(false, "not-a-medium"),
StorageMedia::Unknown,
"an unparseable override falls through to the disabled path"
);
}
#[test]
fn enabled_detection_returns_a_medium_for_this_platform() {
// Whatever this machine reports, it must be one of the known variants and
// it must be stable across calls — a probe that flapped would make the
// scheduler's profile depend on when it asked.
let first = detect_storage_media(true, "");
assert!(matches!(
first,
StorageMedia::Nvme | StorageMedia::Ssd | StorageMedia::Hdd | StorageMedia::Unknown
));
assert_eq!(detect_storage_media(true, ""), first);
}
}
+11 -1
View File
@@ -527,9 +527,19 @@ mod tests {
}
#[tokio::test]
async fn runtime_facade_stops_empty_replay_workers() {
async fn stopping_replay_workers_is_a_no_op_when_there_are_none() {
let (facade, _, _) = build_facade();
facade.stop_replay_workers().await;
// The stop path takes the worker list and hands it to the adapter, so an
// empty facade must come back with the list still empty and dispatch
// released rather than left paused (rustfs/backlog#1836).
assert!(facade.replay_workers.read().await.is_empty());
// Calling it twice must stay harmless: shutdown paths do exactly that.
facade.stop_replay_workers().await;
assert!(facade.replay_workers.read().await.is_empty());
}
#[tokio::test]
+10 -3
View File
@@ -873,9 +873,16 @@ mod tests {
/// now return a finite, non-panicking mask.
#[test]
fn test_mask_never_recurses_for_any_variant() {
for ev in ALL_EVENT_NAMES {
// Must terminate (no infinite recursion / stack overflow).
let _ = ev.mask();
// Terminating is the point — a regression here overflows the stack rather
// than failing an assertion — but the masks are collected and checked so
// the loop cannot be optimised into nothing and so a variant that starts
// returning an empty mask is caught too (rustfs/backlog#1836).
let masks: Vec<u64> = ALL_EVENT_NAMES.iter().map(|ev| ev.mask()).collect();
assert_eq!(masks.len(), ALL_EVENT_NAMES.len());
for (ev, mask) in ALL_EVENT_NAMES.iter().zip(&masks) {
assert_ne!(*mask, 0, "{ev:?} must carry at least one bit");
assert_eq!(ev.mask(), *mask, "{ev:?} must return the same mask every call");
}
}