mirror of
https://github.com/rustfs/rustfs.git
synced 2026-07-26 08:18:18 +00:00
test(e2e): avoid console port 9001 clash and fail fast on dead server (#4603)
This commit is contained in:
@@ -62,6 +62,9 @@ mod tests {
|
||||
let binary_path = rustfs_binary_path();
|
||||
let mut command = Command::new(&binary_path);
|
||||
command.env("RUST_LOG", "rustfs=info,rustfs_notify=debug");
|
||||
// Keep the embedded console off its fixed default port :9001, which may
|
||||
// already be taken by unrelated local services (e.g. Docker Desktop).
|
||||
command.env("RUSTFS_CONSOLE_ENABLE", "false");
|
||||
for (key, value) in extra_env {
|
||||
command.env(key, value);
|
||||
}
|
||||
|
||||
@@ -391,6 +391,10 @@ impl RustFSTestEnvironment {
|
||||
let binary_path = rustfs_binary_path();
|
||||
let mut command = Command::new(&binary_path);
|
||||
command.env("RUST_LOG", "rustfs=info,rustfs_notify=debug");
|
||||
// The embedded console would bind the fixed default port :9001, which
|
||||
// collides with unrelated local services (e.g. Docker Desktop). Tests
|
||||
// that need the console can still override this via extra_env.
|
||||
command.env("RUSTFS_CONSOLE_ENABLE", "false");
|
||||
for (key, value) in extra_env {
|
||||
command.env(key, value);
|
||||
}
|
||||
@@ -435,11 +439,20 @@ impl RustFSTestEnvironment {
|
||||
/// connections before the S3 stack is fully initialized, which causes
|
||||
/// early requests to fail intermittently. Treat readiness as "S3 API
|
||||
/// responds successfully" instead.
|
||||
pub async fn wait_for_server_ready(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
///
|
||||
/// Fails immediately if the spawned server process has already exited
|
||||
/// (e.g. a port bind failure) instead of polling out the full timeout.
|
||||
pub async fn wait_for_server_ready(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
info!("Waiting for RustFS server to be ready on {}", self.address);
|
||||
let client = self.create_s3_client();
|
||||
|
||||
for i in 0..60 {
|
||||
if let Some(process) = self.process.as_mut()
|
||||
&& let Ok(Some(status)) = process.try_wait()
|
||||
{
|
||||
return Err(format!("RustFS server process exited before becoming ready: {status}").into());
|
||||
}
|
||||
|
||||
if TcpStream::connect(&self.address).await.is_ok() && client.list_buckets().send().await.is_ok() {
|
||||
info!("✅ RustFS server is ready after {} attempts", i + 1);
|
||||
return Ok(());
|
||||
|
||||
@@ -46,6 +46,10 @@ mod list_objects_duplicates_test;
|
||||
#[cfg(test)]
|
||||
mod quota_test;
|
||||
|
||||
// Harness regression tests: console port isolation + fail-fast startup
|
||||
#[cfg(test)]
|
||||
mod server_startup_failfast_test;
|
||||
|
||||
#[cfg(test)]
|
||||
mod bucket_policy_check_test;
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
// Copyright 2024 RustFS Team
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Regression tests for e2e harness server-startup behavior.
|
||||
//!
|
||||
//! The harness spawns servers with the embedded console disabled so they never
|
||||
//! contend for its fixed default port :9001 (often held by unrelated local
|
||||
//! services such as Docker Desktop), and `wait_for_server_ready` must report a
|
||||
//! server that dies during startup immediately instead of polling out the full
|
||||
//! readiness timeout.
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::common::{RustFSTestEnvironment, init_logging, rustfs_binary_path};
|
||||
use serial_test::serial;
|
||||
use std::net::TcpListener;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
/// Force the console back on (extra_env overrides the harness default)
|
||||
/// while :9001 is occupied: the server exits at startup, and the harness
|
||||
/// must surface that promptly rather than waiting out the 60s timeout.
|
||||
#[tokio::test]
|
||||
#[serial]
|
||||
async fn test_start_fails_fast_when_server_exits_during_startup() {
|
||||
init_logging();
|
||||
|
||||
// Occupy :9001 on both stacks; a failed bind means another local
|
||||
// process already holds the port, which serves equally well.
|
||||
let _guard_v6 = TcpListener::bind(("::", 9001)).ok();
|
||||
let _guard_v4 = TcpListener::bind(("0.0.0.0", 9001)).ok();
|
||||
|
||||
// Resolve (and possibly build) the binary before starting the timer.
|
||||
let _ = rustfs_binary_path();
|
||||
|
||||
let mut env = RustFSTestEnvironment::new().await.expect("Failed to create test environment");
|
||||
let started = Instant::now();
|
||||
let result = env
|
||||
.start_rustfs_server_with_env(vec![], &[("RUSTFS_CONSOLE_ENABLE", "true")])
|
||||
.await;
|
||||
let elapsed = started.elapsed();
|
||||
|
||||
let err = result.expect_err("server start should fail while :9001 is occupied");
|
||||
assert!(err.to_string().contains("exited before becoming ready"), "unexpected start error: {err}");
|
||||
assert!(
|
||||
elapsed < Duration::from_secs(30),
|
||||
"startup failure should be detected fast, took {elapsed:?}"
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user