wlancfg_lib/mode_management/
iface_manager_api.rs

1// Copyright 2020 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
5use crate::access_point::{state_machine as ap_fsm, types as ap_types};
6use crate::client::types as client_types;
7use crate::config_management::network_config::Credential;
8use crate::mode_management::iface_manager_types::*;
9use crate::mode_management::{Defect, IfaceFailure};
10use crate::telemetry;
11use anyhow::{Error, bail, format_err};
12use async_trait::async_trait;
13use fidl::endpoints::create_proxy;
14use fidl_fuchsia_wlan_sme as fidl_sme;
15use fuchsia_async::TimeoutExt;
16use futures::channel::{mpsc, oneshot};
17use futures::{TryFutureExt, TryStreamExt};
18use log::{info, warn};
19
20// A long amount of time that a scan should be able to finish within. If a scan takes longer than
21// this is indicates something is wrong.
22const SCAN_TIMEOUT: fuchsia_async::MonotonicDuration =
23    fuchsia_async::MonotonicDuration::from_seconds(60);
24const CONNECT_TIMEOUT: fuchsia_async::MonotonicDuration =
25    fuchsia_async::MonotonicDuration::from_seconds(30);
26const DISCONNECT_TIMEOUT: fuchsia_async::MonotonicDuration =
27    fuchsia_async::MonotonicDuration::from_seconds(10);
28const START_AP_TIMEOUT: fuchsia_async::MonotonicDuration =
29    fuchsia_async::MonotonicDuration::from_seconds(30);
30const STOP_AP_TIMEOUT: fuchsia_async::MonotonicDuration =
31    fuchsia_async::MonotonicDuration::from_seconds(10);
32const AP_STATUS_TIMEOUT: fuchsia_async::MonotonicDuration =
33    fuchsia_async::MonotonicDuration::from_seconds(10);
34
35#[async_trait(?Send)]
36pub trait IfaceManagerApi {
37    /// Finds the client iface with the given network configuration, disconnects from the network,
38    /// and removes the client's network configuration information.
39    async fn disconnect(
40        &mut self,
41        network_id: ap_types::NetworkIdentifier,
42        reason: client_types::DisconnectReason,
43    ) -> Result<(), Error>;
44
45    /// Selects a client iface, ensures that a ClientSmeProxy and client connectivity state machine
46    /// exists for the iface, and then issues a connect request to the client connectivity state
47    /// machine.
48    async fn connect(&mut self, connect_req: ConnectAttemptRequest) -> Result<(), Error>;
49
50    /// Marks an existing client interface as unconfigured.
51    async fn record_idle_client(&mut self, iface_id: u16) -> Result<(), Error>;
52
53    /// Returns an indication of whether or not any client interfaces are unconfigured.
54    async fn has_idle_client(&mut self) -> Result<bool, Error>;
55
56    /// Queries the properties of the provided interface ID and internally accounts for the newly
57    /// added client or AP.
58    async fn handle_added_iface(&mut self, iface_id: u16) -> Result<(), Error>;
59
60    /// Removes all internal references of the provided interface ID.
61    async fn handle_removed_iface(&mut self, iface_id: u16) -> Result<(), Error>;
62
63    /// Selects a client iface and return it for use with a scan
64    async fn get_sme_proxy_for_scan(&mut self) -> Result<SmeForScan, Error>;
65
66    /// Disconnects all configured clients and disposes of all client ifaces before instructing
67    /// the PhyManager to stop client connections.
68    async fn stop_client_connections(
69        &mut self,
70        reason: client_types::DisconnectReason,
71    ) -> Result<(), Error>;
72
73    /// Passes the call to start client connections through to the PhyManager.
74    async fn start_client_connections(&mut self) -> Result<(), Error>;
75
76    /// Starts an AP interface with the provided configuration.
77    async fn start_ap(&mut self, config: ap_fsm::ApConfig) -> Result<oneshot::Receiver<()>, Error>;
78
79    /// Stops the AP interface corresponding to the provided configuration and destroys it.
80    async fn stop_ap(&mut self, ssid: Ssid, password: Vec<u8>) -> Result<(), Error>;
81
82    /// Stops all AP interfaces and destroys them.
83    async fn stop_all_aps(&mut self) -> Result<(), Error>;
84
85    /// Sets the country code for WLAN PHYs.
86    async fn set_country(
87        &mut self,
88        country_code: Option<client_types::CountryCode>,
89    ) -> Result<(), Error>;
90}
91
92#[derive(Clone)]
93pub struct IfaceManager {
94    pub sender: mpsc::Sender<IfaceManagerRequest>,
95}
96
97#[async_trait(?Send)]
98impl IfaceManagerApi for IfaceManager {
99    async fn disconnect(
100        &mut self,
101        network_id: ap_types::NetworkIdentifier,
102        reason: client_types::DisconnectReason,
103    ) -> Result<(), Error> {
104        let (responder, receiver) = oneshot::channel();
105        let req = DisconnectRequest { network_id, responder, reason };
106        self.sender.try_send(IfaceManagerRequest::Disconnect(req))?;
107
108        receiver.await?
109    }
110
111    async fn connect(&mut self, connect_req: ConnectAttemptRequest) -> Result<(), Error> {
112        let (responder, receiver) = oneshot::channel();
113        let req = ConnectRequest { request: connect_req, responder };
114        self.sender.try_send(IfaceManagerRequest::Connect(req))?;
115
116        receiver.await?
117    }
118
119    async fn record_idle_client(&mut self, iface_id: u16) -> Result<(), Error> {
120        let (responder, receiver) = oneshot::channel();
121        let req = RecordIdleIfaceRequest { iface_id, responder };
122        self.sender.try_send(IfaceManagerRequest::RecordIdleIface(req))?;
123        receiver.await?;
124        Ok(())
125    }
126
127    async fn has_idle_client(&mut self) -> Result<bool, Error> {
128        let (responder, receiver) = oneshot::channel();
129        let req = HasIdleIfaceRequest { responder };
130        self.sender.try_send(IfaceManagerRequest::HasIdleIface(req))?;
131        receiver.await.map_err(|e| e.into())
132    }
133
134    async fn handle_added_iface(&mut self, iface_id: u16) -> Result<(), Error> {
135        let (responder, receiver) = oneshot::channel();
136        let req = AddIfaceRequest { iface_id, responder };
137        self.sender.try_send(IfaceManagerRequest::AddIface(req))?;
138        receiver.await?;
139        Ok(())
140    }
141
142    async fn handle_removed_iface(&mut self, iface_id: u16) -> Result<(), Error> {
143        let (responder, receiver) = oneshot::channel();
144        let req = RemoveIfaceRequest { iface_id, responder };
145        self.sender.try_send(IfaceManagerRequest::RemoveIface(req))?;
146        receiver.await?;
147        Ok(())
148    }
149
150    async fn get_sme_proxy_for_scan(&mut self) -> Result<SmeForScan, Error> {
151        let (responder, receiver) = oneshot::channel();
152        let req = ScanProxyRequest { responder };
153        self.sender.try_send(IfaceManagerRequest::GetScanProxy(req))?;
154        receiver.await?
155    }
156
157    async fn start_client_connections(&mut self) -> Result<(), Error> {
158        let (responder, receiver) = oneshot::channel();
159        let req = StartClientConnectionsRequest { responder };
160        self.sender.try_send(IfaceManagerRequest::StartClientConnections(req))?;
161        receiver.await?
162    }
163
164    async fn start_ap(&mut self, config: ap_fsm::ApConfig) -> Result<oneshot::Receiver<()>, Error> {
165        let (responder, receiver) = oneshot::channel();
166        let req = StartApRequest { config, responder };
167        self.sender.try_send(IfaceManagerRequest::StartAp(req))?;
168        receiver.await?
169    }
170
171    async fn stop_client_connections(
172        &mut self,
173        reason: client_types::DisconnectReason,
174    ) -> Result<(), Error> {
175        let (responder, receiver) = oneshot::channel();
176        let req = StopClientConnectionsRequest { responder, reason };
177        self.sender.try_send(IfaceManagerRequest::StopClientConnections(req))?;
178        receiver.await?
179    }
180
181    async fn stop_ap(&mut self, ssid: Ssid, password: Vec<u8>) -> Result<(), Error> {
182        let (responder, receiver) = oneshot::channel();
183        let req = StopApRequest { ssid, password, responder };
184        self.sender.try_send(IfaceManagerRequest::StopAp(req))?;
185        receiver.await?
186    }
187
188    async fn stop_all_aps(&mut self) -> Result<(), Error> {
189        let (responder, receiver) = oneshot::channel();
190        let req = StopAllApsRequest { responder };
191        self.sender.try_send(IfaceManagerRequest::StopAllAps(req))?;
192        receiver.await?
193    }
194
195    async fn set_country(
196        &mut self,
197        country_code: Option<client_types::CountryCode>,
198    ) -> Result<(), Error> {
199        let (responder, receiver) = oneshot::channel();
200        let req = SetCountryRequest { country_code, responder };
201        self.sender.try_send(IfaceManagerRequest::SetCountry(req))?;
202        receiver.await?
203    }
204}
205
206trait DefectReporter {
207    fn defect_sender(&self) -> mpsc::Sender<Defect>;
208
209    fn report_defect(&self, defect: Defect) {
210        let mut defect_sender = self.defect_sender();
211        if let Err(e) = defect_sender.try_send(defect) {
212            warn!("Failed to report defect {:?}: {:?}", defect, e)
213        }
214    }
215}
216
217#[derive(Debug)]
218pub struct SmeForScan {
219    proxy: fidl_sme::ClientSmeProxy,
220    iface_id: u16,
221    defect_sender: mpsc::Sender<Defect>,
222}
223
224impl SmeForScan {
225    pub fn new(
226        proxy: fidl_sme::ClientSmeProxy,
227        iface_id: u16,
228        defect_sender: mpsc::Sender<Defect>,
229    ) -> Self {
230        SmeForScan { proxy, iface_id, defect_sender }
231    }
232
233    pub async fn scan(
234        &self,
235        req: &fidl_sme::ScanRequest,
236    ) -> Result<fidl_sme::ClientSmeScanResult, Error> {
237        self.proxy
238            .scan(req)
239            .map_err(|e| format_err!("{:?}", e))
240            .on_timeout(SCAN_TIMEOUT, || {
241                self.report_defect(Defect::Iface(IfaceFailure::Timeout {
242                    iface_id: self.iface_id,
243                    source: telemetry::TimeoutSource::Scan,
244                }));
245                Err(format_err!("Timed out waiting on scan response from SME"))
246            })
247            .await
248    }
249
250    pub fn log_aborted_scan_defect(&self) {
251        self.report_defect(Defect::Iface(IfaceFailure::CanceledScan { iface_id: self.iface_id }))
252    }
253
254    pub fn log_failed_scan_defect(&self) {
255        self.report_defect(Defect::Iface(IfaceFailure::FailedScan { iface_id: self.iface_id }))
256    }
257
258    pub fn log_empty_scan_defect(&self) {
259        self.report_defect(Defect::Iface(IfaceFailure::EmptyScanResults {
260            iface_id: self.iface_id,
261        }))
262    }
263}
264
265impl DefectReporter for SmeForScan {
266    fn defect_sender(&self) -> mpsc::Sender<Defect> {
267        self.defect_sender.clone()
268    }
269}
270
271#[derive(Clone, Debug)]
272pub struct SmeForClientStateMachine {
273    proxy: fidl_sme::ClientSmeProxy,
274    iface_id: u16,
275    defect_sender: mpsc::Sender<Defect>,
276}
277
278impl SmeForClientStateMachine {
279    pub fn new(
280        proxy: fidl_sme::ClientSmeProxy,
281        iface_id: u16,
282        defect_sender: mpsc::Sender<Defect>,
283    ) -> Self {
284        Self { proxy, iface_id, defect_sender }
285    }
286
287    pub async fn connect(
288        &self,
289        req: &fidl_sme::ConnectRequest,
290    ) -> Result<(fidl_sme::ConnectResult, fidl_sme::ConnectTransactionEventStream), anyhow::Error>
291    {
292        let (connect_txn, remote) = create_proxy();
293
294        self.proxy
295            .connect(req, Some(remote))
296            .map_err(|e| format_err!("Failed to send command to wlanstack: {:?}", e))?;
297
298        let mut stream = connect_txn.take_event_stream();
299        let result = wait_for_connect_result(&mut stream)
300            .on_timeout(CONNECT_TIMEOUT, || {
301                self.report_defect(Defect::Iface(IfaceFailure::Timeout {
302                    iface_id: self.iface_id,
303                    source: telemetry::TimeoutSource::Connect,
304                }));
305                Err(format_err!("Timed out waiting for connect result from SME."))
306            })
307            .await?;
308
309        Ok((result, stream))
310    }
311
312    pub async fn disconnect(&self, reason: fidl_sme::UserDisconnectReason) -> Result<(), Error> {
313        self.proxy
314            .disconnect(reason)
315            .map_err(|e| format_err!("Failed to send command to wlanstack: {:?}", e))
316            .on_timeout(DISCONNECT_TIMEOUT, || {
317                self.report_defect(Defect::Iface(IfaceFailure::Timeout {
318                    iface_id: self.iface_id,
319                    source: telemetry::TimeoutSource::Disconnect,
320                }));
321                Err(format_err!("Timed out waiting for disconnect"))
322            })
323            .await
324    }
325
326    pub fn roam(&self, req: &fidl_sme::RoamRequest) -> Result<(), Error> {
327        self.proxy.roam(req).map_err(|e| format_err!("Failed to send roam command: {:}", e))
328    }
329
330    pub fn take_event_stream(&self) -> fidl_sme::ClientSmeEventStream {
331        self.proxy.take_event_stream()
332    }
333
334    pub fn sme_for_scan(&self) -> SmeForScan {
335        SmeForScan {
336            proxy: self.proxy.clone(),
337            iface_id: self.iface_id,
338            defect_sender: self.defect_sender.clone(),
339        }
340    }
341}
342
343impl DefectReporter for SmeForClientStateMachine {
344    fn defect_sender(&self) -> mpsc::Sender<Defect> {
345        self.defect_sender.clone()
346    }
347}
348
349/// Wait until stream returns an OnConnectResult event or None. Ignore other event types.
350async fn wait_for_connect_result(
351    stream: &mut fidl_sme::ConnectTransactionEventStream,
352) -> Result<fidl_sme::ConnectResult, Error> {
353    loop {
354        let stream_fut = stream.try_next();
355        match stream_fut
356            .await
357            .map_err(|e| format_err!("Failed to receive connect result from sme: {:?}", e))?
358        {
359            Some(fidl_sme::ConnectTransactionEvent::OnConnectResult { result }) => {
360                return Ok(result);
361            }
362            Some(other) => {
363                info!(
364                    "Expected ConnectTransactionEvent::OnConnectResult, got {}. Ignoring.",
365                    connect_txn_event_name(&other)
366                );
367            }
368            None => {
369                bail!("Server closed the ConnectTransaction channel before sending a response");
370            }
371        };
372    }
373}
374
375fn connect_txn_event_name(event: &fidl_sme::ConnectTransactionEvent) -> &'static str {
376    match event {
377        fidl_sme::ConnectTransactionEvent::OnConnectResult { .. } => "OnConnectResult",
378        fidl_sme::ConnectTransactionEvent::OnRoamResult { .. } => "OnRoamResult",
379        fidl_sme::ConnectTransactionEvent::OnDisconnect { .. } => "OnDisconnect",
380        fidl_sme::ConnectTransactionEvent::OnSignalReport { .. } => "OnSignalReport",
381        fidl_sme::ConnectTransactionEvent::OnChannelSwitched { .. } => "OnChannelSwitched",
382    }
383}
384
385#[derive(Clone, Debug)]
386pub struct SmeForApStateMachine {
387    proxy: fidl_sme::ApSmeProxy,
388    iface_id: u16,
389    defect_sender: mpsc::Sender<Defect>,
390}
391
392impl SmeForApStateMachine {
393    pub fn new(
394        proxy: fidl_sme::ApSmeProxy,
395        iface_id: u16,
396        defect_sender: mpsc::Sender<Defect>,
397    ) -> Self {
398        Self { proxy, iface_id, defect_sender }
399    }
400
401    pub async fn start(
402        &self,
403        config: &fidl_sme::ApConfig,
404    ) -> Result<fidl_sme::StartApResultCode, Error> {
405        self.proxy
406            .start(config)
407            .map_err(|e| format_err!("Failed to send command to wlanstack: {:?}", e))
408            .on_timeout(START_AP_TIMEOUT, || {
409                self.report_defect(Defect::Iface(IfaceFailure::Timeout {
410                    iface_id: self.iface_id,
411                    source: telemetry::TimeoutSource::ApStart,
412                }));
413                Err(format_err!("Timed out waiting for AP to start"))
414            })
415            .await
416    }
417
418    pub async fn stop(&self) -> Result<fidl_sme::StopApResultCode, Error> {
419        self.proxy
420            .stop()
421            .map_err(|e| format_err!("Failed to send command to wlanstack: {:?}", e))
422            .on_timeout(STOP_AP_TIMEOUT, || {
423                self.report_defect(Defect::Iface(IfaceFailure::Timeout {
424                    iface_id: self.iface_id,
425                    source: telemetry::TimeoutSource::ApStop,
426                }));
427                Err(format_err!("Timed out waiting for AP to stop"))
428            })
429            .await
430    }
431
432    pub async fn status(&self) -> Result<fidl_sme::ApStatusResponse, Error> {
433        self.proxy
434            .status()
435            .map_err(|e| format_err!("Failed to send command to wlanstack: {:?}", e))
436            .on_timeout(AP_STATUS_TIMEOUT, || {
437                self.report_defect(Defect::Iface(IfaceFailure::Timeout {
438                    iface_id: self.iface_id,
439                    source: telemetry::TimeoutSource::ApStatus,
440                }));
441                Err(format_err!("Timed out waiting for AP status"))
442            })
443            .await
444    }
445
446    pub fn take_event_stream(&self) -> fidl_sme::ApSmeEventStream {
447        self.proxy.take_event_stream()
448    }
449}
450
451impl DefectReporter for SmeForApStateMachine {
452    fn defect_sender(&self) -> mpsc::Sender<Defect> {
453        self.defect_sender.clone()
454    }
455}
456
457// A request to connect to a specific candidate, and count of attempts to find a BSS.
458#[cfg_attr(test, derive(Debug))]
459#[derive(Clone, PartialEq)]
460pub struct ConnectAttemptRequest {
461    pub network: client_types::NetworkIdentifier,
462    pub credential: Credential,
463    pub reason: client_types::ConnectReason,
464    pub attempts: u8,
465}
466
467impl ConnectAttemptRequest {
468    pub fn new(
469        network: client_types::NetworkIdentifier,
470        credential: Credential,
471        reason: client_types::ConnectReason,
472    ) -> Self {
473        ConnectAttemptRequest { network, credential, reason, attempts: 0 }
474    }
475}
476
477impl From<client_types::ConnectSelection> for ConnectAttemptRequest {
478    fn from(selection: client_types::ConnectSelection) -> ConnectAttemptRequest {
479        ConnectAttemptRequest::new(
480            selection.target.network,
481            selection.target.credential,
482            selection.reason,
483        )
484    }
485}
486
487#[cfg(test)]
488mod tests {
489    use super::*;
490    use crate::access_point::types;
491    use crate::util::testing::{generate_connect_selection, poll_sme_req};
492    use anyhow::format_err;
493    use assert_matches::assert_matches;
494    use fidl::endpoints::{RequestStream, create_proxy};
495    use futures::StreamExt;
496    use futures::future::LocalBoxFuture;
497    use futures::stream::StreamFuture;
498    use futures::task::Poll;
499    use rand::Rng;
500    use std::pin::pin;
501    use test_case::test_case;
502    use wlan_common::channel::Cbw;
503    use wlan_common::sequestered::Sequestered;
504    use wlan_common::{RadioConfig, random_fidl_bss_description};
505    use {
506        fidl_fuchsia_wlan_common as fidl_common, fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211,
507        fidl_fuchsia_wlan_internal as fidl_internal, fuchsia_async as fasync,
508    };
509
510    struct TestValues {
511        exec: fasync::TestExecutor,
512        iface_manager: IfaceManager,
513        receiver: mpsc::Receiver<IfaceManagerRequest>,
514    }
515
516    fn test_setup() -> TestValues {
517        let exec = fasync::TestExecutor::new();
518        let (sender, receiver) = mpsc::channel(1);
519        TestValues { exec, iface_manager: IfaceManager { sender }, receiver }
520    }
521
522    #[allow(clippy::enum_variant_names, reason = "mass allow for https://fxbug.dev/381896734")]
523    #[derive(Clone)]
524    enum NegativeTestFailureMode {
525        RequestFailure,
526        OperationFailure,
527        ServiceFailure,
528    }
529
530    fn handle_negative_test_result_responder<T: std::fmt::Debug>(
531        responder: oneshot::Sender<Result<T, Error>>,
532        failure_mode: NegativeTestFailureMode,
533    ) {
534        match failure_mode {
535            NegativeTestFailureMode::RequestFailure => {
536                panic!("Test bug: this request should have been handled previously")
537            }
538            NegativeTestFailureMode::OperationFailure => {
539                responder
540                    .send(Err(format_err!("operation failed")))
541                    .expect("failed to send response");
542            }
543            NegativeTestFailureMode::ServiceFailure => {
544                // Just drop the responder so that the client side sees a failure.
545                drop(responder);
546            }
547        }
548    }
549
550    fn handle_negative_test_responder<T: std::fmt::Debug>(
551        responder: oneshot::Sender<T>,
552        failure_mode: NegativeTestFailureMode,
553    ) {
554        match failure_mode {
555            NegativeTestFailureMode::RequestFailure | NegativeTestFailureMode::OperationFailure => {
556                panic!("Test bug: invalid operation")
557            }
558            NegativeTestFailureMode::ServiceFailure => {
559                // Just drop the responder so that the client side sees a failure.
560                drop(responder);
561            }
562        }
563    }
564
565    fn iface_manager_api_negative_test(
566        mut receiver: mpsc::Receiver<IfaceManagerRequest>,
567        failure_mode: NegativeTestFailureMode,
568    ) -> LocalBoxFuture<'static, ()> {
569        if let NegativeTestFailureMode::RequestFailure = failure_mode {
570            // Drop the receiver so that no requests can be made.
571            drop(receiver);
572            let fut = async move {};
573            return Box::pin(fut);
574        }
575
576        let fut = async move {
577            let req = match receiver.next().await {
578                Some(req) => req,
579                None => panic!("no request available."),
580            };
581
582            match req {
583                // Result<(), Err> responder values
584                IfaceManagerRequest::StopClientConnections(StopClientConnectionsRequest {
585                    responder,
586                    ..
587                })
588                | IfaceManagerRequest::Disconnect(DisconnectRequest { responder, .. })
589                | IfaceManagerRequest::StopAp(StopApRequest { responder, .. })
590                | IfaceManagerRequest::StopAllAps(StopAllApsRequest { responder, .. })
591                | IfaceManagerRequest::SetCountry(SetCountryRequest { responder, .. })
592                | IfaceManagerRequest::StartClientConnections(StartClientConnectionsRequest {
593                    responder,
594                })
595                | IfaceManagerRequest::Connect(ConnectRequest { responder, .. }) => {
596                    handle_negative_test_result_responder(responder, failure_mode);
597                }
598                // Result<ClientSmeProxy, Err>
599                IfaceManagerRequest::GetScanProxy(ScanProxyRequest { responder }) => {
600                    handle_negative_test_result_responder(responder, failure_mode);
601                }
602                // Result<oneshot::Receiver<()>, Err>
603                IfaceManagerRequest::StartAp(StartApRequest { responder, .. }) => {
604                    handle_negative_test_result_responder(responder, failure_mode);
605                }
606                // Unit responder values
607                IfaceManagerRequest::RecordIdleIface(RecordIdleIfaceRequest {
608                    responder, ..
609                })
610                | IfaceManagerRequest::AddIface(AddIfaceRequest { responder, .. })
611                | IfaceManagerRequest::RemoveIface(RemoveIfaceRequest { responder, .. }) => {
612                    handle_negative_test_responder(responder, failure_mode);
613                }
614                // Boolean responder values
615                IfaceManagerRequest::HasIdleIface(HasIdleIfaceRequest { responder }) => {
616                    handle_negative_test_responder(responder, failure_mode);
617                }
618            }
619        };
620        Box::pin(fut)
621    }
622
623    #[fuchsia::test]
624    fn test_disconnect_succeeds() {
625        let mut test_values = test_setup();
626
627        // Issue a disconnect command and wait for the command to be sent.
628        let req = ap_types::NetworkIdentifier {
629            ssid: Ssid::try_from("foo").unwrap(),
630            security_type: ap_types::SecurityType::None,
631        };
632        let req_reason = client_types::DisconnectReason::NetworkUnsaved;
633        let disconnect_fut = test_values.iface_manager.disconnect(req.clone(), req_reason);
634        let mut disconnect_fut = pin!(disconnect_fut);
635
636        assert_matches!(test_values.exec.run_until_stalled(&mut disconnect_fut), Poll::Pending);
637
638        // Verify that the receiver sees the command and send back a response.
639        let next_message = test_values.receiver.next();
640        let mut next_message = pin!(next_message);
641
642        assert_matches!(
643            test_values.exec.run_until_stalled(&mut next_message),
644            Poll::Ready(Some(IfaceManagerRequest::Disconnect(DisconnectRequest {
645                network_id, responder, reason
646            }))) => {
647                assert_eq!(network_id, req);
648                assert_eq!(reason, req_reason);
649                responder.send(Ok(())).expect("failed to send disconnect response");
650            }
651        );
652
653        // Verify that the disconnect requestr receives the response.
654        assert_matches!(
655            test_values.exec.run_until_stalled(&mut disconnect_fut),
656            Poll::Ready(Ok(()))
657        );
658    }
659
660    #[test_case(NegativeTestFailureMode::RequestFailure; "request failure")]
661    #[test_case(NegativeTestFailureMode::OperationFailure; "operation failure")]
662    #[test_case(NegativeTestFailureMode::ServiceFailure; "service failure")]
663    #[fuchsia::test(add_test_attr = false)]
664    fn disconnect_negative_test(failure_mode: NegativeTestFailureMode) {
665        let mut test_values = test_setup();
666
667        // Issue a disconnect command and wait for the command to be sent.
668        let req = ap_types::NetworkIdentifier {
669            ssid: Ssid::try_from("foo").unwrap(),
670            security_type: ap_types::SecurityType::None,
671        };
672        let disconnect_fut = test_values
673            .iface_manager
674            .disconnect(req.clone(), client_types::DisconnectReason::NetworkUnsaved);
675        let mut disconnect_fut = pin!(disconnect_fut);
676
677        let service_fut =
678            iface_manager_api_negative_test(test_values.receiver, failure_mode.clone());
679        let mut service_fut = pin!(service_fut);
680
681        match failure_mode {
682            NegativeTestFailureMode::RequestFailure => {}
683            _ => {
684                // Run the request and the servicing of the request
685                assert_matches!(
686                    test_values.exec.run_until_stalled(&mut disconnect_fut),
687                    Poll::Pending
688                );
689                assert_matches!(
690                    test_values.exec.run_until_stalled(&mut service_fut),
691                    Poll::Ready(())
692                );
693            }
694        }
695
696        // Verify that the disconnect requestr receives the response.
697        assert_matches!(
698            test_values.exec.run_until_stalled(&mut disconnect_fut),
699            Poll::Ready(Err(_))
700        );
701    }
702
703    #[fuchsia::test]
704    fn test_connect_succeeds() {
705        let mut test_values = test_setup();
706
707        // Issue a connect command and wait for the command to be sent.
708        let req = ConnectAttemptRequest::new(
709            client_types::NetworkIdentifier {
710                ssid: Ssid::try_from("foo").unwrap(),
711                security_type: client_types::SecurityType::None,
712            },
713            Credential::None,
714            client_types::ConnectReason::FidlConnectRequest,
715        );
716        let connect_fut = test_values.iface_manager.connect(req.clone());
717        let mut connect_fut = pin!(connect_fut);
718
719        assert_matches!(test_values.exec.run_until_stalled(&mut connect_fut), Poll::Pending);
720
721        // Verify that the receiver sees the command and send back a response.
722        let next_message = test_values.receiver.next();
723        let mut next_message = pin!(next_message);
724
725        assert_matches!(
726            test_values.exec.run_until_stalled(&mut next_message),
727            Poll::Ready(Some(IfaceManagerRequest::Connect(ConnectRequest {
728                request, responder
729            }))) => {
730                assert_eq!(request, req);
731                responder.send(Ok(())).expect("failed to send connect response");
732            }
733        );
734
735        // Verify that the connect requestr receives the response.
736        assert_matches!(test_values.exec.run_until_stalled(&mut connect_fut), Poll::Ready(Ok(_)));
737    }
738
739    #[test_case(NegativeTestFailureMode::RequestFailure; "request failure")]
740    #[test_case(NegativeTestFailureMode::OperationFailure; "operation failure")]
741    #[test_case(NegativeTestFailureMode::ServiceFailure; "service failure")]
742    #[fuchsia::test(add_test_attr = false)]
743    fn connect_negative_test(failure_mode: NegativeTestFailureMode) {
744        let mut test_values = test_setup();
745
746        // Issue a connect command and wait for the command to be sent.
747        let req = ConnectAttemptRequest::new(
748            client_types::NetworkIdentifier {
749                ssid: Ssid::try_from("foo").unwrap(),
750                security_type: client_types::SecurityType::None,
751            },
752            Credential::None,
753            client_types::ConnectReason::FidlConnectRequest,
754        );
755        let connect_fut = test_values.iface_manager.connect(req.clone());
756        let mut connect_fut = pin!(connect_fut);
757
758        let service_fut =
759            iface_manager_api_negative_test(test_values.receiver, failure_mode.clone());
760        let mut service_fut = pin!(service_fut);
761
762        match failure_mode {
763            NegativeTestFailureMode::RequestFailure => {}
764            _ => {
765                // Run the request and the servicing of the request
766                assert_matches!(
767                    test_values.exec.run_until_stalled(&mut connect_fut),
768                    Poll::Pending
769                );
770                assert_matches!(
771                    test_values.exec.run_until_stalled(&mut service_fut),
772                    Poll::Ready(())
773                );
774            }
775        }
776
777        // Verify that the request completes in error.
778        assert_matches!(test_values.exec.run_until_stalled(&mut connect_fut), Poll::Ready(Err(_)));
779    }
780
781    #[fuchsia::test]
782    fn test_record_idle_client_succeeds() {
783        let mut test_values = test_setup();
784
785        // Request that an idle client be recorded.
786        let iface_id = 123;
787        let idle_client_fut = test_values.iface_manager.record_idle_client(iface_id);
788        let mut idle_client_fut = pin!(idle_client_fut);
789
790        assert_matches!(test_values.exec.run_until_stalled(&mut idle_client_fut), Poll::Pending);
791
792        // Verify that the receiver sees the request.
793        let next_message = test_values.receiver.next();
794        let mut next_message = pin!(next_message);
795
796        assert_matches!(
797            test_values.exec.run_until_stalled(&mut next_message),
798            Poll::Ready(
799                Some(IfaceManagerRequest::RecordIdleIface(RecordIdleIfaceRequest{ iface_id: 123, responder}))
800            ) => {
801                responder.send(()).expect("failed to send idle iface response");
802            }
803        );
804
805        // Verify that the client sees the response.
806        assert_matches!(
807            test_values.exec.run_until_stalled(&mut idle_client_fut),
808            Poll::Ready(Ok(()))
809        );
810    }
811
812    #[test_case(NegativeTestFailureMode::RequestFailure; "request failure")]
813    #[test_case(NegativeTestFailureMode::ServiceFailure; "service failure")]
814    #[fuchsia::test(add_test_attr = false)]
815    fn test_record_idle_client_service_failure(failure_mode: NegativeTestFailureMode) {
816        let mut test_values = test_setup();
817
818        // Request that an idle client be recorded.
819        let iface_id = 123;
820        let idle_client_fut = test_values.iface_manager.record_idle_client(iface_id);
821        let mut idle_client_fut = pin!(idle_client_fut);
822
823        let service_fut =
824            iface_manager_api_negative_test(test_values.receiver, failure_mode.clone());
825        let mut service_fut = pin!(service_fut);
826
827        match failure_mode {
828            NegativeTestFailureMode::RequestFailure => {}
829            _ => {
830                // Run the request and the servicing of the request
831                assert_matches!(
832                    test_values.exec.run_until_stalled(&mut idle_client_fut),
833                    Poll::Pending
834                );
835                assert_matches!(
836                    test_values.exec.run_until_stalled(&mut service_fut),
837                    Poll::Ready(())
838                );
839            }
840        }
841
842        // Verify that the client side finishes
843        assert_matches!(
844            test_values.exec.run_until_stalled(&mut idle_client_fut),
845            Poll::Ready(Err(_))
846        );
847    }
848
849    #[fuchsia::test]
850    fn test_has_idle_client_success() {
851        let mut test_values = test_setup();
852
853        // Query whether there is an idle client
854        let idle_client_fut = test_values.iface_manager.has_idle_client();
855        let mut idle_client_fut = pin!(idle_client_fut);
856        assert_matches!(test_values.exec.run_until_stalled(&mut idle_client_fut), Poll::Pending);
857
858        // Verify that the service sees the query
859        let next_message = test_values.receiver.next();
860        let mut next_message = pin!(next_message);
861
862        assert_matches!(
863            test_values.exec.run_until_stalled(&mut next_message),
864            Poll::Ready(
865                Some(IfaceManagerRequest::HasIdleIface(HasIdleIfaceRequest{ responder}))
866            ) => responder.send(true).expect("failed to reply to idle client query")
867        );
868
869        // Verify that the client side finishes
870        assert_matches!(
871            test_values.exec.run_until_stalled(&mut idle_client_fut),
872            Poll::Ready(Ok(true))
873        );
874    }
875
876    #[test_case(NegativeTestFailureMode::RequestFailure; "request failure")]
877    #[test_case(NegativeTestFailureMode::ServiceFailure; "service failure")]
878    #[fuchsia::test(add_test_attr = false)]
879    fn idle_client_negative_test(failure_mode: NegativeTestFailureMode) {
880        let mut test_values = test_setup();
881
882        // Query whether there is an idle client
883        let idle_client_fut = test_values.iface_manager.has_idle_client();
884        let mut idle_client_fut = pin!(idle_client_fut);
885        assert_matches!(test_values.exec.run_until_stalled(&mut idle_client_fut), Poll::Pending);
886
887        let service_fut =
888            iface_manager_api_negative_test(test_values.receiver, failure_mode.clone());
889        let mut service_fut = pin!(service_fut);
890
891        match failure_mode {
892            NegativeTestFailureMode::RequestFailure => {}
893            _ => {
894                // Run the request and the servicing of the request
895                assert_matches!(
896                    test_values.exec.run_until_stalled(&mut idle_client_fut),
897                    Poll::Pending
898                );
899                assert_matches!(
900                    test_values.exec.run_until_stalled(&mut service_fut),
901                    Poll::Ready(())
902                );
903            }
904        }
905
906        // Verify that the request completes in error.
907        assert_matches!(
908            test_values.exec.run_until_stalled(&mut idle_client_fut),
909            Poll::Ready(Err(_))
910        );
911    }
912
913    #[fuchsia::test]
914    fn test_add_iface_success() {
915        let mut test_values = test_setup();
916
917        // Add an interface
918        let added_iface_fut = test_values.iface_manager.handle_added_iface(123);
919        let mut added_iface_fut = pin!(added_iface_fut);
920        assert_matches!(test_values.exec.run_until_stalled(&mut added_iface_fut), Poll::Pending);
921
922        // Verify that the service sees the query
923        let next_message = test_values.receiver.next();
924        let mut next_message = pin!(next_message);
925
926        assert_matches!(
927            test_values.exec.run_until_stalled(&mut next_message),
928            Poll::Ready(
929                Some(IfaceManagerRequest::AddIface(AddIfaceRequest{ iface_id: 123, responder }))
930            ) => {
931                responder.send(()).expect("failed to respond while adding iface");
932            }
933        );
934
935        // Verify that the client side finishes
936        assert_matches!(
937            test_values.exec.run_until_stalled(&mut added_iface_fut),
938            Poll::Ready(Ok(()))
939        );
940    }
941
942    #[test_case(NegativeTestFailureMode::RequestFailure; "request failure")]
943    #[test_case(NegativeTestFailureMode::ServiceFailure; "service failure")]
944    #[fuchsia::test(add_test_attr = false)]
945    fn add_iface_negative_test(failure_mode: NegativeTestFailureMode) {
946        let mut test_values = test_setup();
947
948        // Add an interface
949        let added_iface_fut = test_values.iface_manager.handle_added_iface(123);
950        let mut added_iface_fut = pin!(added_iface_fut);
951        assert_matches!(test_values.exec.run_until_stalled(&mut added_iface_fut), Poll::Pending);
952
953        let service_fut =
954            iface_manager_api_negative_test(test_values.receiver, failure_mode.clone());
955        let mut service_fut = pin!(service_fut);
956
957        match failure_mode {
958            NegativeTestFailureMode::RequestFailure => {}
959            _ => {
960                // Run the request and the servicing of the request
961                assert_matches!(
962                    test_values.exec.run_until_stalled(&mut added_iface_fut),
963                    Poll::Pending
964                );
965                assert_matches!(
966                    test_values.exec.run_until_stalled(&mut service_fut),
967                    Poll::Ready(())
968                );
969            }
970        }
971
972        // Verify that the request completes in error.
973        assert_matches!(
974            test_values.exec.run_until_stalled(&mut added_iface_fut),
975            Poll::Ready(Err(_))
976        );
977    }
978
979    #[fuchsia::test]
980    fn test_remove_iface_success() {
981        let mut test_values = test_setup();
982
983        // Report the removal of an interface.
984        let removed_iface_fut = test_values.iface_manager.handle_removed_iface(123);
985        let mut removed_iface_fut = pin!(removed_iface_fut);
986        assert_matches!(test_values.exec.run_until_stalled(&mut removed_iface_fut), Poll::Pending);
987
988        // Verify that the service sees the query
989        let next_message = test_values.receiver.next();
990        let mut next_message = pin!(next_message);
991
992        assert_matches!(
993            test_values.exec.run_until_stalled(&mut next_message),
994            Poll::Ready(
995                Some(IfaceManagerRequest::RemoveIface(RemoveIfaceRequest{ iface_id: 123, responder }))
996            ) => {
997                responder.send(()).expect("failed to respond while adding iface");
998            }
999        );
1000
1001        // Verify that the client side finishes
1002        assert_matches!(
1003            test_values.exec.run_until_stalled(&mut removed_iface_fut),
1004            Poll::Ready(Ok(()))
1005        );
1006    }
1007
1008    #[test_case(NegativeTestFailureMode::RequestFailure; "request failure")]
1009    #[test_case(NegativeTestFailureMode::ServiceFailure; "service failure")]
1010    #[fuchsia::test(add_test_attr = false)]
1011    fn remove_iface_negative_test(failure_mode: NegativeTestFailureMode) {
1012        let mut test_values = test_setup();
1013
1014        // Report the removal of an interface.
1015        let removed_iface_fut = test_values.iface_manager.handle_removed_iface(123);
1016        let mut removed_iface_fut = pin!(removed_iface_fut);
1017        assert_matches!(test_values.exec.run_until_stalled(&mut removed_iface_fut), Poll::Pending);
1018
1019        let service_fut =
1020            iface_manager_api_negative_test(test_values.receiver, failure_mode.clone());
1021        let mut service_fut = pin!(service_fut);
1022
1023        match failure_mode {
1024            NegativeTestFailureMode::RequestFailure => {}
1025            _ => {
1026                // Run the request and the servicing of the request
1027                assert_matches!(
1028                    test_values.exec.run_until_stalled(&mut removed_iface_fut),
1029                    Poll::Pending
1030                );
1031                assert_matches!(
1032                    test_values.exec.run_until_stalled(&mut service_fut),
1033                    Poll::Ready(())
1034                );
1035            }
1036        }
1037
1038        // Verify that the client side finishes
1039        assert_matches!(
1040            test_values.exec.run_until_stalled(&mut removed_iface_fut),
1041            Poll::Ready(Err(_))
1042        );
1043    }
1044
1045    #[fuchsia::test]
1046    fn test_get_scan_proxy_success() {
1047        let mut test_values = test_setup();
1048
1049        // Request a scan
1050        let scan_proxy_fut = test_values.iface_manager.get_sme_proxy_for_scan();
1051        let mut scan_proxy_fut = pin!(scan_proxy_fut);
1052        assert_matches!(test_values.exec.run_until_stalled(&mut scan_proxy_fut), Poll::Pending);
1053
1054        // Verify that the service sees the request.
1055        let next_message = test_values.receiver.next();
1056        let mut next_message = pin!(next_message);
1057
1058        assert_matches!(
1059            test_values.exec.run_until_stalled(&mut next_message),
1060            Poll::Ready(Some(IfaceManagerRequest::GetScanProxy(ScanProxyRequest{
1061                responder
1062            }))) => {
1063                let (proxy, _) = create_proxy::<fidl_sme::ClientSmeMarker>();
1064                let (defect_sender, _defect_receiver) = mpsc::channel(100);
1065                responder.send(Ok(SmeForScan{proxy, iface_id: 0, defect_sender})).expect("failed to send scan sme proxy");
1066            }
1067        );
1068
1069        // Verify that the client side gets the scan proxy
1070        assert_matches!(
1071            test_values.exec.run_until_stalled(&mut scan_proxy_fut),
1072            Poll::Ready(Ok(_))
1073        );
1074    }
1075
1076    #[test_case(NegativeTestFailureMode::RequestFailure; "request failure")]
1077    #[test_case(NegativeTestFailureMode::OperationFailure; "operation failure")]
1078    #[test_case(NegativeTestFailureMode::ServiceFailure; "service failure")]
1079    #[fuchsia::test(add_test_attr = false)]
1080    fn scan_proxy_negative_test(failure_mode: NegativeTestFailureMode) {
1081        let mut test_values = test_setup();
1082
1083        // Request a scan
1084        let scan_proxy_fut = test_values.iface_manager.get_sme_proxy_for_scan();
1085        let mut scan_proxy_fut = pin!(scan_proxy_fut);
1086
1087        let service_fut =
1088            iface_manager_api_negative_test(test_values.receiver, failure_mode.clone());
1089        let mut service_fut = pin!(service_fut);
1090
1091        match failure_mode {
1092            NegativeTestFailureMode::RequestFailure => {}
1093            _ => {
1094                // Run the request and the servicing of the request
1095                assert_matches!(
1096                    test_values.exec.run_until_stalled(&mut scan_proxy_fut),
1097                    Poll::Pending
1098                );
1099                assert_matches!(
1100                    test_values.exec.run_until_stalled(&mut service_fut),
1101                    Poll::Ready(())
1102                );
1103            }
1104        }
1105
1106        // Verify that an error is returned.
1107        assert_matches!(
1108            test_values.exec.run_until_stalled(&mut scan_proxy_fut),
1109            Poll::Ready(Err(_))
1110        );
1111    }
1112
1113    #[fuchsia::test]
1114    fn test_stop_client_connections_succeeds() {
1115        let mut test_values = test_setup();
1116
1117        // Request a scan
1118        let stop_fut = test_values.iface_manager.stop_client_connections(
1119            client_types::DisconnectReason::FidlStopClientConnectionsRequest,
1120        );
1121        let mut stop_fut = pin!(stop_fut);
1122        assert_matches!(test_values.exec.run_until_stalled(&mut stop_fut), Poll::Pending);
1123
1124        // Verify that the service sees the request.
1125        let next_message = test_values.receiver.next();
1126        let mut next_message = pin!(next_message);
1127
1128        assert_matches!(
1129            test_values.exec.run_until_stalled(&mut next_message),
1130            Poll::Ready(Some(IfaceManagerRequest::StopClientConnections(StopClientConnectionsRequest{
1131                responder, reason
1132            }))) => {
1133                assert_eq!(reason, client_types::DisconnectReason::FidlStopClientConnectionsRequest);
1134                responder.send(Ok(())).expect("failed sending stop client connections response");
1135            }
1136        );
1137
1138        // Verify that the client side gets the response.
1139        assert_matches!(test_values.exec.run_until_stalled(&mut stop_fut), Poll::Ready(Ok(())));
1140    }
1141
1142    #[test_case(NegativeTestFailureMode::RequestFailure; "request failure")]
1143    #[test_case(NegativeTestFailureMode::OperationFailure; "operation failure")]
1144    #[test_case(NegativeTestFailureMode::ServiceFailure; "service failure")]
1145    #[fuchsia::test(add_test_attr = false)]
1146    fn stop_client_connections_negative_test(failure_mode: NegativeTestFailureMode) {
1147        let mut test_values = test_setup();
1148
1149        // Request a scan
1150        let stop_fut = test_values.iface_manager.stop_client_connections(
1151            client_types::DisconnectReason::FidlStopClientConnectionsRequest,
1152        );
1153        let mut stop_fut = pin!(stop_fut);
1154        assert_matches!(test_values.exec.run_until_stalled(&mut stop_fut), Poll::Pending);
1155
1156        let service_fut =
1157            iface_manager_api_negative_test(test_values.receiver, failure_mode.clone());
1158        let mut service_fut = pin!(service_fut);
1159
1160        match failure_mode {
1161            NegativeTestFailureMode::RequestFailure => {}
1162            _ => {
1163                // Run the request and the servicing of the request
1164                assert_matches!(test_values.exec.run_until_stalled(&mut stop_fut), Poll::Pending);
1165                assert_matches!(
1166                    test_values.exec.run_until_stalled(&mut service_fut),
1167                    Poll::Ready(())
1168                );
1169            }
1170        }
1171
1172        // Verify that the client side gets the response.
1173        assert_matches!(test_values.exec.run_until_stalled(&mut stop_fut), Poll::Ready(Err(_)));
1174    }
1175
1176    #[fuchsia::test]
1177    fn test_start_client_connections_succeeds() {
1178        let mut test_values = test_setup();
1179
1180        // Start client connections
1181        let start_fut = test_values.iface_manager.start_client_connections();
1182        let mut start_fut = pin!(start_fut);
1183        assert_matches!(test_values.exec.run_until_stalled(&mut start_fut), Poll::Pending);
1184
1185        // Verify that the service sees the request.
1186        let next_message = test_values.receiver.next();
1187        let mut next_message = pin!(next_message);
1188
1189        assert_matches!(
1190            test_values.exec.run_until_stalled(&mut next_message),
1191            Poll::Ready(Some(IfaceManagerRequest::StartClientConnections(StartClientConnectionsRequest{
1192                responder
1193            }))) => {
1194                responder.send(Ok(())).expect("failed sending stop client connections response");
1195            }
1196        );
1197
1198        // Verify that the client side gets the response.
1199        assert_matches!(test_values.exec.run_until_stalled(&mut start_fut), Poll::Ready(Ok(())));
1200    }
1201
1202    #[test_case(NegativeTestFailureMode::RequestFailure; "request failure")]
1203    #[test_case(NegativeTestFailureMode::OperationFailure; "operation failure")]
1204    #[test_case(NegativeTestFailureMode::ServiceFailure; "service failure")]
1205    #[fuchsia::test(add_test_attr = false)]
1206    fn start_client_connections_negative_test(failure_mode: NegativeTestFailureMode) {
1207        let mut test_values = test_setup();
1208
1209        // Start client connections
1210        let start_fut = test_values.iface_manager.start_client_connections();
1211        let mut start_fut = pin!(start_fut);
1212        assert_matches!(test_values.exec.run_until_stalled(&mut start_fut), Poll::Pending);
1213
1214        let service_fut =
1215            iface_manager_api_negative_test(test_values.receiver, failure_mode.clone());
1216        let mut service_fut = pin!(service_fut);
1217
1218        match failure_mode {
1219            NegativeTestFailureMode::RequestFailure => {}
1220            _ => {
1221                // Run the request and the servicing of the request
1222                assert_matches!(test_values.exec.run_until_stalled(&mut start_fut), Poll::Pending);
1223                assert_matches!(
1224                    test_values.exec.run_until_stalled(&mut service_fut),
1225                    Poll::Ready(())
1226                );
1227            }
1228        }
1229
1230        // Verify that the client side gets the response.
1231        assert_matches!(test_values.exec.run_until_stalled(&mut start_fut), Poll::Ready(Err(_)));
1232    }
1233
1234    fn create_ap_config() -> ap_fsm::ApConfig {
1235        ap_fsm::ApConfig {
1236            id: types::NetworkIdentifier {
1237                ssid: Ssid::try_from("foo").unwrap(),
1238                security_type: types::SecurityType::None,
1239            },
1240            credential: vec![],
1241            radio_config: RadioConfig::new(fidl_common::WlanPhyType::Ht, Cbw::Cbw20, 6),
1242            mode: types::ConnectivityMode::Unrestricted,
1243            band: types::OperatingBand::Any,
1244        }
1245    }
1246
1247    #[fuchsia::test]
1248    fn test_start_ap_succeeds() {
1249        let mut test_values = test_setup();
1250
1251        // Start an AP
1252        let start_fut = test_values.iface_manager.start_ap(create_ap_config());
1253        let mut start_fut = pin!(start_fut);
1254        assert_matches!(test_values.exec.run_until_stalled(&mut start_fut), Poll::Pending);
1255
1256        // Verify the service sees the request
1257        let next_message = test_values.receiver.next();
1258        let mut next_message = pin!(next_message);
1259
1260        assert_matches!(
1261            test_values.exec.run_until_stalled(&mut next_message),
1262            Poll::Ready(Some(IfaceManagerRequest::StartAp(StartApRequest{
1263                config, responder
1264            }))) => {
1265                assert_eq!(config, create_ap_config());
1266
1267                let (_, receiver) = oneshot::channel();
1268                responder.send(Ok(receiver)).expect("failed to send start AP response");
1269            }
1270        );
1271
1272        // Verify that the client gets the response
1273        assert_matches!(test_values.exec.run_until_stalled(&mut start_fut), Poll::Ready(Ok(_)));
1274    }
1275
1276    #[test_case(NegativeTestFailureMode::RequestFailure; "request failure")]
1277    #[test_case(NegativeTestFailureMode::OperationFailure; "operation failure")]
1278    #[test_case(NegativeTestFailureMode::ServiceFailure; "service failure")]
1279    #[fuchsia::test(add_test_attr = false)]
1280    fn start_ap_negative_test(failure_mode: NegativeTestFailureMode) {
1281        let mut test_values = test_setup();
1282
1283        // Start an AP
1284        let start_fut = test_values.iface_manager.start_ap(create_ap_config());
1285        let mut start_fut = pin!(start_fut);
1286        assert_matches!(test_values.exec.run_until_stalled(&mut start_fut), Poll::Pending);
1287
1288        let service_fut =
1289            iface_manager_api_negative_test(test_values.receiver, failure_mode.clone());
1290        let mut service_fut = pin!(service_fut);
1291
1292        match failure_mode {
1293            NegativeTestFailureMode::RequestFailure => {}
1294            _ => {
1295                // Run the request and the servicing of the request
1296                assert_matches!(test_values.exec.run_until_stalled(&mut start_fut), Poll::Pending);
1297                assert_matches!(
1298                    test_values.exec.run_until_stalled(&mut service_fut),
1299                    Poll::Ready(())
1300                );
1301            }
1302        }
1303
1304        // Verify that the client gets the response
1305        assert_matches!(test_values.exec.run_until_stalled(&mut start_fut), Poll::Ready(Err(_)));
1306    }
1307
1308    #[fuchsia::test]
1309    fn test_stop_ap_succeeds() {
1310        let mut test_values = test_setup();
1311
1312        // Stop an AP
1313        let stop_fut = test_values
1314            .iface_manager
1315            .stop_ap(Ssid::try_from("foo").unwrap(), "bar".as_bytes().to_vec());
1316        let mut stop_fut = pin!(stop_fut);
1317        assert_matches!(test_values.exec.run_until_stalled(&mut stop_fut), Poll::Pending);
1318
1319        // Verify the service sees the request
1320        let next_message = test_values.receiver.next();
1321        let mut next_message = pin!(next_message);
1322
1323        assert_matches!(
1324            test_values.exec.run_until_stalled(&mut next_message),
1325            Poll::Ready(Some(IfaceManagerRequest::StopAp(StopApRequest{
1326                ssid, password, responder
1327            }))) => {
1328                assert_eq!(ssid, Ssid::try_from("foo").unwrap());
1329                assert_eq!(password, "bar".as_bytes().to_vec());
1330
1331                responder.send(Ok(())).expect("failed to send stop AP response");
1332            }
1333        );
1334
1335        // Verify that the client gets the response
1336        assert_matches!(test_values.exec.run_until_stalled(&mut stop_fut), Poll::Ready(Ok(_)));
1337    }
1338
1339    #[test_case(NegativeTestFailureMode::RequestFailure; "request failure")]
1340    #[test_case(NegativeTestFailureMode::OperationFailure; "operation failure")]
1341    #[test_case(NegativeTestFailureMode::ServiceFailure; "service failure")]
1342    #[fuchsia::test(add_test_attr = false)]
1343    fn stop_ap_negative_test(failure_mode: NegativeTestFailureMode) {
1344        let mut test_values = test_setup();
1345
1346        // Stop an AP
1347        let stop_fut = test_values
1348            .iface_manager
1349            .stop_ap(Ssid::try_from("foo").unwrap(), "bar".as_bytes().to_vec());
1350        let mut stop_fut = pin!(stop_fut);
1351        assert_matches!(test_values.exec.run_until_stalled(&mut stop_fut), Poll::Pending);
1352
1353        let service_fut =
1354            iface_manager_api_negative_test(test_values.receiver, failure_mode.clone());
1355        let mut service_fut = pin!(service_fut);
1356
1357        match failure_mode {
1358            NegativeTestFailureMode::RequestFailure => {}
1359            _ => {
1360                // Run the request and the servicing of the request
1361                assert_matches!(test_values.exec.run_until_stalled(&mut stop_fut), Poll::Pending);
1362                assert_matches!(
1363                    test_values.exec.run_until_stalled(&mut service_fut),
1364                    Poll::Ready(())
1365                );
1366            }
1367        }
1368
1369        // Verify that the client gets the response
1370        assert_matches!(test_values.exec.run_until_stalled(&mut stop_fut), Poll::Ready(Err(_)));
1371    }
1372
1373    #[fuchsia::test]
1374    fn test_stop_all_aps_succeeds() {
1375        let mut test_values = test_setup();
1376
1377        // Stop an AP
1378        let stop_fut = test_values.iface_manager.stop_all_aps();
1379        let mut stop_fut = pin!(stop_fut);
1380        assert_matches!(test_values.exec.run_until_stalled(&mut stop_fut), Poll::Pending);
1381
1382        // Verify the service sees the request
1383        let next_message = test_values.receiver.next();
1384        let mut next_message = pin!(next_message);
1385        assert_matches!(
1386            test_values.exec.run_until_stalled(&mut next_message),
1387            Poll::Ready(Some(IfaceManagerRequest::StopAllAps(StopAllApsRequest{
1388                responder
1389            }))) => {
1390                responder.send(Ok(())).expect("failed to send stop AP response");
1391            }
1392        );
1393
1394        // Verify that the client gets the response
1395        assert_matches!(test_values.exec.run_until_stalled(&mut stop_fut), Poll::Ready(Ok(_)));
1396    }
1397
1398    #[test_case(NegativeTestFailureMode::RequestFailure; "request failure")]
1399    #[test_case(NegativeTestFailureMode::OperationFailure; "operation failure")]
1400    #[test_case(NegativeTestFailureMode::ServiceFailure; "service failure")]
1401    #[fuchsia::test(add_test_attr = false)]
1402    fn stop_all_aps_negative_test(failure_mode: NegativeTestFailureMode) {
1403        let mut test_values = test_setup();
1404
1405        // Stop an AP
1406        let stop_fut = test_values.iface_manager.stop_all_aps();
1407        let mut stop_fut = pin!(stop_fut);
1408        assert_matches!(test_values.exec.run_until_stalled(&mut stop_fut), Poll::Pending);
1409
1410        let service_fut =
1411            iface_manager_api_negative_test(test_values.receiver, failure_mode.clone());
1412        let mut service_fut = pin!(service_fut);
1413
1414        match failure_mode {
1415            NegativeTestFailureMode::RequestFailure => {}
1416            _ => {
1417                // Run the request and the servicing of the request
1418                assert_matches!(test_values.exec.run_until_stalled(&mut stop_fut), Poll::Pending);
1419                assert_matches!(
1420                    test_values.exec.run_until_stalled(&mut service_fut),
1421                    Poll::Ready(())
1422                );
1423            }
1424        }
1425
1426        // Verify that the client gets the response
1427        assert_matches!(test_values.exec.run_until_stalled(&mut stop_fut), Poll::Ready(Err(_)));
1428    }
1429
1430    #[fuchsia::test]
1431    fn test_set_country_succeeds() {
1432        let mut test_values = test_setup();
1433
1434        // Set country code
1435        let set_country_fut = test_values.iface_manager.set_country(None);
1436        let mut set_country_fut = pin!(set_country_fut);
1437        assert_matches!(test_values.exec.run_until_stalled(&mut set_country_fut), Poll::Pending);
1438
1439        // Verify the service sees the request
1440        let next_message = test_values.receiver.next();
1441        let mut next_message = pin!(next_message);
1442
1443        assert_matches!(
1444            test_values.exec.run_until_stalled(&mut next_message),
1445            Poll::Ready(Some(IfaceManagerRequest::SetCountry(SetCountryRequest{
1446                country_code: None,
1447                responder
1448            }))) => {
1449                responder.send(Ok(())).expect("failed to send stop AP response");
1450            }
1451        );
1452
1453        // Verify that the client gets the response
1454        assert_matches!(
1455            test_values.exec.run_until_stalled(&mut set_country_fut),
1456            Poll::Ready(Ok(_))
1457        );
1458    }
1459
1460    #[test_case(NegativeTestFailureMode::RequestFailure; "request failure")]
1461    #[test_case(NegativeTestFailureMode::OperationFailure; "operation failure")]
1462    #[test_case(NegativeTestFailureMode::ServiceFailure; "service failure")]
1463    #[fuchsia::test(add_test_attr = false)]
1464    fn set_country_negative_test(failure_mode: NegativeTestFailureMode) {
1465        let mut test_values = test_setup();
1466
1467        // Set country code
1468        let set_country_fut = test_values.iface_manager.set_country(None);
1469        let mut set_country_fut = pin!(set_country_fut);
1470        assert_matches!(test_values.exec.run_until_stalled(&mut set_country_fut), Poll::Pending);
1471        let service_fut =
1472            iface_manager_api_negative_test(test_values.receiver, failure_mode.clone());
1473        let mut service_fut = pin!(service_fut);
1474
1475        match failure_mode {
1476            NegativeTestFailureMode::RequestFailure => {}
1477            _ => {
1478                // Run the request and the servicing of the request
1479                assert_matches!(
1480                    test_values.exec.run_until_stalled(&mut set_country_fut),
1481                    Poll::Pending
1482                );
1483                assert_matches!(
1484                    test_values.exec.run_until_stalled(&mut service_fut),
1485                    Poll::Ready(())
1486                );
1487            }
1488        }
1489
1490        // Verify that the client gets the response
1491        assert_matches!(
1492            test_values.exec.run_until_stalled(&mut set_country_fut),
1493            Poll::Ready(Err(_))
1494        );
1495    }
1496
1497    #[fuchsia::test]
1498    fn test_sme_for_scan() {
1499        let mut exec = fasync::TestExecutor::new();
1500
1501        // Build an SME specifically for scanning.
1502        let (proxy, server_end) = create_proxy::<fidl_sme::ClientSmeMarker>();
1503        let (defect_sender, _defect_receiver) = mpsc::channel(100);
1504        let sme = SmeForScan::new(proxy, 0, defect_sender);
1505        let mut sme_stream = server_end.into_stream();
1506
1507        // Construct a scan request.
1508        let scan_request = fidl_sme::ScanRequest::Active(fidl_sme::ActiveScanRequest {
1509            ssids: vec![vec![]],
1510            channels: vec![],
1511        });
1512
1513        // Issue the scan request.
1514        let scan_result_fut = sme.scan(&scan_request);
1515        let mut scan_result_fut = pin!(scan_result_fut);
1516        assert_matches!(exec.run_until_stalled(&mut scan_result_fut), Poll::Pending);
1517
1518        // Poll the server end of the SME and expect that a scan request has been forwarded.
1519        assert_matches!(
1520            exec.run_until_stalled(&mut sme_stream.next()),
1521            Poll::Ready(Some(Ok(fidl_sme::ClientSmeRequest::Scan {
1522                req, ..
1523            }))) => {
1524                assert_eq!(scan_request, req)
1525            }
1526        );
1527    }
1528
1529    #[fuchsia::test]
1530    fn sme_for_scan_defects() {
1531        let _exec = fasync::TestExecutor::new();
1532
1533        // Build an SME specifically for scanning.
1534        let (proxy, _) = create_proxy::<fidl_sme::ClientSmeMarker>();
1535        let (defect_sender, mut defect_receiver) = mpsc::channel(100);
1536        let iface_id = rand::random::<u16>();
1537        let sme = SmeForScan::new(proxy, iface_id, defect_sender);
1538
1539        sme.log_aborted_scan_defect();
1540        sme.log_failed_scan_defect();
1541        sme.log_empty_scan_defect();
1542
1543        assert_eq!(
1544            defect_receiver.try_next().expect("missing canceled scan error"),
1545            Some(Defect::Iface(IfaceFailure::CanceledScan { iface_id })),
1546        );
1547        assert_eq!(
1548            defect_receiver.try_next().expect("missing failed scan error"),
1549            Some(Defect::Iface(IfaceFailure::FailedScan { iface_id })),
1550        );
1551        assert_eq!(
1552            defect_receiver.try_next().expect("missing empty scan results error"),
1553            Some(Defect::Iface(IfaceFailure::EmptyScanResults { iface_id })),
1554        );
1555    }
1556
1557    #[fuchsia::test]
1558    fn sme_for_scan_timeout() {
1559        let mut exec = fasync::TestExecutor::new_with_fake_time();
1560        exec.set_fake_time(fasync::MonotonicInstant::from_nanos(0));
1561
1562        // Create the SmeForScan
1563        let (proxy, _server) = create_proxy::<fidl_sme::ClientSmeMarker>();
1564        let (defect_sender, mut defect_receiver) = mpsc::channel(100);
1565        let iface_id = rand::random::<u16>();
1566        let sme = SmeForScan::new(proxy, iface_id, defect_sender);
1567
1568        // Issue the scan request.
1569        let scan_request = fidl_sme::ScanRequest::Active(fidl_sme::ActiveScanRequest {
1570            ssids: vec![vec![]],
1571            channels: vec![],
1572        });
1573        let scan_result_fut = sme.scan(&scan_request);
1574        let mut scan_result_fut = pin!(scan_result_fut);
1575        assert_matches!(exec.run_until_stalled(&mut scan_result_fut), Poll::Pending);
1576
1577        // Advance the clock so that the timeout expires.
1578        exec.set_fake_time(fasync::MonotonicInstant::after(
1579            SCAN_TIMEOUT + fasync::MonotonicDuration::from_seconds(1),
1580        ));
1581
1582        // Verify that the future returns and that a defect is logged.
1583        assert_matches!(exec.run_until_stalled(&mut scan_result_fut), Poll::Ready(Err(_)));
1584        assert_eq!(
1585            defect_receiver.try_next().expect("missing empty scan results error"),
1586            Some(Defect::Iface(IfaceFailure::Timeout {
1587                iface_id,
1588                source: telemetry::TimeoutSource::Scan,
1589            })),
1590        );
1591    }
1592
1593    #[fuchsia::test]
1594    fn state_machine_sme_disconnects_successfully() {
1595        let mut exec = fasync::TestExecutor::new();
1596
1597        // Build an SME wrapper.
1598        let (proxy, sme_fut) = create_proxy::<fidl_sme::ClientSmeMarker>();
1599        let (defect_sender, _defect_receiver) = mpsc::channel(100);
1600        let iface_id = rand::random::<u16>();
1601        let sme = SmeForClientStateMachine::new(proxy, iface_id, defect_sender);
1602
1603        // Request a disconnect and run the future until it stalls.
1604        let fut = sme.disconnect(fidl_sme::UserDisconnectReason::FidlStopClientConnectionsRequest);
1605        let mut fut = pin!(fut);
1606        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1607
1608        // Ack the disconnect request.
1609        let mut sme_fut = pin!(sme_fut.into_stream().into_future());
1610        assert_matches!(
1611            poll_sme_req(&mut exec, &mut sme_fut),
1612            Poll::Ready(fidl_sme::ClientSmeRequest::Disconnect{
1613                responder,
1614                reason: fidl_sme::UserDisconnectReason::FidlStopClientConnectionsRequest
1615            }) => {
1616                responder.send().expect("could not send sme response");
1617            }
1618        );
1619
1620        // Verify that the disconnect was successful.
1621        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(Ok(())));
1622    }
1623
1624    #[fuchsia::test]
1625    fn state_machine_sme_fails_to_disconnect() {
1626        let mut exec = fasync::TestExecutor::new();
1627
1628        // Build an SME wrapper.
1629        let (proxy, _) = create_proxy::<fidl_sme::ClientSmeMarker>();
1630        let (defect_sender, _defect_receiver) = mpsc::channel(100);
1631        let iface_id = rand::random::<u16>();
1632        let sme = SmeForClientStateMachine::new(proxy, iface_id, defect_sender);
1633
1634        // Request a disconnect and expect an immediate error return.
1635        let fut = sme.disconnect(fidl_sme::UserDisconnectReason::FidlStopClientConnectionsRequest);
1636        let mut fut = pin!(fut);
1637        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(Err(_)));
1638    }
1639
1640    #[fuchsia::test]
1641    fn state_machine_sme_disconnect_timeout() {
1642        let mut exec = fasync::TestExecutor::new_with_fake_time();
1643        exec.set_fake_time(fasync::MonotonicInstant::from_nanos(0));
1644
1645        // Build an SME wrapper.
1646        let (proxy, _sme_fut) = create_proxy::<fidl_sme::ClientSmeMarker>();
1647        let (defect_sender, mut defect_receiver) = mpsc::channel(100);
1648        let iface_id = rand::random::<u16>();
1649        let sme = SmeForClientStateMachine::new(proxy, iface_id, defect_sender);
1650
1651        // Request a disconnect and run the future until it stalls.
1652        let fut = sme.disconnect(fidl_sme::UserDisconnectReason::FidlStopClientConnectionsRequest);
1653        let mut fut = pin!(fut);
1654        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1655
1656        // Advance the clock beyond the timeout.
1657        exec.set_fake_time(fasync::MonotonicInstant::after(
1658            DISCONNECT_TIMEOUT + fasync::MonotonicDuration::from_seconds(1),
1659        ));
1660
1661        // Verify that the future returns and that a defect is logged.
1662        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(Err(_)));
1663        assert_eq!(
1664            defect_receiver.try_next().expect("missing empty scan results error"),
1665            Some(Defect::Iface(IfaceFailure::Timeout {
1666                iface_id,
1667                source: telemetry::TimeoutSource::Disconnect,
1668            })),
1669        );
1670    }
1671
1672    #[fuchsia::test]
1673    fn state_machine_sme_roam_sends_request() {
1674        let mut exec = fasync::TestExecutor::new();
1675
1676        // Build an SME wrapper.
1677        let (proxy, sme_fut) = create_proxy::<fidl_sme::ClientSmeMarker>();
1678        let (defect_sender, _defect_receiver) = mpsc::channel(100);
1679        let iface_id = rand::random::<u16>();
1680        let sme = SmeForClientStateMachine::new(proxy, iface_id, defect_sender);
1681
1682        // Request a roam via the sme proxy
1683        let roam_request =
1684            fidl_sme::RoamRequest { bss_description: random_fidl_bss_description!() };
1685        sme.roam(&roam_request).unwrap();
1686
1687        // Verify SME gets the request
1688        let mut sme_fut = pin!(sme_fut.into_stream().into_future());
1689        assert_matches!(
1690            poll_sme_req(&mut exec, &mut sme_fut),
1691            Poll::Ready(fidl_sme::ClientSmeRequest::Roam {
1692                req, ..
1693            }) => {
1694                assert_eq!(req, roam_request);
1695            }
1696        );
1697    }
1698
1699    fn generate_connect_request() -> fidl_sme::ConnectRequest {
1700        let connection_selection = generate_connect_selection();
1701        fidl_sme::ConnectRequest {
1702            ssid: connection_selection.target.network.ssid.to_vec(),
1703            bss_description: Sequestered::release(connection_selection.target.bss.bss_description),
1704            multiple_bss_candidates: connection_selection.target.network_has_multiple_bss,
1705            authentication: connection_selection.target.authenticator.clone().into(),
1706            deprecated_scan_type: fidl_fuchsia_wlan_common::ScanType::Active,
1707        }
1708    }
1709
1710    #[fuchsia::test]
1711    fn state_machine_sme_connects_successfully() {
1712        let mut exec = fasync::TestExecutor::new();
1713
1714        // Build an SME wrapper.
1715        let (proxy, sme_fut) = create_proxy::<fidl_sme::ClientSmeMarker>();
1716        let (defect_sender, _defect_receiver) = mpsc::channel(100);
1717        let iface_id = rand::random::<u16>();
1718        let sme = SmeForClientStateMachine::new(proxy, iface_id, defect_sender);
1719
1720        // Request a connection.
1721        let connect_request = generate_connect_request();
1722        let fut = sme.connect(&connect_request);
1723        let mut fut = pin!(fut);
1724        match exec.run_until_stalled(&mut fut) {
1725            Poll::Pending => {}
1726            _ => panic!("connect request should be pending."),
1727        }
1728
1729        // Ack the connect request.
1730        let mut sme_fut = pin!(sme_fut.into_stream().into_future());
1731        assert_matches!(
1732            poll_sme_req(&mut exec, &mut sme_fut),
1733            Poll::Ready(fidl_sme::ClientSmeRequest::Connect{
1734                txn,
1735                ..
1736            }) => {
1737                let (_stream, ctrl) = txn.expect("connect txn unused")
1738                    .into_stream_and_control_handle();
1739                ctrl
1740                    .send_on_connect_result(&fidl_sme::ConnectResult {
1741                        code: fidl_ieee80211::StatusCode::Success,
1742                        is_credential_rejected: false,
1743                        is_reconnect: false,
1744                    })
1745                    .expect("failed to send connection completion");
1746            }
1747        );
1748
1749        // Expect a successful result.
1750        match exec.run_until_stalled(&mut fut) {
1751            Poll::Ready(Ok((result, txn))) => {
1752                assert_eq!(
1753                    result,
1754                    fidl_sme::ConnectResult {
1755                        code: fidl_ieee80211::StatusCode::Success,
1756                        is_credential_rejected: false,
1757                        is_reconnect: false,
1758                    }
1759                );
1760                // This is required or else the test panics on exit with
1761                // "receivers must not outlive their executor".
1762                drop(txn)
1763            }
1764            Poll::Ready(Err(_)) => panic!("connection should be successful"),
1765            Poll::Pending => panic!("connect request should not be pending."),
1766        }
1767    }
1768
1769    #[fuchsia::test]
1770    fn state_machine_sme_connection_failure() {
1771        let mut exec = fasync::TestExecutor::new();
1772
1773        // Build an SME wrapper.
1774        let (proxy, sme_fut) = create_proxy::<fidl_sme::ClientSmeMarker>();
1775        let (defect_sender, _defect_receiver) = mpsc::channel(100);
1776        let iface_id = rand::random::<u16>();
1777        let sme = SmeForClientStateMachine::new(proxy, iface_id, defect_sender);
1778
1779        // Request a connection.
1780        let connect_request = generate_connect_request();
1781        let fut = sme.connect(&connect_request);
1782        let mut fut = pin!(fut);
1783        match exec.run_until_stalled(&mut fut) {
1784            Poll::Pending => {}
1785            _ => panic!("connect request should be pending."),
1786        }
1787
1788        // Ack the connect request.
1789        let mut sme_fut = pin!(sme_fut.into_stream().into_future());
1790        assert_matches!(
1791            poll_sme_req(&mut exec, &mut sme_fut),
1792            Poll::Ready(fidl_sme::ClientSmeRequest::Connect{
1793                txn,
1794                ..
1795            }) => {
1796                let (_stream, ctrl) = txn.expect("connect txn unused")
1797                    .into_stream_and_control_handle();
1798                ctrl
1799                    .send_on_connect_result(&fidl_sme::ConnectResult {
1800                        code: fidl_ieee80211::StatusCode::RefusedReasonUnspecified,
1801                        is_credential_rejected: false,
1802                        is_reconnect: false,
1803                    })
1804                    .expect("failed to send connection completion");
1805            }
1806        );
1807
1808        // Expect a successful result.
1809        match exec.run_until_stalled(&mut fut) {
1810            Poll::Ready(Ok((result, txn))) => {
1811                assert_eq!(
1812                    result,
1813                    fidl_sme::ConnectResult {
1814                        code: fidl_ieee80211::StatusCode::RefusedReasonUnspecified,
1815                        is_credential_rejected: false,
1816                        is_reconnect: false,
1817                    }
1818                );
1819                // This is required or else the test panics on exit with
1820                // "receivers must not outlive their executor".
1821                drop(txn)
1822            }
1823            Poll::Ready(Err(_)) => panic!("connection should be successful"),
1824            Poll::Pending => panic!("connect request should not be pending."),
1825        }
1826    }
1827
1828    #[fuchsia::test]
1829    fn state_machine_sme_connect_request_fails() {
1830        let mut exec = fasync::TestExecutor::new();
1831
1832        // Build an SME wrapper.
1833        let (proxy, _) = create_proxy::<fidl_sme::ClientSmeMarker>();
1834        let (defect_sender, _defect_receiver) = mpsc::channel(100);
1835        let iface_id = rand::random::<u16>();
1836        let sme = SmeForClientStateMachine::new(proxy, iface_id, defect_sender);
1837
1838        // Request a disconnect and expect an immediate error return.
1839        let connect_request = generate_connect_request();
1840        let fut = sme.connect(&connect_request);
1841        let mut fut = pin!(fut);
1842        match exec.run_until_stalled(&mut fut) {
1843            Poll::Ready(Err(_)) => {}
1844            _ => panic!("connect request should have failed."),
1845        }
1846    }
1847
1848    #[fuchsia::test]
1849    fn state_machine_sme_connect_timeout() {
1850        let mut exec = fasync::TestExecutor::new_with_fake_time();
1851        exec.set_fake_time(fasync::MonotonicInstant::from_nanos(0));
1852
1853        // Build an SME wrapper.
1854        let (proxy, _sme_fut) = create_proxy::<fidl_sme::ClientSmeMarker>();
1855        let (defect_sender, mut defect_receiver) = mpsc::channel(100);
1856        let iface_id = rand::random::<u16>();
1857        let sme = SmeForClientStateMachine::new(proxy, iface_id, defect_sender);
1858
1859        // Request a connection and run the future until it stalls.
1860        let connect_request = generate_connect_request();
1861        let fut = sme.connect(&connect_request);
1862        let mut fut = pin!(fut);
1863        match exec.run_until_stalled(&mut fut) {
1864            Poll::Pending => {}
1865            _ => panic!("connect future completed unexpectedly"),
1866        }
1867
1868        // Advance the clock beyond the timeout.
1869        exec.set_fake_time(fasync::MonotonicInstant::after(
1870            CONNECT_TIMEOUT + fasync::MonotonicDuration::from_seconds(1),
1871        ));
1872
1873        // Verify that the future returns and that a defect is logged.
1874        match exec.run_until_stalled(&mut fut) {
1875            Poll::Ready(Err(_)) => {}
1876            Poll::Ready(Ok(_)) => panic!("connect future completed successfully"),
1877            Poll::Pending => panic!("connect future did not complete"),
1878        }
1879        assert_eq!(
1880            defect_receiver.try_next().expect("missing connection timeout"),
1881            Some(Defect::Iface(IfaceFailure::Timeout {
1882                iface_id,
1883                source: telemetry::TimeoutSource::Connect,
1884            })),
1885        );
1886    }
1887
1888    #[fuchsia::test]
1889    fn wait_for_connect_result_error() {
1890        let mut exec = fasync::TestExecutor::new();
1891        let (connect_txn, remote) = create_proxy::<fidl_sme::ConnectTransactionMarker>();
1892        let mut response_stream = connect_txn.take_event_stream();
1893
1894        let fut = wait_for_connect_result(&mut response_stream);
1895
1896        let mut fut = pin!(fut);
1897        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1898
1899        // Drop server end, and verify future completes with error
1900        drop(remote);
1901        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(Err(_)));
1902    }
1903
1904    #[fuchsia::test]
1905    fn wait_for_connect_result_ignores_other_events() {
1906        let mut exec = fasync::TestExecutor::new();
1907        let (connect_txn, remote) = create_proxy::<fidl_sme::ConnectTransactionMarker>();
1908        let request_handle = remote.into_stream().control_handle();
1909        let mut response_stream = connect_txn.take_event_stream();
1910
1911        let fut = wait_for_connect_result(&mut response_stream);
1912
1913        let mut fut = pin!(fut);
1914        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1915
1916        // Send some unexpected response
1917        let ind = fidl_internal::SignalReportIndication { rssi_dbm: -20, snr_db: 25 };
1918        request_handle.send_on_signal_report(&ind).unwrap();
1919
1920        // Future should still be waiting for OnConnectResult event
1921        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1922
1923        // Send expected ConnectResult response
1924        let sme_result = fidl_sme::ConnectResult {
1925            code: fidl_ieee80211::StatusCode::Success,
1926            is_credential_rejected: false,
1927            is_reconnect: false,
1928        };
1929        request_handle.send_on_connect_result(&sme_result).unwrap();
1930        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(Ok(response)) => {
1931            assert_eq!(sme_result, response);
1932        });
1933    }
1934
1935    fn poll_ap_sme_req(
1936        exec: &mut fasync::TestExecutor,
1937        next_sme_req: &mut StreamFuture<fidl_sme::ApSmeRequestStream>,
1938    ) -> Poll<fidl_sme::ApSmeRequest> {
1939        exec.run_until_stalled(next_sme_req).map(|(req, stream)| {
1940            *next_sme_req = stream.into_future();
1941            req.expect("did not expect the SME request stream to end")
1942                .expect("error polling SME request stream")
1943        })
1944    }
1945
1946    #[fuchsia::test]
1947    fn state_machine_sme_starts_ap_successfully() {
1948        let mut exec = fasync::TestExecutor::new();
1949
1950        // Build an SME wrapper.
1951        let (proxy, sme_fut) = create_proxy::<fidl_sme::ApSmeMarker>();
1952        let (defect_sender, _defect_receiver) = mpsc::channel(100);
1953        let iface_id = rand::random::<u16>();
1954        let sme = SmeForApStateMachine::new(proxy, iface_id, defect_sender);
1955
1956        // Start the AP and run the future until it stalls.
1957        let config = fidl_sme::ApConfig::from(create_ap_config());
1958        let fut = sme.start(&config);
1959        let mut fut = pin!(fut);
1960        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1961
1962        // Respond to the start request.
1963        let mut sme_fut = pin!(sme_fut.into_stream().into_future());
1964        assert_matches!(
1965            poll_ap_sme_req(&mut exec, &mut sme_fut),
1966            Poll::Ready(fidl_sme::ApSmeRequest::Start { responder, .. }) => {
1967                responder.send(fidl_sme::StartApResultCode::Success)
1968                    .expect("could not send sme response");
1969            }
1970        );
1971
1972        // Verify that the start response was returned.
1973        assert_matches!(
1974            exec.run_until_stalled(&mut fut),
1975            Poll::Ready(Ok(fidl_sme::StartApResultCode::Success))
1976        );
1977    }
1978
1979    #[fuchsia::test]
1980    fn state_machine_sme_fails_to_request_start_ap() {
1981        let mut exec = fasync::TestExecutor::new();
1982
1983        // Build an SME wrapper.
1984        let (proxy, _) = create_proxy::<fidl_sme::ApSmeMarker>();
1985        let (defect_sender, _defect_receiver) = mpsc::channel(100);
1986        let iface_id = rand::random::<u16>();
1987        let sme = SmeForApStateMachine::new(proxy, iface_id, defect_sender);
1988
1989        // Start the AP and observe an immediate failure.
1990        let config = fidl_sme::ApConfig::from(create_ap_config());
1991        let fut = sme.start(&config);
1992        let mut fut = pin!(fut);
1993        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(Err(_)));
1994    }
1995
1996    #[fuchsia::test]
1997    fn state_machine_sme_start_ap_timeout() {
1998        let mut exec = fasync::TestExecutor::new_with_fake_time();
1999        exec.set_fake_time(fasync::MonotonicInstant::from_nanos(0));
2000
2001        // Build an SME wrapper.
2002        let (proxy, _sme_fut) = create_proxy::<fidl_sme::ApSmeMarker>();
2003        let (defect_sender, mut defect_receiver) = mpsc::channel(100);
2004        let iface_id = rand::random::<u16>();
2005        let sme = SmeForApStateMachine::new(proxy, iface_id, defect_sender);
2006
2007        // Start the AP and run the future until it stalls.
2008        let config = fidl_sme::ApConfig::from(create_ap_config());
2009        let fut = sme.start(&config);
2010        let mut fut = pin!(fut);
2011        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2012
2013        // Advance the clock beyond the timeout.
2014        exec.set_fake_time(fasync::MonotonicInstant::after(
2015            START_AP_TIMEOUT + fasync::MonotonicDuration::from_seconds(1),
2016        ));
2017
2018        // Verify that the future returns and that a defect is logged.
2019        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(Err(_)));
2020        assert_eq!(
2021            defect_receiver.try_next().expect("missing connection timeout"),
2022            Some(Defect::Iface(IfaceFailure::Timeout {
2023                iface_id,
2024                source: telemetry::TimeoutSource::ApStart,
2025            })),
2026        );
2027    }
2028
2029    #[fuchsia::test]
2030    fn state_machine_sme_stops_ap_successfully() {
2031        let mut exec = fasync::TestExecutor::new();
2032
2033        // Build an SME wrapper.
2034        let (proxy, sme_fut) = create_proxy::<fidl_sme::ApSmeMarker>();
2035        let (defect_sender, _defect_receiver) = mpsc::channel(100);
2036        let iface_id = rand::random::<u16>();
2037        let sme = SmeForApStateMachine::new(proxy, iface_id, defect_sender);
2038
2039        // Stop the AP and run the future until it stalls.
2040        let fut = sme.stop();
2041        let mut fut = pin!(fut);
2042        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2043
2044        // Respond to the stop request.
2045        let mut sme_fut = pin!(sme_fut.into_stream().into_future());
2046        assert_matches!(
2047            poll_ap_sme_req(&mut exec, &mut sme_fut),
2048            Poll::Ready(fidl_sme::ApSmeRequest::Stop { responder }) => {
2049                responder.send(fidl_sme::StopApResultCode::Success)
2050                    .expect("could not send sme response");
2051            }
2052        );
2053
2054        // Verify that the start response was returned.
2055        assert_matches!(
2056            exec.run_until_stalled(&mut fut),
2057            Poll::Ready(Ok(fidl_sme::StopApResultCode::Success))
2058        );
2059    }
2060
2061    #[fuchsia::test]
2062    fn state_machine_sme_fails_to_request_stop_ap() {
2063        let mut exec = fasync::TestExecutor::new();
2064
2065        // Build an SME wrapper.
2066        let (proxy, _) = create_proxy::<fidl_sme::ApSmeMarker>();
2067        let (defect_sender, _defect_receiver) = mpsc::channel(100);
2068        let iface_id = rand::random::<u16>();
2069        let sme = SmeForApStateMachine::new(proxy, iface_id, defect_sender);
2070
2071        // Stop the AP and observe an immediate failure.
2072        let fut = sme.stop();
2073        let mut fut = pin!(fut);
2074        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(Err(_)));
2075    }
2076
2077    #[fuchsia::test]
2078    fn state_machine_sme_stop_ap_timeout() {
2079        let mut exec = fasync::TestExecutor::new_with_fake_time();
2080        exec.set_fake_time(fasync::MonotonicInstant::from_nanos(0));
2081
2082        // Build an SME wrapper.
2083        let (proxy, _sme_fut) = create_proxy::<fidl_sme::ApSmeMarker>();
2084        let (defect_sender, mut defect_receiver) = mpsc::channel(100);
2085        let iface_id = rand::random::<u16>();
2086        let sme = SmeForApStateMachine::new(proxy, iface_id, defect_sender);
2087
2088        // Stop the AP and run the future until it stalls.
2089        let fut = sme.stop();
2090        let mut fut = pin!(fut);
2091        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2092
2093        // Advance the clock beyond the timeout.
2094        exec.set_fake_time(fasync::MonotonicInstant::after(
2095            START_AP_TIMEOUT + fasync::MonotonicDuration::from_seconds(1),
2096        ));
2097
2098        // Verify that the future returns and that a defect is logged.
2099        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(Err(_)));
2100        assert_eq!(
2101            defect_receiver.try_next().expect("missing connection timeout"),
2102            Some(Defect::Iface(IfaceFailure::Timeout {
2103                iface_id,
2104                source: telemetry::TimeoutSource::ApStop,
2105            })),
2106        );
2107    }
2108
2109    #[fuchsia::test]
2110    fn state_machine_sme_successfully_queries_ap_status() {
2111        let mut exec = fasync::TestExecutor::new();
2112
2113        // Build an SME wrapper.
2114        let (proxy, sme_fut) = create_proxy::<fidl_sme::ApSmeMarker>();
2115        let (defect_sender, _defect_receiver) = mpsc::channel(100);
2116        let iface_id = rand::random::<u16>();
2117        let sme = SmeForApStateMachine::new(proxy, iface_id, defect_sender);
2118
2119        // Query AP status and run the future until it stalls.
2120        let fut = sme.status();
2121        let mut fut = pin!(fut);
2122        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2123
2124        // Respond to the status request.
2125        let mut sme_fut = pin!(sme_fut.into_stream().into_future());
2126        assert_matches!(
2127            poll_ap_sme_req(&mut exec, &mut sme_fut),
2128            Poll::Ready(fidl_sme::ApSmeRequest::Status{ responder }) => {
2129                let response = fidl_sme::ApStatusResponse { running_ap: None };
2130                responder.send(&response).expect("could not send AP status response");
2131            }
2132        );
2133
2134        // Verify that the status response was returned.
2135        assert_matches!(
2136            exec.run_until_stalled(&mut fut),
2137            Poll::Ready(Ok(fidl_sme::ApStatusResponse { running_ap: None }))
2138        );
2139    }
2140
2141    #[fuchsia::test]
2142    fn state_machine_sme_fails_to_query_ap_status() {
2143        let mut exec = fasync::TestExecutor::new();
2144
2145        // Build an SME wrapper.
2146        let (proxy, _) = create_proxy::<fidl_sme::ApSmeMarker>();
2147        let (defect_sender, _defect_receiver) = mpsc::channel(100);
2148        let iface_id = rand::random::<u16>();
2149        let sme = SmeForApStateMachine::new(proxy, iface_id, defect_sender);
2150
2151        // Query status and observe an immediate failure.
2152        let fut = sme.status();
2153        let mut fut = pin!(fut);
2154        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(Err(_)));
2155    }
2156
2157    #[fuchsia::test]
2158    fn state_machine_sme_query_ap_status_timeout() {
2159        let mut exec = fasync::TestExecutor::new_with_fake_time();
2160        exec.set_fake_time(fasync::MonotonicInstant::from_nanos(0));
2161
2162        // Build an SME wrapper.
2163        let (proxy, _sme_fut) = create_proxy::<fidl_sme::ApSmeMarker>();
2164        let (defect_sender, mut defect_receiver) = mpsc::channel(100);
2165        let iface_id = rand::random::<u16>();
2166        let sme = SmeForApStateMachine::new(proxy, iface_id, defect_sender);
2167
2168        // Query AP status and run the future until it stalls.
2169        let fut = sme.status();
2170        let mut fut = pin!(fut);
2171        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2172
2173        // Advance the clock beyond the timeout.
2174        exec.set_fake_time(fasync::MonotonicInstant::after(
2175            AP_STATUS_TIMEOUT + fasync::MonotonicDuration::from_seconds(1),
2176        ));
2177
2178        // Verify that the future returns and that a defect is logged.
2179        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(Err(_)));
2180        assert_eq!(
2181            defect_receiver.try_next().expect("missing connection timeout"),
2182            Some(Defect::Iface(IfaceFailure::Timeout {
2183                iface_id,
2184                source: telemetry::TimeoutSource::ApStatus,
2185            })),
2186        );
2187    }
2188}