netstack3_base/time/
testutil.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Test utilities for dealing with time.
6
7use alloc::collections::BinaryHeap;
8use alloc::format;
9use alloc::string::String;
10use alloc::vec::Vec;
11use core::fmt::{self, Debug, Formatter};
12use core::hash::Hash;
13use core::ops;
14use core::sync::atomic::Ordering;
15use core::time::Duration;
16use netstack3_sync::Mutex;
17
18use assert_matches::assert_matches;
19use netstack3_hashmap::HashMap;
20
21use crate::context::CtxPair;
22use crate::ref_counted_hash_map::{RefCountedHashSet, RemoveResult};
23use crate::time::{
24    AtomicInstant, Instant, InstantBindingsTypes, InstantContext, TimerBindingsTypes, TimerContext,
25    TimerHandler,
26};
27
28/// A fake implementation of `Instant` for use in testing.
29#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
30pub struct FakeInstant {
31    /// A FakeInstant is just an offset from some arbitrary epoch.
32    pub offset: Duration,
33}
34
35impl crate::inspect::InspectableValue for FakeInstant {
36    fn record<I: crate::inspect::Inspector>(&self, name: &str, inspector: &mut I) {
37        inspector.record_uint(name, self.offset.as_nanos() as u64)
38    }
39}
40
41impl FakeInstant {
42    /// The maximum value represented by a fake instant.
43    pub const LATEST: FakeInstant = FakeInstant { offset: Duration::MAX };
44
45    /// Adds to this fake instant, saturating at [`LATEST`].
46    pub fn saturating_add(self, dur: Duration) -> FakeInstant {
47        FakeInstant { offset: self.offset.saturating_add(dur) }
48    }
49}
50
51impl From<Duration> for FakeInstant {
52    fn from(offset: Duration) -> FakeInstant {
53        FakeInstant { offset }
54    }
55}
56
57impl Instant for FakeInstant {
58    fn checked_duration_since(&self, earlier: FakeInstant) -> Option<Duration> {
59        self.offset.checked_sub(earlier.offset)
60    }
61
62    fn checked_add(&self, duration: Duration) -> Option<FakeInstant> {
63        self.offset.checked_add(duration).map(|offset| FakeInstant { offset })
64    }
65
66    fn saturating_add(&self, duration: Duration) -> Self {
67        FakeInstant { offset: self.offset.saturating_add(duration) }
68    }
69
70    fn checked_sub(&self, duration: Duration) -> Option<FakeInstant> {
71        self.offset.checked_sub(duration).map(|offset| FakeInstant { offset })
72    }
73}
74
75impl ops::Add<Duration> for FakeInstant {
76    type Output = FakeInstant;
77
78    fn add(self, dur: Duration) -> FakeInstant {
79        FakeInstant { offset: self.offset + dur }
80    }
81}
82
83impl ops::Sub<FakeInstant> for FakeInstant {
84    type Output = Duration;
85
86    fn sub(self, other: FakeInstant) -> Duration {
87        self.offset - other.offset
88    }
89}
90
91impl ops::Sub<Duration> for FakeInstant {
92    type Output = FakeInstant;
93
94    fn sub(self, dur: Duration) -> FakeInstant {
95        FakeInstant { offset: self.offset - dur }
96    }
97}
98
99impl Debug for FakeInstant {
100    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
101        write!(f, "{:?}", self.offset)
102    }
103}
104
105/// A fake implementation of [`AtomicInstant`] for use in testing.
106#[derive(Debug)]
107pub struct FakeAtomicInstant {
108    value: Mutex<FakeInstant>,
109}
110
111impl AtomicInstant<FakeInstant> for FakeAtomicInstant {
112    fn new(instant: FakeInstant) -> FakeAtomicInstant {
113        FakeAtomicInstant { value: Mutex::new(instant) }
114    }
115
116    fn load(&self, _ordering: Ordering) -> FakeInstant {
117        *self.value.lock()
118    }
119
120    fn store(&self, instant: FakeInstant, _ordering: Ordering) {
121        *self.value.lock() = instant
122    }
123
124    fn store_max(&self, instant: FakeInstant, _ordering: Ordering) {
125        let mut guard = self.value.lock();
126        if *guard < instant {
127            *guard = instant
128        }
129    }
130}
131
132/// A fake [`InstantContext`] which stores the current time as a
133/// [`FakeInstant`].
134#[derive(Default)]
135pub struct FakeInstantCtx {
136    /// The fake instant held by this fake context.
137    pub time: FakeInstant,
138}
139
140impl FakeInstantCtx {
141    /// Advance the current time by the given duration.
142    pub fn sleep(&mut self, dur: Duration) {
143        self.time.offset += dur;
144    }
145
146    /// Advance the current time to the given instant.
147    ///
148    /// Panics if `instant` is not in the future compared to current time.
149    pub fn sleep_until(&mut self, instant: FakeInstant) {
150        assert!(instant > self.time, "sleep until the past not allowed");
151        self.time = instant;
152    }
153}
154
155impl InstantBindingsTypes for FakeInstantCtx {
156    type Instant = FakeInstant;
157    type AtomicInstant = FakeAtomicInstant;
158}
159
160impl InstantContext for FakeInstantCtx {
161    fn now(&self) -> FakeInstant {
162        self.time
163    }
164}
165
166/// Arbitrary data of type `D` attached to a `FakeInstant`.
167///
168/// `InstantAndData` implements `Ord` and `Eq` to be used in a `BinaryHeap`
169/// and ordered by `FakeInstant`.
170#[derive(Clone, Debug)]
171pub struct InstantAndData<D>(pub FakeInstant, pub D);
172
173impl<D> InstantAndData<D> {
174    /// Creates a new `InstantAndData`.
175    pub fn new(time: FakeInstant, data: D) -> Self {
176        Self(time, data)
177    }
178}
179
180impl<D> Eq for InstantAndData<D> {}
181
182impl<D> PartialEq for InstantAndData<D> {
183    fn eq(&self, other: &Self) -> bool {
184        self.0 == other.0
185    }
186}
187
188impl<D> Ord for InstantAndData<D> {
189    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
190        other.0.cmp(&self.0)
191    }
192}
193
194impl<D> PartialOrd for InstantAndData<D> {
195    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
196        Some(self.cmp(other))
197    }
198}
199
200/// A fake timer vended by [`FakeTimerCtx`].
201#[derive(Debug, Clone)]
202pub struct FakeTimer<Id> {
203    timer_id: usize,
204    pub dispatch_id: Id,
205}
206
207impl<Id> FakeTimer<Id> {
208    /// Gets the unique ID for this timer.
209    pub fn timer_id(&self) -> FakeTimerId {
210        FakeTimerId(Some(self.timer_id))
211    }
212
213    /// Consumes this `FakeTimer` returning the dispatch id and the timer id.
214    pub fn into_dispatch_and_timer_id(self) -> (Id, FakeTimerId) {
215        let Self { timer_id, dispatch_id } = self;
216        (dispatch_id, FakeTimerId(Some(timer_id)))
217    }
218}
219
220/// The unique timer identifier for [`FakeTimer`].
221///
222/// The default implementation returns a timer ID that doesn't match any timers.
223#[derive(PartialEq, Eq, Copy, Clone, Debug, Default)]
224pub struct FakeTimerId(Option<usize>);
225
226/// A fake [`TimerContext`] which stores time as a [`FakeInstantCtx`].
227pub struct FakeTimerCtx<Id> {
228    /// The instant context within this fake timer context.
229    pub instant: FakeInstantCtx,
230    /// The timer heap kept by the fake implementation.
231    pub timers: BinaryHeap<InstantAndData<FakeTimer<Id>>>,
232    /// Used to issue new [`FakeTimer`] ids.
233    next_timer_id: usize,
234}
235
236impl<Id> Default for FakeTimerCtx<Id> {
237    fn default() -> FakeTimerCtx<Id> {
238        FakeTimerCtx {
239            instant: FakeInstantCtx::default(),
240            timers: BinaryHeap::default(),
241            next_timer_id: 0,
242        }
243    }
244}
245
246impl<Id: Clone> FakeTimerCtx<Id> {
247    /// Get an ordered list of all currently-scheduled timers.
248    pub fn timers(&self) -> Vec<(FakeInstant, Id)> {
249        self.timers
250            .clone()
251            .into_sorted_vec()
252            .into_iter()
253            .map(|InstantAndData(i, FakeTimer { timer_id: _, dispatch_id })| (i, dispatch_id))
254            .collect()
255    }
256}
257
258impl<Id: Debug + Clone + Hash + Eq> FakeTimerCtx<Id> {
259    /// Asserts that `self` contains exactly the timers in `timers`.
260    ///
261    /// # Panics
262    ///
263    /// Panics if `timers` contains the same ID more than once or if `self`
264    /// does not contain exactly the timers in `timers`.
265    ///
266    /// [`RangeBounds<FakeInstant>`]: core::ops::RangeBounds
267    #[track_caller]
268    pub fn assert_timers_installed<I: IntoIterator<Item = (Id, FakeInstant)>>(&self, timers: I) {
269        self.assert_timers_installed_range(
270            timers.into_iter().map(|(id, instant)| (id, instant..=instant)),
271        );
272    }
273
274    /// Like [`assert_timers_installed`] but receives a range instants to
275    /// match.
276    ///
277    /// Each timer must be present, and its deadline must fall into the
278    /// specified range.
279    #[track_caller]
280    pub fn assert_timers_installed_range<
281        R: ops::RangeBounds<FakeInstant> + Debug,
282        I: IntoIterator<Item = (Id, R)>,
283    >(
284        &self,
285        timers: I,
286    ) {
287        self.assert_timers_installed_inner(timers, true);
288    }
289
290    /// Asserts that `self` contains at least the timers in `timers`.
291    ///
292    /// Like [`assert_timers_installed`], but only asserts that `timers` is
293    /// a subset of the timers installed; other timers may be installed in
294    /// addition to those in `timers`.
295    #[track_caller]
296    pub fn assert_some_timers_installed<I: IntoIterator<Item = (Id, FakeInstant)>>(
297        &self,
298        timers: I,
299    ) {
300        self.assert_some_timers_installed_range(
301            timers.into_iter().map(|(id, instant)| (id, instant..=instant)),
302        );
303    }
304
305    /// Like [`assert_some_timers_installed`] but receives instant ranges
306    /// to match like [`assert_timers_installed_range`].
307    #[track_caller]
308    pub fn assert_some_timers_installed_range<
309        R: ops::RangeBounds<FakeInstant> + Debug,
310        I: IntoIterator<Item = (Id, R)>,
311    >(
312        &self,
313        timers: I,
314    ) {
315        self.assert_timers_installed_inner(timers, false);
316    }
317
318    /// Asserts that no timers are installed.
319    ///
320    /// # Panics
321    ///
322    /// Panics if any timers are installed.
323    #[track_caller]
324    pub fn assert_no_timers_installed(&self) {
325        self.assert_timers_installed([]);
326    }
327
328    #[track_caller]
329    fn assert_timers_installed_inner<
330        R: ops::RangeBounds<FakeInstant> + Debug,
331        I: IntoIterator<Item = (Id, R)>,
332    >(
333        &self,
334        timers: I,
335        exact: bool,
336    ) {
337        let mut timers = timers.into_iter().fold(HashMap::new(), |mut timers, (id, range)| {
338            assert_matches!(timers.insert(id, range), None);
339            timers
340        });
341
342        enum Error<Id, R: ops::RangeBounds<FakeInstant>> {
343            ExpectedButMissing { id: Id, range: R },
344            UnexpectedButPresent { id: Id, instant: FakeInstant },
345            UnexpectedInstant { id: Id, range: R, instant: FakeInstant },
346        }
347
348        let mut errors = Vec::new();
349
350        // Make sure that all installed timers were expected (present in
351        // `timers`).
352        for InstantAndData(instant, FakeTimer { timer_id: _, dispatch_id: id }) in
353            self.timers.iter().cloned()
354        {
355            match timers.remove(&id) {
356                None => {
357                    if exact {
358                        errors.push(Error::UnexpectedButPresent { id, instant })
359                    }
360                }
361                Some(range) => {
362                    if !range.contains(&instant) {
363                        errors.push(Error::UnexpectedInstant { id, range, instant })
364                    }
365                }
366            }
367        }
368
369        // Make sure that all expected timers were already found in
370        // `self.timers` (and removed from `timers`).
371        errors.extend(timers.drain().map(|(id, range)| Error::ExpectedButMissing { id, range }));
372
373        if errors.len() > 0 {
374            let mut s = String::from("Unexpected timer contents:");
375            for err in errors {
376                s += &match err {
377                    Error::ExpectedButMissing { id, range } => {
378                        format!("\n\tMissing timer {:?} with deadline {:?}", id, range)
379                    }
380                    Error::UnexpectedButPresent { id, instant } => {
381                        format!("\n\tUnexpected timer {:?} with deadline {:?}", id, instant)
382                    }
383                    Error::UnexpectedInstant { id, range, instant } => format!(
384                        "\n\tTimer {:?} has unexpected deadline {:?} (wanted {:?})",
385                        id, instant, range
386                    ),
387                };
388            }
389            panic!("{}", s);
390        }
391    }
392}
393
394impl<Id: PartialEq> FakeTimerCtx<Id> {
395    fn cancel_timer_inner(&mut self, timer: &FakeTimer<Id>) -> Option<FakeInstant> {
396        let mut r: Option<FakeInstant> = None;
397        // NB: Cancelling timers can be made faster than this if we keep two
398        // data structures and require that `Id: Hash`.
399        self.timers.retain(|InstantAndData(instant, FakeTimer { timer_id, dispatch_id: _ })| {
400            if timer.timer_id == *timer_id {
401                r = Some(*instant);
402                false
403            } else {
404                true
405            }
406        });
407        r
408    }
409}
410
411impl<Id> InstantBindingsTypes for FakeTimerCtx<Id> {
412    type Instant = FakeInstant;
413    type AtomicInstant = FakeAtomicInstant;
414}
415
416impl<Id> InstantContext for FakeTimerCtx<Id> {
417    fn now(&self) -> FakeInstant {
418        self.instant.now()
419    }
420}
421
422impl<Id: Debug + Clone + Send + Sync> TimerBindingsTypes for FakeTimerCtx<Id> {
423    type Timer = FakeTimer<Id>;
424    type DispatchId = Id;
425    type UniqueTimerId = FakeTimerId;
426}
427
428impl<Id: PartialEq + Debug + Clone + Send + Sync> TimerContext for FakeTimerCtx<Id> {
429    fn new_timer(&mut self, dispatch_id: Self::DispatchId) -> Self::Timer {
430        let timer_id = self.next_timer_id;
431        self.next_timer_id += 1;
432        FakeTimer { timer_id, dispatch_id }
433    }
434
435    fn schedule_timer_instant(
436        &mut self,
437        time: Self::Instant,
438        timer: &mut Self::Timer,
439    ) -> Option<Self::Instant> {
440        let ret = self.cancel_timer_inner(timer);
441        self.timers.push(InstantAndData::new(time, timer.clone()));
442        ret
443    }
444
445    fn cancel_timer(&mut self, timer: &mut Self::Timer) -> Option<Self::Instant> {
446        self.cancel_timer_inner(timer)
447    }
448
449    fn scheduled_instant(&self, timer: &mut Self::Timer) -> Option<Self::Instant> {
450        self.timers.iter().find_map(
451            |InstantAndData(instant, FakeTimer { timer_id, dispatch_id: _ })| {
452                (timer.timer_id == *timer_id).then_some(*instant)
453            },
454        )
455    }
456
457    fn unique_timer_id(&self, timer: &Self::Timer) -> Self::UniqueTimerId {
458        timer.timer_id()
459    }
460}
461
462/// A trait abstracting access to a [`FakeTimerCtx`] instance.
463pub trait WithFakeTimerContext<TimerId> {
464    /// Calls the callback with a borrow of `FakeTimerCtx`.
465    fn with_fake_timer_ctx<O, F: FnOnce(&FakeTimerCtx<TimerId>) -> O>(&self, f: F) -> O;
466
467    /// Calls the callback with a mutable borrow of `FakeTimerCtx`.
468    fn with_fake_timer_ctx_mut<O, F: FnOnce(&mut FakeTimerCtx<TimerId>) -> O>(&mut self, f: F)
469    -> O;
470}
471
472impl<TimerId> WithFakeTimerContext<TimerId> for FakeTimerCtx<TimerId> {
473    fn with_fake_timer_ctx<O, F: FnOnce(&FakeTimerCtx<TimerId>) -> O>(&self, f: F) -> O {
474        f(self)
475    }
476
477    fn with_fake_timer_ctx_mut<O, F: FnOnce(&mut FakeTimerCtx<TimerId>) -> O>(
478        &mut self,
479        f: F,
480    ) -> O {
481        f(self)
482    }
483}
484
485impl<TimerId, CC, BC> WithFakeTimerContext<TimerId> for CtxPair<CC, BC>
486where
487    BC: WithFakeTimerContext<TimerId>,
488{
489    fn with_fake_timer_ctx<O, F: FnOnce(&FakeTimerCtx<TimerId>) -> O>(&self, f: F) -> O {
490        self.bindings_ctx.with_fake_timer_ctx(f)
491    }
492
493    fn with_fake_timer_ctx_mut<O, F: FnOnce(&mut FakeTimerCtx<TimerId>) -> O>(
494        &mut self,
495        f: F,
496    ) -> O {
497        self.bindings_ctx.with_fake_timer_ctx_mut(f)
498    }
499}
500
501/// Adds methods for interacting with [`FakeTimerCtx`] and its wrappers.
502pub trait FakeTimerCtxExt<Id>: Sized + TimerBindingsTypes {
503    /// Triggers the next timer, if any, by using the provided `handler`.
504    ///
505    /// `trigger_next_timer` triggers the next timer, if any, advances the
506    /// internal clock to the timer's scheduled time, and returns its ID.
507    fn trigger_next_timer<H: TimerHandler<Self, Id>>(&mut self, handler: &mut H) -> Option<Id>;
508
509    /// Skips the current time forward until `instant`, triggering all timers
510    /// until then, inclusive, by calling `f` on them.
511    ///
512    /// Returns the timers which were triggered.
513    ///
514    /// # Panics
515    ///
516    /// Panics if `instant` is in the past.
517    fn trigger_timers_until_instant<H: TimerHandler<Self, Id>>(
518        &mut self,
519        instant: FakeInstant,
520        handler: &mut H,
521    ) -> Vec<Id>;
522
523    /// Skips the current time forward by `duration`, triggering all timers
524    /// until then, inclusive, by passing them to the `handler`.
525    ///
526    /// Returns the timers which were triggered.
527    fn trigger_timers_for<H: TimerHandler<Self, Id>>(
528        &mut self,
529        duration: Duration,
530        handler: &mut H,
531    ) -> Vec<Id>;
532
533    /// Triggers timers and expects them to be the given timers.
534    ///
535    /// The number of timers to be triggered is taken to be the number of timers
536    /// produced by `timers`. Timers may be triggered in any order.
537    ///
538    /// # Panics
539    ///
540    /// Panics under the following conditions:
541    /// - Fewer timers could be triggered than expected
542    /// - Timers were triggered that were not expected
543    /// - Timers that were expected were not triggered
544    #[track_caller]
545    fn trigger_timers_and_expect_unordered<I: IntoIterator<Item = Id>, H: TimerHandler<Self, Id>>(
546        &mut self,
547        timers: I,
548        handler: &mut H,
549    ) where
550        Id: Debug + Hash + Eq;
551
552    /// Triggers timers until `instant` and expects them to be the given timers.
553    ///
554    /// Like `trigger_timers_and_expect_unordered`, except that timers will only
555    /// be triggered until `instant` (inclusive).
556    fn trigger_timers_until_and_expect_unordered<
557        I: IntoIterator<Item = Id>,
558        H: TimerHandler<Self, Id>,
559    >(
560        &mut self,
561        instant: FakeInstant,
562        timers: I,
563        handler: &mut H,
564    ) where
565        Id: Debug + Hash + Eq;
566
567    /// Triggers timers for `duration` and expects them to be the given timers.
568    ///
569    /// Like `trigger_timers_and_expect_unordered`, except that timers will only
570    /// be triggered for `duration` (inclusive).
571    fn trigger_timers_for_and_expect<I: IntoIterator<Item = Id>, H: TimerHandler<Self, Id>>(
572        &mut self,
573        duration: Duration,
574        timers: I,
575        handler: &mut H,
576    ) where
577        Id: Debug + Hash + Eq;
578}
579
580// TODO(https://fxbug.dev/42081080): hold lock on `FakeTimerCtx` across entire
581// method to avoid potential race conditions.
582impl<Id: Clone, Ctx: WithFakeTimerContext<Id> + TimerBindingsTypes<UniqueTimerId = FakeTimerId>>
583    FakeTimerCtxExt<Id> for Ctx
584{
585    /// Triggers the next timer, if any, by calling `f` on it.
586    ///
587    /// `trigger_next_timer` triggers the next timer, if any, advances the
588    /// internal clock to the timer's scheduled time, and returns its ID.
589    fn trigger_next_timer<H: TimerHandler<Self, Id>>(&mut self, handler: &mut H) -> Option<Id> {
590        self.with_fake_timer_ctx_mut(|timers| {
591            timers.timers.pop().map(|InstantAndData(t, id)| {
592                timers.instant.time = t;
593                id
594            })
595        })
596        .map(|fake_timer| {
597            let (dispatch_id, timer_id) = fake_timer.into_dispatch_and_timer_id();
598            handler.handle_timer(self, dispatch_id.clone(), timer_id);
599            dispatch_id
600        })
601    }
602
603    /// Skips the current time forward until `instant`, triggering all timers
604    /// until then, inclusive, by giving them to `handler`.
605    ///
606    /// Returns the timers which were triggered.
607    ///
608    /// # Panics
609    ///
610    /// Panics if `instant` is in the past.
611    fn trigger_timers_until_instant<H: TimerHandler<Self, Id>>(
612        &mut self,
613        instant: FakeInstant,
614        handler: &mut H,
615    ) -> Vec<Id> {
616        assert!(instant >= self.with_fake_timer_ctx(|ctx| ctx.now()));
617        let mut timers = Vec::new();
618
619        while self.with_fake_timer_ctx_mut(|ctx| {
620            ctx.timers.peek().map(|InstantAndData(i, _id)| i <= &instant).unwrap_or(false)
621        }) {
622            timers.push(self.trigger_next_timer(handler).unwrap())
623        }
624
625        self.with_fake_timer_ctx_mut(|ctx| {
626            assert!(ctx.now() <= instant);
627            ctx.instant.time = instant;
628        });
629
630        timers
631    }
632
633    /// Skips the current time forward by `duration`, triggering all timers
634    /// until then, inclusive, by calling `f` on them.
635    ///
636    /// Returns the timers which were triggered.
637    fn trigger_timers_for<H: TimerHandler<Self, Id>>(
638        &mut self,
639        duration: Duration,
640        handler: &mut H,
641    ) -> Vec<Id> {
642        let instant = self.with_fake_timer_ctx(|ctx| ctx.now().saturating_add(duration));
643        // We know the call to `self.trigger_timers_until_instant` will not
644        // panic because we provide an instant that is greater than or equal
645        // to the current time.
646        self.trigger_timers_until_instant(instant, handler)
647    }
648
649    /// Triggers timers and expects them to be the given timers.
650    ///
651    /// The number of timers to be triggered is taken to be the number of
652    /// timers produced by `timers`. Timers may be triggered in any order.
653    ///
654    /// # Panics
655    ///
656    /// Panics under the following conditions:
657    /// - Fewer timers could be triggered than expected
658    /// - Timers were triggered that were not expected
659    /// - Timers that were expected were not triggered
660    #[track_caller]
661    fn trigger_timers_and_expect_unordered<I: IntoIterator<Item = Id>, H: TimerHandler<Self, Id>>(
662        &mut self,
663        timers: I,
664        handler: &mut H,
665    ) where
666        Id: Debug + Hash + Eq,
667    {
668        let mut timers = RefCountedHashSet::from_iter(timers);
669
670        for _ in 0..timers.len() {
671            let id = self.trigger_next_timer(handler).expect("ran out of timers to trigger");
672            match timers.remove(id.clone()) {
673                RemoveResult::Removed(()) | RemoveResult::StillPresent => {}
674                RemoveResult::NotPresent => panic!("triggered unexpected timer: {:?}", id),
675            }
676        }
677
678        if timers.len() > 0 {
679            let mut s = String::from("Expected timers did not trigger:");
680            for (id, count) in timers.iter_counts() {
681                s += &format!("\n\t{count}x {id:?}");
682            }
683            panic!("{}", s);
684        }
685    }
686
687    /// Triggers timers until `instant` and expects them to be the given
688    /// timers.
689    ///
690    /// Like `trigger_timers_and_expect_unordered`, except that timers will
691    /// only be triggered until `instant` (inclusive).
692    fn trigger_timers_until_and_expect_unordered<
693        I: IntoIterator<Item = Id>,
694        H: TimerHandler<Self, Id>,
695    >(
696        &mut self,
697        instant: FakeInstant,
698        timers: I,
699        handler: &mut H,
700    ) where
701        Id: Debug + Hash + Eq,
702    {
703        let mut timers = RefCountedHashSet::from_iter(timers);
704
705        let triggered_timers = self.trigger_timers_until_instant(instant, handler);
706
707        for id in triggered_timers {
708            match timers.remove(id.clone()) {
709                RemoveResult::Removed(()) | RemoveResult::StillPresent => {}
710                RemoveResult::NotPresent => panic!("triggered unexpected timer: {:?}", id),
711            }
712        }
713
714        if timers.len() > 0 {
715            let mut s = String::from("Expected timers did not trigger:");
716            for (id, count) in timers.iter_counts() {
717                s += &format!("\n\t{count}x {id:?}");
718            }
719            panic!("{}", s);
720        }
721    }
722
723    /// Triggers timers for `duration` and expects them to be the given
724    /// timers.
725    ///
726    /// Like `trigger_timers_and_expect_unordered`, except that timers will
727    /// only be triggered for `duration` (inclusive).
728    fn trigger_timers_for_and_expect<I: IntoIterator<Item = Id>, H: TimerHandler<Self, Id>>(
729        &mut self,
730        duration: Duration,
731        timers: I,
732        handler: &mut H,
733    ) where
734        Id: Debug + Hash + Eq,
735    {
736        let instant = self.with_fake_timer_ctx(|ctx| ctx.now().saturating_add(duration));
737        self.trigger_timers_until_and_expect_unordered(instant, timers, handler);
738    }
739}
740
741#[cfg(test)]
742mod tests {
743    use super::*;
744
745    use crate::HandleableTimer;
746
747    use alloc::vec;
748
749    const ONE_SEC: Duration = Duration::from_secs(1);
750    const ONE_SEC_INSTANT: FakeInstant = FakeInstant { offset: ONE_SEC };
751
752    #[derive(Debug, Eq, PartialEq, Clone, Hash)]
753    struct TimerId(usize);
754    #[derive(Default)]
755    struct CoreCtx(Vec<(TimerId, FakeInstant)>);
756
757    impl CoreCtx {
758        fn take(&mut self) -> Vec<(TimerId, FakeInstant)> {
759            core::mem::take(&mut self.0)
760        }
761    }
762
763    impl HandleableTimer<CoreCtx, FakeTimerCtx<Self>> for TimerId {
764        fn handle(
765            self,
766            CoreCtx(expired): &mut CoreCtx,
767            bindings_ctx: &mut FakeTimerCtx<Self>,
768            _: FakeTimerId,
769        ) {
770            expired.push((self, bindings_ctx.now()))
771        }
772    }
773
774    #[test]
775    fn instant_and_data() {
776        // Verify implementation of InstantAndData to be used as a complex
777        // type in a BinaryHeap.
778        let mut heap = BinaryHeap::<InstantAndData<usize>>::new();
779        let now = FakeInstant::default();
780
781        fn new_data(time: FakeInstant, id: usize) -> InstantAndData<usize> {
782            InstantAndData::new(time, id)
783        }
784
785        heap.push(new_data(now + Duration::from_secs(1), 1));
786        heap.push(new_data(now + Duration::from_secs(2), 2));
787
788        // Earlier timer is popped first.
789        assert_eq!(heap.pop().unwrap().1, 1);
790        assert_eq!(heap.pop().unwrap().1, 2);
791        assert_eq!(heap.pop(), None);
792
793        heap.push(new_data(now + Duration::from_secs(1), 1));
794        heap.push(new_data(now + Duration::from_secs(1), 1));
795
796        // Can pop twice with identical data.
797        assert_eq!(heap.pop().unwrap().1, 1);
798        assert_eq!(heap.pop().unwrap().1, 1);
799        assert_eq!(heap.pop(), None);
800    }
801
802    #[test]
803    fn fake_timer_context() {
804        let mut core_ctx = CoreCtx::default();
805        let mut bindings_ctx = FakeTimerCtx::<TimerId>::default();
806
807        // When no timers are installed, `trigger_next_timer` should return
808        // `false`.
809        assert_eq!(bindings_ctx.trigger_next_timer(&mut core_ctx), None);
810        assert_eq!(core_ctx.take(), vec![]);
811
812        let mut timer0 = bindings_ctx.new_timer(TimerId(0));
813        let mut timer1 = bindings_ctx.new_timer(TimerId(1));
814        let mut timer2 = bindings_ctx.new_timer(TimerId(2));
815
816        // No timer with id `0` exists yet.
817        assert_eq!(bindings_ctx.scheduled_instant(&mut timer0), None);
818
819        assert_eq!(bindings_ctx.schedule_timer(ONE_SEC, &mut timer0), None);
820
821        // Timer with id `0` scheduled to execute at `ONE_SEC_INSTANT`.
822        assert_eq!(bindings_ctx.scheduled_instant(&mut timer0).unwrap(), ONE_SEC_INSTANT);
823
824        assert_eq!(bindings_ctx.trigger_next_timer(&mut core_ctx), Some(TimerId(0)));
825        assert_eq!(core_ctx.take(), vec![(TimerId(0), ONE_SEC_INSTANT)]);
826
827        // After the timer fires, it should not still be scheduled at some
828        // instant.
829        assert_eq!(bindings_ctx.scheduled_instant(&mut timer0), None);
830
831        // The time should have been advanced.
832        assert_eq!(bindings_ctx.now(), ONE_SEC_INSTANT);
833
834        // Once it's been triggered, it should be canceled and not
835        // triggerable again.
836        assert_eq!(bindings_ctx.trigger_next_timer(&mut core_ctx), None);
837        assert_eq!(core_ctx.take(), vec![]);
838
839        // Unwind back time.
840        bindings_ctx.instant.time = Default::default();
841
842        // If we schedule a timer but then cancel it, it shouldn't fire.
843        assert_eq!(bindings_ctx.schedule_timer(ONE_SEC, &mut timer0), None);
844        assert_eq!(bindings_ctx.cancel_timer(&mut timer0), Some(ONE_SEC_INSTANT));
845        assert_eq!(bindings_ctx.trigger_next_timer(&mut core_ctx), None);
846        assert_eq!(core_ctx.take(), vec![]);
847
848        // If we schedule a timer but then schedule the same ID again, the
849        // second timer should overwrite the first one.
850        assert_eq!(bindings_ctx.schedule_timer(Duration::from_secs(0), &mut timer0), None);
851        assert_eq!(
852            bindings_ctx.schedule_timer(ONE_SEC, &mut timer0),
853            Some(Duration::from_secs(0).into())
854        );
855        assert_eq!(bindings_ctx.cancel_timer(&mut timer0), Some(ONE_SEC_INSTANT));
856
857        // If we schedule three timers and then run `trigger_timers_until`
858        // with the appropriate value, only two of them should fire.
859        assert_eq!(bindings_ctx.schedule_timer(Duration::from_secs(0), &mut timer0), None);
860        assert_eq!(bindings_ctx.schedule_timer(Duration::from_secs(1), &mut timer1), None);
861        assert_eq!(bindings_ctx.schedule_timer(Duration::from_secs(2), &mut timer2), None);
862        assert_eq!(
863            bindings_ctx.trigger_timers_until_instant(ONE_SEC_INSTANT, &mut core_ctx),
864            vec![TimerId(0), TimerId(1)],
865        );
866
867        // The first two timers should have fired.
868        assert_eq!(
869            core_ctx.take(),
870            vec![
871                (TimerId(0), FakeInstant::from(Duration::from_secs(0))),
872                (TimerId(1), ONE_SEC_INSTANT)
873            ]
874        );
875
876        // They should be canceled now.
877        assert_eq!(bindings_ctx.cancel_timer(&mut timer0), None);
878        assert_eq!(bindings_ctx.cancel_timer(&mut timer1), None);
879
880        // The clock should have been updated.
881        assert_eq!(bindings_ctx.now(), ONE_SEC_INSTANT);
882
883        // The last timer should not have fired.
884        assert_eq!(
885            bindings_ctx.cancel_timer(&mut timer2),
886            Some(FakeInstant::from(Duration::from_secs(2)))
887        );
888    }
889
890    #[test]
891    fn trigger_timers_until_and_expect_unordered() {
892        // If the requested instant does not coincide with a timer trigger
893        // point, the time should still be advanced.
894        let mut core_ctx = CoreCtx::default();
895        let mut bindings_ctx = FakeTimerCtx::default();
896        let mut timer0 = bindings_ctx.new_timer(TimerId(0));
897        let mut timer1 = bindings_ctx.new_timer(TimerId(1));
898        assert_eq!(bindings_ctx.schedule_timer(Duration::from_secs(0), &mut timer0), None);
899        assert_eq!(bindings_ctx.schedule_timer(Duration::from_secs(2), &mut timer1), None);
900        bindings_ctx.trigger_timers_until_and_expect_unordered(
901            ONE_SEC_INSTANT,
902            vec![TimerId(0)],
903            &mut core_ctx,
904        );
905        assert_eq!(bindings_ctx.now(), ONE_SEC_INSTANT);
906    }
907}