holochain/test_utils/
wait_for.rs1#![allow(missing_docs)]
2use std::time::Duration;
3
4#[macro_export]
5macro_rules! wait_for {
6 ($wait:expr, $test:expr, $check:expr, $assert:expr) => {{
7 let mut w = $wait;
8 let assert = $assert;
9 loop {
10 let o = $test;
11 let check = $check;
12 if !w.wait_any().await || check(&o) {
13 assert(o);
14 break;
15 }
16 }
17 }};
18}
19
20#[macro_export]
21macro_rules! wait_for_10s {
22 ($test:expr, $check:expr, $assert:expr) => {{
23 let wait_for = $crate::test_utils::WaitFor::ten_s();
24 $crate::wait_for!(wait_for, $test, $check, $assert)
25 }};
26}
27
28#[macro_export]
29macro_rules! wait_for_1m {
30 ($test:expr, $check:expr, $assert:expr) => {
31 let wait_for = $crate::test_utils::WaitFor::one_m();
32 $crate::wait_for!(wait_for, $test, $check, $assert)
33 };
34}
35
36#[macro_export]
37macro_rules! assert_retry {
38 ($wait:expr, $test:expr $(, $reason:literal)?) => {
39 $crate::wait_for!($wait, $test, |x: &bool| *x, |x: bool| assert!(x $(, $reason)?))
40 };
41}
42
43#[macro_export]
44macro_rules! assert_eq_retry {
45 ($wait:expr, $test:expr, $check:expr $(, $reason:literal)?) => {
46 $crate::wait_for!($wait, $test, |x| x == &$check, |x| assert_eq!(x, $check $(, $reason)?))
47 };
48}
49
50#[macro_export]
51macro_rules! assert_retry_10s {
52 ($test:expr $(, $reason:literal)? $(,)?) => {
53 let wait_for = $crate::test_utils::WaitFor::ten_s();
54 $crate::assert_retry!(wait_for, $test $(, $reason:literal)?)
55 };
56}
57
58#[macro_export]
59macro_rules! assert_eq_retry_10s {
60 ($test:expr, $check:expr $(, $reason:literal)? $(,)?) => {
61 let wait_for = $crate::test_utils::WaitFor::ten_s();
62 $crate::assert_eq_retry!(wait_for, $test, $check $(, $reason:literal)?)
63 };
64}
65
66#[macro_export]
67macro_rules! assert_retry_1m {
68 ($test:expr $(, $reason:literal)? $(,)?) => {
69 let wait_for = $crate::test_utils::WaitFor::one_m();
70 $crate::assert_retry!(wait_for, $test $(, $reason:literal)?)
71 };
72}
73
74#[macro_export]
75macro_rules! assert_eq_retry_1m {
76 ($test:expr, $check:expr $(, $reason:literal)? $(,)?) => {
77 let wait_for = $crate::test_utils::WaitFor::one_m();
78 $crate::assert_eq_retry!(wait_for, $test, $check $(, $reason:literal)?)
79 };
80}
81
82#[macro_export]
83macro_rules! assert_eq_retry_5m {
84 ($test:expr, $check:expr $(, $reason:literal)? $(,)?) => {
85 let wait_for = $crate::test_utils::WaitFor::five_m();
86 $crate::assert_eq_retry!(wait_for, $test, $check $(, $reason:literal)?)
87 };
88}
89
90#[derive(Debug, Clone)]
95pub struct WaitFor {
96 num_attempts: u32,
97 attempt: u32,
98 delay: Duration,
99}
100
101impl WaitFor {
102 pub fn new(total: Duration, num_attempts: u32) -> Self {
104 Self {
105 num_attempts,
106 attempt: 0,
107 delay: total / num_attempts,
108 }
109 }
110
111 pub fn one_s() -> Self {
113 Self::new(std::time::Duration::from_secs(1), 10)
114 }
115
116 pub fn ten_s() -> Self {
118 Self::new(std::time::Duration::from_secs(10), 100)
119 }
120
121 pub fn one_m() -> Self {
123 Self::new(std::time::Duration::from_secs(60), 120)
124 }
125
126 pub fn five_m() -> Self {
128 Self::new(std::time::Duration::from_secs(5 * 60), 5 * 60)
129 }
130
131 #[cfg_attr(feature = "instrument", tracing::instrument(skip(self)))]
134 pub async fn wait_any(&mut self) -> bool {
135 if self.attempt >= self.num_attempts {
136 return false;
137 }
138 self.attempt += 1;
139 tracing::debug!(attempt = ?self.attempt, out_of = ?self.num_attempts, delaying_for = ?self.delay);
140 tokio::time::sleep(self.delay).await;
141 true
142 }
143}
144
145#[tokio::test]
146async fn wait_for_tests() {
147 wait_for!(WaitFor::one_s(), true, |&x| x, |x: bool| assert!(x));
148 wait_for!(WaitFor::one_s(), false, |&x| x, |x: bool| assert!(!x));
149}