mirror of
https://github.com/rustfs/rustfs.git
synced 2026-07-26 08:18:18 +00:00
226 lines
6.7 KiB
Rust
226 lines
6.7 KiB
Rust
// 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.
|
|
|
|
//! Tests for audit configuration parsing and validation
|
|
|
|
use rustfs_config::server_config::KVS;
|
|
|
|
#[test]
|
|
fn test_webhook_valid_fields() {
|
|
let expected_fields = vec![
|
|
"enable",
|
|
"endpoint",
|
|
"auth_token",
|
|
"client_cert",
|
|
"client_key",
|
|
"batch_size",
|
|
"queue_size",
|
|
"queue_dir",
|
|
"max_retry",
|
|
"retry_interval",
|
|
"http_timeout",
|
|
];
|
|
|
|
// This tests the webhook configuration fields we support
|
|
for field in expected_fields {
|
|
// Basic validation that field names are consistent
|
|
assert!(!field.is_empty());
|
|
assert!(!field.contains(" "));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_mqtt_valid_fields() {
|
|
let expected_fields = vec![
|
|
"enable",
|
|
"broker",
|
|
"topic",
|
|
"username",
|
|
"password",
|
|
"qos",
|
|
"keep_alive_interval",
|
|
"reconnect_interval",
|
|
"queue_dir",
|
|
"queue_limit",
|
|
"tls_policy",
|
|
"tls_ca",
|
|
"tls_client_cert",
|
|
"tls_client_key",
|
|
"tls_trust_leaf_as_ca",
|
|
"ws_path_allowlist",
|
|
];
|
|
|
|
// This tests the MQTT configuration fields we support
|
|
for field in expected_fields {
|
|
// Basic validation that field names are consistent
|
|
assert!(!field.is_empty());
|
|
assert!(!field.contains(" "));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_config_section_names() {
|
|
// Test audit route prefix and section naming
|
|
let webhook_section = "audit_webhook";
|
|
let mqtt_section = "audit_mqtt";
|
|
|
|
assert_eq!(webhook_section, "audit_webhook");
|
|
assert_eq!(mqtt_section, "audit_mqtt");
|
|
|
|
// Verify section names follow expected pattern
|
|
assert!(webhook_section.starts_with("audit_"));
|
|
assert!(mqtt_section.starts_with("audit_"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_environment_variable_parsing() {
|
|
// Test environment variable prefix patterns
|
|
let env_prefix = "RUSTFS_";
|
|
let audit_webhook_prefix = format!("{env_prefix}AUDIT_WEBHOOK_");
|
|
let audit_mqtt_prefix = format!("{env_prefix}AUDIT_MQTT_");
|
|
|
|
assert_eq!(audit_webhook_prefix, "RUSTFS_AUDIT_WEBHOOK_");
|
|
assert_eq!(audit_mqtt_prefix, "RUSTFS_AUDIT_MQTT_");
|
|
|
|
// Test instance parsing
|
|
let example_env_var = "RUSTFS_AUDIT_WEBHOOK_ENABLE_PRIMARY";
|
|
assert!(example_env_var.starts_with(&audit_webhook_prefix));
|
|
|
|
let suffix = &example_env_var[audit_webhook_prefix.len()..];
|
|
assert_eq!(suffix, "ENABLE_PRIMARY");
|
|
|
|
// Parse field and instance
|
|
if let Some(last_underscore) = suffix.rfind('_') {
|
|
let field = &suffix[..last_underscore];
|
|
let instance = &suffix[last_underscore + 1..];
|
|
assert_eq!(field, "ENABLE");
|
|
assert_eq!(instance, "PRIMARY");
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_configuration_merge() {
|
|
// Test configuration merging precedence: ENV > file instance > file default
|
|
let mut default_config = KVS::new();
|
|
default_config.insert("enable".to_string(), "off".to_string());
|
|
default_config.insert("endpoint".to_string(), "http://default".to_string());
|
|
|
|
let mut instance_config = KVS::new();
|
|
instance_config.insert("endpoint".to_string(), "http://instance".to_string());
|
|
|
|
let mut env_config = KVS::new();
|
|
env_config.insert("enable".to_string(), "on".to_string());
|
|
|
|
// Simulate merge: default < instance < env
|
|
let mut merged = default_config.clone();
|
|
merged.extend(instance_config);
|
|
merged.extend(env_config);
|
|
|
|
// Verify merge results
|
|
assert_eq!(merged.lookup("enable"), Some("on".to_string()));
|
|
assert_eq!(merged.lookup("endpoint"), Some("http://instance".to_string()));
|
|
}
|
|
|
|
#[test]
|
|
fn test_duration_parsing_formats() {
|
|
let test_cases = vec![
|
|
("3s", Some(3)),
|
|
("5m", Some(300)), // 5 minutes = 300 seconds
|
|
("1000ms", Some(1)), // 1000ms = 1 second
|
|
("60", Some(60)), // Default to seconds
|
|
("invalid", None),
|
|
("", None),
|
|
];
|
|
|
|
for (input, expected_seconds) in test_cases {
|
|
let result = parse_duration_test(input);
|
|
match (result, expected_seconds) {
|
|
(Some(duration), Some(expected)) => {
|
|
assert_eq!(duration.as_secs(), expected, "Failed for input: {input}");
|
|
}
|
|
(None, None) => {
|
|
// Both None, test passes
|
|
}
|
|
_ => {
|
|
panic!("Mismatch for input: {input}, got: {result:?}, expected: {expected_seconds:?}");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Helper function for duration parsing (extracted from registry.rs logic)
|
|
fn parse_duration_test(s: &str) -> Option<std::time::Duration> {
|
|
use std::time::Duration;
|
|
|
|
if let Some(stripped) = s.strip_suffix("ms") {
|
|
stripped.parse::<u64>().ok().map(Duration::from_millis)
|
|
} else if let Some(stripped) = s.strip_suffix('s') {
|
|
stripped.parse::<u64>().ok().map(Duration::from_secs)
|
|
} else if let Some(stripped) = s.strip_suffix('m') {
|
|
stripped.parse::<u64>().ok().map(|m| Duration::from_secs(m * 60))
|
|
} else {
|
|
s.parse::<u64>().ok().map(Duration::from_secs)
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_url_validation() {
|
|
use url::Url;
|
|
|
|
let valid_urls = vec![
|
|
"http://localhost:3020/webhook",
|
|
"https://api.example.com/audit",
|
|
"mqtt://broker.example.com:1883",
|
|
"tcp://localhost:1883",
|
|
];
|
|
|
|
let invalid_urls = [
|
|
"",
|
|
"not-a-url",
|
|
"http://",
|
|
"ftp://unsupported.com", // Not invalid, but might not be supported
|
|
];
|
|
|
|
for url_str in valid_urls {
|
|
let result = Url::parse(url_str);
|
|
assert!(result.is_ok(), "Valid URL should parse: {url_str}");
|
|
}
|
|
|
|
for url_str in &invalid_urls[..3] {
|
|
// Skip the ftp one as it's technically valid
|
|
let result = Url::parse(url_str);
|
|
assert!(result.is_err(), "Invalid URL should not parse: {url_str}");
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_qos_parsing() {
|
|
// Test QoS level parsing for MQTT
|
|
let test_cases = vec![
|
|
("0", Some(0)),
|
|
("1", Some(1)),
|
|
("2", Some(2)),
|
|
("3", None), // Invalid QoS level
|
|
("invalid", None),
|
|
];
|
|
|
|
for (input, expected) in test_cases {
|
|
let result = input.parse::<u8>().ok().and_then(|q| match q {
|
|
0..=2 => Some(q),
|
|
_ => None,
|
|
});
|
|
assert_eq!(result, expected, "Failed for QoS input: {input}");
|
|
}
|
|
}
|