feat: enhance test coverage and fix compilation errors

This commit is contained in:
overtrue
2025-05-25 12:56:43 +08:00
parent 136118ed21
commit a6c3b122bd
4 changed files with 711 additions and 6 deletions
+209
View File
@@ -89,3 +89,212 @@ pub const DEFAULT_CONSOLE_PORT: u16 = 9002;
/// Default address for rustfs console
/// This is the default address for rustfs console.
pub const DEFAULT_CONSOLE_ADDRESS: &str = concat!(":", DEFAULT_CONSOLE_PORT);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_app_basic_constants() {
// 测试应用基本常量
assert_eq!(APP_NAME, "RustFs");
assert!(!APP_NAME.is_empty(), "App name should not be empty");
assert!(!APP_NAME.contains(' '), "App name should not contain spaces");
assert_eq!(VERSION, "0.0.1");
assert!(!VERSION.is_empty(), "Version should not be empty");
assert_eq!(SERVICE_VERSION, "0.0.1");
assert_eq!(VERSION, SERVICE_VERSION, "Version and service version should be consistent");
}
#[test]
fn test_logging_constants() {
// 测试日志相关常量
assert_eq!(DEFAULT_LOG_LEVEL, "info");
assert!(["trace", "debug", "info", "warn", "error"].contains(&DEFAULT_LOG_LEVEL),
"Log level should be a valid tracing level");
assert_eq!(USE_STDOUT, true);
assert_eq!(SAMPLE_RATIO, 1.0);
assert!(SAMPLE_RATIO >= 0.0 && SAMPLE_RATIO <= 1.0,
"Sample ratio should be between 0.0 and 1.0");
assert_eq!(METER_INTERVAL, 30);
assert!(METER_INTERVAL > 0, "Meter interval should be positive");
}
#[test]
fn test_environment_constants() {
// 测试环境相关常量
assert_eq!(ENVIRONMENT, "production");
assert!(["development", "staging", "production", "test"].contains(&ENVIRONMENT),
"Environment should be a standard environment name");
}
#[test]
fn test_connection_constants() {
// 测试连接相关常量
assert_eq!(MAX_CONNECTIONS, 100);
assert!(MAX_CONNECTIONS > 0, "Max connections should be positive");
assert!(MAX_CONNECTIONS <= 10000, "Max connections should be reasonable");
assert_eq!(DEFAULT_TIMEOUT_MS, 3000);
assert!(DEFAULT_TIMEOUT_MS > 0, "Timeout should be positive");
assert!(DEFAULT_TIMEOUT_MS >= 1000, "Timeout should be at least 1 second");
}
#[test]
fn test_security_constants() {
// 测试安全相关常量
assert_eq!(DEFAULT_ACCESS_KEY, "rustfsadmin");
assert!(!DEFAULT_ACCESS_KEY.is_empty(), "Access key should not be empty");
assert!(DEFAULT_ACCESS_KEY.len() >= 8, "Access key should be at least 8 characters");
assert_eq!(DEFAULT_SECRET_KEY, "rustfsadmin");
assert!(!DEFAULT_SECRET_KEY.is_empty(), "Secret key should not be empty");
assert!(DEFAULT_SECRET_KEY.len() >= 8, "Secret key should be at least 8 characters");
// 在生产环境中,访问密钥和秘密密钥应该不同
// 这里是默认值,所以相同是可以接受的,但应该在文档中警告
println!("Warning: Default access key and secret key are the same. Change them in production!");
}
#[test]
fn test_file_path_constants() {
// 测试文件路径相关常量
assert_eq!(DEFAULT_OBS_CONFIG, "./deploy/config/obs.toml");
assert!(DEFAULT_OBS_CONFIG.ends_with(".toml"), "Config file should be TOML format");
assert!(!DEFAULT_OBS_CONFIG.is_empty(), "Config path should not be empty");
assert_eq!(RUSTFS_TLS_KEY, "rustfs_key.pem");
assert!(RUSTFS_TLS_KEY.ends_with(".pem"), "TLS key should be PEM format");
assert_eq!(RUSTFS_TLS_CERT, "rustfs_cert.pem");
assert!(RUSTFS_TLS_CERT.ends_with(".pem"), "TLS cert should be PEM format");
}
#[test]
fn test_port_constants() {
// 测试端口相关常量
assert_eq!(DEFAULT_PORT, 9000);
assert!(DEFAULT_PORT > 1024, "Default port should be above reserved range");
// u16类型自动保证端口在有效范围内(0-65535)
assert_eq!(DEFAULT_CONSOLE_PORT, 9002);
assert!(DEFAULT_CONSOLE_PORT > 1024, "Console port should be above reserved range");
// u16类型自动保证端口在有效范围内(0-65535)
assert_ne!(DEFAULT_PORT, DEFAULT_CONSOLE_PORT,
"Main port and console port should be different");
}
#[test]
fn test_address_constants() {
// 测试地址相关常量
assert_eq!(DEFAULT_ADDRESS, ":9000");
assert!(DEFAULT_ADDRESS.starts_with(':'), "Address should start with colon");
assert!(DEFAULT_ADDRESS.contains(&DEFAULT_PORT.to_string()),
"Address should contain the default port");
assert_eq!(DEFAULT_CONSOLE_ADDRESS, ":9002");
assert!(DEFAULT_CONSOLE_ADDRESS.starts_with(':'), "Console address should start with colon");
assert!(DEFAULT_CONSOLE_ADDRESS.contains(&DEFAULT_CONSOLE_PORT.to_string()),
"Console address should contain the console port");
assert_ne!(DEFAULT_ADDRESS, DEFAULT_CONSOLE_ADDRESS,
"Main address and console address should be different");
}
#[test]
fn test_const_str_concat_functionality() {
// 测试const_str::concat宏的功能
let expected_address = format!(":{}", DEFAULT_PORT);
assert_eq!(DEFAULT_ADDRESS, expected_address);
let expected_console_address = format!(":{}", DEFAULT_CONSOLE_PORT);
assert_eq!(DEFAULT_CONSOLE_ADDRESS, expected_console_address);
}
#[test]
fn test_string_constants_validity() {
// 测试字符串常量的有效性
let string_constants = [
APP_NAME,
VERSION,
DEFAULT_LOG_LEVEL,
SERVICE_VERSION,
ENVIRONMENT,
DEFAULT_ACCESS_KEY,
DEFAULT_SECRET_KEY,
DEFAULT_OBS_CONFIG,
RUSTFS_TLS_KEY,
RUSTFS_TLS_CERT,
DEFAULT_ADDRESS,
DEFAULT_CONSOLE_ADDRESS,
];
for constant in &string_constants {
assert!(!constant.is_empty(), "String constant should not be empty: {}", constant);
assert!(!constant.starts_with(' '), "String constant should not start with space: {}", constant);
assert!(!constant.ends_with(' '), "String constant should not end with space: {}", constant);
}
}
#[test]
fn test_numeric_constants_validity() {
// 测试数值常量的有效性
assert!(SAMPLE_RATIO.is_finite(), "Sample ratio should be finite");
assert!(!SAMPLE_RATIO.is_nan(), "Sample ratio should not be NaN");
assert!(METER_INTERVAL < u64::MAX, "Meter interval should be reasonable");
assert!(MAX_CONNECTIONS < usize::MAX, "Max connections should be reasonable");
assert!(DEFAULT_TIMEOUT_MS < u64::MAX, "Timeout should be reasonable");
assert!(DEFAULT_PORT != 0, "Default port should not be zero");
assert!(DEFAULT_CONSOLE_PORT != 0, "Console port should not be zero");
}
#[test]
fn test_security_best_practices() {
// 测试安全最佳实践
// 这些是默认值,在生产环境中应该被更改
println!("Security Warning: Default credentials detected!");
println!("Access Key: {}", DEFAULT_ACCESS_KEY);
println!("Secret Key: {}", DEFAULT_SECRET_KEY);
println!("These should be changed in production environments!");
// 验证密钥长度符合最低安全要求
assert!(DEFAULT_ACCESS_KEY.len() >= 8, "Access key should be at least 8 characters");
assert!(DEFAULT_SECRET_KEY.len() >= 8, "Secret key should be at least 8 characters");
// 检查默认凭据是否包含常见的不安全模式
let _insecure_patterns = ["admin", "password", "123456", "default"];
let _access_key_lower = DEFAULT_ACCESS_KEY.to_lowercase();
let _secret_key_lower = DEFAULT_SECRET_KEY.to_lowercase();
// 注意:这里可以添加更多的安全检查逻辑
// 例如检查密钥是否包含不安全的模式
}
#[test]
fn test_configuration_consistency() {
// 测试配置的一致性
// 版本一致性
assert_eq!(VERSION, SERVICE_VERSION, "Application version should match service version");
// 端口不冲突
let ports = [DEFAULT_PORT, DEFAULT_CONSOLE_PORT];
let mut unique_ports = std::collections::HashSet::new();
for port in &ports {
assert!(unique_ports.insert(port), "Port {} is duplicated", port);
}
// 地址格式一致性
assert_eq!(DEFAULT_ADDRESS, format!(":{}", DEFAULT_PORT));
assert_eq!(DEFAULT_CONSOLE_ADDRESS, format!(":{}", DEFAULT_CONSOLE_PORT));
}
}
+2 -1
View File
@@ -22,4 +22,5 @@ default = ["ip"] # features that are enabled by default
ip = ["dep:local-ip-address"] # ip characteristics and their dependencies
tls = ["dep:rustls", "dep:rustls-pemfile", "dep:rustls-pki-types"] # tls characteristics and their dependencies
net = ["ip"] # empty network features
full = ["ip", "tls", "net"] # all features
integration = [] # integration test features
full = ["ip", "tls", "net", "integration"] # all features
+167 -5
View File
@@ -31,13 +31,175 @@ pub fn get_local_ip_with_default() -> String {
#[cfg(test)]
mod tests {
use super::*;
use std::net::Ipv4Addr;
#[test]
fn test_get_local_ip() {
match get_local_ip() {
Some(ip) => println!("the ip address of this machine:{}", ip),
None => println!("Unable to obtain the IP address of the machine"),
fn test_get_local_ip_returns_some_ip() {
// 测试获取本地IP地址,应该返回Some值
let ip = get_local_ip();
assert!(ip.is_some(), "Should be able to get local IP address");
if let Some(ip_addr) = ip {
println!("Local IP address: {}", ip_addr);
// 验证返回的是有效的IP地址
match ip_addr {
IpAddr::V4(ipv4) => {
assert!(!ipv4.is_unspecified(), "IPv4 should not be unspecified (0.0.0.0)");
println!("Got IPv4 address: {}", ipv4);
}
IpAddr::V6(ipv6) => {
assert!(!ipv6.is_unspecified(), "IPv6 should not be unspecified (::)");
println!("Got IPv6 address: {}", ipv6);
}
}
}
}
#[test]
fn test_get_local_ip_with_default_never_empty() {
// 测试带默认值的函数永远不会返回空字符串
let ip_string = get_local_ip_with_default();
assert!(!ip_string.is_empty(), "IP string should never be empty");
// 验证返回的字符串可以解析为有效的IP地址
let parsed_ip: Result<IpAddr, _> = ip_string.parse();
assert!(parsed_ip.is_ok(), "Returned string should be a valid IP address: {}", ip_string);
println!("Local IP with default: {}", ip_string);
}
#[test]
fn test_get_local_ip_with_default_fallback() {
// 测试默认值是否为127.0.0.1
let default_ip = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
let ip_string = get_local_ip_with_default();
// 如果无法获取真实IP,应该返回默认值
if get_local_ip().is_none() {
assert_eq!(ip_string, default_ip.to_string());
}
// 无论如何,返回的都应该是有效的IP地址字符串
let parsed: Result<IpAddr, _> = ip_string.parse();
assert!(parsed.is_ok(), "Should always return a valid IP string");
}
#[test]
fn test_ip_address_types() {
// 测试IP地址类型的识别
if let Some(ip) = get_local_ip() {
match ip {
IpAddr::V4(ipv4) => {
// 测试IPv4地址的属性
println!("IPv4 address: {}", ipv4);
assert!(!ipv4.is_multicast(), "Local IP should not be multicast");
assert!(!ipv4.is_broadcast(), "Local IP should not be broadcast");
// 检查是否为私有地址(通常本地IP是私有的)
let is_private = ipv4.is_private();
let is_loopback = ipv4.is_loopback();
println!("IPv4 is private: {}, is loopback: {}", is_private, is_loopback);
}
IpAddr::V6(ipv6) => {
// 测试IPv6地址的属性
println!("IPv6 address: {}", ipv6);
assert!(!ipv6.is_multicast(), "Local IP should not be multicast");
let is_loopback = ipv6.is_loopback();
println!("IPv6 is loopback: {}", is_loopback);
}
}
}
}
#[test]
fn test_ip_string_format() {
// 测试IP地址字符串格式
let ip_string = get_local_ip_with_default();
// 验证字符串格式
assert!(!ip_string.contains(' '), "IP string should not contain spaces");
assert!(!ip_string.is_empty(), "IP string should not be empty");
// 验证可以往返转换
let parsed_ip: IpAddr = ip_string.parse().expect("Should parse as valid IP");
let back_to_string = parsed_ip.to_string();
// 对于标准IP地址,往返转换应该保持一致
println!("Original: {}, Parsed back: {}", ip_string, back_to_string);
}
#[test]
fn test_default_fallback_value() {
// 测试默认回退值的正确性
let default_ip = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
assert_eq!(default_ip.to_string(), "127.0.0.1");
// 验证默认IP的属性
if let IpAddr::V4(ipv4) = default_ip {
assert!(ipv4.is_loopback(), "Default IP should be loopback");
assert!(!ipv4.is_unspecified(), "Default IP should not be unspecified");
assert!(!ipv4.is_multicast(), "Default IP should not be multicast");
}
}
#[test]
fn test_consistency_between_functions() {
// 测试两个函数之间的一致性
let ip_option = get_local_ip();
let ip_string = get_local_ip_with_default();
match ip_option {
Some(ip) => {
// 如果get_local_ip返回Some,那么get_local_ip_with_default应该返回相同的IP
assert_eq!(ip.to_string(), ip_string,
"Both functions should return the same IP when available");
}
None => {
// 如果get_local_ip返回None,那么get_local_ip_with_default应该返回默认值
assert_eq!(ip_string, "127.0.0.1",
"Should return default value when no IP is available");
}
}
}
#[test]
fn test_multiple_calls_consistency() {
// 测试多次调用的一致性
let ip1 = get_local_ip();
let ip2 = get_local_ip();
let ip_str1 = get_local_ip_with_default();
let ip_str2 = get_local_ip_with_default();
// 多次调用应该返回相同的结果
assert_eq!(ip1, ip2, "Multiple calls to get_local_ip should return same result");
assert_eq!(ip_str1, ip_str2, "Multiple calls to get_local_ip_with_default should return same result");
}
#[cfg(feature = "integration")]
#[test]
fn test_network_connectivity() {
// 集成测试:验证获取的IP地址是否可用于网络连接
if let Some(ip) = get_local_ip() {
match ip {
IpAddr::V4(ipv4) => {
// 对于IPv4,检查是否为有效的网络地址
assert!(!ipv4.is_unspecified(), "Should not be 0.0.0.0");
// 如果不是回环地址,应该是可路由的
if !ipv4.is_loopback() {
println!("Got routable IPv4: {}", ipv4);
}
}
IpAddr::V6(ipv6) => {
// 对于IPv6,检查是否为有效的网络地址
assert!(!ipv6.is_unspecified(), "Should not be ::");
if !ipv6.is_loopback() {
println!("Got routable IPv6: {}", ipv6);
}
}
}
}
assert!(get_local_ip().is_some());
}
}