Skip to main content

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                    && *t <= ctx.now()
324                {
325                    timers.push((timer.dispatch_id.clone(), timer.timer_id()));
326                    assert_ne!(ctx.timers.pop(), None);
327                }
328            });
329
330            for (dispatch_id, timer_id) in timers {
331                Spec::handle_timer(ctx, dispatch_id, timer_id);
332                ret.timers_fired += 1;
333            }
334        }
335        ret
336    }
337
338    /// Collects and dispatches all pending frames without advancing time or
339    /// triggering any timers.
340    ///
341    /// # Panics
342    ///
343    /// Panics under the same conditions as [`dispatch_pending_frames`].
344    pub fn step_deliver_frames(&mut self) -> StepResult
345    where
346        Spec::TimerId: Debug,
347    {
348        self.step_deliver_frames_with(|_, meta, frame| Some((meta, frame)))
349    }
350
351    /// Like [`FakeNetwork::step_deliver_frames`], but receives a function
352    /// `filter_map_frame` that can modify frames, or drop them if it returns
353    /// `None`.
354    pub fn step_deliver_frames_with<
355        F: FnMut(
356            &mut Spec::Context,
357            Spec::RecvMeta,
358            Buf<Vec<u8>>,
359        ) -> Option<(Spec::RecvMeta, Buf<Vec<u8>>)>,
360    >(
361        &mut self,
362        filter_map_frame: F,
363    ) -> StepResult
364    where
365        Spec::TimerId: Debug,
366    {
367        let mut ret = StepResult::new_idle();
368        // Drive all queues before checking for the network simulation.
369        for (_, ctx) in self.contexts.iter_mut() {
370            if Spec::process_queues(ctx) {
371                ret.contexts_with_queued_frames += 1;
372            }
373        }
374
375        self.collect_frames();
376        ret.frames_sent = self.dispatch_pending_frames(filter_map_frame);
377
378        ret
379    }
380
381    /// Runs the network until it is starved of events.
382    ///
383    /// # Panics
384    ///
385    /// Panics if 1,000,000 steps are performed without becoming idle.
386    /// Also panics under the same conditions as [`step`].
387    pub fn run_until_idle(&mut self)
388    where
389        Spec::TimerId: Debug,
390    {
391        self.run_until_idle_with(|_, meta, frame| Some((meta, frame)))
392    }
393
394    /// Like [`FakeNetwork::run_until_idle`] but receives a function
395    /// `filter_map_frame` that can modify the an inbound frame before
396    /// delivery or drop it altogether by returning `None`.
397    pub fn run_until_idle_with<
398        F: FnMut(
399            &mut Spec::Context,
400            Spec::RecvMeta,
401            Buf<Vec<u8>>,
402        ) -> Option<(Spec::RecvMeta, Buf<Vec<u8>>)>,
403    >(
404        &mut self,
405        mut filter_map_frame: F,
406    ) where
407        Spec::TimerId: Debug,
408    {
409        for _ in 0..1_000_000 {
410            if self.step_with(&mut filter_map_frame).is_idle() {
411                return;
412            }
413        }
414        panic!("FakeNetwork seems to have gotten stuck in a loop.");
415    }
416
417    /// Collects all queued frames.
418    ///
419    /// Collects all pending frames and schedules them for delivery to the
420    /// destination context/device based on the result of `links`. The
421    /// collected frames are queued for dispatching in the `FakeNetwork`,
422    /// ordered by their scheduled delivery time given by the latency result
423    /// provided by `links`.
424    pub fn collect_frames(&mut self) {
425        let all_frames = self.contexts.iter_mut().filter_map(|(n, ctx)| {
426            Spec::fake_frames(ctx).with_fake_frame_ctx_mut(|ctx| {
427                let frames = ctx.take_frames();
428                if frames.is_empty() { None } else { Some((n.clone(), frames)) }
429            })
430        });
431
432        for (src_context, frames) in all_frames {
433            for (send_meta, frame) in frames.into_iter() {
434                for (dst_context, recv_meta, latency) in self.links.map_link(src_context, send_meta)
435                {
436                    self.pending_frames.push(PendingFrame::new(
437                        self.current_time + latency.unwrap_or(Duration::from_millis(0)),
438                        PendingFrameData { frame: frame.clone(), dst_context, meta: recv_meta },
439                    ));
440                }
441            }
442        }
443    }
444
445    /// Dispatches scheduled frames that were previously collected with
446    /// [`collect_frames`].
447    ///
448    /// Only frames for which the current deadline is less than or equal to the
449    /// current simulation time are delivered.
450    ///
451    /// # Panics
452    ///
453    /// If `FakeNetwork` was set up with a bad `links`, calls may panic when
454    /// trying to route frames to their context/device destinations.
455    pub fn dispatch_pending_frames<
456        F: FnMut(
457            &mut Spec::Context,
458            Spec::RecvMeta,
459            Buf<Vec<u8>>,
460        ) -> Option<(Spec::RecvMeta, Buf<Vec<u8>>)>,
461    >(
462        &mut self,
463        mut filter_map_frame: F,
464    ) -> usize {
465        let mut frames_sent = 0;
466        while let Some(InstantAndData(t, _)) = self.pending_frames.peek()
467            && *t <= self.current_time
468        {
469            // We can unwrap because we just peeked.
470            let PendingFrameData { dst_context, meta, frame } =
471                self.pending_frames.pop().unwrap().1;
472            let dst_context = self.context(dst_context);
473            if let Some((meta, frame)) = filter_map_frame(dst_context, meta, Buf::new(frame, ..)) {
474                Spec::handle_frame(dst_context, meta, frame)
475            }
476            frames_sent += 1;
477        }
478
479        frames_sent
480    }
481
482    /// Calculates the next `FakeInstant` when events are available.
483    ///
484    /// Returns the smallest `FakeInstant` greater than or equal to the
485    /// current time for which an event is available. If no events are
486    /// available, returns `None`.
487    pub fn next_step(&self) -> Option<FakeInstant> {
488        // Get earliest timer in all contexts.
489        let next_timer = self
490            .contexts
491            .iter()
492            .filter_map(|(_, ctx)| {
493                ctx.with_fake_timer_ctx(|ctx| match ctx.timers.peek() {
494                    Some(tmr) => Some(tmr.0),
495                    None => None,
496                })
497            })
498            .min();
499        // Get the instant for the next packet.
500        let next_packet_due = self.pending_frames.peek().map(|t| t.0);
501
502        // Return the earliest of them both, and protect against returning a
503        // time in the past.
504        match next_timer {
505            Some(t) if next_packet_due.is_some() => Some(t).min(next_packet_due),
506            Some(t) => Some(t),
507            None => next_packet_due,
508        }
509        .map(|t| t.max(self.current_time))
510    }
511}
512
513#[cfg(test)]
514mod tests {
515    use super::*;
516
517    use alloc::vec;
518
519    use crate::testutil::{FakeFrameCtx, FakeTimerCtx};
520    use crate::{SendFrameContext as _, TimerContext as _};
521
522    // Define some fake contexts and links specifically to test the fake
523    // network timers implementation.
524    #[derive(Default)]
525    struct FakeNetworkTestCtx {
526        timer_ctx: FakeTimerCtx<u32>,
527        frame_ctx: FakeFrameCtx<()>,
528        fired_timers: HashMap<u32, usize>,
529        frames_received: usize,
530    }
531
532    impl FakeNetworkTestCtx {
533        #[track_caller]
534        fn drain_and_assert_timers(&mut self, iter: impl IntoIterator<Item = (u32, usize)>) {
535            for (timer, fire_count) in iter {
536                assert_eq!(self.fired_timers.remove(&timer), Some(fire_count), "for timer {timer}");
537            }
538            assert!(self.fired_timers.is_empty(), "remaining timers: {:?}", self.fired_timers);
539        }
540
541        /// Generates an arbitrary request.
542        fn request() -> Vec<u8> {
543            vec![1, 2, 3, 4]
544        }
545
546        /// Generates an arbitrary response.
547        fn response() -> Vec<u8> {
548            vec![4, 3, 2, 1]
549        }
550    }
551
552    impl FakeNetworkSpec for FakeNetworkTestCtx {
553        type Context = Self;
554        type TimerId = u32;
555        type SendMeta = ();
556        type RecvMeta = ();
557
558        fn handle_frame(ctx: &mut Self, _recv: (), data: Buf<Vec<u8>>) {
559            ctx.frames_received += 1;
560            // If data is a request, generate a response. This mimics ICMP echo
561            // behavior.
562            if data.into_inner() == Self::request() {
563                ctx.frame_ctx.push((), Self::response())
564            }
565        }
566
567        fn handle_timer(ctx: &mut Self, dispatch: u32, _: FakeTimerId) {
568            *ctx.fired_timers.entry(dispatch).or_insert(0) += 1;
569        }
570
571        fn process_queues(_ctx: &mut Self) -> bool {
572            false
573        }
574
575        fn fake_frames(ctx: &mut Self) -> &mut impl WithFakeFrameContext<Self::SendMeta> {
576            ctx
577        }
578    }
579
580    impl WithFakeFrameContext<()> for FakeNetworkTestCtx {
581        fn with_fake_frame_ctx_mut<O, F: FnOnce(&mut FakeFrameCtx<()>) -> O>(&mut self, f: F) -> O {
582            f(&mut self.frame_ctx)
583        }
584    }
585
586    impl WithFakeTimerContext<u32> for FakeNetworkTestCtx {
587        fn with_fake_timer_ctx<O, F: FnOnce(&FakeTimerCtx<u32>) -> O>(&self, f: F) -> O {
588            f(&self.timer_ctx)
589        }
590
591        fn with_fake_timer_ctx_mut<O, F: FnOnce(&mut FakeTimerCtx<u32>) -> O>(
592            &mut self,
593            f: F,
594        ) -> O {
595            f(&mut self.timer_ctx)
596        }
597    }
598
599    fn new_fake_network_with_latency(
600        latency: Option<Duration>,
601    ) -> FakeNetwork<FakeNetworkTestCtx, i32, impl FakeNetworkLinks<(), (), i32>> {
602        FakeNetwork::new(
603            [(1, FakeNetworkTestCtx::default()), (2, FakeNetworkTestCtx::default())],
604            move |id, ()| {
605                vec![(
606                    match id {
607                        1 => 2,
608                        2 => 1,
609                        _ => unreachable!(),
610                    },
611                    (),
612                    latency,
613                )]
614            },
615        )
616    }
617
618    #[test]
619    fn timers() {
620        let mut net = new_fake_network_with_latency(None);
621
622        let (mut t1, mut t4, mut t5) =
623            net.with_context(1, |FakeNetworkTestCtx { timer_ctx, .. }| {
624                (timer_ctx.new_timer(1), timer_ctx.new_timer(4), timer_ctx.new_timer(5))
625            });
626
627        net.with_context(1, |FakeNetworkTestCtx { timer_ctx, .. }| {
628            assert_eq!(timer_ctx.schedule_timer(Duration::from_secs(1), &mut t1), None);
629            assert_eq!(timer_ctx.schedule_timer(Duration::from_secs(4), &mut t4), None);
630            assert_eq!(timer_ctx.schedule_timer(Duration::from_secs(5), &mut t5), None);
631        });
632
633        let (mut t2, mut t3, mut t6) =
634            net.with_context(2, |FakeNetworkTestCtx { timer_ctx, .. }| {
635                (timer_ctx.new_timer(2), timer_ctx.new_timer(3), timer_ctx.new_timer(6))
636            });
637
638        net.with_context(2, |FakeNetworkTestCtx { timer_ctx, .. }| {
639            assert_eq!(timer_ctx.schedule_timer(Duration::from_secs(2), &mut t2), None);
640            assert_eq!(timer_ctx.schedule_timer(Duration::from_secs(3), &mut t3), None);
641            assert_eq!(timer_ctx.schedule_timer(Duration::from_secs(5), &mut t6), None);
642        });
643
644        // No timers fired before.
645        net.context(1).drain_and_assert_timers([]);
646        net.context(2).drain_and_assert_timers([]);
647        assert_eq!(net.step().timers_fired, 1);
648        // Only timer in context 1 should have fired.
649        net.context(1).drain_and_assert_timers([(1, 1)]);
650        net.context(2).drain_and_assert_timers([]);
651        assert_eq!(net.step().timers_fired, 1);
652        // Only timer in context 2 should have fired.
653        net.context(1).drain_and_assert_timers([]);
654        net.context(2).drain_and_assert_timers([(2, 1)]);
655        assert_eq!(net.step().timers_fired, 1);
656        // Only timer in context 2 should have fired.
657        net.context(1).drain_and_assert_timers([]);
658        net.context(2).drain_and_assert_timers([(3, 1)]);
659        assert_eq!(net.step().timers_fired, 1);
660        // Only timer in context 1 should have fired.
661        net.context(1).drain_and_assert_timers([(4, 1)]);
662        net.context(2).drain_and_assert_timers([]);
663        assert_eq!(net.step().timers_fired, 2);
664        // Both timers have fired at the same time.
665        net.context(1).drain_and_assert_timers([(5, 1)]);
666        net.context(2).drain_and_assert_timers([(6, 1)]);
667
668        assert!(net.step().is_idle());
669        // Check that current time on contexts tick together.
670        let t1 = net.with_context(1, |FakeNetworkTestCtx { timer_ctx, .. }| timer_ctx.now());
671        let t2 = net.with_context(2, |FakeNetworkTestCtx { timer_ctx, .. }| timer_ctx.now());
672        assert_eq!(t1, t2);
673    }
674
675    #[test]
676    fn until_idle() {
677        let mut net = new_fake_network_with_latency(None);
678
679        let mut t1 =
680            net.with_context(1, |FakeNetworkTestCtx { timer_ctx, .. }| timer_ctx.new_timer(1));
681        net.with_context(1, |FakeNetworkTestCtx { timer_ctx, .. }| {
682            assert_eq!(timer_ctx.schedule_timer(Duration::from_secs(1), &mut t1), None);
683        });
684
685        let (mut t2, mut t3) = net.with_context(2, |FakeNetworkTestCtx { timer_ctx, .. }| {
686            (timer_ctx.new_timer(2), timer_ctx.new_timer(3))
687        });
688        net.with_context(2, |FakeNetworkTestCtx { timer_ctx, .. }| {
689            assert_eq!(timer_ctx.schedule_timer(Duration::from_secs(2), &mut t2), None);
690            assert_eq!(timer_ctx.schedule_timer(Duration::from_secs(3), &mut t3), None);
691        });
692
693        while !net.step().is_idle() && net.context(1).fired_timers.len() < 1
694            || net.context(2).fired_timers.len() < 1
695        {}
696        // Assert that we stopped before all times were fired, meaning we can
697        // step again.
698        assert_eq!(net.step().timers_fired, 1);
699    }
700
701    #[test]
702    fn delayed_packets() {
703        // Create a network that takes 5ms to get any packet to go through.
704        let mut net = new_fake_network_with_latency(Some(Duration::from_millis(5)));
705
706        // 1 sends 2 a request and schedules a timer.
707        let mut t11 =
708            net.with_context(1, |FakeNetworkTestCtx { timer_ctx, .. }| timer_ctx.new_timer(1));
709        net.with_context(1, |FakeNetworkTestCtx { frame_ctx, timer_ctx, .. }| {
710            frame_ctx.push((), FakeNetworkTestCtx::request());
711            assert_eq!(timer_ctx.schedule_timer(Duration::from_millis(3), &mut t11), None);
712        });
713        // 2 schedules some timers.
714        let (mut t21, mut t22) = net.with_context(2, |FakeNetworkTestCtx { timer_ctx, .. }| {
715            (timer_ctx.new_timer(1), timer_ctx.new_timer(2))
716        });
717        net.with_context(2, |FakeNetworkTestCtx { timer_ctx, .. }| {
718            assert_eq!(timer_ctx.schedule_timer(Duration::from_millis(7), &mut t22), None);
719            assert_eq!(timer_ctx.schedule_timer(Duration::from_millis(10), &mut t21), None);
720        });
721
722        // Order of expected events is as follows:
723        // - ctx1's timer expires at t = 3
724        // - ctx2 receives ctx1's packet at t = 5
725        // - ctx2's timer expires at t = 7
726        // - ctx1 receives ctx2's response and ctx2's last timer fires at t = 10
727
728        let assert_full_state = |net: &mut FakeNetwork<FakeNetworkTestCtx, _, _>,
729                                 ctx1_timers,
730                                 ctx2_timers,
731                                 ctx2_frames,
732                                 ctx1_frames| {
733            let ctx1 = net.context(1);
734            assert_eq!(ctx1.fired_timers.len(), ctx1_timers);
735            assert_eq!(ctx1.frames_received, ctx1_frames);
736            let ctx2 = net.context(2);
737            assert_eq!(ctx2.fired_timers.len(), ctx2_timers);
738            assert_eq!(ctx2.frames_received, ctx2_frames);
739        };
740
741        assert_eq!(net.step().timers_fired, 1);
742        assert_full_state(&mut net, 1, 0, 0, 0);
743        assert_eq!(net.step().frames_sent, 1);
744        assert_full_state(&mut net, 1, 0, 1, 0);
745        assert_eq!(net.step().timers_fired, 1);
746        assert_full_state(&mut net, 1, 1, 1, 0);
747        let step = net.step();
748        assert_eq!(step.frames_sent, 1);
749        assert_eq!(step.timers_fired, 1);
750        assert_full_state(&mut net, 1, 2, 1, 1);
751
752        // Should've starved all events.
753        assert!(net.step().is_idle());
754    }
755
756    #[test]
757    fn fake_network_transmits_packets() {
758        let mut net = new_fake_network_with_latency(None);
759
760        // Send a frame from 1 to 2.
761        net.with_context(1, |FakeNetworkTestCtx { frame_ctx, .. }| {
762            frame_ctx.send_frame(&mut (), (), Buf::new(FakeNetworkTestCtx::request(), ..)).unwrap();
763        });
764
765        // Send from 1 to 2.
766        assert_eq!(net.step().frames_sent, 1);
767        // Respond from 2 to 1.
768        assert_eq!(net.step().frames_sent, 1);
769        // Should've starved all events.
770        assert!(net.step().is_idle());
771    }
772
773    #[test]
774    fn send_to_many() {
775        let mut net = FakeNetworkTestCtx::new_network(
776            [
777                (1, FakeNetworkTestCtx::default()),
778                (2, FakeNetworkTestCtx::default()),
779                (3, FakeNetworkTestCtx::default()),
780            ],
781            |id, ()| match id {
782                // 1 sends to both 2 and 3.
783                1 => vec![(2, (), None), (3, (), None)],
784                // 2 only sends to 1.
785                2 => vec![(1, (), None)],
786                // 3 doesn't send anything.
787                3 => vec![],
788                _ => unreachable!(),
789            },
790        );
791        net.assert_no_pending_frames();
792
793        // 2 and 3 should get any packet sent by 1.
794        net.with_context(1, |FakeNetworkTestCtx { frame_ctx, .. }| {
795            frame_ctx.send_frame(&mut (), (), Buf::new(vec![], ..)).unwrap();
796        });
797        net.collect_frames();
798        assert_eq!(net.iter_pending_frames().count(), 2);
799        assert!(net.iter_pending_frames().any(|InstantAndData(_, x)| x.dst_context == 2));
800        assert!(net.iter_pending_frames().any(|InstantAndData(_, x)| x.dst_context == 3));
801        net.drop_pending_frames();
802
803        // Only 1 should get packets sent by 2.
804        net.with_context(2, |FakeNetworkTestCtx { frame_ctx, .. }| {
805            frame_ctx.send_frame(&mut (), (), Buf::new(vec![], ..)).unwrap();
806        });
807        net.collect_frames();
808        assert_eq!(net.iter_pending_frames().count(), 1);
809        assert!(net.iter_pending_frames().any(|InstantAndData(_, x)| x.dst_context == 1));
810        net.drop_pending_frames();
811
812        // No one receives packets sent by 3.
813        net.with_context(3, |FakeNetworkTestCtx { frame_ctx, .. }| {
814            frame_ctx.send_frame(&mut (), (), Buf::new(vec![], ..)).unwrap();
815        });
816        net.collect_frames();
817        net.assert_no_pending_frames();
818
819        // Because we didn't run the simulation, no one actually received any of
820        // these frames they were always in the pending queue.
821        for i in 1..=3 {
822            assert_eq!(net.context(i).frames_received, 0, "context: {i}");
823        }
824    }
825}