resolve: merge conflicts in last_minute.rs tests

This commit is contained in:
overtrue
2025-05-28 14:48:53 +08:00
49 changed files with 7719 additions and 249 deletions
+246
View File
@@ -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"));
}
}
+127 -4
View File
@@ -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));
}
}