fidl_fuchsia_net_neighbor_ext/
testutil.rs1use flex_fuchsia_net as fnet;
12use flex_fuchsia_net_neighbor as fnet_neighbor;
13use futures::future::FusedFuture;
14use futures::{FutureExt, Stream, StreamExt as _};
15
16fn handle_get_next(
18 request: fnet_neighbor::EntryIteratorRequest,
19 event_batch: Vec<fnet_neighbor::EntryIteratorItem>,
20) {
21 match request {
22 fnet_neighbor::EntryIteratorRequest::GetNext { responder } => {
23 responder.send(&event_batch).expect("failed to respond to `GetNext`")
24 }
25 }
26}
27
28async fn fake_entry_iterator_impl(
32 events: impl Stream<Item = Vec<fnet_neighbor::EntryIteratorItem>>,
33 server_end: fidl::endpoints::ServerEnd<fnet_neighbor::EntryIteratorMarker>,
34) {
35 let request_stream = server_end.into_stream();
36 request_stream
37 .zip(events)
38 .for_each(|(request, event_batch)| {
39 handle_get_next(request.expect("failed to receive `GetNext` request"), event_batch);
40 futures::future::ready(())
41 })
42 .await
43}
44
45pub async fn serve_view_request(
49 request: fnet_neighbor::ViewRequest,
50 event_stream: impl Stream<Item = Vec<fnet_neighbor::EntryIteratorItem>>,
51) {
52 match request {
53 fnet_neighbor::ViewRequest::OpenEntryIterator { it, .. } => {
54 fake_entry_iterator_impl(event_stream, it)
55 }
56 }
57 .await
58}
59
60pub fn create_fake_view(
65 event_stream: impl Stream<Item = Vec<fnet_neighbor::EntryIteratorItem>>,
66) -> (fnet_neighbor::ViewProxy, impl FusedFuture<Output = ()>) {
67 let (view, view_server_end) = fidl::endpoints::create_proxy::<fnet_neighbor::ViewMarker>();
68
69 let entry_iter_fut = view_server_end
70 .into_stream()
71 .into_future()
72 .then(async |(req, _rest)| {
73 serve_view_request(
74 req.expect("View request stream unexpectedly ended")
75 .expect("failed to receive `OpenEntryIterator` request"),
76 event_stream,
77 )
78 .await
79 })
80 .fuse();
81
82 (view, entry_iter_fut)
83}
84
85#[derive(Clone, Debug, PartialEq)]
87pub enum EventSpec {
88 Existing(u8),
90 Added(u8),
92 Changed(u8),
94 Removed(u8),
96 Idle,
98}
99
100fn generate_entry(seed: u8) -> fnet_neighbor::Entry {
102 fnet_neighbor::Entry {
103 interface: Some(1),
104 neighbor: Some(fnet::IpAddress::Ipv4(fnet::Ipv4Address { addr: [192, 168, 0, seed] })),
105 state: Some(fnet_neighbor::EntryState::Reachable),
106 mac: Some(fnet::MacAddress { octets: [0, 1, 2, 3, 4, 5] }),
107 updated_at: Some(12345),
108 ..Default::default()
109 }
110}
111
112pub fn generate_event_from_spec(spec: &EventSpec) -> fnet_neighbor::EntryIteratorItem {
114 match *spec {
115 EventSpec::Existing(seed) => {
116 fnet_neighbor::EntryIteratorItem::Existing(generate_entry(seed))
117 }
118 EventSpec::Added(seed) => fnet_neighbor::EntryIteratorItem::Added(generate_entry(seed)),
119 EventSpec::Changed(seed) => fnet_neighbor::EntryIteratorItem::Changed(generate_entry(seed)),
120 EventSpec::Removed(seed) => fnet_neighbor::EntryIteratorItem::Removed(generate_entry(seed)),
121 EventSpec::Idle => fnet_neighbor::EntryIteratorItem::Idle(fnet_neighbor::IdleEvent),
122 }
123}
124
125pub fn generate_events_from_spec(spec: &[EventSpec]) -> Vec<fnet_neighbor::EntryIteratorItem> {
127 spec.iter().map(generate_event_from_spec).collect()
128}
129
130pub fn generate_event(seed: u8) -> fnet_neighbor::EntryIteratorItem {
133 generate_event_from_spec(&EventSpec::Added(seed))
134}
135
136pub fn generate_events_in_range(
139 seeds: std::ops::Range<u8>,
140) -> Vec<fnet_neighbor::EntryIteratorItem> {
141 seeds.into_iter().map(generate_event).collect()
142}
143
144#[cfg(test)]
145mod tests {
146 use super::*;
147
148 use assert_matches::assert_matches;
149 use futures::FutureExt;
150 use test_case::test_case;
151
152 #[test_case(Vec::new(); "no events")]
153 #[test_case(vec![0..1]; "single_batch_single_event")]
154 #[test_case(vec![0..10]; "single_batch_many_events")]
155 #[test_case(vec![0..10, 10..20, 20..30]; "many_batches_many_events")]
156 #[fuchsia_async::run_singlethreaded(test)]
157 async fn fake_view_impl_against_shape(test_shape: Vec<std::ops::Range<u8>>) {
158 let (event_stream_sender, event_stream_receiver) =
161 futures::channel::mpsc::unbounded::<Vec<fnet_neighbor::EntryIteratorItem>>();
162 for batch_shape in &test_shape {
163 event_stream_sender
164 .unbounded_send(generate_events_in_range(batch_shape.clone()))
165 .expect("failed to send event batch");
166 }
167
168 let (view, entry_iter_fut) = create_fake_view(event_stream_receiver);
170 futures::pin_mut!(entry_iter_fut);
171
172 let (entry_iter, entry_iter_server_end) =
174 fidl::endpoints::create_proxy::<fnet_neighbor::EntryIteratorMarker>();
175 view.open_entry_iterator(entry_iter_server_end, &Default::default())
176 .expect("failed to open entry iterator");
177 for batch_shape in test_shape {
178 futures::select!(
179 () = entry_iter_fut => panic!("fake view implementation unexpectedly finished"),
180 events = entry_iter.get_next().fuse() => assert_eq!(
181 events.expect("failed to watch for events"),
182 generate_events_in_range(batch_shape.clone())));
183 }
184
185 event_stream_sender.close_channel();
187 entry_iter_fut.await;
188
189 assert_matches!(
192 entry_iter.get_next().await,
193 Err(fidl::Error::ClientChannelClosed { status: zx_status::Status::PEER_CLOSED, .. })
194 );
195 }
196
197 #[test]
198 fn generate_entry_unique_to_seed() {
199 assert_eq!(generate_entry(1), generate_entry(1));
200 assert_ne!(generate_entry(1), generate_entry(2));
201 }
202
203 #[test]
204 fn generate_multiple_events_from_spec() {
205 use EventSpec::*;
206 assert_eq!(
207 generate_events_from_spec(&[Existing(1), Added(2), Changed(3), Removed(4), Idle]),
208 &[
209 fnet_neighbor::EntryIteratorItem::Existing(generate_entry(1)),
210 fnet_neighbor::EntryIteratorItem::Added(generate_entry(2)),
211 fnet_neighbor::EntryIteratorItem::Changed(generate_entry(3)),
212 fnet_neighbor::EntryIteratorItem::Removed(generate_entry(4)),
213 fnet_neighbor::EntryIteratorItem::Idle(fnet_neighbor::IdleEvent),
214 ]
215 );
216 }
217}