From a97f3a9c5218a4ce141b59a3c04e70bb100f5b9d Mon Sep 17 00:00:00 2001 From: Zhengchao An Date: Sat, 11 Jul 2026 13:39:34 +0800 Subject: [PATCH] fix(test): isolate health tests from minimal-response env var race (#4702) Three health handler tests assert on payload fields (degradedReasons, details) that are absent when RUSTFS_HEALTH_MINIMAL_RESPONSE_ENABLE is true. The minimal-mode sibling test sets that env var via temp_env::with_var, which leaks across parallel test threads. Wrap the three affected tests with their own with_var guard pinning the env var to false so they are deterministic regardless of thread order. --- rustfs/src/admin/handlers/health.rs | 107 ++++++++++++++++------------ 1 file changed, 62 insertions(+), 45 deletions(-) diff --git a/rustfs/src/admin/handlers/health.rs b/rustfs/src/admin/handlers/health.rs index 855195d5e..b44e2922d 100644 --- a/rustfs/src/admin/handlers/health.rs +++ b/rustfs/src/admin/handlers/health.rs @@ -88,6 +88,7 @@ impl Operation for HealthCheckHandler { #[cfg(test)] mod tests { use super::*; + use serial_test::serial; use temp_env::with_var; #[test] @@ -285,6 +286,7 @@ mod tests { } #[test] + #[serial] fn test_build_health_payload_minimal_mode_returns_status_and_ready_only() { let health = health_check_state(true, false, true, true, HealthProbe::Readiness); with_var(rustfs_config::ENV_HEALTH_MINIMAL_RESPONSE_ENABLE, Some("true"), || { @@ -309,20 +311,23 @@ mod tests { } #[test] + #[serial] fn test_build_health_payload_includes_degraded_reasons() { - let health = health_check_state(false, false, false, true, HealthProbe::Readiness); - let payload = build_health_payload(HealthPayloadContext { - health, - storage_ready: false, - iam_ready: false, - lock_quorum_ready: false, - degraded_reasons: &[crate::server::ReadinessDegradedReason::StorageAndIamUnavailable], - service: "rustfs-endpoint", - uptime: None, - kms_ready: None, - include_dependency_details: true, + with_var(rustfs_config::ENV_HEALTH_MINIMAL_RESPONSE_ENABLE, Some("false"), || { + let health = health_check_state(false, false, false, true, HealthProbe::Readiness); + let payload = build_health_payload(HealthPayloadContext { + health, + storage_ready: false, + iam_ready: false, + lock_quorum_ready: false, + degraded_reasons: &[crate::server::ReadinessDegradedReason::StorageAndIamUnavailable], + service: "rustfs-endpoint", + uptime: None, + kms_ready: None, + include_dependency_details: true, + }); + assert_eq!(payload["degradedReasons"][0], "storage_and_iam_unavailable"); }); - assert_eq!(payload["degradedReasons"][0], "storage_and_iam_unavailable"); } #[test] @@ -343,43 +348,55 @@ mod tests { } #[test] + #[serial] fn test_build_health_response_parts_get_includes_payload() { - let report = crate::server::DependencyReadinessReport { - readiness: crate::server::DependencyReadiness { - storage_ready: false, - iam_ready: true, - lock_quorum_ready: true, - peer_health_ready: true, - }, - degraded_reasons: vec![crate::server::ReadinessDegradedReason::StorageQuorumUnavailable], - }; - let parts = - build_health_response_parts(Method::GET, HealthProbe::Readiness, Some(&report), "rustfs-endpoint", None, None); - assert_eq!(parts.status_code, StatusCode::SERVICE_UNAVAILABLE); - let payload = parts.payload.expect("GET should include payload"); - assert_eq!(payload["status"], "degraded"); - assert_eq!(payload["ready"], false); - assert_eq!(payload["degradedReasons"][0], "storage_quorum_unavailable"); + with_var(rustfs_config::ENV_HEALTH_MINIMAL_RESPONSE_ENABLE, Some("false"), || { + let report = crate::server::DependencyReadinessReport { + readiness: crate::server::DependencyReadiness { + storage_ready: false, + iam_ready: true, + lock_quorum_ready: true, + peer_health_ready: true, + }, + degraded_reasons: vec![crate::server::ReadinessDegradedReason::StorageQuorumUnavailable], + }; + let parts = + build_health_response_parts(Method::GET, HealthProbe::Readiness, Some(&report), "rustfs-endpoint", None, None); + assert_eq!(parts.status_code, StatusCode::SERVICE_UNAVAILABLE); + let payload = parts.payload.expect("GET should include payload"); + assert_eq!(payload["status"], "degraded"); + assert_eq!(payload["ready"], false); + assert_eq!(payload["degradedReasons"][0], "storage_quorum_unavailable"); + }); } #[test] + #[serial] fn test_build_health_response_parts_readiness_marks_kms_not_ready() { - let report = crate::server::DependencyReadinessReport { - readiness: crate::server::DependencyReadiness { - storage_ready: true, - iam_ready: true, - lock_quorum_ready: true, - peer_health_ready: true, - }, - degraded_reasons: Vec::new(), - }; - let parts = - build_health_response_parts(Method::GET, HealthProbe::Readiness, Some(&report), "rustfs-endpoint", None, Some(false)); - assert_eq!(parts.status_code, StatusCode::SERVICE_UNAVAILABLE); - let payload = parts.payload.expect("GET should include payload"); - assert_eq!(payload["ready"], false); - assert_eq!(payload["details"]["lock"]["ready"], true); - assert_eq!(payload["details"]["kms"]["ready"], false); - assert_eq!(payload["degradedReasons"][0], "kms_not_ready"); + with_var(rustfs_config::ENV_HEALTH_MINIMAL_RESPONSE_ENABLE, Some("false"), || { + let report = crate::server::DependencyReadinessReport { + readiness: crate::server::DependencyReadiness { + storage_ready: true, + iam_ready: true, + lock_quorum_ready: true, + peer_health_ready: true, + }, + degraded_reasons: Vec::new(), + }; + let parts = build_health_response_parts( + Method::GET, + HealthProbe::Readiness, + Some(&report), + "rustfs-endpoint", + None, + Some(false), + ); + assert_eq!(parts.status_code, StatusCode::SERVICE_UNAVAILABLE); + let payload = parts.payload.expect("GET should include payload"); + assert_eq!(payload["ready"], false); + assert_eq!(payload["details"]["lock"]["ready"], true); + assert_eq!(payload["details"]["kms"]["ready"], false); + assert_eq!(payload["degradedReasons"][0], "kms_not_ready"); + }); } }