mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-20 11:32:19 +00:00
resolve: merge conflicts in last_minute.rs tests
This commit is contained in:
@@ -89,3 +89,249 @@ impl std::fmt::Display for Error {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::io;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct CustomTestError {
|
||||
message: String,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for CustomTestError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Custom test error: {}", self.message)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for CustomTestError {}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct AnotherTestError;
|
||||
|
||||
impl std::fmt::Display for AnotherTestError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Another test error")
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for AnotherTestError {}
|
||||
|
||||
#[test]
|
||||
fn test_error_new_from_std_error() {
|
||||
let io_error = io::Error::new(io::ErrorKind::NotFound, "File not found");
|
||||
let error = Error::new(io_error);
|
||||
|
||||
assert!(error.inner_string().contains("File not found"));
|
||||
assert!(error.is::<io::Error>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_error_from_std_error() {
|
||||
let io_error = io::Error::new(io::ErrorKind::PermissionDenied, "Permission denied");
|
||||
let boxed_error: StdError = Box::new(io_error);
|
||||
let error = Error::from_std_error(boxed_error);
|
||||
|
||||
assert!(error.inner_string().contains("Permission denied"));
|
||||
assert!(error.is::<io::Error>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_error_from_string() {
|
||||
let error = Error::from_string("Test error message");
|
||||
assert_eq!(error.inner_string(), "Test error message");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_error_msg() {
|
||||
let error = Error::msg("Another test message");
|
||||
assert_eq!(error.inner_string(), "Another test message");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_error_msg_with_string() {
|
||||
let message = String::from("String message");
|
||||
let error = Error::msg(message);
|
||||
assert_eq!(error.inner_string(), "String message");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_error_is_type_checking() {
|
||||
let io_error = io::Error::new(io::ErrorKind::InvalidInput, "Invalid input");
|
||||
let error = Error::new(io_error);
|
||||
|
||||
assert!(error.is::<io::Error>());
|
||||
assert!(!error.is::<CustomTestError>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_error_downcast_ref() {
|
||||
let io_error = io::Error::new(io::ErrorKind::TimedOut, "Operation timed out");
|
||||
let error = Error::new(io_error);
|
||||
|
||||
let downcast_io = error.downcast_ref::<io::Error>();
|
||||
assert!(downcast_io.is_some());
|
||||
assert_eq!(downcast_io.unwrap().kind(), io::ErrorKind::TimedOut);
|
||||
|
||||
let downcast_custom = error.downcast_ref::<CustomTestError>();
|
||||
assert!(downcast_custom.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_error_downcast_mut() {
|
||||
let io_error = io::Error::new(io::ErrorKind::Interrupted, "Operation interrupted");
|
||||
let mut error = Error::new(io_error);
|
||||
|
||||
let downcast_io = error.downcast_mut::<io::Error>();
|
||||
assert!(downcast_io.is_some());
|
||||
assert_eq!(downcast_io.unwrap().kind(), io::ErrorKind::Interrupted);
|
||||
|
||||
let downcast_custom = error.downcast_mut::<CustomTestError>();
|
||||
assert!(downcast_custom.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_error_to_io_err() {
|
||||
// Test with IO error
|
||||
let original_io_error = io::Error::new(io::ErrorKind::BrokenPipe, "Broken pipe");
|
||||
let error = Error::new(original_io_error);
|
||||
|
||||
let converted_io_error = error.to_io_err();
|
||||
assert!(converted_io_error.is_some());
|
||||
let io_err = converted_io_error.unwrap();
|
||||
assert_eq!(io_err.kind(), io::ErrorKind::BrokenPipe);
|
||||
assert!(io_err.to_string().contains("Broken pipe"));
|
||||
|
||||
// Test with non-IO error
|
||||
let custom_error = CustomTestError {
|
||||
message: "Not an IO error".to_string(),
|
||||
};
|
||||
let error = Error::new(custom_error);
|
||||
|
||||
let converted_io_error = error.to_io_err();
|
||||
assert!(converted_io_error.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_error_inner_string() {
|
||||
let custom_error = CustomTestError {
|
||||
message: "Test message".to_string(),
|
||||
};
|
||||
let error = Error::new(custom_error);
|
||||
|
||||
assert_eq!(error.inner_string(), "Custom test error: Test message");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_error_from_trait() {
|
||||
let io_error = io::Error::new(io::ErrorKind::UnexpectedEof, "Unexpected EOF");
|
||||
let error: Error = io_error.into();
|
||||
|
||||
assert!(error.is::<io::Error>());
|
||||
assert!(error.inner_string().contains("Unexpected EOF"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_error_display() {
|
||||
let custom_error = CustomTestError {
|
||||
message: "Display test".to_string(),
|
||||
};
|
||||
let error = Error::new(custom_error);
|
||||
|
||||
let display_string = format!("{}", error);
|
||||
assert!(display_string.contains("Custom test error: Display test"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_error_debug() {
|
||||
let error = Error::msg("Debug test");
|
||||
let debug_string = format!("{:?}", error);
|
||||
|
||||
assert!(debug_string.contains("Error"));
|
||||
assert!(debug_string.contains("inner"));
|
||||
assert!(debug_string.contains("span_trace"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multiple_error_types() {
|
||||
let errors = vec![
|
||||
Error::new(io::Error::new(io::ErrorKind::NotFound, "Not found")),
|
||||
Error::new(CustomTestError { message: "Custom".to_string() }),
|
||||
Error::new(AnotherTestError),
|
||||
Error::msg("String error"),
|
||||
];
|
||||
|
||||
assert!(errors[0].is::<io::Error>());
|
||||
assert!(errors[1].is::<CustomTestError>());
|
||||
assert!(errors[2].is::<AnotherTestError>());
|
||||
assert!(!errors[3].is::<io::Error>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_error_chain_compatibility() {
|
||||
// Test that our Error type works well with error chains
|
||||
let io_error = io::Error::new(io::ErrorKind::InvalidData, "Invalid data");
|
||||
let error = Error::new(io_error);
|
||||
|
||||
// Should be able to convert back to Result
|
||||
let result: Result<(), Error> = Err(error);
|
||||
assert!(result.is_err());
|
||||
|
||||
// Test the error from the result
|
||||
if let Err(err) = result {
|
||||
assert!(err.is::<io::Error>());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_result_type_alias() {
|
||||
// Test the Result type alias
|
||||
fn test_function() -> Result<String> {
|
||||
Ok("Success".to_string())
|
||||
}
|
||||
|
||||
fn test_function_with_error() -> Result<String> {
|
||||
Err(Error::msg("Test error"))
|
||||
}
|
||||
|
||||
let success_result = test_function();
|
||||
assert!(success_result.is_ok());
|
||||
assert_eq!(success_result.unwrap(), "Success");
|
||||
|
||||
let error_result = test_function_with_error();
|
||||
assert!(error_result.is_err());
|
||||
assert_eq!(error_result.unwrap_err().inner_string(), "Test error");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_error_with_empty_message() {
|
||||
let error = Error::msg("");
|
||||
assert_eq!(error.inner_string(), "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_error_with_unicode_message() {
|
||||
let unicode_message = "错误信息 🚨 Error message with émojis and ñon-ASCII";
|
||||
let error = Error::msg(unicode_message);
|
||||
assert_eq!(error.inner_string(), unicode_message);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_error_with_very_long_message() {
|
||||
let long_message = "A".repeat(10000);
|
||||
let error = Error::msg(&long_message);
|
||||
assert_eq!(error.inner_string(), long_message);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_span_trace_capture() {
|
||||
// Test that span trace is captured (though we can't easily test the content)
|
||||
let error = Error::msg("Span trace test");
|
||||
let display_string = format!("{}", error);
|
||||
|
||||
// The error should at least contain the message
|
||||
assert!(display_string.contains("Span trace test"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,7 +316,7 @@ mod tests {
|
||||
assert_eq!(latency.totals[0].n, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[test]
|
||||
fn test_last_minute_latency_forward_to_large_gap() {
|
||||
let mut latency = LastMinuteLatency::default();
|
||||
latency.last_sec = 100;
|
||||
@@ -493,7 +493,7 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[test]
|
||||
fn test_last_minute_latency_realistic_scenario() {
|
||||
let mut latency = LastMinuteLatency::default();
|
||||
let base_time = 1000u64;
|
||||
@@ -511,7 +511,7 @@ mod tests {
|
||||
latency.add_all(current_time, &acc_elem);
|
||||
}
|
||||
|
||||
// Count non-empty slots after filling the window
|
||||
// Count non-empty slots after filling the window
|
||||
let mut non_empty_count = 0;
|
||||
let mut total_n = 0;
|
||||
let mut total_sum = 0;
|
||||
@@ -571,7 +571,7 @@ mod tests {
|
||||
assert_eq!(latency.totals[0].n, cloned.totals[0].n);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[test]
|
||||
fn test_edge_case_max_values() {
|
||||
let mut elem = AccElem {
|
||||
total: u64::MAX - 50,
|
||||
@@ -612,4 +612,127 @@ mod tests {
|
||||
assert_eq!(elem.n, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_total_with_data() {
|
||||
let mut latency = LastMinuteLatency::default();
|
||||
|
||||
// Set a recent timestamp to avoid forward_to clearing data
|
||||
let current_time = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.expect("Time went backwards")
|
||||
.as_secs();
|
||||
latency.last_sec = current_time;
|
||||
|
||||
// Add data to multiple slots
|
||||
latency.totals[0] = AccElem { total: 10, size: 100, n: 1 };
|
||||
latency.totals[1] = AccElem { total: 20, size: 200, n: 2 };
|
||||
latency.totals[59] = AccElem { total: 30, size: 300, n: 3 };
|
||||
|
||||
let total = latency.get_total();
|
||||
|
||||
assert_eq!(total.total, 60);
|
||||
assert_eq!(total.size, 600);
|
||||
assert_eq!(total.n, 6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_window_index_calculation() {
|
||||
// Test that window index calculation works correctly
|
||||
let _latency = LastMinuteLatency::default();
|
||||
|
||||
let acc_elem = AccElem {
|
||||
total: 1,
|
||||
size: 1,
|
||||
n: 1,
|
||||
};
|
||||
|
||||
// Test various timestamps
|
||||
let test_cases = [
|
||||
(0, 0),
|
||||
(1, 1),
|
||||
(59, 59),
|
||||
(60, 0),
|
||||
(61, 1),
|
||||
(119, 59),
|
||||
(120, 0),
|
||||
];
|
||||
|
||||
for (timestamp, expected_idx) in test_cases {
|
||||
let mut test_latency = LastMinuteLatency::default();
|
||||
test_latency.add_all(timestamp, &acc_elem);
|
||||
|
||||
assert_eq!(test_latency.totals[expected_idx].n, 1,
|
||||
"Failed for timestamp {} (expected index {})", timestamp, expected_idx);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_concurrent_safety_simulation() {
|
||||
// Simulate concurrent access patterns
|
||||
let mut latency = LastMinuteLatency::default();
|
||||
|
||||
// Use current time to ensure data doesn't get cleared by get_total
|
||||
let current_time = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.expect("Time went backwards")
|
||||
.as_secs();
|
||||
|
||||
// Simulate rapid additions within a 60-second window
|
||||
for i in 0..1000 {
|
||||
let acc_elem = AccElem {
|
||||
total: (i % 10) + 1, // Ensure non-zero values
|
||||
size: (i % 100) + 1,
|
||||
n: 1,
|
||||
};
|
||||
// Keep all timestamps within the current minute window
|
||||
latency.add_all(current_time - (i % 60), &acc_elem);
|
||||
}
|
||||
|
||||
let total = latency.get_total();
|
||||
assert!(total.n > 0, "Total count should be greater than 0");
|
||||
assert!(total.total > 0, "Total time should be greater than 0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_acc_elem_debug_format() {
|
||||
let elem = AccElem {
|
||||
total: 123,
|
||||
size: 456,
|
||||
n: 789,
|
||||
};
|
||||
|
||||
let debug_str = format!("{:?}", elem);
|
||||
assert!(debug_str.contains("123"));
|
||||
assert!(debug_str.contains("456"));
|
||||
assert!(debug_str.contains("789"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_large_values() {
|
||||
let mut elem = AccElem::default();
|
||||
|
||||
// Test with large duration values
|
||||
let large_duration = Duration::from_secs(u64::MAX / 2);
|
||||
elem.add(&large_duration);
|
||||
|
||||
assert_eq!(elem.total, u64::MAX / 2);
|
||||
assert_eq!(elem.n, 1);
|
||||
|
||||
// Test average calculation with large values
|
||||
let avg = elem.avg();
|
||||
assert_eq!(avg, Duration::from_secs(u64::MAX / 2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zero_duration_handling() {
|
||||
let mut elem = AccElem::default();
|
||||
|
||||
let zero_duration = Duration::from_secs(0);
|
||||
elem.add(&zero_duration);
|
||||
|
||||
assert_eq!(elem.total, 0);
|
||||
assert_eq!(elem.n, 1);
|
||||
assert_eq!(elem.avg(), Duration::from_secs(0));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user