polkadot_node_clock/
mock.rs1use crate::{BoxedDelay, Clock};
31use futures::channel::oneshot;
32use std::{
33 sync::{Arc, Mutex},
34 time::{Duration, Instant},
35};
36
37#[derive(Clone, Debug, Default)]
42pub struct MockClock {
43 inner: Arc<Mutex<MockClockInner>>,
44}
45
46impl MockClock {
47 pub fn advance(&self, dur: Duration) {
49 let new_now = {
50 let mut inner = self.inner.lock().expect("MockClock mutex poisoned");
51 inner.now += dur;
52 inner.wall_clock_ms = inner.wall_clock_ms.saturating_add(dur.as_millis());
53 inner.now
54 };
55 self.inner.lock().expect("MockClock mutex poisoned").wakeup_up_to(new_now);
56 }
57
58 pub fn advance_secs(&self, secs: u64) {
60 self.advance(Duration::from_secs(secs));
61 }
62
63 pub fn advance_to_next_wakeup(&self) -> Option<Duration> {
66 let next = self.inner.lock().expect("MockClock mutex poisoned").next_wakeup()?;
67 let now = self.inner.lock().expect("MockClock mutex poisoned").now;
68 let dur = next.saturating_duration_since(now);
69 self.advance(dur);
70 Some(dur)
71 }
72
73 pub fn next_wakeup_in(&self) -> Option<Duration> {
76 let inner = self.inner.lock().expect("MockClock mutex poisoned");
77 let next = inner.next_wakeup()?;
78 Some(next.saturating_duration_since(inner.now))
79 }
80}
81
82impl Clock for MockClock {
83 fn now(&self) -> Instant {
84 self.inner.lock().expect("MockClock mutex poisoned").now
85 }
86
87 fn delay(&self, dur: Duration) -> BoxedDelay {
88 let deadline = {
89 let inner = self.inner.lock().expect("MockClock mutex poisoned");
90 inner.now + dur
91 };
92 let rx = self.inner.lock().expect("MockClock mutex poisoned").register_wakeup(deadline);
93
94 Box::pin(async move {
95 let _ = rx.await;
99 })
100 }
101
102 fn duration_since_epoch(&self) -> Duration {
103 Duration::from_millis(
104 self.inner.lock().expect("MockClock mutex poisoned").wall_clock_ms as u64,
105 )
106 }
107}
108
109#[derive(Debug)]
110struct MockClockInner {
111 now: Instant,
112 wall_clock_ms: u128,
113 wakeups: Vec<(Instant, oneshot::Sender<()>)>,
115}
116
117impl Default for MockClockInner {
118 fn default() -> Self {
119 Self { now: Instant::now(), wall_clock_ms: 0, wakeups: Vec::new() }
120 }
121}
122
123impl MockClockInner {
124 fn wakeup_up_to(&mut self, up_to: Instant) {
126 let drain_up_to = self.wakeups.partition_point(|w| w.0 <= up_to);
127 for (_, wakeup) in self.wakeups.drain(..drain_up_to) {
128 let _ = wakeup.send(());
129 }
130 }
131
132 fn next_wakeup(&self) -> Option<Instant> {
134 self.wakeups.first().map(|w| w.0)
135 }
136
137 fn register_wakeup(&mut self, deadline: Instant) -> oneshot::Receiver<()> {
139 let (tx, rx) = oneshot::channel();
140 let pos = self.wakeups.partition_point(|w| w.0 <= deadline);
141 self.wakeups.insert(pos, (deadline, tx));
142 self.wakeup_up_to(self.now);
144 rx
145 }
146}
147
148#[cfg(test)]
149mod tests {
150 use super::*;
151 use futures::FutureExt;
152
153 #[test]
154 fn now_advances() {
155 let clock = MockClock::default();
156 let start = clock.now();
157 clock.advance(Duration::from_secs(1));
158 assert_eq!(clock.now(), start + Duration::from_secs(1));
159 }
160
161 #[test]
162 fn duration_since_epoch_advances() {
163 let clock = MockClock::default();
164 assert_eq!(clock.duration_since_epoch().as_millis(), 0);
165 clock.advance(Duration::from_millis(123));
166 assert_eq!(clock.duration_since_epoch().as_millis(), 123);
167 clock.advance_secs(1);
168 assert_eq!(clock.duration_since_epoch().as_millis(), 1_123);
169 }
170
171 #[tokio::test]
172 async fn delay_resolves_on_advance() {
173 let clock = Arc::new(MockClock::default());
174 let mut delay = clock.delay(Duration::from_millis(100));
175 assert!((&mut delay).now_or_never().is_none());
177 clock.advance(Duration::from_millis(50));
178 assert!((&mut delay).now_or_never().is_none());
179 clock.advance(Duration::from_millis(50));
180 assert!(delay.now_or_never().is_some());
181 }
182
183 #[tokio::test]
184 async fn advance_to_next_wakeup_jumps() {
185 let clock = Arc::new(MockClock::default());
186 let _delay_a = clock.delay(Duration::from_millis(200));
187 let _delay_b = clock.delay(Duration::from_millis(500));
188 let elapsed = clock.advance_to_next_wakeup().expect("a wakeup is pending");
189 assert_eq!(elapsed, Duration::from_millis(200));
190 let elapsed = clock.advance_to_next_wakeup().expect("a wakeup is pending");
191 assert_eq!(elapsed, Duration::from_millis(300));
192 assert!(clock.advance_to_next_wakeup().is_none());
193 }
194}