Skip to main content

reifydb_runtime/context/clock/
mod.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 ReifyDB
3
4//! Platform-agnostic clock abstraction.
5//!
6//! Provides a `Clock` enum that can be either real system time or mock time for testing.
7//! The clock is shared across all threads within a runtime instance.
8//!
9//! - **Native**: Uses system time via the time module
10//! - **WASM**: Uses JavaScript's Date.now() via the time module
11
12#[cfg(reifydb_target = "native")]
13mod native;
14#[cfg(reifydb_target = "wasi")]
15mod wasi;
16#[cfg(reifydb_target = "wasm")]
17mod wasm;
18
19#[cfg(reifydb_target = "native")]
20pub use native::{Clock, Instant, MockClock};
21#[cfg(reifydb_target = "wasi")]
22pub use wasi::{Clock, Instant, MockClock};
23#[cfg(reifydb_target = "wasm")]
24pub use wasm::{Clock, Instant, MockClock};
25
26#[cfg(test)]
27mod tests {
28	use std::thread;
29
30	use super::*;
31
32	#[test]
33	fn test_real_clock() {
34		let clock = Clock::Real;
35		let t1 = clock.now_millis();
36		// Small busy loop to ensure time passes
37		let mut sum = 0;
38		for i in 0..10000 {
39			sum += i;
40		}
41		let t2 = clock.now_millis();
42		assert!(t2 >= t1, "Time should not go backwards");
43		let _ = sum;
44	}
45
46	#[test]
47	fn test_mock_clock_initial() {
48		let mock = MockClock::from_millis(1000);
49		let clock = Clock::Mock(mock);
50
51		assert_eq!(clock.now_millis(), 1000);
52		assert_eq!(clock.now_micros(), 1_000_000);
53		assert_eq!(clock.now_nanos(), 1_000_000_000);
54	}
55
56	#[test]
57	fn test_mock_clock_set() {
58		let mock = MockClock::from_millis(0);
59		mock.set_millis(5000);
60
61		assert_eq!(mock.now_millis(), 5000);
62
63		mock.set_micros(6_000_000);
64		assert_eq!(mock.now_millis(), 6000);
65	}
66
67	#[test]
68	fn test_mock_clock_advance() {
69		let mock = MockClock::from_millis(1000);
70		let clock = Clock::Mock(mock.clone());
71
72		assert_eq!(clock.now_millis(), 1000);
73
74		mock.advance_millis(500);
75		assert_eq!(clock.now_millis(), 1500);
76
77		mock.advance_micros(500_000);
78		assert_eq!(clock.now_millis(), 2000);
79
80		mock.advance_nanos(500_000_000);
81		assert_eq!(clock.now_millis(), 2500);
82	}
83
84	#[cfg(reifydb_target = "native")]
85	#[test]
86	fn test_mock_clock_thread_safe() {
87		let mock = MockClock::from_millis(1000);
88		let mock_clone = mock.clone();
89
90		let handle = thread::spawn(move || {
91			mock_clone.advance_millis(500);
92			mock_clone.now_millis()
93		});
94
95		let result = handle.join().unwrap();
96		assert_eq!(result, 1500);
97		assert_eq!(mock.now_millis(), 1500);
98	}
99
100	#[test]
101	fn test_clock_default() {
102		let clock = Clock::default();
103		match clock {
104			Clock::Real => {}
105			Clock::Mock(_) => panic!("Default should be Real"),
106		}
107	}
108
109	#[test]
110	fn test_nanosecond_precision() {
111		let mock = MockClock::new(1_234_567_890_123_456_789);
112		let clock = Clock::Mock(mock);
113
114		assert_eq!(clock.now_nanos(), 1_234_567_890_123_456_789);
115		assert_eq!(clock.now_micros(), 1_234_567_890_123_456);
116		assert_eq!(clock.now_millis(), 1_234_567_890_123);
117		assert_eq!(clock.now_secs(), 1_234_567_890);
118	}
119}