From 7f8a8cdbac9b44a59d6a933db146ab6acfc26de2 Mon Sep 17 00:00:00 2001 From: houseme Date: Wed, 19 Aug 2026 23:33:06 +0800 Subject: [PATCH] fix(madmin): send background-heal status over POST (#6270) --- crates/madmin/src/client.rs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/crates/madmin/src/client.rs b/crates/madmin/src/client.rs index 273f922a3..4f7c6fb66 100644 --- a/crates/madmin/src/client.rs +++ b/crates/madmin/src/client.rs @@ -368,9 +368,10 @@ impl AdminClient { } } - /// Cluster-aggregated background heal status. + /// Cluster-aggregated background heal status. The route is registered + /// POST-only on the server, so this must not go out as a GET. pub async fn background_heal_status(&self) -> Result { - self.get_json("/v3/background-heal/status").await + self.post_json("/v3/background-heal/status", &[], Vec::new()).await } /// Data scanner status (enabled state, freshness, runtime config). @@ -698,6 +699,21 @@ mod tests { assert!(!request.query.contains("clientToken")); } + #[tokio::test] + async fn background_heal_status_posts_to_the_registered_route() { + let body = r#"{"state":"idle","healQueueLength":0,"healActiveTasks":0,"clusterStatusComplete":true}"#; + let server = TestServer::spawn(body, 200).await; + let client = AdminClient::new(&format!("http://{}", server.addr), "ak", "sk").unwrap(); + + let status = client.background_heal_status().await.expect("status decodes"); + assert_eq!(status.state, "idle"); + let request = server.recorded(); + // The server registers this route POST-only; a GET here answers 405. + assert_eq!(request.method, "POST"); + assert_eq!(request.path, "/rustfs/admin/v3/background-heal/status"); + assert_eq!(request.query, ""); + } + #[tokio::test] async fn http_error_status_maps_to_a_typed_error_with_body() { let server = TestServer::spawn(r#"{"code":"AccessDenied","message":"denied"}"#, 403).await;