netstack3_base/testutil/
fake_network.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//! Fake network definitions to place core contexts in a network together.
6
7use alloc::collections::BinaryHeap;
8use alloc::vec::Vec;
9use core::fmt::Debug;
10use core::hash::Hash;
11use core::time::Duration;
12use netstack3_hashmap::HashMap;
13
14use packet::Buf;
15
16use crate::InstantContext as _;
17use crate::testutil::{
18    FakeInstant, FakeTimerId, InstantAndData, WithFakeFrameContext, WithFakeTimerContext,
19};
20
21/// A fake network, composed of many `FakeCoreCtx`s.
22///
23/// Provides a utility to have many contexts keyed by `CtxId` that can
24/// exchange frames.
25pub struct FakeNetwork<Spec: FakeNetworkSpec, CtxId, Links> {
26    links: Links,
27    current_time: FakeInstant,
28    pending_frames: BinaryHeap<PendingFrame<CtxId, Spec::RecvMeta>>,
29    // Declare `contexts` last to ensure that it is dropped last. See
30    // https://doc.rust-lang.org/std/ops/trait.Drop.html#drop-order for
31    // details.
32    contexts: HashMap<CtxId, Spec::Context>,
33}
34
35/// The data associated with a [`FakeNetwork`]'s pending frame.
36#[derive(Debug)]
37pub struct PendingFrameData<CtxId, Meta> {
38    /// The frame's destination context ID.
39    pub dst_context: CtxId,
40    /// The associated frame metadata.
41    pub meta: Meta,
42    /// Frame contents.
43    pub frame: Vec<u8>,
44}
45
46/// A [`PendingFrameData`] and the instant it was sent.
47pub type PendingFrame<CtxId, Meta> = InstantAndData<PendingFrameData<CtxId, Meta>>;
48
49/// A network spec that defines a [`FakeNetwork`].
50pub trait FakeNetworkSpec: Sized {
51    /// The context type, which represents a node in the network.
52    type Context: WithFakeTimerContext<Self::TimerId>;
53    /// The type of timer IDs handled by [`Self::Context`].
54    type TimerId: Clone;
55    /// The type of metadata associated with frames sent by this nodes in the
56    /// network.
57    type SendMeta;
58    /// The type of metadata associated with frames received by nodes in the
59    /// network.
60    type RecvMeta;
61
62    /// Handles a single received frame by `ctx`.
63    fn handle_frame(ctx: &mut Self::Context, recv: Self::RecvMeta, data: Buf<Vec<u8>>);
64    /// Handles a single timer id in `ctx`.
65    ///
66    /// `dispatch` is the timer's dispatch identifier, i.e., an implementer of
67    /// `HandleableTimer`. `timer` is the unique timer identifier for the fake
68    /// timer that fired.
69    fn handle_timer(ctx: &mut Self::Context, dispatch: Self::TimerId, timer: FakeTimerId);
70    /// Processes any context-internal queues, returning `true` if any work
71    /// was done.
72    ///
73    /// This is used to drive queued frames that may be sitting inside the
74    /// context and invisible to the [`FakeNetwork`].
75    fn process_queues(ctx: &mut Self::Context) -> bool;
76
77    /// Extracts accesses to fake frames from [`Self::Context`].
78    fn fake_frames(ctx: &mut Self::Context) -> &mut impl WithFakeFrameContext<Self::SendMeta>;
79
80    /// Creates a new fake network from this spec.
81    fn new_network<CtxId, Links, I>(contexts: I, links: Links) -> FakeNetwork<Self, CtxId, Links>
82    where
83        CtxId: Eq + Hash + Copy + Debug,
84        I: IntoIterator<Item = (CtxId, Self::Context)>,
85        Links: FakeNetworkLinks<Self::SendMeta, Self::RecvMeta, CtxId>,
86    {
87        FakeNetwork::new(contexts, links)
88    }
89}
90
91/// A set of links in a `FakeNetwork`.
92///
93/// A `FakeNetworkLinks` represents the set of links in a `FakeNetwork`.
94/// It exposes the link information by providing the ability to map from a
95/// frame's sending metadata - including its context, local state, and
96/// `SendMeta` - to the set of appropriate receivers, each represented by
97/// a context ID, receive metadata, and latency.
98pub trait FakeNetworkLinks<SendMeta, RecvMeta, CtxId> {
99    /// Maps a link from the send metadata of the context to the receive
100    /// metadata.
101    fn map_link(&self, ctx: CtxId, meta: SendMeta) -> Vec<(CtxId, RecvMeta, Option<Duration>)>;
102}
103
104impl<SendMeta, RecvMeta, CtxId, F: Fn(CtxId, SendMeta) -> Vec<(CtxId, RecvMeta, Option<Duration>)>>
105    FakeNetworkLinks<SendMeta, RecvMeta, CtxId> for F
106{
107    fn map_link(&self, ctx: CtxId, meta: SendMeta) -> Vec<(CtxId, RecvMeta, Option<Duration>)> {
108        (self)(ctx, meta)
109    }
110}
111
112/// The result of a single step in a `FakeNetwork`
113#[derive(Debug)]
114pub struct StepResult {
115    /// The number of timers fired.
116    pub timers_fired: usize,
117    /// The number of frames sent.
118    pub frames_sent: usize,
119    /// The number of contexts that had frames queued in their receive queues.
120    pub contexts_with_queued_frames: usize,
121}
122
123impl StepResult {
124    fn new_idle() -> Self {
125        Self { timers_fired: 0, frames_sent: 0, contexts_with_queued_frames: 0 }
126    }
127
128    /// Returns `true` if the last step did not perform any operations.
129    pub fn is_idle(&self) -> bool {
130        return self.timers_fired == 0
131            && self.frames_sent == 0
132            && self.contexts_with_queued_frames == 0;
133    }
134}
135
136impl<Spec, CtxId, Links> FakeNetwork<Spec, CtxId, Links>
137where
138    CtxId: Eq + Hash,
139    Spec: FakeNetworkSpec,
140{
141    /// Retrieves a context named `context`.
142    pub fn context<K: Into<CtxId>>(&mut self, context: K) -> &mut Spec::Context {
143        self.contexts.get_mut(&context.into()).unwrap()
144    }
145
146    /// Calls `f` with a mutable reference to the context named `context`.
147    pub fn with_context<K: Into<CtxId>, O, F: FnOnce(&mut Spec::Context) -> O>(
148        &mut self,
149        context: K,
150        f: F,
151    ) -> O {
152        f(self.context(context))
153    }
154}
155
156impl<Spec, CtxId, Links> FakeNetwork<Spec, CtxId, Links>
157where
158    Spec: FakeNetworkSpec,
159    CtxId: Eq + Hash + Copy + Debug,
160    Links: FakeNetworkLinks<Spec::SendMeta, Spec::RecvMeta, CtxId>,
161{
162    /// Creates a new `FakeNetwork`.
163    ///
164    /// Creates a new `FakeNetwork` with the collection of `FakeCoreCtx`s in
165    /// `contexts`. `Ctx`s are named by type parameter `CtxId`.
166    ///
167    /// # Panics
168    ///
169    /// Calls to `new` will panic if given a `FakeCoreCtx` with timer events.
170    /// `FakeCoreCtx`s given to `FakeNetwork` **must not** have any timer
171    /// events already attached to them, because `FakeNetwork` maintains
172    /// all the internal timers in dispatchers in sync to enable synchronous
173    /// simulation steps.
174    pub fn new<I: IntoIterator<Item = (CtxId, Spec::Context)>>(contexts: I, links: Links) -> Self {
175        let mut contexts = contexts.into_iter().collect::<HashMap<_, _>>();
176        // Take the current time to be the latest of the times of any of the
177        // contexts. This ensures that no context has state which is based
178        // on having observed a time in the future, which could cause bugs.
179        // For any contexts which have a time further in the past, it will
180        // appear as though time has jumped forwards, but that's fine. The
181        // only way that this could be a problem would be if a timer were
182        // installed which should have fired in the interim (code might
183        // become buggy in this case). However, we assert below that no
184        // timers are installed.
185        let latest_time = contexts
186            .iter()
187            .map(|(_, ctx)| ctx.with_fake_timer_ctx(|ctx| ctx.instant.time))
188            .max()
189            // If `max` returns `None`, it means that we were called with no
190            // contexts. That's kind of silly, but whatever - arbitrarily
191            // choose the current time as the epoch.
192            .unwrap_or_else(FakeInstant::default);
193
194        assert!(
195            !contexts
196                .iter()
197                .any(|(_, ctx)| { !ctx.with_fake_timer_ctx(|ctx| ctx.timers.is_empty()) }),
198            "can't start network with contexts that already have timers set"
199        );
200
201        // Synchronize all contexts' current time to the latest time of any
202        // of the contexts. See comment above for more details.
203        for (_, ctx) in contexts.iter_mut() {
204            ctx.with_fake_timer_ctx_mut(|ctx| ctx.instant.time = latest_time);
205        }
206
207        Self { contexts, current_time: latest_time, pending_frames: BinaryHeap::new(), links }
208    }
209
210    /// Iterates over pending frames in an arbitrary order.
211    pub fn iter_pending_frames(
212        &self,
213    ) -> impl Iterator<Item = &PendingFrame<CtxId, Spec::RecvMeta>> {
214        self.pending_frames.iter()
215    }
216
217    /// Asserts no pending frames exist.
218    #[track_caller]
219    pub fn assert_no_pending_frames(&self)
220    where
221        Spec::RecvMeta: Debug,
222    {
223        assert!(self.pending_frames.is_empty(), "pending frames: {:?}", self.pending_frames);
224    }
225
226    /// Drops all pending frames; they will not be delivered.
227    pub fn drop_pending_frames(&mut self) {
228        self.pending_frames.clear();
229    }
230
231    /// Performs a single step in network simulation.
232    ///
233    /// `step` performs a single logical step in the collection of `Ctx`s
234    /// held by this `FakeNetwork`. A single step consists of the following
235    /// operations:
236    ///
237    /// - All pending frames, kept in each `FakeCoreCtx`, are mapped to their
238    ///   destination context/device pairs and moved to an internal
239    ///   collection of pending frames.
240    /// - The collection of pending timers and scheduled frames is inspected
241    ///   and a simulation time step is retrieved, which will cause a next
242    ///   event to trigger. The simulation time is updated to the new time.
243    /// - All scheduled frames whose deadline is less than or equal to the
244    ///   new simulation time are sent to their destinations, handled using
245    ///   `handle_frame`.
246    /// - All timer events whose deadline is less than or equal to the new
247    ///   simulation time are fired, handled using `handle_timer`.
248    ///
249    /// If any new events are created during the operation of frames or
250    /// timers, they **will not** be taken into account in the current
251    /// `step`. That is, `step` collects all the pending events before
252    /// dispatching them, ensuring that an infinite loop can't be created as
253    /// a side effect of calling `step`.
254    ///
255    /// The return value of `step` indicates which of the operations were
256    /// performed.
257    ///
258    /// # Panics
259    ///
260    /// If `FakeNetwork` was set up with a bad `links`, calls to `step` may
261    /// panic when trying to route frames to their context/device
262    /// destinations.
263    pub fn step(&mut self) -> StepResult
264    where
265        Spec::TimerId: Debug,
266    {
267        self.step_with(|_, meta, buf| Some((meta, buf)))
268    }
269
270    /// Like [`FakeNetwork::step`], but receives a function
271    /// `filter_map_frame` that can modify the an inbound frame before
272    /// delivery or drop it altogether by returning `None`.
273    pub fn step_with<
274        F: FnMut(
275            &mut Spec::Context,
276            Spec::RecvMeta,
277            Buf<Vec<u8>>,
278        ) -> Option<(Spec::RecvMeta, Buf<Vec<u8>>)>,
279    >(
280        &mut self,
281        filter_map_frame: F,
282    ) -> StepResult
283    where
284        Spec::TimerId: Debug,
285    {
286        let mut ret = StepResult::new_idle();
287        // Drive all queues before checking for the network and time
288        // simulation.
289        for (_, ctx) in self.contexts.iter_mut() {
290            if Spec::process_queues(ctx) {
291                ret.contexts_with_queued_frames += 1;
292            }
293        }
294
295        self.collect_frames();
296
297        let next_step = if let Some(t) = self.next_step() {
298            t
299        } else {
300            return ret;
301        };
302
303        // This assertion holds the contract that `next_step` does not
304        // return a time in the past.
305        assert!(next_step >= self.current_time);
306
307        // Move time forward:
308        self.current_time = next_step;
309        for (_, ctx) in self.contexts.iter_mut() {
310            ctx.with_fake_timer_ctx_mut(|ctx| ctx.instant.time = next_step);
311        }
312
313        ret.frames_sent = self.dispatch_pending_frames(filter_map_frame);
314
315        // Dispatch all pending timers.
316        for (_, ctx) in self.contexts.iter_mut() {
317            // We have to collect the timers before dispatching them, to
318            // avoid an infinite loop in case handle_timer schedules another
319            // timer for the same or older FakeInstant.
320            let mut timers = Vec::<(Spec::TimerId, FakeTimerId)>::new();
321            ctx.with_fake_timer_ctx_mut(|ctx| {
322                while let Some(InstantAndData(t, timer)) = ctx.timers.peek() {
323                    // TODO(https://github.com/rust-lang/rust/issues/53667):
324                    // Remove this break once let_chains is stable.
325                    if *t > ctx.now() {
326                        break;
327                    }
328                    timers.push((timer.dispatch_id.clone(), timer.timer_id()));
329                    assert_ne!(ctx.timers.pop(), None);
330                }
331            });
332
333            for (dispatch_id, timer_id) in timers {
334                Spec::handle_timer(ctx, dispatch_id, timer_id);
335                ret.timers_fired += 1;
336            }
337        }
338        ret
339    }
340
341    /// Collects and dispatches all pending frames without advancing time or
342    /// triggering any timers.
343    ///
344    /// # Panics
345    ///
346    /// Panics under the same conditions as [`dispatch_pending_frames`].
347    pub fn step_deliver_frames(&mut self) -> StepResult
348    where
349        Spec::TimerId: Debug,
350    {
351        self.step_deliver_frames_with(|_, meta, frame| Some((meta, frame)))
352    }
353
354    /// Like [`FakeNetwork::step_deliver_frames`], but receives a function
355    /// `filter_map_frame` that can modify frames, or drop them if it returns
356    /// `None`.
357    pub fn step_deliver_frames_with<
358        F: FnMut(
359            &mut Spec::Context,
360            Spec::RecvMeta,
361            Buf<Vec<u8>>,
362        ) -> Option<(Spec::RecvMeta, Buf<Vec<u8>>)>,
363    >(
364        &mut self,
365        filter_map_frame: F,
366    ) -> StepResult
367    where
368        Spec::TimerId: Debug,
369    {
370        let mut ret = StepResult::new_idle();
371        // Drive all queues before checking for the network simulation.
372        for (_, ctx) in self.contexts.iter_mut() {
373            if Spec::process_queues(ctx) {
374                ret.contexts_with_queued_frames += 1;
375            }
376        }
377
378        self.collect_frames();
379        ret.frames_sent = self.dispatch_pending_frames(filter_map_frame);
380
381        ret
382    }
383
384    /// Runs the network until it is starved of events.
385    ///
386    /// # Panics
387    ///
388    /// Panics if 1,000,000 steps are performed without becoming idle.
389    /// Also panics under the same conditions as [`step`].
390    pub fn run_until_idle(&mut self)
391    where
392        Spec::TimerId: Debug,
393    {
394        self.run_until_idle_with(|_, meta, frame| Some((meta, frame)))
395    }
396
397    /// Like [`FakeNetwork::run_until_idle`] but receives a function
398    /// `filter_map_frame` that can modify the an inbound frame before
399    /// delivery or drop it altogether by returning `None`.
400    pub fn run_until_idle_with<
401        F: FnMut(
402            &mut Spec::Context,
403            Spec::RecvMeta,
404            Buf<Vec<u8>>,
405        ) -> Option<(Spec::RecvMeta, Buf<Vec<u8>>)>,
406    >(
407        &mut self,
408        mut filter_map_frame: F,
409    ) where
410        Spec::TimerId: Debug,
411    {
412        for _ in 0..1_000_000 {
413            if self.step_with(&mut filter_map_frame).is_idle() {
414                return;
415            }
416        }
417        panic!("FakeNetwork seems to have gotten stuck in a loop.");
418    }
419
420    /// Collects all queued frames.
421    ///
422    /// Collects all pending frames and schedules them for delivery to the
423    /// destination context/device based on the result of `links`. The
424    /// collected frames are queued for dispatching in the `FakeNetwork`,
425    /// ordered by their scheduled delivery time given by the latency result
426    /// provided by `links`.
427    pub fn collect_frames(&mut self) {
428        let all_frames = self.contexts.iter_mut().filter_map(|(n, ctx)| {
429            Spec::fake_frames(ctx).with_fake_frame_ctx_mut(|ctx| {
430                let frames = ctx.take_frames();
431                if frames.is_empty() { None } else { Some((n.clone(), frames)) }
432            })
433        });
434
435        for (src_context, frames) in all_frames {
436            for (send_meta, frame) in frames.into_iter() {
437                for (dst_context, recv_meta, latency) in self.links.map_link(src_context, send_meta)
438                {
439                    self.pending_frames.push(PendingFrame::new(
440                        self.current_time + latency.unwrap_or(Duration::from_millis(0)),
441                        PendingFrameData { frame: frame.clone(), dst_context, meta: recv_meta },
442                    ));
443                }
444            }
445        }
446    }
447
448    /// Dispatches scheduled frames that were previously collected with
449    /// [`collect_frames`].
450    ///
451    /// Only frames for which the current deadline is less than or equal to the
452    /// current simulation time are delivered.
453    ///
454    /// # Panics
455    ///
456    /// If `FakeNetwork` was set up with a bad `links`, calls may panic when
457    /// trying to route frames to their context/device destinations.
458    pub fn dispatch_pending_frames<
459        F: FnMut(
460            &mut Spec::Context,
461            Spec::RecvMeta,
462            Buf<Vec<u8>>,
463        ) -> Option<(Spec::RecvMeta, Buf<Vec<u8>>)>,
464    >(
465        &mut self,
466        mut filter_map_frame: F,
467    ) -> usize {
468        let mut frames_sent = 0;
469        while let Some(InstantAndData(t, _)) = self.pending_frames.peek() {
470            // TODO(https://github.com/rust-lang/rust/issues/53667): Remove
471            // this break once let_chains is stable.
472            if *t > self.current_time {
473                break;
474            }
475            // We can unwrap because we just peeked.
476            let PendingFrameData { dst_context, meta, frame } =
477                self.pending_frames.pop().unwrap().1;
478            let dst_context = self.context(dst_context);
479            if let Some((meta, frame)) = filter_map_frame(dst_context, meta, Buf::new(frame, ..)) {
480                Spec::handle_frame(dst_context, meta, frame)
481            }
482            frames_sent += 1;
483        }
484
485        frames_sent
486    }
487
488    /// Calculates the next `FakeInstant` when events are available.
489    ///
490    /// Returns the smallest `FakeInstant` greater than or equal to the
491    /// current time for which an event is available. If no events are
492    /// available, returns `None`.
493    pub fn next_step(&self) -> Option<FakeInstant> {
494        // Get earliest timer in all contexts.
495        let next_timer = self
496            .contexts
497            .iter()
498            .filter_map(|(_, ctx)| {
499                ctx.with_fake_timer_ctx(|ctx| match ctx.timers.peek() {
500                    Some(tmr) => Some(tmr.0),
501                    None => None,
502                })
503            })
504            .min();
505        // Get the instant for the next packet.
506        let next_packet_due = self.pending_frames.peek().map(|t| t.0);
507
508        // Return the earliest of them both, and protect against returning a
509        // time in the past.
510        match next_timer {
511            Some(t) if next_packet_due.is_some() => Some(t).min(next_packet_due),
512            Some(t) => Some(t),
513            None => next_packet_due,
514        }
515        .map(|t| t.max(self.current_time))
516    }
517}
518
519#[cfg(test)]
520mod tests {
521    use super::*;
522
523    use alloc::vec;
524
525    use crate::testutil::{FakeFrameCtx, FakeTimerCtx};
526    use crate::{SendFrameContext as _, TimerContext as _};
527
528    // Define some fake contexts and links specifically to test the fake
529    // network timers implementation.
530    #[derive(Default)]
531    struct FakeNetworkTestCtx {
532        timer_ctx: FakeTimerCtx<u32>,
533        frame_ctx: FakeFrameCtx<()>,
534        fired_timers: HashMap<u32, usize>,
535        frames_received: usize,
536    }
537
538    impl FakeNetworkTestCtx {
539        #[track_caller]
540        fn drain_and_assert_timers(&mut self, iter: impl IntoIterator<Item = (u32, usize)>) {
541            for (timer, fire_count) in iter {
542                assert_eq!(self.fired_timers.remove(&timer), Some(fire_count), "for timer {timer}");
543            }
544            assert!(self.fired_timers.is_empty(), "remaining timers: {:?}", self.fired_timers);
545        }
546
547        /// Generates an arbitrary request.
548        fn request() -> Vec<u8> {
549            vec![1, 2, 3, 4]
550        }
551
552        /// Generates an arbitrary response.
553        fn response() -> Vec<u8> {
554            vec![4, 3, 2, 1]
555        }
556    }
557
558    impl FakeNetworkSpec for FakeNetworkTestCtx {
559        type Context = Self;
560        type TimerId = u32;
561        type SendMeta = ();
562        type RecvMeta = ();
563
564        fn handle_frame(ctx: &mut Self, _recv: (), data: Buf<Vec<u8>>) {
565            ctx.frames_received += 1;
566            // If data is a request, generate a response. This mimics ICMP echo
567            // behavior.
568            if data.into_inner() == Self::request() {
569                ctx.frame_ctx.push((), Self::response())
570            }
571        }
572
573        fn handle_timer(ctx: &mut Self, dispatch: u32, _: FakeTimerId) {
574            *ctx.fired_timers.entry(dispatch).or_insert(0) += 1;
575        }
576
577        fn process_queues(_ctx: &mut Self) -> bool {
578            false
579        }
580
581        fn fake_frames(ctx: &mut Self) -> &mut impl WithFakeFrameContext<Self::SendMeta> {
582            ctx
583        }
584    }
585
586    impl WithFakeFrameContext<()> for FakeNetworkTestCtx {
587        fn with_fake_frame_ctx_mut<O, F: FnOnce(&mut FakeFrameCtx<()>) -> O>(&mut self, f: F) -> O {
588            f(&mut self.frame_ctx)
589        }
590    }
591
592    impl WithFakeTimerContext<u32> for FakeNetworkTestCtx {
593        fn with_fake_timer_ctx<O, F: FnOnce(&FakeTimerCtx<u32>) -> O>(&self, f: F) -> O {
594            f(&self.timer_ctx)
595        }
596
597        fn with_fake_timer_ctx_mut<O, F: FnOnce(&mut FakeTimerCtx<u32>) -> O>(
598            &mut self,
599            f: F,
600        ) -> O {
601            f(&mut self.timer_ctx)
602        }
603    }
604
605    fn new_fake_network_with_latency(
606        latency: Option<Duration>,
607    ) -> FakeNetwork<FakeNetworkTestCtx, i32, impl FakeNetworkLinks<(), (), i32>> {
608        FakeNetwork::new(
609            [(1, FakeNetworkTestCtx::default()), (2, FakeNetworkTestCtx::default())],
610            move |id, ()| {
611                vec![(
612                    match id {
613                        1 => 2,
614                        2 => 1,
615                        _ => unreachable!(),
616                    },
617                    (),
618                    latency,
619                )]
620            },
621        )
622    }
623
624    #[test]
625    fn timers() {
626        let mut net = new_fake_network_with_latency(None);
627
628        let (mut t1, mut t4, mut t5) =
629            net.with_context(1, |FakeNetworkTestCtx { timer_ctx, .. }| {
630                (timer_ctx.new_timer(1), timer_ctx.new_timer(4), timer_ctx.new_timer(5))
631            });
632
633        net.with_context(1, |FakeNetworkTestCtx { timer_ctx, .. }| {
634            assert_eq!(timer_ctx.schedule_timer(Duration::from_secs(1), &mut t1), None);
635            assert_eq!(timer_ctx.schedule_timer(Duration::from_secs(4), &mut t4), None);
636            assert_eq!(timer_ctx.schedule_timer(Duration::from_secs(5), &mut t5), None);
637        });
638
639        let (mut t2, mut t3, mut t6) =
640            net.with_context(2, |FakeNetworkTestCtx { timer_ctx, .. }| {
641                (timer_ctx.new_timer(2), timer_ctx.new_timer(3), timer_ctx.new_timer(6))
642            });
643
644        net.with_context(2, |FakeNetworkTestCtx { timer_ctx, .. }| {
645            assert_eq!(timer_ctx.schedule_timer(Duration::from_secs(2), &mut t2), None);
646            assert_eq!(timer_ctx.schedule_timer(Duration::from_secs(3), &mut t3), None);
647            assert_eq!(timer_ctx.schedule_timer(Duration::from_secs(5), &mut t6), None);
648        });
649
650        // No timers fired before.
651        net.context(1).drain_and_assert_timers([]);
652        net.context(2).drain_and_assert_timers([]);
653        assert_eq!(net.step().timers_fired, 1);
654        // Only timer in context 1 should have fired.
655        net.context(1).drain_and_assert_timers([(1, 1)]);
656        net.context(2).drain_and_assert_timers([]);
657        assert_eq!(net.step().timers_fired, 1);
658        // Only timer in context 2 should have fired.
659        net.context(1).drain_and_assert_timers([]);
660        net.context(2).drain_and_assert_timers([(2, 1)]);
661        assert_eq!(net.step().timers_fired, 1);
662        // Only timer in context 2 should have fired.
663        net.context(1).drain_and_assert_timers([]);
664        net.context(2).drain_and_assert_timers([(3, 1)]);
665        assert_eq!(net.step().timers_fired, 1);
666        // Only timer in context 1 should have fired.
667        net.context(1).drain_and_assert_timers([(4, 1)]);
668        net.context(2).drain_and_assert_timers([]);
669        assert_eq!(net.step().timers_fired, 2);
670        // Both timers have fired at the same time.
671        net.context(1).drain_and_assert_timers([(5, 1)]);
672        net.context(2).drain_and_assert_timers([(6, 1)]);
673
674        assert!(net.step().is_idle());
675        // Check that current time on contexts tick together.
676        let t1 = net.with_context(1, |FakeNetworkTestCtx { timer_ctx, .. }| timer_ctx.now());
677        let t2 = net.with_context(2, |FakeNetworkTestCtx { timer_ctx, .. }| timer_ctx.now());
678        assert_eq!(t1, t2);
679    }
680
681    #[test]
682    fn until_idle() {
683        let mut net = new_fake_network_with_latency(None);
684
685        let mut t1 =
686            net.with_context(1, |FakeNetworkTestCtx { timer_ctx, .. }| timer_ctx.new_timer(1));
687        net.with_context(1, |FakeNetworkTestCtx { timer_ctx, .. }| {
688            assert_eq!(timer_ctx.schedule_timer(Duration::from_secs(1), &mut t1), None);
689        });
690
691        let (mut t2, mut t3) = net.with_context(2, |FakeNetworkTestCtx { timer_ctx, .. }| {
692            (timer_ctx.new_timer(2), timer_ctx.new_timer(3))
693        });
694        net.with_context(2, |FakeNetworkTestCtx { timer_ctx, .. }| {
695            assert_eq!(timer_ctx.schedule_timer(Duration::from_secs(2), &mut t2), None);
696            assert_eq!(timer_ctx.schedule_timer(Duration::from_secs(3), &mut t3), None);
697        });
698
699        while !net.step().is_idle() && net.context(1).fired_timers.len() < 1
700            || net.context(2).fired_timers.len() < 1
701        {}
702        // Assert that we stopped before all times were fired, meaning we can
703        // step again.
704        assert_eq!(net.step().timers_fired, 1);
705    }
706
707    #[test]
708    fn delayed_packets() {
709        // Create a network that takes 5ms to get any packet to go through.
710        let mut net = new_fake_network_with_latency(Some(Duration::from_millis(5)));
711
712        // 1 sends 2 a request and schedules a timer.
713        let mut t11 =
714            net.with_context(1, |FakeNetworkTestCtx { timer_ctx, .. }| timer_ctx.new_timer(1));
715        net.with_context(1, |FakeNetworkTestCtx { frame_ctx, timer_ctx, .. }| {
716            frame_ctx.push((), FakeNetworkTestCtx::request());
717            assert_eq!(timer_ctx.schedule_timer(Duration::from_millis(3), &mut t11), None);
718        });
719        // 2 schedules some timers.
720        let (mut t21, mut t22) = net.with_context(2, |FakeNetworkTestCtx { timer_ctx, .. }| {
721            (timer_ctx.new_timer(1), timer_ctx.new_timer(2))
722        });
723        net.with_context(2, |FakeNetworkTestCtx { timer_ctx, .. }| {
724            assert_eq!(timer_ctx.schedule_timer(Duration::from_millis(7), &mut t22), None);
725            assert_eq!(timer_ctx.schedule_timer(Duration::from_millis(10), &mut t21), None);
726        });
727
728        // Order of expected events is as follows:
729        // - ctx1's timer expires at t = 3
730        // - ctx2 receives ctx1's packet at t = 5
731        // - ctx2's timer expires at t = 7
732        // - ctx1 receives ctx2's response and ctx2's last timer fires at t = 10
733
734        let assert_full_state = |net: &mut FakeNetwork<FakeNetworkTestCtx, _, _>,
735                                 ctx1_timers,
736                                 ctx2_timers,
737                                 ctx2_frames,
738                                 ctx1_frames| {
739            let ctx1 = net.context(1);
740            assert_eq!(ctx1.fired_timers.len(), ctx1_timers);
741            assert_eq!(ctx1.frames_received, ctx1_frames);
742            let ctx2 = net.context(2);
743            assert_eq!(ctx2.fired_timers.len(), ctx2_timers);
744            assert_eq!(ctx2.frames_received, ctx2_frames);
745        };
746
747        assert_eq!(net.step().timers_fired, 1);
748        assert_full_state(&mut net, 1, 0, 0, 0);
749        assert_eq!(net.step().frames_sent, 1);
750        assert_full_state(&mut net, 1, 0, 1, 0);
751        assert_eq!(net.step().timers_fired, 1);
752        assert_full_state(&mut net, 1, 1, 1, 0);
753        let step = net.step();
754        assert_eq!(step.frames_sent, 1);
755        assert_eq!(step.timers_fired, 1);
756        assert_full_state(&mut net, 1, 2, 1, 1);
757
758        // Should've starved all events.
759        assert!(net.step().is_idle());
760    }
761
762    #[test]
763    fn fake_network_transmits_packets() {
764        let mut net = new_fake_network_with_latency(None);
765
766        // Send a frame from 1 to 2.
767        net.with_context(1, |FakeNetworkTestCtx { frame_ctx, .. }| {
768            frame_ctx.send_frame(&mut (), (), Buf::new(FakeNetworkTestCtx::request(), ..)).unwrap();
769        });
770
771        // Send from 1 to 2.
772        assert_eq!(net.step().frames_sent, 1);
773        // Respond from 2 to 1.
774        assert_eq!(net.step().frames_sent, 1);
775        // Should've starved all events.
776        assert!(net.step().is_idle());
777    }
778
779    #[test]
780    fn send_to_many() {
781        let mut net = FakeNetworkTestCtx::new_network(
782            [
783                (1, FakeNetworkTestCtx::default()),
784                (2, FakeNetworkTestCtx::default()),
785                (3, FakeNetworkTestCtx::default()),
786            ],
787            |id, ()| match id {
788                // 1 sends to both 2 and 3.
789                1 => vec![(2, (), None), (3, (), None)],
790                // 2 only sends to 1.
791                2 => vec![(1, (), None)],
792                // 3 doesn't send anything.
793                3 => vec![],
794                _ => unreachable!(),
795            },
796        );
797        net.assert_no_pending_frames();
798
799        // 2 and 3 should get any packet sent by 1.
800        net.with_context(1, |FakeNetworkTestCtx { frame_ctx, .. }| {
801            frame_ctx.send_frame(&mut (), (), Buf::new(vec![], ..)).unwrap();
802        });
803        net.collect_frames();
804        assert_eq!(net.iter_pending_frames().count(), 2);
805        assert!(net.iter_pending_frames().any(|InstantAndData(_, x)| x.dst_context == 2));
806        assert!(net.iter_pending_frames().any(|InstantAndData(_, x)| x.dst_context == 3));
807        net.drop_pending_frames();
808
809        // Only 1 should get packets sent by 2.
810        net.with_context(2, |FakeNetworkTestCtx { frame_ctx, .. }| {
811            frame_ctx.send_frame(&mut (), (), Buf::new(vec![], ..)).unwrap();
812        });
813        net.collect_frames();
814        assert_eq!(net.iter_pending_frames().count(), 1);
815        assert!(net.iter_pending_frames().any(|InstantAndData(_, x)| x.dst_context == 1));
816        net.drop_pending_frames();
817
818        // No one receives packets sent by 3.
819        net.with_context(3, |FakeNetworkTestCtx { frame_ctx, .. }| {
820            frame_ctx.send_frame(&mut (), (), Buf::new(vec![], ..)).unwrap();
821        });
822        net.collect_frames();
823        net.assert_no_pending_frames();
824
825        // Because we didn't run the simulation, no one actually received any of
826        // these frames they were always in the pending queue.
827        for i in 1..=3 {
828            assert_eq!(net.context(i).frames_received, 0, "context: {i}");
829        }
830    }
831}