- Replace all Chinese comments with English equivalents in: - src/health_monitor.rs - src/lib.rs - tests/integration_test.rs - Add comprehensive README.md with: - Project overview and features - Architecture diagram - Installation and configuration guide - Data format specifications - Health monitoring documentation - Troubleshooting guide
149 lines
4.5 KiB
Rust
149 lines
4.5 KiB
Rust
use std::sync::atomic::{AtomicU32, Ordering};
|
|
use std::sync::Arc;
|
|
use std::time::Duration;
|
|
use tokio::time::sleep;
|
|
use network_monitor::retry::{RetryConfig, retry_with_config};
|
|
|
|
/// Test simulating network failure recovery
|
|
#[tokio::test]
|
|
async fn test_network_failure_recovery() {
|
|
// Simulate an operation that fails a few times then succeeds
|
|
let attempt_count = Arc::new(AtomicU32::new(0));
|
|
let max_failures = 3;
|
|
|
|
let config = RetryConfig {
|
|
max_attempts: 10,
|
|
initial_delay: Duration::from_millis(10),
|
|
max_delay: Duration::from_millis(100),
|
|
backoff_multiplier: 1.5,
|
|
jitter: false, // Disable jitter for more predictable testing
|
|
};
|
|
|
|
let attempt_count_clone = attempt_count.clone();
|
|
let result = retry_with_config(config, move || {
|
|
let attempt_count = attempt_count_clone.clone();
|
|
async move {
|
|
let current_attempt = attempt_count.fetch_add(1, Ordering::SeqCst) + 1;
|
|
|
|
if current_attempt <= max_failures {
|
|
// Simulate network error
|
|
Err(format!("Network error on attempt {}", current_attempt))
|
|
} else {
|
|
// Simulate successful recovery
|
|
Ok(format!("Success on attempt {}", current_attempt))
|
|
}
|
|
}
|
|
}).await;
|
|
|
|
assert!(result.is_ok());
|
|
assert_eq!(result.unwrap(), "Success on attempt 4");
|
|
assert_eq!(attempt_count.load(Ordering::SeqCst), 4);
|
|
}
|
|
|
|
/// Test connection timeout scenario
|
|
#[tokio::test]
|
|
async fn test_connection_timeout_scenario() {
|
|
let config = RetryConfig {
|
|
max_attempts: 3,
|
|
initial_delay: Duration::from_millis(5),
|
|
max_delay: Duration::from_millis(20),
|
|
backoff_multiplier: 2.0,
|
|
jitter: false,
|
|
};
|
|
|
|
let attempt_count = Arc::new(AtomicU32::new(0));
|
|
|
|
let attempt_count_clone = attempt_count.clone();
|
|
let result: Result<String, &str> = retry_with_config(config, move || {
|
|
let attempt_count = attempt_count_clone.clone();
|
|
async move {
|
|
attempt_count.fetch_add(1, Ordering::SeqCst);
|
|
|
|
// Simulate connection timeout
|
|
sleep(Duration::from_millis(1)).await;
|
|
Err("Connection timeout")
|
|
}
|
|
}).await;
|
|
|
|
assert!(result.is_err());
|
|
assert_eq!(attempt_count.load(Ordering::SeqCst), 3); // Should have attempted 3 times
|
|
}
|
|
|
|
/// Test fast recovery scenario
|
|
#[tokio::test]
|
|
async fn test_fast_recovery() {
|
|
let config = RetryConfig::fast();
|
|
|
|
let attempt_count = Arc::new(AtomicU32::new(0));
|
|
|
|
let attempt_count_clone = attempt_count.clone();
|
|
let result = retry_with_config(config, move || {
|
|
let attempt_count = attempt_count_clone.clone();
|
|
async move {
|
|
let current_attempt = attempt_count.fetch_add(1, Ordering::SeqCst) + 1;
|
|
|
|
if current_attempt == 1 {
|
|
Err("Temporary failure")
|
|
} else {
|
|
Ok("Quick recovery")
|
|
}
|
|
}
|
|
}).await;
|
|
|
|
assert!(result.is_ok());
|
|
assert_eq!(result.unwrap(), "Quick recovery");
|
|
assert_eq!(attempt_count.load(Ordering::SeqCst), 2);
|
|
}
|
|
|
|
/// Test slow retry scenario
|
|
#[tokio::test]
|
|
async fn test_slow_retry_scenario() {
|
|
let config = RetryConfig::slow();
|
|
|
|
let attempt_count = Arc::new(AtomicU32::new(0));
|
|
|
|
let attempt_count_clone = attempt_count.clone();
|
|
let result = retry_with_config(config, move || {
|
|
let attempt_count = attempt_count_clone.clone();
|
|
async move {
|
|
let current_attempt = attempt_count.fetch_add(1, Ordering::SeqCst) + 1;
|
|
|
|
if current_attempt <= 2 {
|
|
Err("Service unavailable")
|
|
} else {
|
|
Ok("Service restored")
|
|
}
|
|
}
|
|
}).await;
|
|
|
|
assert!(result.is_ok());
|
|
assert_eq!(result.unwrap(), "Service restored");
|
|
assert_eq!(attempt_count.load(Ordering::SeqCst), 3);
|
|
}
|
|
|
|
/// Test maximum retry limit
|
|
#[tokio::test]
|
|
async fn test_max_retry_limit() {
|
|
let config = RetryConfig {
|
|
max_attempts: 2,
|
|
initial_delay: Duration::from_millis(1),
|
|
max_delay: Duration::from_millis(5),
|
|
backoff_multiplier: 2.0,
|
|
jitter: false,
|
|
};
|
|
|
|
let attempt_count = Arc::new(AtomicU32::new(0));
|
|
|
|
let attempt_count_clone = attempt_count.clone();
|
|
let result = retry_with_config(config, move || {
|
|
let attempt_count = attempt_count_clone.clone();
|
|
async move {
|
|
attempt_count.fetch_add(1, Ordering::SeqCst);
|
|
Err::<String, &str>("Persistent failure")
|
|
}
|
|
}).await;
|
|
|
|
assert!(result.is_err());
|
|
assert_eq!(attempt_count.load(Ordering::SeqCst), 2);
|
|
}
|