test(e2e): gate protocol runner by requested features (#2912)

This commit is contained in:
Henry Guo
2026-05-11 21:59:24 +08:00
committed by GitHub
parent aba65a448c
commit 941986b331
3 changed files with 192 additions and 40 deletions
+121 -28
View File
@@ -15,6 +15,7 @@
//! Protocol test runner
use crate::common::init_logging;
use crate::common::{requested_rustfs_build_features, rustfs_build_feature_enabled};
use crate::protocols::ftps_core::test_ftps_core_operations;
use crate::protocols::sftp_compliance::{
test_sftp_compliance_readonly, test_sftp_compliance_standalone, test_sftp_compliance_suite,
@@ -59,36 +60,22 @@ pub struct ProtocolTestSuite {
#[derive(Debug, Clone)]
struct TestDefinition {
name: String,
name: &'static str,
required_feature: &'static str,
}
impl ProtocolTestSuite {
/// Create default test suite
pub fn new() -> Self {
let tests = vec![
TestDefinition {
name: "test_ftps_core_operations".to_string(),
},
TestDefinition {
name: "test_webdav_core_operations".to_string(),
},
TestDefinition {
name: "test_sftp_core_operations".to_string(),
},
TestDefinition {
name: "test_sftp_compliance_suite".to_string(),
},
TestDefinition {
name: "test_sftp_compliance_readonly".to_string(),
},
TestDefinition {
name: "test_sftp_idle_timeout_disconnects".to_string(),
},
TestDefinition {
name: "test_sftp_compliance_standalone".to_string(),
},
];
let requested_features = requested_rustfs_build_features();
Self::with_requested_features(requested_features.as_deref())
}
fn with_requested_features(requested_features: Option<&str>) -> Self {
let tests = all_protocol_tests()
.into_iter()
.filter(|test| rustfs_build_feature_enabled(requested_features, test.required_feature))
.collect();
Self { tests }
}
@@ -104,7 +91,7 @@ impl ProtocolTestSuite {
// Run tests
for (i, test_def) in self.tests.iter().enumerate() {
let test_description = match test_def.name.as_str() {
let test_description = match test_def.name {
"test_ftps_core_operations" => {
info!("=== Starting FTPS Module Test ===");
"FTPS core operations (put, ls, mkdir, rmdir, delete)"
@@ -147,11 +134,11 @@ impl ProtocolTestSuite {
match result {
Ok(_) => {
info!("Test passed: {} ({:.2}s)", test_def.name, test_duration.as_secs_f64());
results.push(TestResult::success(test_def.name.clone()));
results.push(TestResult::success(test_def.name.to_string()));
}
Err(e) => {
error!("Test failed: {} ({:.2}s): {}", test_def.name, test_duration.as_secs_f64(), e);
results.push(TestResult::failure(test_def.name.clone(), e.to_string()));
results.push(TestResult::failure(test_def.name.to_string(), e.to_string()));
}
}
@@ -169,7 +156,7 @@ impl ProtocolTestSuite {
/// Run a single test
async fn run_single_test(&self, test_def: &TestDefinition) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
match test_def.name.as_str() {
match test_def.name {
"test_ftps_core_operations" => test_ftps_core_operations().await.map_err(|e| e.into()),
"test_webdav_core_operations" => test_webdav_core_operations().await.map_err(|e| e.into()),
"test_sftp_core_operations" => test_sftp_core_operations().await.map_err(|e| e.into()),
@@ -186,6 +173,10 @@ impl ProtocolTestSuite {
info!("=== Test Suite Summary ===");
info!("Total duration: {:.2}s", total_duration.as_secs_f64());
info!("Total tests: {}", results.len());
if results.is_empty() {
info!("No protocol tests scheduled for the requested feature set");
return;
}
let passed = results.iter().filter(|r| r.success).count();
let failed = results.len() - passed;
@@ -203,6 +194,39 @@ impl ProtocolTestSuite {
}
}
fn all_protocol_tests() -> Vec<TestDefinition> {
vec![
TestDefinition {
name: "test_ftps_core_operations",
required_feature: "ftps",
},
TestDefinition {
name: "test_webdav_core_operations",
required_feature: "webdav",
},
TestDefinition {
name: "test_sftp_core_operations",
required_feature: "sftp",
},
TestDefinition {
name: "test_sftp_compliance_suite",
required_feature: "sftp",
},
TestDefinition {
name: "test_sftp_compliance_readonly",
required_feature: "sftp",
},
TestDefinition {
name: "test_sftp_idle_timeout_disconnects",
required_feature: "sftp",
},
TestDefinition {
name: "test_sftp_compliance_standalone",
required_feature: "sftp",
},
]
}
/// Test suite
#[tokio::test]
#[serial]
@@ -218,3 +242,72 @@ async fn test_protocol_core_suite() -> Result<(), Box<dyn std::error::Error + Se
info!("All protocol tests passed");
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
fn scheduled_names(suite: ProtocolTestSuite) -> Vec<&'static str> {
suite.tests.into_iter().map(|test| test.name).collect()
}
#[test]
fn schedules_all_protocol_tests_without_feature_filter() {
let names = scheduled_names(ProtocolTestSuite::with_requested_features(None));
assert_eq!(names.len(), 7);
assert!(names.contains(&"test_ftps_core_operations"));
assert!(names.contains(&"test_webdav_core_operations"));
assert!(names.contains(&"test_sftp_core_operations"));
assert!(names.contains(&"test_sftp_compliance_standalone"));
}
#[test]
fn schedules_only_requested_non_sftp_protocols() {
let names = scheduled_names(ProtocolTestSuite::with_requested_features(Some("ftps, webdav")));
assert_eq!(names, vec!["test_ftps_core_operations", "test_webdav_core_operations"]);
}
#[test]
fn schedules_all_sftp_entries_for_sftp_feature() {
let names = scheduled_names(ProtocolTestSuite::with_requested_features(Some("sftp")));
assert_eq!(
names,
vec![
"test_sftp_core_operations",
"test_sftp_compliance_suite",
"test_sftp_compliance_readonly",
"test_sftp_idle_timeout_disconnects",
"test_sftp_compliance_standalone",
]
);
}
#[test]
fn feature_filter_is_case_insensitive() {
let names = scheduled_names(ProtocolTestSuite::with_requested_features(Some("SFTP")));
assert_eq!(names.len(), 5);
assert!(names.iter().all(|name| name.contains("sftp")));
}
#[test]
fn full_feature_schedules_all_protocol_tests() {
let names = scheduled_names(ProtocolTestSuite::with_requested_features(Some("full")));
assert_eq!(names.len(), 7);
assert!(names.contains(&"test_ftps_core_operations"));
assert!(names.contains(&"test_webdav_core_operations"));
assert!(names.contains(&"test_sftp_core_operations"));
assert!(names.contains(&"test_sftp_compliance_standalone"));
}
#[test]
fn schedules_no_tests_when_requested_features_have_no_protocols() {
let names = scheduled_names(ProtocolTestSuite::with_requested_features(Some("diagnostics")));
assert!(names.is_empty());
}
}