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> FakeTimerCtx<Id> {
395    /// Pops the next timer to fire, returning its Id and advances the current
396    /// time.
397    pub fn pop_next_timer_and_advance_time(&mut self) -> Option<Id> {
398        let InstantAndData(instant, timer) = self.timers.pop()?;
399        assert!(instant >= self.instant.time);
400        self.instant.time = instant;
401        Some(timer.dispatch_id)
402    }
403}
404
405impl<Id: PartialEq> FakeTimerCtx<Id> {
406    fn cancel_timer_inner(&mut self, timer: &FakeTimer<Id>) -> Option<FakeInstant> {
407        let mut r: Option<FakeInstant> = None;
408        // NB: Cancelling timers can be made faster than this if we keep two
409        // data structures and require that `Id: Hash`.
410        self.timers.retain(|InstantAndData(instant, FakeTimer { timer_id, dispatch_id: _ })| {
411            if timer.timer_id == *timer_id {
412                r = Some(*instant);
413                false
414            } else {
415                true
416            }
417        });
418        r
419    }
420}
421
422impl<Id> InstantBindingsTypes for FakeTimerCtx<Id> {
423    type Instant = FakeInstant;
424    type AtomicInstant = FakeAtomicInstant;
425}
426
427impl<Id> InstantContext for FakeTimerCtx<Id> {
428    fn now(&self) -> FakeInstant {
429        self.instant.now()
430    }
431}
432
433impl<Id: Debug + Clone + Send + Sync> TimerBindingsTypes for FakeTimerCtx<Id> {
434    type Timer = FakeTimer<Id>;
435    type DispatchId = Id;
436    type UniqueTimerId = FakeTimerId;
437}
438
439impl<Id: PartialEq + Debug + Clone + Send + Sync> TimerContext for FakeTimerCtx<Id> {
440    fn new_timer(&mut self, dispatch_id: Self::DispatchId) -> Self::Timer {
441        let timer_id = self.next_timer_id;
442        self.next_timer_id += 1;
443        FakeTimer { timer_id, dispatch_id }
444    }
445
446    fn schedule_timer_instant(
447        &mut self,
448        time: Self::Instant,
449        timer: &mut Self::Timer,
450    ) -> Option<Self::Instant> {
451        let ret = self.cancel_timer_inner(timer);
452        self.timers.push(InstantAndData::new(time, timer.clone()));
453        ret
454    }
455
456    fn cancel_timer(&mut self, timer: &mut Self::Timer) -> Option<Self::Instant> {
457        self.cancel_timer_inner(timer)
458    }
459
460    fn scheduled_instant(&self, timer: &mut Self::Timer) -> Option<Self::Instant> {
461        self.timers.iter().find_map(
462            |InstantAndData(instant, FakeTimer { timer_id, dispatch_id: _ })| {
463                (timer.timer_id == *timer_id).then_some(*instant)
464            },
465        )
466    }
467
468    fn unique_timer_id(&self, timer: &Self::Timer) -> Self::UniqueTimerId {
469        timer.timer_id()
470    }
471}
472
473/// A trait abstracting access to a [`FakeTimerCtx`] instance.
474pub trait WithFakeTimerContext<TimerId> {
475    /// Calls the callback with a borrow of `FakeTimerCtx`.
476    fn with_fake_timer_ctx<O, F: FnOnce(&FakeTimerCtx<TimerId>) -> O>(&self, f: F) -> O;
477
478    /// Calls the callback with a mutable borrow of `FakeTimerCtx`.
479    fn with_fake_timer_ctx_mut<O, F: FnOnce(&mut FakeTimerCtx<TimerId>) -> O>(&mut self, f: F)
480    -> O;
481}
482
483impl<TimerId> WithFakeTimerContext<TimerId> for FakeTimerCtx<TimerId> {
484    fn with_fake_timer_ctx<O, F: FnOnce(&FakeTimerCtx<TimerId>) -> O>(&self, f: F) -> O {
485        f(self)
486    }
487
488    fn with_fake_timer_ctx_mut<O, F: FnOnce(&mut FakeTimerCtx<TimerId>) -> O>(
489        &mut self,
490        f: F,
491    ) -> O {
492        f(self)
493    }
494}
495
496impl<TimerId, CC, BC> WithFakeTimerContext<TimerId> for CtxPair<CC, BC>
497where
498    BC: WithFakeTimerContext<TimerId>,
499{
500    fn with_fake_timer_ctx<O, F: FnOnce(&FakeTimerCtx<TimerId>) -> O>(&self, f: F) -> O {
501        self.bindings_ctx.with_fake_timer_ctx(f)
502    }
503
504    fn with_fake_timer_ctx_mut<O, F: FnOnce(&mut FakeTimerCtx<TimerId>) -> O>(
505        &mut self,
506        f: F,
507    ) -> O {
508        self.bindings_ctx.with_fake_timer_ctx_mut(f)
509    }
510}
511
512/// Adds methods for interacting with [`FakeTimerCtx`] and its wrappers.
513pub trait FakeTimerCtxExt<Id>: Sized + TimerBindingsTypes {
514    /// Triggers the next timer, if any, by using the provided `handler`.
515    ///
516    /// `trigger_next_timer` triggers the next timer, if any, advances the
517    /// internal clock to the timer's scheduled time, and returns its ID.
518    fn trigger_next_timer<H: TimerHandler<Self, Id>>(&mut self, handler: &mut H) -> Option<Id>;
519
520    /// Skips the current time forward until `instant`, triggering all timers
521    /// until then, inclusive, by calling `f` on them.
522    ///
523    /// Returns the timers which were triggered.
524    ///
525    /// # Panics
526    ///
527    /// Panics if `instant` is in the past.
528    fn trigger_timers_until_instant<H: TimerHandler<Self, Id>>(
529        &mut self,
530        instant: FakeInstant,
531        handler: &mut H,
532    ) -> Vec<Id>;
533
534    /// Skips the current time forward by `duration`, triggering all timers
535    /// until then, inclusive, by passing them to the `handler`.
536    ///
537    /// Returns the timers which were triggered.
538    fn trigger_timers_for<H: TimerHandler<Self, Id>>(
539        &mut self,
540        duration: Duration,
541        handler: &mut H,
542    ) -> Vec<Id>;
543
544    /// Triggers timers and expects them to be the given timers.
545    ///
546    /// The number of timers to be triggered is taken to be the number of timers
547    /// produced by `timers`. Timers may be triggered in any order.
548    ///
549    /// # Panics
550    ///
551    /// Panics under the following conditions:
552    /// - Fewer timers could be triggered than expected
553    /// - Timers were triggered that were not expected
554    /// - Timers that were expected were not triggered
555    #[track_caller]
556    fn trigger_timers_and_expect_unordered<I: IntoIterator<Item = Id>, H: TimerHandler<Self, Id>>(
557        &mut self,
558        timers: I,
559        handler: &mut H,
560    ) where
561        Id: Debug + Hash + Eq;
562
563    /// Triggers timers until `instant` and expects them to be the given timers.
564    ///
565    /// Like `trigger_timers_and_expect_unordered`, except that timers will only
566    /// be triggered until `instant` (inclusive).
567    fn trigger_timers_until_and_expect_unordered<
568        I: IntoIterator<Item = Id>,
569        H: TimerHandler<Self, Id>,
570    >(
571        &mut self,
572        instant: FakeInstant,
573        timers: I,
574        handler: &mut H,
575    ) where
576        Id: Debug + Hash + Eq;
577
578    /// Triggers timers for `duration` and expects them to be the given timers.
579    ///
580    /// Like `trigger_timers_and_expect_unordered`, except that timers will only
581    /// be triggered for `duration` (inclusive).
582    fn trigger_timers_for_and_expect<I: IntoIterator<Item = Id>, H: TimerHandler<Self, Id>>(
583        &mut self,
584        duration: Duration,
585        timers: I,
586        handler: &mut H,
587    ) where
588        Id: Debug + Hash + Eq;
589}
590
591// TODO(https://fxbug.dev/42081080): hold lock on `FakeTimerCtx` across entire
592// method to avoid potential race conditions.
593impl<Id: Clone, Ctx: WithFakeTimerContext<Id> + TimerBindingsTypes<UniqueTimerId = FakeTimerId>>
594    FakeTimerCtxExt<Id> for Ctx
595{
596    /// Triggers the next timer, if any, by calling `f` on it.
597    ///
598    /// `trigger_next_timer` triggers the next timer, if any, advances the
599    /// internal clock to the timer's scheduled time, and returns its ID.
600    fn trigger_next_timer<H: TimerHandler<Self, Id>>(&mut self, handler: &mut H) -> Option<Id> {
601        self.with_fake_timer_ctx_mut(|timers| {
602            timers.timers.pop().map(|InstantAndData(t, id)| {
603                timers.instant.time = t;
604                id
605            })
606        })
607        .map(|fake_timer| {
608            let (dispatch_id, timer_id) = fake_timer.into_dispatch_and_timer_id();
609            handler.handle_timer(self, dispatch_id.clone(), timer_id);
610            dispatch_id
611        })
612    }
613
614    /// Skips the current time forward until `instant`, triggering all timers
615    /// until then, inclusive, by giving them to `handler`.
616    ///
617    /// Returns the timers which were triggered.
618    ///
619    /// # Panics
620    ///
621    /// Panics if `instant` is in the past.
622    fn trigger_timers_until_instant<H: TimerHandler<Self, Id>>(
623        &mut self,
624        instant: FakeInstant,
625        handler: &mut H,
626    ) -> Vec<Id> {
627        assert!(instant >= self.with_fake_timer_ctx(|ctx| ctx.now()));
628        let mut timers = Vec::new();
629
630        while self.with_fake_timer_ctx_mut(|ctx| {
631            ctx.timers.peek().map(|InstantAndData(i, _id)| i <= &instant).unwrap_or(false)
632        }) {
633            timers.push(self.trigger_next_timer(handler).unwrap())
634        }
635
636        self.with_fake_timer_ctx_mut(|ctx| {
637            assert!(ctx.now() <= instant);
638            ctx.instant.time = instant;
639        });
640
641        timers
642    }
643
644    /// Skips the current time forward by `duration`, triggering all timers
645    /// until then, inclusive, by calling `f` on them.
646    ///
647    /// Returns the timers which were triggered.
648    fn trigger_timers_for<H: TimerHandler<Self, Id>>(
649        &mut self,
650        duration: Duration,
651        handler: &mut H,
652    ) -> Vec<Id> {
653        let instant = self.with_fake_timer_ctx(|ctx| ctx.now().saturating_add(duration));
654        // We know the call to `self.trigger_timers_until_instant` will not
655        // panic because we provide an instant that is greater than or equal
656        // to the current time.
657        self.trigger_timers_until_instant(instant, handler)
658    }
659
660    /// Triggers timers and expects them to be the given timers.
661    ///
662    /// The number of timers to be triggered is taken to be the number of
663    /// timers produced by `timers`. Timers may be triggered in any order.
664    ///
665    /// # Panics
666    ///
667    /// Panics under the following conditions:
668    /// - Fewer timers could be triggered than expected
669    /// - Timers were triggered that were not expected
670    /// - Timers that were expected were not triggered
671    #[track_caller]
672    fn trigger_timers_and_expect_unordered<I: IntoIterator<Item = Id>, H: TimerHandler<Self, Id>>(
673        &mut self,
674        timers: I,
675        handler: &mut H,
676    ) where
677        Id: Debug + Hash + Eq,
678    {
679        let mut timers = RefCountedHashSet::from_iter(timers);
680
681        for _ in 0..timers.len() {
682            let id = self.trigger_next_timer(handler).expect("ran out of timers to trigger");
683            match timers.remove(id.clone()) {
684                RemoveResult::Removed(()) | RemoveResult::StillPresent => {}
685                RemoveResult::NotPresent => panic!("triggered unexpected timer: {:?}", id),
686            }
687        }
688
689        if timers.len() > 0 {
690            let mut s = String::from("Expected timers did not trigger:");
691            for (id, count) in timers.iter_counts() {
692                s += &format!("\n\t{count}x {id:?}");
693            }
694            panic!("{}", s);
695        }
696    }
697
698    /// Triggers timers until `instant` and expects them to be the given
699    /// timers.
700    ///
701    /// Like `trigger_timers_and_expect_unordered`, except that timers will
702    /// only be triggered until `instant` (inclusive).
703    fn trigger_timers_until_and_expect_unordered<
704        I: IntoIterator<Item = Id>,
705        H: TimerHandler<Self, Id>,
706    >(
707        &mut self,
708        instant: FakeInstant,
709        timers: I,
710        handler: &mut H,
711    ) where
712        Id: Debug + Hash + Eq,
713    {
714        let mut timers = RefCountedHashSet::from_iter(timers);
715
716        let triggered_timers = self.trigger_timers_until_instant(instant, handler);
717
718        for id in triggered_timers {
719            match timers.remove(id.clone()) {
720                RemoveResult::Removed(()) | RemoveResult::StillPresent => {}
721                RemoveResult::NotPresent => panic!("triggered unexpected timer: {:?}", id),
722            }
723        }
724
725        if timers.len() > 0 {
726            let mut s = String::from("Expected timers did not trigger:");
727            for (id, count) in timers.iter_counts() {
728                s += &format!("\n\t{count}x {id:?}");
729            }
730            panic!("{}", s);
731        }
732    }
733
734    /// Triggers timers for `duration` and expects them to be the given
735    /// timers.
736    ///
737    /// Like `trigger_timers_and_expect_unordered`, except that timers will
738    /// only be triggered for `duration` (inclusive).
739    fn trigger_timers_for_and_expect<I: IntoIterator<Item = Id>, H: TimerHandler<Self, Id>>(
740        &mut self,
741        duration: Duration,
742        timers: I,
743        handler: &mut H,
744    ) where
745        Id: Debug + Hash + Eq,
746    {
747        let instant = self.with_fake_timer_ctx(|ctx| ctx.now().saturating_add(duration));
748        self.trigger_timers_until_and_expect_unordered(instant, timers, handler);
749    }
750}
751
752#[cfg(test)]
753mod tests {
754    use super::*;
755
756    use crate::HandleableTimer;
757
758    use alloc::vec;
759
760    const ONE_SEC: Duration = Duration::from_secs(1);
761    const ONE_SEC_INSTANT: FakeInstant = FakeInstant { offset: ONE_SEC };
762
763    #[derive(Debug, Eq, PartialEq, Clone, Hash)]
764    struct TimerId(usize);
765    #[derive(Default)]
766    struct CoreCtx(Vec<(TimerId, FakeInstant)>);
767
768    impl CoreCtx {
769        fn take(&mut self) -> Vec<(TimerId, FakeInstant)> {
770            core::mem::take(&mut self.0)
771        }
772    }
773
774    impl HandleableTimer<CoreCtx, FakeTimerCtx<Self>> for TimerId {
775        fn handle(
776            self,
777            CoreCtx(expired): &mut CoreCtx,
778            bindings_ctx: &mut FakeTimerCtx<Self>,
779            _: FakeTimerId,
780        ) {
781            expired.push((self, bindings_ctx.now()))
782        }
783    }
784
785    #[test]
786    fn instant_and_data() {
787        // Verify implementation of InstantAndData to be used as a complex
788        // type in a BinaryHeap.
789        let mut heap = BinaryHeap::<InstantAndData<usize>>::new();
790        let now = FakeInstant::default();
791
792        fn new_data(time: FakeInstant, id: usize) -> InstantAndData<usize> {
793            InstantAndData::new(time, id)
794        }
795
796        heap.push(new_data(now + Duration::from_secs(1), 1));
797        heap.push(new_data(now + Duration::from_secs(2), 2));
798
799        // Earlier timer is popped first.
800        assert_eq!(heap.pop().unwrap().1, 1);
801        assert_eq!(heap.pop().unwrap().1, 2);
802        assert_eq!(heap.pop(), None);
803
804        heap.push(new_data(now + Duration::from_secs(1), 1));
805        heap.push(new_data(now + Duration::from_secs(1), 1));
806
807        // Can pop twice with identical data.
808        assert_eq!(heap.pop().unwrap().1, 1);
809        assert_eq!(heap.pop().unwrap().1, 1);
810        assert_eq!(heap.pop(), None);
811    }
812
813    #[test]
814    fn fake_timer_context() {
815        let mut core_ctx = CoreCtx::default();
816        let mut bindings_ctx = FakeTimerCtx::<TimerId>::default();
817
818        // When no timers are installed, `trigger_next_timer` should return
819        // `false`.
820        assert_eq!(bindings_ctx.trigger_next_timer(&mut core_ctx), None);
821        assert_eq!(core_ctx.take(), vec![]);
822
823        let mut timer0 = bindings_ctx.new_timer(TimerId(0));
824        let mut timer1 = bindings_ctx.new_timer(TimerId(1));
825        let mut timer2 = bindings_ctx.new_timer(TimerId(2));
826
827        // No timer with id `0` exists yet.
828        assert_eq!(bindings_ctx.scheduled_instant(&mut timer0), None);
829
830        assert_eq!(bindings_ctx.schedule_timer(ONE_SEC, &mut timer0), None);
831
832        // Timer with id `0` scheduled to execute at `ONE_SEC_INSTANT`.
833        assert_eq!(bindings_ctx.scheduled_instant(&mut timer0).unwrap(), ONE_SEC_INSTANT);
834
835        assert_eq!(bindings_ctx.trigger_next_timer(&mut core_ctx), Some(TimerId(0)));
836        assert_eq!(core_ctx.take(), vec![(TimerId(0), ONE_SEC_INSTANT)]);
837
838        // After the timer fires, it should not still be scheduled at some
839        // instant.
840        assert_eq!(bindings_ctx.scheduled_instant(&mut timer0), None);
841
842        // The time should have been advanced.
843        assert_eq!(bindings_ctx.now(), ONE_SEC_INSTANT);
844
845        // Once it's been triggered, it should be canceled and not
846        // triggerable again.
847        assert_eq!(bindings_ctx.trigger_next_timer(&mut core_ctx), None);
848        assert_eq!(core_ctx.take(), vec![]);
849
850        // Unwind back time.
851        bindings_ctx.instant.time = Default::default();
852
853        // If we schedule a timer but then cancel it, it shouldn't fire.
854        assert_eq!(bindings_ctx.schedule_timer(ONE_SEC, &mut timer0), None);
855        assert_eq!(bindings_ctx.cancel_timer(&mut timer0), Some(ONE_SEC_INSTANT));
856        assert_eq!(bindings_ctx.trigger_next_timer(&mut core_ctx), None);
857        assert_eq!(core_ctx.take(), vec![]);
858
859        // If we schedule a timer but then schedule the same ID again, the
860        // second timer should overwrite the first one.
861        assert_eq!(bindings_ctx.schedule_timer(Duration::from_secs(0), &mut timer0), None);
862        assert_eq!(
863            bindings_ctx.schedule_timer(ONE_SEC, &mut timer0),
864            Some(Duration::from_secs(0).into())
865        );
866        assert_eq!(bindings_ctx.cancel_timer(&mut timer0), Some(ONE_SEC_INSTANT));
867
868        // If we schedule three timers and then run `trigger_timers_until`
869        // with the appropriate value, only two of them should fire.
870        assert_eq!(bindings_ctx.schedule_timer(Duration::from_secs(0), &mut timer0), None);
871        assert_eq!(bindings_ctx.schedule_timer(Duration::from_secs(1), &mut timer1), None);
872        assert_eq!(bindings_ctx.schedule_timer(Duration::from_secs(2), &mut timer2), None);
873        assert_eq!(
874            bindings_ctx.trigger_timers_until_instant(ONE_SEC_INSTANT, &mut core_ctx),
875            vec![TimerId(0), TimerId(1)],
876        );
877
878        // The first two timers should have fired.
879        assert_eq!(
880            core_ctx.take(),
881            vec![
882                (TimerId(0), FakeInstant::from(Duration::from_secs(0))),
883                (TimerId(1), ONE_SEC_INSTANT)
884            ]
885        );
886
887        // They should be canceled now.
888        assert_eq!(bindings_ctx.cancel_timer(&mut timer0), None);
889        assert_eq!(bindings_ctx.cancel_timer(&mut timer1), None);
890
891        // The clock should have been updated.
892        assert_eq!(bindings_ctx.now(), ONE_SEC_INSTANT);
893
894        // The last timer should not have fired.
895        assert_eq!(
896            bindings_ctx.cancel_timer(&mut timer2),
897            Some(FakeInstant::from(Duration::from_secs(2)))
898        );
899    }
900
901    #[test]
902    fn trigger_timers_until_and_expect_unordered() {
903        // If the requested instant does not coincide with a timer trigger
904        // point, the time should still be advanced.
905        let mut core_ctx = CoreCtx::default();
906        let mut bindings_ctx = FakeTimerCtx::default();
907        let mut timer0 = bindings_ctx.new_timer(TimerId(0));
908        let mut timer1 = bindings_ctx.new_timer(TimerId(1));
909        assert_eq!(bindings_ctx.schedule_timer(Duration::from_secs(0), &mut timer0), None);
910        assert_eq!(bindings_ctx.schedule_timer(Duration::from_secs(2), &mut timer1), None);
911        bindings_ctx.trigger_timers_until_and_expect_unordered(
912            ONE_SEC_INSTANT,
913            vec![TimerId(0)],
914            &mut core_ctx,
915        );
916        assert_eq!(bindings_ctx.now(), ONE_SEC_INSTANT);
917    }
918}