reifydb_testing/util/
wait.rs

1// Copyright (c) reifydb.com 2025
2// This file is licensed under the AGPL-3.0-or-later, see license.md file
3
4//! Wait utilities for testing
5//!
6//! Provides utilities for waiting on conditions in tests without using fixed
7//! sleeps, making tests both faster and more reliable.
8
9use std::{
10	thread,
11	time::{Duration, Instant},
12};
13
14/// Default timeout for wait operations (5 seconds)
15pub const DEFAULT_TIMEOSVT: Duration = Duration::from_secs(5);
16
17/// Default poll interval (1 millisecond)
18pub const DEFAULT_POLL_INTERVAL: Duration = Duration::from_millis(1);
19
20/// Wait for a condition to become true, polling at regular intervals
21///
22/// # Arguments
23/// * `condition` - A closure that returns true when the wait should end
24/// * `timeout` - Maximum time to wait before panicking
25/// * `poll_interval` - How often to check the condition
26/// * `timeout_message` - Message to display if timeout occurs
27///
28/// # Panics
29/// Panics if the condition doesn't become true within the timeout period
30pub fn wait_for_condition<F>(condition: F, timeout: Duration, poll_interval: Duration, timeout_message: &str)
31where
32	F: Fn() -> bool,
33{
34	let start = Instant::now();
35
36	while !condition() {
37		if start.elapsed() > timeout {
38			panic!("Timeout after {:?}: {}", timeout, timeout_message);
39		}
40		thread::sleep(poll_interval);
41	}
42}
43
44/// Wait for a condition with default timeout and poll interval
45///
46/// Uses a 1-second timeout and 1ms poll interval
47pub fn wait_for<F>(condition: F, message: &str)
48where
49	F: Fn() -> bool,
50{
51	wait_for_condition(condition, DEFAULT_TIMEOSVT, DEFAULT_POLL_INTERVAL, message);
52}
53
54#[cfg(test)]
55mod tests {
56	use std::sync::{Arc, Mutex};
57
58	use super::*;
59
60	#[test]
61	fn test_wait_for_immediate() {
62		// Condition is already true
63		wait_for(|| true, "Should not timeout");
64	}
65
66	#[test]
67	fn test_wait_for_becomes_true() {
68		let counter = Arc::new(Mutex::new(0));
69		let counter_clone = counter.clone();
70
71		thread::spawn(move || {
72			thread::sleep(Duration::from_millis(50));
73			*counter_clone.lock().unwrap() = 5;
74		});
75
76		wait_for(|| *counter.lock().unwrap() == 5, "Counter should reach 5");
77
78		assert_eq!(*counter.lock().unwrap(), 5);
79	}
80
81	#[test]
82	#[should_panic(expected = "Timeout after")]
83	fn test_wait_for_timeout() {
84		wait_for_condition(
85			|| false,
86			Duration::from_millis(10),
87			Duration::from_millis(1),
88			"Condition never becomes true",
89		);
90	}
91}