Skip to content

test(admin): cover rebalance status dispatch#187

Merged
overtrue merged 1 commit intomainfrom
codex/test-rebalance-status-dispatch
May 8, 2026
Merged

test(admin): cover rebalance status dispatch#187
overtrue merged 1 commit intomainfrom
codex/test-rebalance-status-dispatch

Conversation

@overtrue
Copy link
Copy Markdown
Contributor

@overtrue overtrue commented May 8, 2026

Related Issue(s)

None.

Problem Background and User Impact

Recent admin rebalance work added rc admin rebalance status as a direct CLI command. Existing coverage verifies command parsing and the lower-level S3 admin route, while the expansion wrapper path is already covered separately. The direct AdminCommands::Rebalance execution path still lacked an end-to-end command test.

Root Cause Summary

No integration test executed the built rc binary for admin rebalance status, so a future regression could misroute or remove that command branch while parser and lower-level client tests still passed.

Solution Overview

This PR adds one focused non-Windows integration test. It runs rc --json admin rebalance status against a loopback admin test server, asserts the returned JSON status payload, and verifies the CLI sends a GET request to /rustfs/admin/v3/rebalance/status.

Test Status

  • cargo test -p rustfs-cli --test admin_rebalance rebalance_status_dispatches_to_rebalance_status_json -- --nocapture
  • make pre-commit

@overtrue overtrue marked this pull request as ready for review May 8, 2026 04:15
Copilot AI review requested due to automatic review settings May 8, 2026 04:15
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a non-Windows CLI integration test to ensure the direct rc admin rebalance status command path dispatches to the correct admin endpoint and returns the expected JSON payload, preventing regressions that parser/client unit tests might not catch.

Changes:

  • Introduces a loopback admin test server that captures the HTTP method/path and returns a stubbed JSON response.
  • Adds an end-to-end test executing the built rc binary with --json admin rebalance status and asserting both output JSON and request routing.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +17 to +104
fn rc_binary() -> PathBuf {
if let Ok(path) = std::env::var("CARGO_BIN_EXE_rc") {
return PathBuf::from(path);
}

let workspace_root = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.parent()
.expect("cli crate has parent directory")
.parent()
.expect("workspace root exists")
.to_path_buf();

let debug_binary = workspace_root.join("target/debug/rc");
if debug_binary.exists() {
return debug_binary;
}

workspace_root.join("target/release/rc")
}

fn read_admin_request(stream: &mut TcpStream) -> CapturedAdminRequest {
stream
.set_read_timeout(Some(Duration::from_secs(5)))
.expect("set read timeout");

let mut request = Vec::new();
let mut buffer = [0_u8; 8192];
loop {
let bytes_read = stream.read(&mut buffer).expect("read admin request");
if bytes_read == 0 {
break;
}
request.extend_from_slice(&buffer[..bytes_read]);
if request.windows(4).any(|window| window == b"\r\n\r\n") {
break;
}
}

let request = String::from_utf8(request).expect("admin request should be UTF-8");
let request_line = request.lines().next().expect("request line");
let mut parts = request_line.split_whitespace();
let method = parts.next().expect("request method").to_string();
let target = parts.next().expect("request target").to_string();

CapturedAdminRequest { method, target }
}

fn start_admin_test_server(
response_body: &'static str,
) -> (String, Receiver<CapturedAdminRequest>, JoinHandle<()>) {
let listener = TcpListener::bind("127.0.0.1:0").expect("bind admin test server");
listener
.set_nonblocking(true)
.expect("set admin test server nonblocking");
let endpoint = format!("http://{}", listener.local_addr().expect("server address"));
let (sender, receiver) = mpsc::channel();

let handle = thread::spawn(move || {
let deadline = Instant::now() + Duration::from_secs(10);
let (mut stream, _) = loop {
match listener.accept() {
Ok(accepted) => break accepted,
Err(e) if e.kind() == ErrorKind::WouldBlock && Instant::now() < deadline => {
thread::sleep(Duration::from_millis(10));
}
Err(e) => panic!("accept admin request: {e}"),
}
};
let request = read_admin_request(&mut stream);
sender.send(request).expect("send captured request");

let response = format!(
"HTTP/1.1 200 OK\r\ncontent-type: application/json\r\ncontent-length: {}\r\nconnection: close\r\n\r\n{}",
response_body.len(),
response_body
);
stream
.write_all(response.as_bytes())
.expect("write admin response");
});

(endpoint, receiver, handle)
}

fn rc_host_alias(endpoint: &str) -> String {
let (_, endpoint_authority) = endpoint.split_once("://").expect("endpoint has scheme");
format!("http://ACCESS_KEY:SECRET_KEY@{endpoint_authority}")
}
Comment on lines +74 to +84
let handle = thread::spawn(move || {
let deadline = Instant::now() + Duration::from_secs(10);
let (mut stream, _) = loop {
match listener.accept() {
Ok(accepted) => break accepted,
Err(e) if e.kind() == ErrorKind::WouldBlock && Instant::now() < deadline => {
thread::sleep(Duration::from_millis(10));
}
Err(e) => panic!("accept admin request: {e}"),
}
};
Comment on lines +88 to +92
let response = format!(
"HTTP/1.1 200 OK\r\ncontent-type: application/json\r\ncontent-length: {}\r\nconnection: close\r\n\r\n{}",
response_body.len(),
response_body
);
@overtrue overtrue merged commit 7353408 into main May 8, 2026
19 checks passed
@overtrue overtrue deleted the codex/test-rebalance-status-dispatch branch May 8, 2026 05:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants