mirror of
https://github.com/rustfs/rustfs.git
synced 2026-07-26 16:28:15 +00:00
Merge pull request #427 from rustfs/feat/improve-common-module-tests
feat: add comprehensive test coverage for common module
This commit is contained in:
@@ -89,3 +89,247 @@ 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());
|
||||
|
||||
let err = result.unwrap_err();
|
||||
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"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,3 +110,450 @@ impl LastMinuteLatency {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_acc_elem_default() {
|
||||
let elem = AccElem::default();
|
||||
assert_eq!(elem.total, 0);
|
||||
assert_eq!(elem.size, 0);
|
||||
assert_eq!(elem.n, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_acc_elem_add() {
|
||||
let mut elem = AccElem::default();
|
||||
|
||||
// Add first duration
|
||||
let dur1 = Duration::from_secs(5);
|
||||
elem.add(&dur1);
|
||||
assert_eq!(elem.total, 5);
|
||||
assert_eq!(elem.n, 1);
|
||||
assert_eq!(elem.size, 0); // size is not modified by add
|
||||
|
||||
// Add second duration
|
||||
let dur2 = Duration::from_secs(10);
|
||||
elem.add(&dur2);
|
||||
assert_eq!(elem.total, 15);
|
||||
assert_eq!(elem.n, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_acc_elem_add_with_subsecond_duration() {
|
||||
let mut elem = AccElem::default();
|
||||
|
||||
// Add duration less than 1 second (should be truncated to 0)
|
||||
let dur = Duration::from_millis(500);
|
||||
elem.add(&dur);
|
||||
assert_eq!(elem.total, 0);
|
||||
assert_eq!(elem.n, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_acc_elem_merge() {
|
||||
let mut elem1 = AccElem {
|
||||
total: 10,
|
||||
size: 100,
|
||||
n: 2,
|
||||
};
|
||||
|
||||
let elem2 = AccElem {
|
||||
total: 20,
|
||||
size: 200,
|
||||
n: 3,
|
||||
};
|
||||
|
||||
elem1.merge(&elem2);
|
||||
assert_eq!(elem1.total, 30);
|
||||
assert_eq!(elem1.size, 300);
|
||||
assert_eq!(elem1.n, 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_acc_elem_merge_with_empty() {
|
||||
let mut elem = AccElem {
|
||||
total: 10,
|
||||
size: 100,
|
||||
n: 2,
|
||||
};
|
||||
|
||||
let empty_elem = AccElem::default();
|
||||
elem.merge(&empty_elem);
|
||||
|
||||
assert_eq!(elem.total, 10);
|
||||
assert_eq!(elem.size, 100);
|
||||
assert_eq!(elem.n, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_acc_elem_avg() {
|
||||
// Test with valid data
|
||||
let elem = AccElem {
|
||||
total: 15,
|
||||
size: 0,
|
||||
n: 3,
|
||||
};
|
||||
assert_eq!(elem.avg(), Duration::from_secs(5));
|
||||
|
||||
// Test with zero count
|
||||
let elem_zero_n = AccElem {
|
||||
total: 10,
|
||||
size: 0,
|
||||
n: 0,
|
||||
};
|
||||
assert_eq!(elem_zero_n.avg(), Duration::from_secs(0));
|
||||
|
||||
// Test with zero total
|
||||
let elem_zero_total = AccElem {
|
||||
total: 0,
|
||||
size: 0,
|
||||
n: 5,
|
||||
};
|
||||
assert_eq!(elem_zero_total.avg(), Duration::from_secs(0));
|
||||
|
||||
// Test with both zero
|
||||
let elem_both_zero = AccElem::default();
|
||||
assert_eq!(elem_both_zero.avg(), Duration::from_secs(0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_acc_elem_avg_with_single_element() {
|
||||
let elem = AccElem {
|
||||
total: 7,
|
||||
size: 0,
|
||||
n: 1,
|
||||
};
|
||||
assert_eq!(elem.avg(), Duration::from_secs(7));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_last_minute_latency_default() {
|
||||
let latency = LastMinuteLatency::default();
|
||||
assert_eq!(latency.totals.len(), 60);
|
||||
assert_eq!(latency.last_sec, 0);
|
||||
|
||||
// All elements should be default
|
||||
for elem in &latency.totals {
|
||||
assert_eq!(elem.total, 0);
|
||||
assert_eq!(elem.size, 0);
|
||||
assert_eq!(elem.n, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_last_minute_latency_clone() {
|
||||
let mut latency = LastMinuteLatency::default();
|
||||
latency.last_sec = 12345;
|
||||
latency.totals[0].total = 100;
|
||||
|
||||
let cloned = latency.clone();
|
||||
assert_eq!(cloned.last_sec, 12345);
|
||||
assert_eq!(cloned.totals[0].total, 100);
|
||||
assert_eq!(cloned.totals.len(), 60);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_forward_to_same_time() {
|
||||
let mut latency = LastMinuteLatency::default();
|
||||
latency.last_sec = 100;
|
||||
|
||||
// Forward to same time should not change anything
|
||||
latency.forward_to(100);
|
||||
assert_eq!(latency.last_sec, 100);
|
||||
|
||||
// Forward to earlier time should not change anything
|
||||
latency.forward_to(99);
|
||||
assert_eq!(latency.last_sec, 100);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_forward_to_large_gap() {
|
||||
let mut latency = LastMinuteLatency::default();
|
||||
latency.last_sec = 100;
|
||||
latency.totals[0].total = 999; // Set some data
|
||||
|
||||
// Forward by more than 60 seconds should reset all totals
|
||||
latency.forward_to(200);
|
||||
assert_eq!(latency.last_sec, 100); // last_sec is not updated in this case
|
||||
|
||||
// All totals should be reset
|
||||
for elem in &latency.totals {
|
||||
assert_eq!(elem.total, 0);
|
||||
assert_eq!(elem.size, 0);
|
||||
assert_eq!(elem.n, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_forward_to_small_gap() {
|
||||
let mut latency = LastMinuteLatency::default();
|
||||
latency.last_sec = 100;
|
||||
latency.totals[1].total = 999; // Set some data at index 1
|
||||
|
||||
// Forward by 2 seconds
|
||||
latency.forward_to(102);
|
||||
assert_eq!(latency.last_sec, 102);
|
||||
|
||||
// Index 1 should still have data
|
||||
assert_eq!(latency.totals[1].total, 999);
|
||||
|
||||
// Indices that were cleared should be zero
|
||||
assert_eq!(latency.totals[(101 % 60) as usize].total, 0);
|
||||
assert_eq!(latency.totals[(102 % 60) as usize].total, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_add_all() {
|
||||
let mut latency = LastMinuteLatency::default();
|
||||
let acc_elem = AccElem {
|
||||
total: 50,
|
||||
size: 1000,
|
||||
n: 5,
|
||||
};
|
||||
|
||||
let test_sec = 12345;
|
||||
latency.add_all(test_sec, &acc_elem);
|
||||
|
||||
assert_eq!(latency.last_sec, test_sec);
|
||||
let win_idx = (test_sec % 60) as usize;
|
||||
assert_eq!(latency.totals[win_idx].total, 50);
|
||||
assert_eq!(latency.totals[win_idx].size, 1000);
|
||||
assert_eq!(latency.totals[win_idx].n, 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_add_all_multiple_times() {
|
||||
let mut latency = LastMinuteLatency::default();
|
||||
|
||||
let acc_elem1 = AccElem {
|
||||
total: 10,
|
||||
size: 100,
|
||||
n: 1,
|
||||
};
|
||||
|
||||
let acc_elem2 = AccElem {
|
||||
total: 20,
|
||||
size: 200,
|
||||
n: 2,
|
||||
};
|
||||
|
||||
let test_sec = 12345;
|
||||
latency.add_all(test_sec, &acc_elem1);
|
||||
latency.add_all(test_sec, &acc_elem2);
|
||||
|
||||
let win_idx = (test_sec % 60) as usize;
|
||||
assert_eq!(latency.totals[win_idx].total, 30);
|
||||
assert_eq!(latency.totals[win_idx].size, 300);
|
||||
assert_eq!(latency.totals[win_idx].n, 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_merge_with_same_last_sec() {
|
||||
let mut latency1 = LastMinuteLatency::default();
|
||||
let mut latency2 = LastMinuteLatency::default();
|
||||
|
||||
latency1.last_sec = 100;
|
||||
latency2.last_sec = 100;
|
||||
|
||||
latency1.totals[0].total = 10;
|
||||
latency1.totals[0].n = 1;
|
||||
|
||||
latency2.totals[0].total = 20;
|
||||
latency2.totals[0].n = 2;
|
||||
|
||||
let merged = latency1.merge(&mut latency2);
|
||||
|
||||
assert_eq!(merged.last_sec, 100);
|
||||
assert_eq!(merged.totals[0].total, 30);
|
||||
assert_eq!(merged.totals[0].n, 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_merge_with_different_last_sec() {
|
||||
let mut latency1 = LastMinuteLatency::default();
|
||||
let mut latency2 = LastMinuteLatency::default();
|
||||
|
||||
latency1.last_sec = 100;
|
||||
latency2.last_sec = 105;
|
||||
|
||||
latency1.totals[0].total = 10;
|
||||
latency2.totals[5].total = 20;
|
||||
|
||||
let merged = latency1.merge(&mut latency2);
|
||||
|
||||
// Should use the later timestamp
|
||||
assert_eq!(merged.last_sec, 105);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_merge_all_slots() {
|
||||
let mut latency1 = LastMinuteLatency::default();
|
||||
let mut latency2 = LastMinuteLatency::default();
|
||||
|
||||
// Fill all slots with different values
|
||||
for i in 0..60 {
|
||||
latency1.totals[i].total = i as u64;
|
||||
latency1.totals[i].n = 1;
|
||||
|
||||
latency2.totals[i].total = (i * 2) as u64;
|
||||
latency2.totals[i].n = 2;
|
||||
}
|
||||
|
||||
let merged = latency1.merge(&mut latency2);
|
||||
|
||||
for i in 0..60 {
|
||||
assert_eq!(merged.totals[i].total, (i + i * 2) as u64);
|
||||
assert_eq!(merged.totals[i].n, 3);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_total_empty() {
|
||||
let mut latency = LastMinuteLatency::default();
|
||||
let total = latency.get_total();
|
||||
|
||||
assert_eq!(total.total, 0);
|
||||
assert_eq!(total.size, 0);
|
||||
assert_eq!(total.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 mut 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_edge_case_boundary_conditions() {
|
||||
let mut latency = LastMinuteLatency::default();
|
||||
|
||||
// Test boundary at 60 seconds
|
||||
latency.last_sec = 59;
|
||||
latency.forward_to(119); // Exactly 60 seconds later
|
||||
|
||||
// Should reset all totals
|
||||
for elem in &latency.totals {
|
||||
assert_eq!(elem.total, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[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