use core::cell::{Cell, RefCell};
use core::future::{Future, ready};
use core::pin::Pin;
use core::task::{Context, Poll, Waker};
use std::sync::Arc;
use relentless::{AsyncRetryExt, RetryError, RetryPolicy, stop};
const SUCCESS_VALUE: i32 = 42;
const ERROR_VALUE: &str = "fail";
const MAX_ATTEMPTS: u32 = 3;
fn noop_waker() -> Waker {
struct NoopWake;
impl std::task::Wake for NoopWake {
fn wake(self: Arc<Self>) {}
}
Waker::from(Arc::new(NoopWake))
}
fn block_on<F: Future>(future: F) -> F::Output {
let mut future = Box::pin(future);
let waker = noop_waker();
let mut cx = Context::from_waker(&waker);
loop {
match Future::poll(Pin::as_mut(&mut future), &mut cx) {
Poll::Ready(output) => return output,
Poll::Pending => std::thread::yield_now(),
}
}
}
#[test]
fn policy_async_retry_remains_available_without_alloc() {
let attempts = Cell::new(0_u32);
let events: RefCell<Vec<char>> = RefCell::new(Vec::new());
let policy = RetryPolicy::new().stop(stop::attempts(MAX_ATTEMPTS));
let result: Result<i32, RetryError<i32, &str>> = block_on(
policy
.retry_async(|_| {
attempts.set(attempts.get().saturating_add(1));
if attempts.get() < MAX_ATTEMPTS {
ready(Err(ERROR_VALUE))
} else {
ready(Ok(SUCCESS_VALUE))
}
})
.before_attempt(|_state| events.borrow_mut().push('b'))
.before_attempt(|_state| events.borrow_mut().push('B'))
.after_attempt(|_state| events.borrow_mut().push('a'))
.on_exit(|_state| events.borrow_mut().push('x'))
.sleep(|_dur| ready(()))
.call(),
);
assert_eq!(result, Ok(SUCCESS_VALUE));
assert_eq!(attempts.get(), MAX_ATTEMPTS);
assert_eq!(
*events.borrow(),
vec!['b', 'B', 'a', 'b', 'B', 'a', 'b', 'B', 'a', 'x']
);
}
#[test]
fn async_retry_ext_remains_available_without_alloc() {
let attempts = Cell::new(0_u32);
let events: RefCell<Vec<char>> = RefCell::new(Vec::new());
let result: Result<i32, RetryError<i32, &str>> = block_on(
(|| {
attempts.set(attempts.get().saturating_add(1));
if attempts.get() < MAX_ATTEMPTS {
ready(Err(ERROR_VALUE))
} else {
ready(Ok(SUCCESS_VALUE))
}
})
.retry_async()
.stop(stop::attempts(MAX_ATTEMPTS))
.before_attempt(|_state| events.borrow_mut().push('b'))
.after_attempt(|_state| events.borrow_mut().push('a'))
.on_exit(|_state| events.borrow_mut().push('x'))
.sleep(|_dur| ready(()))
.call(),
);
assert_eq!(result, Ok(SUCCESS_VALUE));
assert_eq!(attempts.get(), MAX_ATTEMPTS);
assert_eq!(*events.borrow(), vec!['b', 'a', 'b', 'a', 'b', 'a', 'x']);
}