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: flex_client::fidl::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 serve_view_impl(
64 event_stream: impl Stream<Item = Vec<fnet_neighbor::EntryIteratorItem>>,
65 server_end: flex_client::fidl::ServerEnd<fnet_neighbor::ViewMarker>,
66) -> impl FusedFuture<Output = ()> {
67 server_end
68 .into_stream()
69 .into_future()
70 .then(async |(req, _rest)| {
71 serve_view_request(
72 req.expect("View request stream unexpectedly ended")
73 .expect("failed to receive `OpenEntryIterator` request"),
74 event_stream,
75 )
76 .await
77 })
78 .fuse()
79}
80
81#[cfg(not(feature = "fdomain"))]
86pub fn create_fake_view(
87 event_stream: impl Stream<Item = Vec<fnet_neighbor::EntryIteratorItem>>,
88) -> (fnet_neighbor::ViewProxy, impl FusedFuture<Output = ()>) {
89 let (view, view_server_end) = fidl::endpoints::create_proxy::<fnet_neighbor::ViewMarker>();
90 let entry_iter_fut = serve_view_impl(event_stream, view_server_end);
91 (view, entry_iter_fut)
92}
93
94#[derive(Clone, Debug, PartialEq)]
96pub enum EventSpec {
97 Existing(u8),
99 Added(u8),
101 Changed(u8),
103 Removed(u8),
105 Idle,
107}
108
109fn generate_entry(seed: u8) -> fnet_neighbor::Entry {
111 fnet_neighbor::Entry {
112 interface: Some(1),
113 neighbor: Some(fnet::IpAddress::Ipv4(fnet::Ipv4Address { addr: [192, 168, 0, seed] })),
114 state: Some(fnet_neighbor::EntryState::Reachable),
115 mac: Some(fnet::MacAddress { octets: [0, 1, 2, 3, 4, 5] }),
116 updated_at: Some(12345),
117 ..Default::default()
118 }
119}
120
121pub fn generate_event_from_spec(spec: &EventSpec) -> fnet_neighbor::EntryIteratorItem {
123 match *spec {
124 EventSpec::Existing(seed) => {
125 fnet_neighbor::EntryIteratorItem::Existing(generate_entry(seed))
126 }
127 EventSpec::Added(seed) => fnet_neighbor::EntryIteratorItem::Added(generate_entry(seed)),
128 EventSpec::Changed(seed) => fnet_neighbor::EntryIteratorItem::Changed(generate_entry(seed)),
129 EventSpec::Removed(seed) => fnet_neighbor::EntryIteratorItem::Removed(generate_entry(seed)),
130 EventSpec::Idle => fnet_neighbor::EntryIteratorItem::Idle(fnet_neighbor::IdleEvent),
131 }
132}
133
134pub fn generate_events_from_spec(spec: &[EventSpec]) -> Vec<fnet_neighbor::EntryIteratorItem> {
136 spec.iter().map(generate_event_from_spec).collect()
137}
138
139pub fn generate_event(seed: u8) -> fnet_neighbor::EntryIteratorItem {
142 generate_event_from_spec(&EventSpec::Added(seed))
143}
144
145pub fn generate_events_in_range(
148 seeds: std::ops::Range<u8>,
149) -> Vec<fnet_neighbor::EntryIteratorItem> {
150 seeds.into_iter().map(generate_event).collect()
151}
152
153#[cfg(test)]
154mod tests {
155 use super::*;
156
157 use assert_matches::assert_matches;
158 use futures::FutureExt;
159 use test_case::test_case;
160
161 #[test_case(Vec::new(); "no events")]
162 #[test_case(vec![0..1]; "single_batch_single_event")]
163 #[test_case(vec![0..10]; "single_batch_many_events")]
164 #[test_case(vec![0..10, 10..20, 20..30]; "many_batches_many_events")]
165 #[fuchsia::test]
166 async fn fake_view_impl_against_shape(test_shape: Vec<std::ops::Range<u8>>) {
167 let (event_stream_sender, event_stream_receiver) =
170 futures::channel::mpsc::unbounded::<Vec<fnet_neighbor::EntryIteratorItem>>();
171 for batch_shape in &test_shape {
172 event_stream_sender
173 .unbounded_send(generate_events_in_range(batch_shape.clone()))
174 .expect("failed to send event batch");
175 }
176
177 #[cfg(feature = "fdomain")]
179 let client = fdomain_local::local_client_empty();
180 #[cfg(not(feature = "fdomain"))]
181 let client = fidl::endpoints::ZirconClient;
182 let (view, view_server_end) = client.create_proxy::<fnet_neighbor::ViewMarker>();
183 let entry_iter_fut = serve_view_impl(event_stream_receiver, view_server_end);
184 futures::pin_mut!(entry_iter_fut);
185
186 use flex_client::ProxyHasDomain as _;
188 let (entry_iter, entry_iter_server_end) =
189 view.domain().create_proxy::<fnet_neighbor::EntryIteratorMarker>();
190 view.open_entry_iterator(entry_iter_server_end, &Default::default())
191 .expect("failed to open entry iterator");
192 for batch_shape in test_shape {
193 futures::select!(
194 () = entry_iter_fut => panic!("fake view implementation unexpectedly finished"),
195 events = entry_iter.get_next().fuse() => assert_eq!(
196 events.expect("failed to watch for events"),
197 generate_events_in_range(batch_shape.clone())));
198 }
199
200 event_stream_sender.close_channel();
202 entry_iter_fut.await;
203
204 assert_matches!(
207 entry_iter.get_next().await,
208 Err(fidl::Error::ClientChannelClosed { epitaph: fidl::Epitaph::PeerClosed, .. })
209 );
210 }
211
212 #[test]
213 fn generate_entry_unique_to_seed() {
214 assert_eq!(generate_entry(1), generate_entry(1));
215 assert_ne!(generate_entry(1), generate_entry(2));
216 }
217
218 #[test]
219 fn generate_multiple_events_from_spec() {
220 use EventSpec::*;
221 assert_eq!(
222 generate_events_from_spec(&[Existing(1), Added(2), Changed(3), Removed(4), Idle]),
223 &[
224 fnet_neighbor::EntryIteratorItem::Existing(generate_entry(1)),
225 fnet_neighbor::EntryIteratorItem::Added(generate_entry(2)),
226 fnet_neighbor::EntryIteratorItem::Changed(generate_entry(3)),
227 fnet_neighbor::EntryIteratorItem::Removed(generate_entry(4)),
228 fnet_neighbor::EntryIteratorItem::Idle(fnet_neighbor::IdleEvent),
229 ]
230 );
231 }
232}