tracing_throttle/infrastructure/
clock.rs

1//! Clock adapters for time operations.
2//!
3//! Provides concrete implementations of the Clock port defined in the
4//! application layer, enabling both production (SystemClock) and test
5//! (MockClock) scenarios.
6
7use crate::application::ports::Clock;
8use std::time::Instant;
9
10/// System clock implementation using `Instant::now()`.
11#[derive(Debug, Clone, Copy, Default)]
12pub struct SystemClock;
13
14impl SystemClock {
15    /// Create a new system clock.
16    pub fn new() -> Self {
17        Self
18    }
19}
20
21impl Clock for SystemClock {
22    fn now(&self) -> Instant {
23        Instant::now()
24    }
25}
26
27/// Mock clock for testing.
28///
29/// Allows tests to control time progression explicitly.
30#[cfg(test)]
31#[derive(Debug, Clone)]
32pub struct MockClock {
33    current_time: std::sync::Arc<std::sync::Mutex<Instant>>,
34}
35
36#[cfg(test)]
37impl MockClock {
38    /// Create a mock clock starting at a specific instant.
39    pub fn new(start: Instant) -> Self {
40        Self {
41            current_time: std::sync::Arc::new(std::sync::Mutex::new(start)),
42        }
43    }
44
45    /// Advance the clock by a duration.
46    pub fn advance(&self, duration: std::time::Duration) {
47        let mut time = self.current_time.lock().unwrap();
48        *time += duration;
49    }
50
51    /// Set the clock to a specific instant.
52    pub fn set(&self, instant: Instant) {
53        let mut time = self.current_time.lock().unwrap();
54        *time = instant;
55    }
56}
57
58#[cfg(test)]
59impl Clock for MockClock {
60    fn now(&self) -> Instant {
61        *self.current_time.lock().unwrap()
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68    use std::time::Duration;
69
70    #[test]
71    fn test_system_clock() {
72        let clock = SystemClock::new();
73        let t1 = clock.now();
74        std::thread::sleep(Duration::from_millis(10));
75        let t2 = clock.now();
76
77        assert!(t2 > t1);
78    }
79
80    #[test]
81    fn test_mock_clock() {
82        let start = Instant::now();
83        let clock = MockClock::new(start);
84
85        assert_eq!(clock.now(), start);
86
87        clock.advance(Duration::from_secs(10));
88        assert_eq!(clock.now(), start + Duration::from_secs(10));
89
90        let new_time = start + Duration::from_secs(100);
91        clock.set(new_time);
92        assert_eq!(clock.now(), new_time);
93    }
94}