1use std::future::Future;
10use std::pin::Pin;
11use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
12use std::sync::Arc;
13use std::task::{Context, Poll, Waker};
14use std::time::Duration;
15
16use crate::clock::{Clock, SystemClock};
17use crate::runtime::Runtime;
18use futures::executor::{LocalPool, LocalSpawner};
19use futures::future::BoxFuture;
20use futures::task::LocalSpawnExt;
21use parking_lot::Mutex;
22
23pub const WALL_EPOCH_MS: i64 = 1_788_868_800_000;
25
26pub const ABSENT_MARKER: &str = "$dialcache::testing::Absent";
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
39pub struct Absent;
40
41impl serde::Serialize for Absent {
42 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
43 serializer.serialize_unit_struct(ABSENT_MARKER)
44 }
45}
46
47impl std::fmt::Debug for VirtualClock {
48 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49 f.debug_struct("VirtualClock")
50 .field("wall_ms", &self.wall_ms())
51 .field("elapsed", &self.elapsed())
52 .finish()
53 }
54}
55
56struct TimerState {
57 at_ns: u128,
58 id: u64,
59 fired: AtomicBool,
60 cancelled: AtomicBool,
61 waker: Mutex<Option<Waker>>,
62}
63
64struct ClockState {
65 wall_ns: i128,
66 elapsed_ns: u128,
67 scheduler_ns: u128,
68 next_timer: u64,
69 timers: Vec<Arc<TimerState>>,
70}
71
72pub struct VirtualClock {
76 state: Mutex<ClockState>,
77}
78
79impl VirtualClock {
80 pub fn new(wall_ms: i64) -> Arc<Self> {
83 Arc::new(VirtualClock {
84 state: Mutex::new(ClockState {
85 wall_ns: wall_ms as i128 * 1_000_000,
86 elapsed_ns: 0,
87 scheduler_ns: 0,
88 next_timer: 0,
89 timers: Vec::new(),
90 }),
91 })
92 }
93
94 pub fn shift(&self, delta_ms: i64, wall_only: bool) {
96 self.shift_ns(delta_ms as i128 * 1_000_000, wall_only);
97 }
98
99 pub fn shift_ns(&self, delta_ns: i128, wall_only: bool) {
101 let mut state = self.state.lock();
102 state.wall_ns += delta_ns;
103 if !wall_only {
104 state.elapsed_ns = (state.elapsed_ns as i128 + delta_ns).max(0) as u128;
105 }
106 }
107
108 fn pop_due(&self, target_ns: u128) -> Option<Arc<TimerState>> {
110 let mut state = self.state.lock();
111 state
112 .timers
113 .retain(|t| !t.cancelled.load(Ordering::SeqCst) && !t.fired.load(Ordering::SeqCst));
114 let mut best: Option<usize> = None;
115 for (index, timer) in state.timers.iter().enumerate() {
116 if timer.at_ns <= target_ns {
117 let better = match best {
118 None => true,
119 Some(current) => {
120 let c = &state.timers[current];
121 timer.at_ns < c.at_ns || (timer.at_ns == c.at_ns && timer.id < c.id)
122 }
123 };
124 if better {
125 best = Some(index);
126 }
127 }
128 }
129 best.map(|index| state.timers.remove(index))
130 }
131
132 fn set_scheduler(&self, at_ns: u128) {
133 let mut state = self.state.lock();
134 let delta = at_ns.saturating_sub(state.scheduler_ns);
135 state.wall_ns += delta as i128;
136 state.elapsed_ns += delta;
137 state.scheduler_ns = at_ns;
138 }
139
140 fn scheduler_ns(&self) -> u128 {
141 self.state.lock().scheduler_ns
142 }
143
144 pub fn pending_timers(&self) -> usize {
146 let state = self.state.lock();
147 state
148 .timers
149 .iter()
150 .filter(|t| !t.cancelled.load(Ordering::SeqCst) && !t.fired.load(Ordering::SeqCst))
151 .count()
152 }
153}
154
155impl Clock for VirtualClock {
156 fn wall_ms(&self) -> i64 {
157 (self.state.lock().wall_ns.div_euclid(1_000_000)) as i64
158 }
159
160 fn elapsed(&self) -> Duration {
161 let ns = self.state.lock().elapsed_ns;
162 Duration::from_nanos(ns.min(u64::MAX as u128) as u64)
163 }
164}
165
166impl VirtualClock {
167 pub fn sleep(&self, duration: Duration) -> BoxFuture<'static, ()> {
169 let delay_ns = duration.as_nanos();
172 let delay_ms = delay_ns.div_ceil(1_000_000);
173 let mut state = self.state.lock();
174 state.next_timer += 1;
175 let timer = Arc::new(TimerState {
176 at_ns: state.scheduler_ns + delay_ms * 1_000_000,
177 id: state.next_timer,
178 fired: AtomicBool::new(false),
179 cancelled: AtomicBool::new(false),
180 waker: Mutex::new(None),
181 });
182 state.timers.push(timer.clone());
183 Box::pin(Sleep { timer })
184 }
185}
186
187struct Sleep {
188 timer: Arc<TimerState>,
189}
190
191impl Future for Sleep {
192 type Output = ();
193
194 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
195 if self.timer.fired.load(Ordering::SeqCst) {
196 return Poll::Ready(());
197 }
198 *self.timer.waker.lock() = Some(cx.waker().clone());
199 Poll::Pending
200 }
201}
202
203impl Drop for Sleep {
204 fn drop(&mut self) {
205 self.timer.cancelled.store(true, Ordering::SeqCst);
206 }
207}
208
209#[derive(Default)]
212struct Queues {
213 immediate: Vec<BoxFuture<'static, ()>>,
214 deferred: Vec<BoxFuture<'static, ()>>,
215}
216
217pub struct StepRuntime {
220 queues: Mutex<Queues>,
221 spawned: AtomicU64,
222 clock: Arc<VirtualClock>,
223}
224
225impl StepRuntime {
226 pub fn new(clock: Arc<VirtualClock>) -> Arc<Self> {
229 Arc::new(StepRuntime {
230 queues: Mutex::new(Queues::default()),
231 spawned: AtomicU64::new(0),
232 clock,
233 })
234 }
235
236 pub fn spawned(&self) -> u64 {
238 self.spawned.load(Ordering::Relaxed)
239 }
240}
241
242impl std::fmt::Debug for StepRuntime {
243 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
244 f.debug_struct("StepRuntime")
245 .field("spawned", &self.spawned())
246 .finish()
247 }
248}
249
250impl Runtime for StepRuntime {
251 fn spawn(&self, task: BoxFuture<'static, ()>) {
252 self.spawned.fetch_add(1, Ordering::Relaxed);
253 self.queues.lock().immediate.push(task);
254 }
255
256 fn defer(&self, task: BoxFuture<'static, ()>) {
257 self.spawned.fetch_add(1, Ordering::Relaxed);
258 self.queues.lock().deferred.push(task);
259 }
260
261 fn spawn_blocking(
262 &self,
263 task: Box<dyn FnOnce() + Send + 'static>,
264 ) -> Result<(), crate::BoxError> {
265 self.spawn(Box::pin(async move { task() }));
266 Ok(())
267 }
268
269 fn sleep(&self, duration: Duration) -> BoxFuture<'static, ()> {
270 self.clock.sleep(duration)
271 }
272}
273
274pub struct TestExecutor {
277 pool: LocalPool,
278 local: LocalSpawner,
279 polls: Arc<AtomicU64>,
280 pub clock: Arc<VirtualClock>,
282 pub runtime: Arc<StepRuntime>,
284}
285
286impl std::fmt::Debug for TestExecutor {
287 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
288 f.debug_struct("TestExecutor")
289 .field("wall_ms", &self.clock.wall_ms())
290 .finish()
291 }
292}
293
294impl TestExecutor {
295 pub fn new(wall_ms: i64) -> Self {
298 let pool = LocalPool::new();
299 let local = pool.spawner();
300 let clock = VirtualClock::new(wall_ms);
301 let runtime = StepRuntime::new(clock.clone());
302 TestExecutor {
303 pool,
304 local,
305 polls: Arc::new(AtomicU64::new(0)),
306 clock,
307 runtime,
308 }
309 }
310
311 pub fn poll_count(&self) -> u64 {
314 self.polls.load(Ordering::Relaxed)
315 }
316
317 fn tracked<F: Future>(&self, future: F) -> impl Future<Output = F::Output> + use<F> {
318 let polls = self.polls.clone();
319 let mut future = Box::pin(future);
320 futures::future::poll_fn(move |cx| {
321 polls.fetch_add(1, Ordering::Relaxed);
322 future.as_mut().poll(cx)
323 })
324 }
325
326 pub fn block_on<R: 'static>(&mut self, future: impl Future<Output = R> + 'static) -> R {
330 let slot: std::rc::Rc<std::cell::RefCell<Option<R>>> =
331 std::rc::Rc::new(std::cell::RefCell::new(None));
332 let sink = slot.clone();
333 self.local
334 .spawn_local(self.tracked(async move {
335 let result = future.await;
336 *sink.borrow_mut() = Some(result);
337 }))
338 .expect("pool accepts tasks");
339 self.drain();
340 let result = slot.borrow_mut().take();
341 result.expect("block_on future stayed blocked on a test-owned gate")
342 }
343
344 pub fn spawn(&self, task: impl Future<Output = ()> + 'static) {
346 self.local
347 .spawn_local(self.tracked(task))
348 .expect("pool accepts tasks");
349 }
350
351 fn move_immediate(&mut self) -> bool {
352 let tasks = std::mem::take(&mut self.runtime.queues.lock().immediate);
353 let moved = !tasks.is_empty();
354 for task in tasks {
355 self.local
356 .spawn_local(self.tracked(task))
357 .expect("pool accepts tasks");
358 }
359 moved
360 }
361
362 fn move_deferred(&mut self) -> bool {
363 let tasks = std::mem::take(&mut self.runtime.queues.lock().deferred);
364 let moved = !tasks.is_empty();
365 for task in tasks {
366 self.local
367 .spawn_local(self.tracked(task))
368 .expect("pool accepts tasks");
369 }
370 moved
371 }
372
373 pub fn drain(&mut self) {
377 loop {
378 loop {
379 self.pool.run_until_stalled();
380 if !self.move_immediate() {
381 break;
382 }
383 }
384 if !self.move_deferred() {
385 return;
386 }
387 }
388 }
389
390 pub fn advance(&mut self, ms: i64, deliver: bool) {
394 if !deliver {
395 self.clock.shift(ms, false);
396 self.drain();
397 return;
398 }
399 let target = self.clock.scheduler_ns() + (ms.max(0) as u128) * 1_000_000;
400 loop {
401 self.drain();
402 match self.clock.pop_due(target) {
403 Some(timer) => {
404 self.clock.set_scheduler(timer.at_ns);
405 timer.fired.store(true, Ordering::SeqCst);
406 if let Some(waker) = timer.waker.lock().take() {
407 waker.wake();
408 }
409 }
410 None => {
411 self.clock.set_scheduler(target);
412 break;
413 }
414 }
415 }
416 self.drain();
417 }
418
419 pub fn advance_micros(&mut self, micros: i64) {
422 self.clock.shift_ns(micros as i128 * 1_000, false);
423 self.drain();
424 }
425}
426
427pub fn grid_clock(base: &Arc<VirtualClock>) -> SystemClock {
435 let monotonic = base.clone();
436 let wall = base.clone();
437 SystemClock::with_sources(
438 move || {
439 let ns = monotonic.state.lock().elapsed_ns;
440 Duration::from_nanos(ns.min(u64::MAX as u128) as u64)
441 },
442 move || wall.wall_ms(),
443 )
444}