Skip to main content

reifydb_testing/util/
wait.rs

1// SPDX-License-Identifier: AGPL-3.0-or-later
2// Copyright (c) 2026 ReifyDB
3
4use std::time::{Duration, Instant};
5
6use tokio::time::sleep;
7
8pub const DEFAULT_TIMEOSVT: Duration = Duration::from_secs(5);
9
10pub const DEFAULT_POLL_INTERVAL: Duration = Duration::from_millis(1);
11
12pub async fn wait_for_condition<F>(condition: F, timeout: Duration, poll_interval: Duration, timeout_message: &str)
13where
14	F: Fn() -> bool,
15{
16	#[allow(clippy::disallowed_methods)]
17	let start = Instant::now();
18	let mut poll_count = 0u64;
19
20	while !condition() {
21		if start.elapsed() > timeout {
22			println!(
23				"[DEBUG:await] TIMEOUT elapsed={:.1}s polls={poll_count} msg={timeout_message}",
24				start.elapsed().as_secs_f64()
25			);
26			panic!("Timeout after {:?}: {}", timeout, timeout_message);
27		}
28		poll_count += 1;
29		if poll_count.is_multiple_of(1000) {
30			println!(
31				"[DEBUG:await] poll #{poll_count} elapsed={:.1}s msg={timeout_message}",
32				start.elapsed().as_secs_f64()
33			);
34		}
35		sleep(poll_interval).await;
36	}
37	println!(
38		"[DEBUG:await] condition met after {poll_count} polls elapsed={:.3}s msg={timeout_message}",
39		start.elapsed().as_secs_f64()
40	);
41}
42
43pub async fn wait_for<F>(condition: F, message: &str)
44where
45	F: Fn() -> bool,
46{
47	wait_for_condition(condition, DEFAULT_TIMEOSVT, DEFAULT_POLL_INTERVAL, message).await;
48}
49
50#[cfg(test)]
51pub mod tests {
52	use std::{sync::Arc, thread};
53
54	use reifydb_runtime::sync::mutex::Mutex;
55
56	use super::*;
57
58	#[tokio::test]
59	async fn test_wait_for_immediate() {
60		// Condition is already true
61		wait_for(|| true, "Should not timeout").await;
62	}
63
64	#[tokio::test]
65	async fn test_wait_for_becomes_true() {
66		let counter = Arc::new(Mutex::new(0));
67		let counter_clone = counter.clone();
68
69		thread::spawn(move || {
70			thread::sleep(Duration::from_millis(50));
71			*counter_clone.lock() = 5;
72		});
73
74		wait_for(|| *counter.lock() == 5, "Counter should reach 5").await;
75
76		assert_eq!(*counter.lock(), 5);
77	}
78
79	#[tokio::test]
80	#[should_panic(expected = "Timeout after")]
81	async fn test_wait_for_timeout() {
82		wait_for_condition(
83			|| false,
84			Duration::from_millis(10),
85			Duration::from_millis(1),
86			"Condition never becomes true",
87		)
88		.await;
89	}
90}