Skip to main content

reifydb_runtime/clock/
mod.rs

1// SPDX-License-Identifier: AGPL-3.0-or-later
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 = "wasm")]
15mod wasm;
16
17#[cfg(reifydb_target = "native")]
18pub use native::{Clock, Instant, MockClock};
19#[cfg(reifydb_target = "wasm")]
20pub use wasm::{Clock, Instant, MockClock};
21
22#[cfg(test)]
23mod tests {
24	use super::*;
25
26	#[test]
27	fn test_real_clock() {
28		let clock = Clock::Real;
29		let t1 = clock.now_millis();
30		// Small busy loop to ensure time passes
31		let mut sum = 0;
32		for i in 0..10000 {
33			sum += i;
34		}
35		let t2 = clock.now_millis();
36		assert!(t2 >= t1, "Time should not go backwards");
37		let _ = sum;
38	}
39
40	#[test]
41	fn test_mock_clock_initial() {
42		let mock = MockClock::from_millis(1000);
43		let clock = Clock::Mock(mock);
44
45		assert_eq!(clock.now_millis(), 1000);
46		assert_eq!(clock.now_micros(), 1_000_000);
47		assert_eq!(clock.now_nanos(), 1_000_000_000);
48	}
49
50	#[test]
51	fn test_mock_clock_set() {
52		let mock = MockClock::from_millis(0);
53		mock.set_millis(5000);
54
55		assert_eq!(mock.now_millis(), 5000);
56
57		mock.set_micros(6_000_000);
58		assert_eq!(mock.now_millis(), 6000);
59	}
60
61	#[test]
62	fn test_mock_clock_advance() {
63		let mock = MockClock::from_millis(1000);
64		let clock = Clock::Mock(mock.clone());
65
66		assert_eq!(clock.now_millis(), 1000);
67
68		mock.advance_millis(500);
69		assert_eq!(clock.now_millis(), 1500);
70
71		mock.advance_micros(500_000);
72		assert_eq!(clock.now_millis(), 2000);
73
74		mock.advance_nanos(500_000_000);
75		assert_eq!(clock.now_millis(), 2500);
76	}
77
78	#[cfg(reifydb_target = "native")]
79	#[test]
80	fn test_mock_clock_thread_safe() {
81		use std::thread;
82
83		let mock = MockClock::from_millis(1000);
84		let mock_clone = mock.clone();
85
86		let handle = thread::spawn(move || {
87			mock_clone.advance_millis(500);
88			mock_clone.now_millis()
89		});
90
91		let result = handle.join().unwrap();
92		assert_eq!(result, 1500);
93		assert_eq!(mock.now_millis(), 1500);
94	}
95
96	#[test]
97	fn test_clock_default() {
98		let clock = Clock::default();
99		match clock {
100			Clock::Real => {}
101			Clock::Mock(_) => panic!("Default should be Real"),
102		}
103	}
104
105	#[test]
106	fn test_nanosecond_precision() {
107		let mock = MockClock::new(1_234_567_890_123_456_789);
108		let clock = Clock::Mock(mock);
109
110		assert_eq!(clock.now_nanos(), 1_234_567_890_123_456_789);
111		assert_eq!(clock.now_micros(), 1_234_567_890_123_456);
112		assert_eq!(clock.now_millis(), 1_234_567_890_123);
113		assert_eq!(clock.now_secs(), 1_234_567_890);
114	}
115}