Skip to content

Commit e7fa784

Browse files
committed
Add Retry and RetryPolicy tests
1 parent e2f29a4 commit e7fa784

File tree

1 file changed

+98
-0
lines changed

1 file changed

+98
-0
lines changed

tests/retry_tests.rs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
#[cfg(test)]
2+
mod retry_tests {
3+
use std::io;
4+
use std::sync::atomic::{AtomicU32, Ordering};
5+
use std::sync::Arc;
6+
use std::time::Duration;
7+
8+
use vss_client::error::VssError;
9+
use vss_client::util::retry::{retry, ExponentialBackoffRetryPolicy, RetryPolicy};
10+
11+
#[tokio::test]
12+
async fn test_async_retry() {
13+
let base_delay = Duration::from_millis(10);
14+
let max_attempts = 3;
15+
let max_total_delay = Duration::from_secs(60);
16+
let max_jitter = Duration::from_millis(5);
17+
18+
let exponential_backoff_jitter_policy = ExponentialBackoffRetryPolicy::new(base_delay)
19+
.skip_retry_on_error(|e| matches!(e, VssError::InvalidRequestError(..)))
20+
.with_max_attempts(max_attempts)
21+
.with_max_total_delay(max_total_delay)
22+
.with_max_jitter(max_jitter);
23+
24+
let mut call_count = Arc::new(AtomicU32::new(0));
25+
let count = call_count.clone();
26+
let async_function = move || {
27+
let count = count.clone();
28+
async move {
29+
let attempts_made = count.fetch_add(1, Ordering::SeqCst);
30+
if attempts_made < max_attempts - 1 {
31+
return Err(VssError::InternalServerError("Failure".to_string()));
32+
}
33+
tokio::time::sleep(Duration::from_millis(100)).await;
34+
Ok(42)
35+
}
36+
};
37+
38+
let result = retry(async_function, &exponential_backoff_jitter_policy).await;
39+
assert_eq!(result.ok(), Some(42));
40+
assert_eq!(call_count.load(Ordering::SeqCst), max_attempts);
41+
42+
call_count = Arc::new(AtomicU32::new(0));
43+
let count = call_count.clone();
44+
let failing_async_function = move || {
45+
let count = count.clone();
46+
async move {
47+
count.fetch_add(1, Ordering::SeqCst);
48+
tokio::time::sleep(Duration::from_millis(100)).await;
49+
Err::<(), VssError>(VssError::InternalServerError("Failed".to_string()))
50+
}
51+
};
52+
53+
let failed_result = retry(failing_async_function, &exponential_backoff_jitter_policy).await;
54+
assert!(failed_result.is_err());
55+
assert_eq!(call_count.load(Ordering::SeqCst), 3);
56+
}
57+
58+
#[tokio::test]
59+
async fn test_retry_on_all_errors() {
60+
let retry_policy = ExponentialBackoffRetryPolicy::new(Duration::from_millis(10)).with_max_attempts(3);
61+
62+
let call_count = Arc::new(AtomicU32::new(0));
63+
let count = call_count.clone();
64+
let failing_async_function = move || {
65+
let count = count.clone();
66+
async move {
67+
count.fetch_add(1, Ordering::SeqCst);
68+
tokio::time::sleep(Duration::from_millis(100)).await;
69+
Err::<(), io::Error>(io::Error::new(io::ErrorKind::InvalidData, "Failure"))
70+
}
71+
};
72+
73+
let failed_result = retry(failing_async_function, &retry_policy).await;
74+
assert!(failed_result.is_err());
75+
assert_eq!(call_count.load(Ordering::SeqCst), 3);
76+
}
77+
78+
#[tokio::test]
79+
async fn test_retry_capped_by_max_total_delay() {
80+
let retry_policy = ExponentialBackoffRetryPolicy::new(Duration::from_millis(100))
81+
.with_max_total_delay(Duration::from_millis(350));
82+
83+
let call_count = Arc::new(AtomicU32::new(0));
84+
let count = call_count.clone();
85+
let failing_async_function = move || {
86+
let count = count.clone();
87+
async move {
88+
count.fetch_add(1, Ordering::SeqCst);
89+
tokio::time::sleep(Duration::from_millis(100)).await;
90+
Err::<(), VssError>(VssError::InternalServerError("Failed".to_string()))
91+
}
92+
};
93+
94+
let failed_result = retry(failing_async_function, &retry_policy).await;
95+
assert!(failed_result.is_err());
96+
assert_eq!(call_count.load(Ordering::SeqCst), 2);
97+
}
98+
}

0 commit comments

Comments
 (0)