mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-12 08:06:54 +00:00
test: cover runtime and repair preservation (#3964)
This commit is contained in:
@@ -234,4 +234,20 @@ mod tests {
|
||||
assert!(RuntimeDriveHealthState::Returning.is_snapshot_eligible());
|
||||
assert!(!RuntimeDriveHealthState::Offline.is_snapshot_eligible());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn runtime_drive_health_state_preserves_strict_online_boundary() {
|
||||
assert!(RuntimeDriveHealthState::Online.is_strictly_online());
|
||||
assert!(!RuntimeDriveHealthState::Suspect.is_strictly_online());
|
||||
assert!(!RuntimeDriveHealthState::Returning.is_strictly_online());
|
||||
assert!(!RuntimeDriveHealthState::Offline.is_strictly_online());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn runtime_drive_health_state_preserves_admin_probe_boundary() {
|
||||
assert!(RuntimeDriveHealthState::Online.should_probe_for_admin());
|
||||
assert!(RuntimeDriveHealthState::Returning.should_probe_for_admin());
|
||||
assert!(!RuntimeDriveHealthState::Suspect.should_probe_for_admin());
|
||||
assert!(!RuntimeDriveHealthState::Offline.should_probe_for_admin());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,21 @@ const EVENT_HEAL_CHANNEL_STATE: &str = "heal_channel_state";
|
||||
const EVENT_HEAL_CHANNEL_REQUEST: &str = "heal_channel_request";
|
||||
const EVENT_HEAL_CHANNEL_RESPONSE: &str = "heal_channel_response";
|
||||
|
||||
fn admission_response(request_id: String, admission: HealAdmissionResult) -> HealChannelResponse {
|
||||
let (success, error) = match admission {
|
||||
HealAdmissionResult::Accepted | HealAdmissionResult::Merged => (true, None),
|
||||
HealAdmissionResult::Full => (false, Some("Heal request queue is full".to_string())),
|
||||
HealAdmissionResult::Dropped(reason) => (false, Some(format!("Heal request dropped: {}", reason.as_str()))),
|
||||
};
|
||||
|
||||
HealChannelResponse {
|
||||
request_id,
|
||||
success,
|
||||
data: Some(format!("admission={},reason={}", admission.result_label(), admission.reason_label()).into_bytes()),
|
||||
error,
|
||||
}
|
||||
}
|
||||
|
||||
/// Heal channel processor
|
||||
pub struct HealChannelProcessor {
|
||||
/// Heal manager
|
||||
@@ -201,22 +216,7 @@ impl HealChannelProcessor {
|
||||
|
||||
let _ = response_tx.send(Ok(admission));
|
||||
|
||||
let (success, error) = match admission {
|
||||
HealAdmissionResult::Accepted | HealAdmissionResult::Merged => (true, None),
|
||||
HealAdmissionResult::Full => (false, Some("Heal request queue is full".to_string())),
|
||||
HealAdmissionResult::Dropped(reason) => (false, Some(format!("Heal request dropped: {}", reason.as_str()))),
|
||||
};
|
||||
|
||||
let response = HealChannelResponse {
|
||||
request_id: request.id,
|
||||
success,
|
||||
data: Some(
|
||||
format!("admission={},reason={}", admission.result_label(), admission.reason_label()).into_bytes(),
|
||||
),
|
||||
error,
|
||||
};
|
||||
|
||||
self.publish_response(response);
|
||||
self.publish_response(admission_response(request.id, admission));
|
||||
}
|
||||
Err(e) => {
|
||||
let error_text = e.to_string();
|
||||
@@ -534,7 +534,7 @@ mod tests {
|
||||
use crate::heal::manager::HealConfig;
|
||||
use crate::heal::storage::{HealObjectInfo, HealStorageAPI};
|
||||
use rustfs_common::heal_channel::{
|
||||
HealAdmissionResult, HealChannelPriority, HealChannelRequest, HealRequestSource, HealScanMode,
|
||||
HealAdmissionDropReason, HealAdmissionResult, HealChannelPriority, HealChannelRequest, HealRequestSource, HealScanMode,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -637,6 +637,35 @@ mod tests {
|
||||
// If we can get the sender, processor was created correctly
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn admission_response_preserves_all_admission_outcomes() {
|
||||
let cases = [
|
||||
(HealAdmissionResult::Accepted, true, None, "admission=accepted,reason=none"),
|
||||
(HealAdmissionResult::Merged, true, None, "admission=merged,reason=none"),
|
||||
(
|
||||
HealAdmissionResult::Full,
|
||||
false,
|
||||
Some("Heal request queue is full"),
|
||||
"admission=full,reason=none",
|
||||
),
|
||||
(
|
||||
HealAdmissionResult::Dropped(HealAdmissionDropReason::PolicyDropped),
|
||||
false,
|
||||
Some("Heal request dropped: policy_dropped"),
|
||||
"admission=dropped,reason=policy_dropped",
|
||||
),
|
||||
];
|
||||
|
||||
for (admission, success, error, data) in cases {
|
||||
let response = admission_response("request-id".to_string(), admission);
|
||||
|
||||
assert_eq!(response.request_id, "request-id");
|
||||
assert_eq!(response.success, success);
|
||||
assert_eq!(response.error.as_deref(), error);
|
||||
assert_eq!(response.data.as_deref(), Some(data.as_bytes()));
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_convert_to_heal_request_bucket() {
|
||||
let heal_manager = create_test_heal_manager();
|
||||
|
||||
@@ -4235,6 +4235,48 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_submit_heal_request_returns_full_for_normal_priority_when_full() {
|
||||
let storage: Arc<dyn HealStorageAPI> = Arc::new(MockStorage);
|
||||
let manager = HealManager::new(
|
||||
storage,
|
||||
Some(HealConfig {
|
||||
queue_size: 1,
|
||||
..HealConfig::default()
|
||||
}),
|
||||
);
|
||||
|
||||
let accepted = HealRequest::new(
|
||||
HealType::Bucket {
|
||||
bucket: "bucket-a".to_string(),
|
||||
},
|
||||
HealOptions::default(),
|
||||
HealPriority::Normal,
|
||||
);
|
||||
let full = HealRequest::new(
|
||||
HealType::Bucket {
|
||||
bucket: "bucket-b".to_string(),
|
||||
},
|
||||
HealOptions::default(),
|
||||
HealPriority::Normal,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
manager
|
||||
.submit_heal_request(accepted)
|
||||
.await
|
||||
.expect("first request should be accepted"),
|
||||
HealAdmissionResult::Accepted
|
||||
);
|
||||
assert_eq!(
|
||||
manager
|
||||
.submit_heal_request(full)
|
||||
.await
|
||||
.expect("normal priority request should surface full admission"),
|
||||
HealAdmissionResult::Full
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_high_priority_request_displaces_lower_priority_when_queue_full() {
|
||||
let storage: Arc<dyn HealStorageAPI> = Arc::new(MockStorage);
|
||||
|
||||
@@ -231,4 +231,23 @@ mod tests {
|
||||
assert_eq!(budget.reason(), Some(ScannerCycleBudgetReason::Directories));
|
||||
assert!(budget.token().is_cancelled());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn first_budget_cancellation_reason_remains_observable() {
|
||||
let parent = CancellationToken::new();
|
||||
let budget = ScannerCycleBudget::new(
|
||||
&parent,
|
||||
ScannerCycleBudgetConfig {
|
||||
max_objects: Some(1),
|
||||
max_directories: Some(0),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
budget.record_object_scanned();
|
||||
assert!(!budget.try_start_directory());
|
||||
|
||||
assert_eq!(budget.reason(), Some(ScannerCycleBudgetReason::Objects));
|
||||
assert!(budget.token().is_cancelled());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user