Skip to main content

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 fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211;
496    use fidl_fuchsia_wlan_internal as fidl_internal;
497    use fuchsia_async as fasync;
498    use futures::StreamExt;
499    use futures::future::LocalBoxFuture;
500    use futures::stream::StreamFuture;
501    use futures::task::Poll;
502    use rand::Rng;
503    use std::pin::pin;
504    use test_case::test_case;
505    use wlan_common::channel::Cbw;
506    use wlan_common::sequestered::Sequestered;
507    use wlan_common::{RadioConfig, random_fidl_bss_description};
508
509    struct TestValues {
510        exec: fasync::TestExecutor,
511        iface_manager: IfaceManager,
512        receiver: mpsc::Receiver<IfaceManagerRequest>,
513    }
514
515    fn test_setup() -> TestValues {
516        let exec = fasync::TestExecutor::new();
517        let (sender, receiver) = mpsc::channel(1);
518        TestValues { exec, iface_manager: IfaceManager { sender }, receiver }
519    }
520
521    #[allow(clippy::enum_variant_names, reason = "mass allow for https://fxbug.dev/381896734")]
522    #[derive(Clone)]
523    enum NegativeTestFailureMode {
524        RequestFailure,
525        OperationFailure,
526        ServiceFailure,
527    }
528
529    fn handle_negative_test_result_responder<T: std::fmt::Debug>(
530        responder: oneshot::Sender<Result<T, Error>>,
531        failure_mode: NegativeTestFailureMode,
532    ) {
533        match failure_mode {
534            NegativeTestFailureMode::RequestFailure => {
535                panic!("Test bug: this request should have been handled previously")
536            }
537            NegativeTestFailureMode::OperationFailure => {
538                responder
539                    .send(Err(format_err!("operation failed")))
540                    .expect("failed to send response");
541            }
542            NegativeTestFailureMode::ServiceFailure => {
543                // Just drop the responder so that the client side sees a failure.
544                drop(responder);
545            }
546        }
547    }
548
549    fn handle_negative_test_responder<T: std::fmt::Debug>(
550        responder: oneshot::Sender<T>,
551        failure_mode: NegativeTestFailureMode,
552    ) {
553        match failure_mode {
554            NegativeTestFailureMode::RequestFailure | NegativeTestFailureMode::OperationFailure => {
555                panic!("Test bug: invalid operation")
556            }
557            NegativeTestFailureMode::ServiceFailure => {
558                // Just drop the responder so that the client side sees a failure.
559                drop(responder);
560            }
561        }
562    }
563
564    fn iface_manager_api_negative_test(
565        mut receiver: mpsc::Receiver<IfaceManagerRequest>,
566        failure_mode: NegativeTestFailureMode,
567    ) -> LocalBoxFuture<'static, ()> {
568        if let NegativeTestFailureMode::RequestFailure = failure_mode {
569            // Drop the receiver so that no requests can be made.
570            drop(receiver);
571            let fut = async move {};
572            return Box::pin(fut);
573        }
574
575        let fut = async move {
576            let req = match receiver.next().await {
577                Some(req) => req,
578                None => panic!("no request available."),
579            };
580
581            match req {
582                // Result<(), Err> responder values
583                IfaceManagerRequest::StopClientConnections(StopClientConnectionsRequest {
584                    responder,
585                    ..
586                })
587                | IfaceManagerRequest::Disconnect(DisconnectRequest { responder, .. })
588                | IfaceManagerRequest::StopAp(StopApRequest { responder, .. })
589                | IfaceManagerRequest::StopAllAps(StopAllApsRequest { responder, .. })
590                | IfaceManagerRequest::SetCountry(SetCountryRequest { responder, .. })
591                | IfaceManagerRequest::StartClientConnections(StartClientConnectionsRequest {
592                    responder,
593                })
594                | IfaceManagerRequest::Connect(ConnectRequest { responder, .. }) => {
595                    handle_negative_test_result_responder(responder, failure_mode);
596                }
597                // Result<ClientSmeProxy, Err>
598                IfaceManagerRequest::GetScanProxy(ScanProxyRequest { responder }) => {
599                    handle_negative_test_result_responder(responder, failure_mode);
600                }
601                // Result<oneshot::Receiver<()>, Err>
602                IfaceManagerRequest::StartAp(StartApRequest { responder, .. }) => {
603                    handle_negative_test_result_responder(responder, failure_mode);
604                }
605                // Unit responder values
606                IfaceManagerRequest::RecordIdleIface(RecordIdleIfaceRequest {
607                    responder, ..
608                })
609                | IfaceManagerRequest::AddIface(AddIfaceRequest { responder, .. })
610                | IfaceManagerRequest::RemoveIface(RemoveIfaceRequest { responder, .. }) => {
611                    handle_negative_test_responder(responder, failure_mode);
612                }
613                // Boolean responder values
614                IfaceManagerRequest::HasIdleIface(HasIdleIfaceRequest { responder }) => {
615                    handle_negative_test_responder(responder, failure_mode);
616                }
617            }
618        };
619        Box::pin(fut)
620    }
621
622    #[fuchsia::test]
623    fn test_disconnect_succeeds() {
624        let mut test_values = test_setup();
625
626        // Issue a disconnect command and wait for the command to be sent.
627        let req = ap_types::NetworkIdentifier {
628            ssid: Ssid::try_from("foo").unwrap(),
629            security_type: ap_types::SecurityType::None,
630        };
631        let req_reason = client_types::DisconnectReason::NetworkUnsaved;
632        let disconnect_fut = test_values.iface_manager.disconnect(req.clone(), req_reason);
633        let mut disconnect_fut = pin!(disconnect_fut);
634
635        assert_matches!(test_values.exec.run_until_stalled(&mut disconnect_fut), Poll::Pending);
636
637        // Verify that the receiver sees the command and send back a response.
638        let next_message = test_values.receiver.next();
639        let mut next_message = pin!(next_message);
640
641        assert_matches!(
642            test_values.exec.run_until_stalled(&mut next_message),
643            Poll::Ready(Some(IfaceManagerRequest::Disconnect(DisconnectRequest {
644                network_id, responder, reason
645            }))) => {
646                assert_eq!(network_id, req);
647                assert_eq!(reason, req_reason);
648                responder.send(Ok(())).expect("failed to send disconnect response");
649            }
650        );
651
652        // Verify that the disconnect requestr receives the response.
653        assert_matches!(
654            test_values.exec.run_until_stalled(&mut disconnect_fut),
655            Poll::Ready(Ok(()))
656        );
657    }
658
659    #[test_case(NegativeTestFailureMode::RequestFailure; "request failure")]
660    #[test_case(NegativeTestFailureMode::OperationFailure; "operation failure")]
661    #[test_case(NegativeTestFailureMode::ServiceFailure; "service failure")]
662    #[fuchsia::test(add_test_attr = false)]
663    fn disconnect_negative_test(failure_mode: NegativeTestFailureMode) {
664        let mut test_values = test_setup();
665
666        // Issue a disconnect command and wait for the command to be sent.
667        let req = ap_types::NetworkIdentifier {
668            ssid: Ssid::try_from("foo").unwrap(),
669            security_type: ap_types::SecurityType::None,
670        };
671        let disconnect_fut = test_values
672            .iface_manager
673            .disconnect(req.clone(), client_types::DisconnectReason::NetworkUnsaved);
674        let mut disconnect_fut = pin!(disconnect_fut);
675
676        let service_fut =
677            iface_manager_api_negative_test(test_values.receiver, failure_mode.clone());
678        let mut service_fut = pin!(service_fut);
679
680        match failure_mode {
681            NegativeTestFailureMode::RequestFailure => {}
682            _ => {
683                // Run the request and the servicing of the request
684                assert_matches!(
685                    test_values.exec.run_until_stalled(&mut disconnect_fut),
686                    Poll::Pending
687                );
688                assert_matches!(
689                    test_values.exec.run_until_stalled(&mut service_fut),
690                    Poll::Ready(())
691                );
692            }
693        }
694
695        // Verify that the disconnect requestr receives the response.
696        assert_matches!(
697            test_values.exec.run_until_stalled(&mut disconnect_fut),
698            Poll::Ready(Err(_))
699        );
700    }
701
702    #[fuchsia::test]
703    fn test_connect_succeeds() {
704        let mut test_values = test_setup();
705
706        // Issue a connect command and wait for the command to be sent.
707        let req = ConnectAttemptRequest::new(
708            client_types::NetworkIdentifier {
709                ssid: Ssid::try_from("foo").unwrap(),
710                security_type: client_types::SecurityType::None,
711            },
712            Credential::None,
713            client_types::ConnectReason::FidlConnectRequest,
714        );
715        let connect_fut = test_values.iface_manager.connect(req.clone());
716        let mut connect_fut = pin!(connect_fut);
717
718        assert_matches!(test_values.exec.run_until_stalled(&mut connect_fut), Poll::Pending);
719
720        // Verify that the receiver sees the command and send back a response.
721        let next_message = test_values.receiver.next();
722        let mut next_message = pin!(next_message);
723
724        assert_matches!(
725            test_values.exec.run_until_stalled(&mut next_message),
726            Poll::Ready(Some(IfaceManagerRequest::Connect(ConnectRequest {
727                request, responder
728            }))) => {
729                assert_eq!(request, req);
730                responder.send(Ok(())).expect("failed to send connect response");
731            }
732        );
733
734        // Verify that the connect requestr receives the response.
735        assert_matches!(test_values.exec.run_until_stalled(&mut connect_fut), Poll::Ready(Ok(_)));
736    }
737
738    #[test_case(NegativeTestFailureMode::RequestFailure; "request failure")]
739    #[test_case(NegativeTestFailureMode::OperationFailure; "operation failure")]
740    #[test_case(NegativeTestFailureMode::ServiceFailure; "service failure")]
741    #[fuchsia::test(add_test_attr = false)]
742    fn connect_negative_test(failure_mode: NegativeTestFailureMode) {
743        let mut test_values = test_setup();
744
745        // Issue a connect command and wait for the command to be sent.
746        let req = ConnectAttemptRequest::new(
747            client_types::NetworkIdentifier {
748                ssid: Ssid::try_from("foo").unwrap(),
749                security_type: client_types::SecurityType::None,
750            },
751            Credential::None,
752            client_types::ConnectReason::FidlConnectRequest,
753        );
754        let connect_fut = test_values.iface_manager.connect(req.clone());
755        let mut connect_fut = pin!(connect_fut);
756
757        let service_fut =
758            iface_manager_api_negative_test(test_values.receiver, failure_mode.clone());
759        let mut service_fut = pin!(service_fut);
760
761        match failure_mode {
762            NegativeTestFailureMode::RequestFailure => {}
763            _ => {
764                // Run the request and the servicing of the request
765                assert_matches!(
766                    test_values.exec.run_until_stalled(&mut connect_fut),
767                    Poll::Pending
768                );
769                assert_matches!(
770                    test_values.exec.run_until_stalled(&mut service_fut),
771                    Poll::Ready(())
772                );
773            }
774        }
775
776        // Verify that the request completes in error.
777        assert_matches!(test_values.exec.run_until_stalled(&mut connect_fut), Poll::Ready(Err(_)));
778    }
779
780    #[fuchsia::test]
781    fn test_record_idle_client_succeeds() {
782        let mut test_values = test_setup();
783
784        // Request that an idle client be recorded.
785        let iface_id = 123;
786        let idle_client_fut = test_values.iface_manager.record_idle_client(iface_id);
787        let mut idle_client_fut = pin!(idle_client_fut);
788
789        assert_matches!(test_values.exec.run_until_stalled(&mut idle_client_fut), Poll::Pending);
790
791        // Verify that the receiver sees the request.
792        let next_message = test_values.receiver.next();
793        let mut next_message = pin!(next_message);
794
795        assert_matches!(
796            test_values.exec.run_until_stalled(&mut next_message),
797            Poll::Ready(
798                Some(IfaceManagerRequest::RecordIdleIface(RecordIdleIfaceRequest{ iface_id: 123, responder}))
799            ) => {
800                responder.send(()).expect("failed to send idle iface response");
801            }
802        );
803
804        // Verify that the client sees the response.
805        assert_matches!(
806            test_values.exec.run_until_stalled(&mut idle_client_fut),
807            Poll::Ready(Ok(()))
808        );
809    }
810
811    #[test_case(NegativeTestFailureMode::RequestFailure; "request failure")]
812    #[test_case(NegativeTestFailureMode::ServiceFailure; "service failure")]
813    #[fuchsia::test(add_test_attr = false)]
814    fn test_record_idle_client_service_failure(failure_mode: NegativeTestFailureMode) {
815        let mut test_values = test_setup();
816
817        // Request that an idle client be recorded.
818        let iface_id = 123;
819        let idle_client_fut = test_values.iface_manager.record_idle_client(iface_id);
820        let mut idle_client_fut = pin!(idle_client_fut);
821
822        let service_fut =
823            iface_manager_api_negative_test(test_values.receiver, failure_mode.clone());
824        let mut service_fut = pin!(service_fut);
825
826        match failure_mode {
827            NegativeTestFailureMode::RequestFailure => {}
828            _ => {
829                // Run the request and the servicing of the request
830                assert_matches!(
831                    test_values.exec.run_until_stalled(&mut idle_client_fut),
832                    Poll::Pending
833                );
834                assert_matches!(
835                    test_values.exec.run_until_stalled(&mut service_fut),
836                    Poll::Ready(())
837                );
838            }
839        }
840
841        // Verify that the client side finishes
842        assert_matches!(
843            test_values.exec.run_until_stalled(&mut idle_client_fut),
844            Poll::Ready(Err(_))
845        );
846    }
847
848    #[fuchsia::test]
849    fn test_has_idle_client_success() {
850        let mut test_values = test_setup();
851
852        // Query whether there is an idle client
853        let idle_client_fut = test_values.iface_manager.has_idle_client();
854        let mut idle_client_fut = pin!(idle_client_fut);
855        assert_matches!(test_values.exec.run_until_stalled(&mut idle_client_fut), Poll::Pending);
856
857        // Verify that the service sees the query
858        let next_message = test_values.receiver.next();
859        let mut next_message = pin!(next_message);
860
861        assert_matches!(
862            test_values.exec.run_until_stalled(&mut next_message),
863            Poll::Ready(
864                Some(IfaceManagerRequest::HasIdleIface(HasIdleIfaceRequest{ responder}))
865            ) => responder.send(true).expect("failed to reply to idle client query")
866        );
867
868        // Verify that the client side finishes
869        assert_matches!(
870            test_values.exec.run_until_stalled(&mut idle_client_fut),
871            Poll::Ready(Ok(true))
872        );
873    }
874
875    #[test_case(NegativeTestFailureMode::RequestFailure; "request failure")]
876    #[test_case(NegativeTestFailureMode::ServiceFailure; "service failure")]
877    #[fuchsia::test(add_test_attr = false)]
878    fn idle_client_negative_test(failure_mode: NegativeTestFailureMode) {
879        let mut test_values = test_setup();
880
881        // Query whether there is an idle client
882        let idle_client_fut = test_values.iface_manager.has_idle_client();
883        let mut idle_client_fut = pin!(idle_client_fut);
884        assert_matches!(test_values.exec.run_until_stalled(&mut idle_client_fut), Poll::Pending);
885
886        let service_fut =
887            iface_manager_api_negative_test(test_values.receiver, failure_mode.clone());
888        let mut service_fut = pin!(service_fut);
889
890        match failure_mode {
891            NegativeTestFailureMode::RequestFailure => {}
892            _ => {
893                // Run the request and the servicing of the request
894                assert_matches!(
895                    test_values.exec.run_until_stalled(&mut idle_client_fut),
896                    Poll::Pending
897                );
898                assert_matches!(
899                    test_values.exec.run_until_stalled(&mut service_fut),
900                    Poll::Ready(())
901                );
902            }
903        }
904
905        // Verify that the request completes in error.
906        assert_matches!(
907            test_values.exec.run_until_stalled(&mut idle_client_fut),
908            Poll::Ready(Err(_))
909        );
910    }
911
912    #[fuchsia::test]
913    fn test_add_iface_success() {
914        let mut test_values = test_setup();
915
916        // Add an interface
917        let added_iface_fut = test_values.iface_manager.handle_added_iface(123);
918        let mut added_iface_fut = pin!(added_iface_fut);
919        assert_matches!(test_values.exec.run_until_stalled(&mut added_iface_fut), Poll::Pending);
920
921        // Verify that the service sees the query
922        let next_message = test_values.receiver.next();
923        let mut next_message = pin!(next_message);
924
925        assert_matches!(
926            test_values.exec.run_until_stalled(&mut next_message),
927            Poll::Ready(
928                Some(IfaceManagerRequest::AddIface(AddIfaceRequest{ iface_id: 123, responder }))
929            ) => {
930                responder.send(()).expect("failed to respond while adding iface");
931            }
932        );
933
934        // Verify that the client side finishes
935        assert_matches!(
936            test_values.exec.run_until_stalled(&mut added_iface_fut),
937            Poll::Ready(Ok(()))
938        );
939    }
940
941    #[test_case(NegativeTestFailureMode::RequestFailure; "request failure")]
942    #[test_case(NegativeTestFailureMode::ServiceFailure; "service failure")]
943    #[fuchsia::test(add_test_attr = false)]
944    fn add_iface_negative_test(failure_mode: NegativeTestFailureMode) {
945        let mut test_values = test_setup();
946
947        // Add an interface
948        let added_iface_fut = test_values.iface_manager.handle_added_iface(123);
949        let mut added_iface_fut = pin!(added_iface_fut);
950        assert_matches!(test_values.exec.run_until_stalled(&mut added_iface_fut), Poll::Pending);
951
952        let service_fut =
953            iface_manager_api_negative_test(test_values.receiver, failure_mode.clone());
954        let mut service_fut = pin!(service_fut);
955
956        match failure_mode {
957            NegativeTestFailureMode::RequestFailure => {}
958            _ => {
959                // Run the request and the servicing of the request
960                assert_matches!(
961                    test_values.exec.run_until_stalled(&mut added_iface_fut),
962                    Poll::Pending
963                );
964                assert_matches!(
965                    test_values.exec.run_until_stalled(&mut service_fut),
966                    Poll::Ready(())
967                );
968            }
969        }
970
971        // Verify that the request completes in error.
972        assert_matches!(
973            test_values.exec.run_until_stalled(&mut added_iface_fut),
974            Poll::Ready(Err(_))
975        );
976    }
977
978    #[fuchsia::test]
979    fn test_remove_iface_success() {
980        let mut test_values = test_setup();
981
982        // Report the removal of an interface.
983        let removed_iface_fut = test_values.iface_manager.handle_removed_iface(123);
984        let mut removed_iface_fut = pin!(removed_iface_fut);
985        assert_matches!(test_values.exec.run_until_stalled(&mut removed_iface_fut), Poll::Pending);
986
987        // Verify that the service sees the query
988        let next_message = test_values.receiver.next();
989        let mut next_message = pin!(next_message);
990
991        assert_matches!(
992            test_values.exec.run_until_stalled(&mut next_message),
993            Poll::Ready(
994                Some(IfaceManagerRequest::RemoveIface(RemoveIfaceRequest{ iface_id: 123, responder }))
995            ) => {
996                responder.send(()).expect("failed to respond while adding iface");
997            }
998        );
999
1000        // Verify that the client side finishes
1001        assert_matches!(
1002            test_values.exec.run_until_stalled(&mut removed_iface_fut),
1003            Poll::Ready(Ok(()))
1004        );
1005    }
1006
1007    #[test_case(NegativeTestFailureMode::RequestFailure; "request failure")]
1008    #[test_case(NegativeTestFailureMode::ServiceFailure; "service failure")]
1009    #[fuchsia::test(add_test_attr = false)]
1010    fn remove_iface_negative_test(failure_mode: NegativeTestFailureMode) {
1011        let mut test_values = test_setup();
1012
1013        // Report the removal of an interface.
1014        let removed_iface_fut = test_values.iface_manager.handle_removed_iface(123);
1015        let mut removed_iface_fut = pin!(removed_iface_fut);
1016        assert_matches!(test_values.exec.run_until_stalled(&mut removed_iface_fut), Poll::Pending);
1017
1018        let service_fut =
1019            iface_manager_api_negative_test(test_values.receiver, failure_mode.clone());
1020        let mut service_fut = pin!(service_fut);
1021
1022        match failure_mode {
1023            NegativeTestFailureMode::RequestFailure => {}
1024            _ => {
1025                // Run the request and the servicing of the request
1026                assert_matches!(
1027                    test_values.exec.run_until_stalled(&mut removed_iface_fut),
1028                    Poll::Pending
1029                );
1030                assert_matches!(
1031                    test_values.exec.run_until_stalled(&mut service_fut),
1032                    Poll::Ready(())
1033                );
1034            }
1035        }
1036
1037        // Verify that the client side finishes
1038        assert_matches!(
1039            test_values.exec.run_until_stalled(&mut removed_iface_fut),
1040            Poll::Ready(Err(_))
1041        );
1042    }
1043
1044    #[fuchsia::test]
1045    fn test_get_scan_proxy_success() {
1046        let mut test_values = test_setup();
1047
1048        // Request a scan
1049        let scan_proxy_fut = test_values.iface_manager.get_sme_proxy_for_scan();
1050        let mut scan_proxy_fut = pin!(scan_proxy_fut);
1051        assert_matches!(test_values.exec.run_until_stalled(&mut scan_proxy_fut), Poll::Pending);
1052
1053        // Verify that the service sees the request.
1054        let next_message = test_values.receiver.next();
1055        let mut next_message = pin!(next_message);
1056
1057        assert_matches!(
1058            test_values.exec.run_until_stalled(&mut next_message),
1059            Poll::Ready(Some(IfaceManagerRequest::GetScanProxy(ScanProxyRequest{
1060                responder
1061            }))) => {
1062                let (proxy, _) = create_proxy::<fidl_sme::ClientSmeMarker>();
1063                let (defect_sender, _defect_receiver) = mpsc::channel(100);
1064                responder.send(Ok(SmeForScan{proxy, iface_id: 0, defect_sender})).expect("failed to send scan sme proxy");
1065            }
1066        );
1067
1068        // Verify that the client side gets the scan proxy
1069        assert_matches!(
1070            test_values.exec.run_until_stalled(&mut scan_proxy_fut),
1071            Poll::Ready(Ok(_))
1072        );
1073    }
1074
1075    #[test_case(NegativeTestFailureMode::RequestFailure; "request failure")]
1076    #[test_case(NegativeTestFailureMode::OperationFailure; "operation failure")]
1077    #[test_case(NegativeTestFailureMode::ServiceFailure; "service failure")]
1078    #[fuchsia::test(add_test_attr = false)]
1079    fn scan_proxy_negative_test(failure_mode: NegativeTestFailureMode) {
1080        let mut test_values = test_setup();
1081
1082        // Request a scan
1083        let scan_proxy_fut = test_values.iface_manager.get_sme_proxy_for_scan();
1084        let mut scan_proxy_fut = pin!(scan_proxy_fut);
1085
1086        let service_fut =
1087            iface_manager_api_negative_test(test_values.receiver, failure_mode.clone());
1088        let mut service_fut = pin!(service_fut);
1089
1090        match failure_mode {
1091            NegativeTestFailureMode::RequestFailure => {}
1092            _ => {
1093                // Run the request and the servicing of the request
1094                assert_matches!(
1095                    test_values.exec.run_until_stalled(&mut scan_proxy_fut),
1096                    Poll::Pending
1097                );
1098                assert_matches!(
1099                    test_values.exec.run_until_stalled(&mut service_fut),
1100                    Poll::Ready(())
1101                );
1102            }
1103        }
1104
1105        // Verify that an error is returned.
1106        assert_matches!(
1107            test_values.exec.run_until_stalled(&mut scan_proxy_fut),
1108            Poll::Ready(Err(_))
1109        );
1110    }
1111
1112    #[fuchsia::test]
1113    fn test_stop_client_connections_succeeds() {
1114        let mut test_values = test_setup();
1115
1116        // Request a scan
1117        let stop_fut = test_values.iface_manager.stop_client_connections(
1118            client_types::DisconnectReason::FidlStopClientConnectionsRequest,
1119        );
1120        let mut stop_fut = pin!(stop_fut);
1121        assert_matches!(test_values.exec.run_until_stalled(&mut stop_fut), Poll::Pending);
1122
1123        // Verify that the service sees the request.
1124        let next_message = test_values.receiver.next();
1125        let mut next_message = pin!(next_message);
1126
1127        assert_matches!(
1128            test_values.exec.run_until_stalled(&mut next_message),
1129            Poll::Ready(Some(IfaceManagerRequest::StopClientConnections(StopClientConnectionsRequest{
1130                responder, reason
1131            }))) => {
1132                assert_eq!(reason, client_types::DisconnectReason::FidlStopClientConnectionsRequest);
1133                responder.send(Ok(())).expect("failed sending stop client connections response");
1134            }
1135        );
1136
1137        // Verify that the client side gets the response.
1138        assert_matches!(test_values.exec.run_until_stalled(&mut stop_fut), Poll::Ready(Ok(())));
1139    }
1140
1141    #[test_case(NegativeTestFailureMode::RequestFailure; "request failure")]
1142    #[test_case(NegativeTestFailureMode::OperationFailure; "operation failure")]
1143    #[test_case(NegativeTestFailureMode::ServiceFailure; "service failure")]
1144    #[fuchsia::test(add_test_attr = false)]
1145    fn stop_client_connections_negative_test(failure_mode: NegativeTestFailureMode) {
1146        let mut test_values = test_setup();
1147
1148        // Request a scan
1149        let stop_fut = test_values.iface_manager.stop_client_connections(
1150            client_types::DisconnectReason::FidlStopClientConnectionsRequest,
1151        );
1152        let mut stop_fut = pin!(stop_fut);
1153        assert_matches!(test_values.exec.run_until_stalled(&mut stop_fut), Poll::Pending);
1154
1155        let service_fut =
1156            iface_manager_api_negative_test(test_values.receiver, failure_mode.clone());
1157        let mut service_fut = pin!(service_fut);
1158
1159        match failure_mode {
1160            NegativeTestFailureMode::RequestFailure => {}
1161            _ => {
1162                // Run the request and the servicing of the request
1163                assert_matches!(test_values.exec.run_until_stalled(&mut stop_fut), Poll::Pending);
1164                assert_matches!(
1165                    test_values.exec.run_until_stalled(&mut service_fut),
1166                    Poll::Ready(())
1167                );
1168            }
1169        }
1170
1171        // Verify that the client side gets the response.
1172        assert_matches!(test_values.exec.run_until_stalled(&mut stop_fut), Poll::Ready(Err(_)));
1173    }
1174
1175    #[fuchsia::test]
1176    fn test_start_client_connections_succeeds() {
1177        let mut test_values = test_setup();
1178
1179        // Start client connections
1180        let start_fut = test_values.iface_manager.start_client_connections();
1181        let mut start_fut = pin!(start_fut);
1182        assert_matches!(test_values.exec.run_until_stalled(&mut start_fut), Poll::Pending);
1183
1184        // Verify that the service sees the request.
1185        let next_message = test_values.receiver.next();
1186        let mut next_message = pin!(next_message);
1187
1188        assert_matches!(
1189            test_values.exec.run_until_stalled(&mut next_message),
1190            Poll::Ready(Some(IfaceManagerRequest::StartClientConnections(StartClientConnectionsRequest{
1191                responder
1192            }))) => {
1193                responder.send(Ok(())).expect("failed sending stop client connections response");
1194            }
1195        );
1196
1197        // Verify that the client side gets the response.
1198        assert_matches!(test_values.exec.run_until_stalled(&mut start_fut), Poll::Ready(Ok(())));
1199    }
1200
1201    #[test_case(NegativeTestFailureMode::RequestFailure; "request failure")]
1202    #[test_case(NegativeTestFailureMode::OperationFailure; "operation failure")]
1203    #[test_case(NegativeTestFailureMode::ServiceFailure; "service failure")]
1204    #[fuchsia::test(add_test_attr = false)]
1205    fn start_client_connections_negative_test(failure_mode: NegativeTestFailureMode) {
1206        let mut test_values = test_setup();
1207
1208        // Start client connections
1209        let start_fut = test_values.iface_manager.start_client_connections();
1210        let mut start_fut = pin!(start_fut);
1211        assert_matches!(test_values.exec.run_until_stalled(&mut start_fut), Poll::Pending);
1212
1213        let service_fut =
1214            iface_manager_api_negative_test(test_values.receiver, failure_mode.clone());
1215        let mut service_fut = pin!(service_fut);
1216
1217        match failure_mode {
1218            NegativeTestFailureMode::RequestFailure => {}
1219            _ => {
1220                // Run the request and the servicing of the request
1221                assert_matches!(test_values.exec.run_until_stalled(&mut start_fut), Poll::Pending);
1222                assert_matches!(
1223                    test_values.exec.run_until_stalled(&mut service_fut),
1224                    Poll::Ready(())
1225                );
1226            }
1227        }
1228
1229        // Verify that the client side gets the response.
1230        assert_matches!(test_values.exec.run_until_stalled(&mut start_fut), Poll::Ready(Err(_)));
1231    }
1232
1233    fn create_ap_config() -> ap_fsm::ApConfig {
1234        ap_fsm::ApConfig {
1235            id: types::NetworkIdentifier {
1236                ssid: Ssid::try_from("foo").unwrap(),
1237                security_type: types::SecurityType::None,
1238            },
1239            credential: vec![],
1240            radio_config: RadioConfig::new(
1241                fidl_fuchsia_wlan_ieee80211::WlanPhyType::Ht,
1242                Cbw::Cbw20,
1243                6,
1244                fidl_fuchsia_wlan_ieee80211::WlanBand::TwoGhz,
1245            ),
1246            mode: types::ConnectivityMode::Unrestricted,
1247            band: types::OperatingBand::Any,
1248        }
1249    }
1250
1251    #[fuchsia::test]
1252    fn test_start_ap_succeeds() {
1253        let mut test_values = test_setup();
1254
1255        // Start an AP
1256        let start_fut = test_values.iface_manager.start_ap(create_ap_config());
1257        let mut start_fut = pin!(start_fut);
1258        assert_matches!(test_values.exec.run_until_stalled(&mut start_fut), Poll::Pending);
1259
1260        // Verify the service sees the request
1261        let next_message = test_values.receiver.next();
1262        let mut next_message = pin!(next_message);
1263
1264        assert_matches!(
1265            test_values.exec.run_until_stalled(&mut next_message),
1266            Poll::Ready(Some(IfaceManagerRequest::StartAp(StartApRequest{
1267                config, responder
1268            }))) => {
1269                assert_eq!(config, create_ap_config());
1270
1271                let (_, receiver) = oneshot::channel();
1272                responder.send(Ok(receiver)).expect("failed to send start AP response");
1273            }
1274        );
1275
1276        // Verify that the client gets the response
1277        assert_matches!(test_values.exec.run_until_stalled(&mut start_fut), Poll::Ready(Ok(_)));
1278    }
1279
1280    #[test_case(NegativeTestFailureMode::RequestFailure; "request failure")]
1281    #[test_case(NegativeTestFailureMode::OperationFailure; "operation failure")]
1282    #[test_case(NegativeTestFailureMode::ServiceFailure; "service failure")]
1283    #[fuchsia::test(add_test_attr = false)]
1284    fn start_ap_negative_test(failure_mode: NegativeTestFailureMode) {
1285        let mut test_values = test_setup();
1286
1287        // Start an AP
1288        let start_fut = test_values.iface_manager.start_ap(create_ap_config());
1289        let mut start_fut = pin!(start_fut);
1290        assert_matches!(test_values.exec.run_until_stalled(&mut start_fut), Poll::Pending);
1291
1292        let service_fut =
1293            iface_manager_api_negative_test(test_values.receiver, failure_mode.clone());
1294        let mut service_fut = pin!(service_fut);
1295
1296        match failure_mode {
1297            NegativeTestFailureMode::RequestFailure => {}
1298            _ => {
1299                // Run the request and the servicing of the request
1300                assert_matches!(test_values.exec.run_until_stalled(&mut start_fut), Poll::Pending);
1301                assert_matches!(
1302                    test_values.exec.run_until_stalled(&mut service_fut),
1303                    Poll::Ready(())
1304                );
1305            }
1306        }
1307
1308        // Verify that the client gets the response
1309        assert_matches!(test_values.exec.run_until_stalled(&mut start_fut), Poll::Ready(Err(_)));
1310    }
1311
1312    #[fuchsia::test]
1313    fn test_stop_ap_succeeds() {
1314        let mut test_values = test_setup();
1315
1316        // Stop an AP
1317        let stop_fut = test_values
1318            .iface_manager
1319            .stop_ap(Ssid::try_from("foo").unwrap(), "bar".as_bytes().to_vec());
1320        let mut stop_fut = pin!(stop_fut);
1321        assert_matches!(test_values.exec.run_until_stalled(&mut stop_fut), Poll::Pending);
1322
1323        // Verify the service sees the request
1324        let next_message = test_values.receiver.next();
1325        let mut next_message = pin!(next_message);
1326
1327        assert_matches!(
1328            test_values.exec.run_until_stalled(&mut next_message),
1329            Poll::Ready(Some(IfaceManagerRequest::StopAp(StopApRequest{
1330                ssid, password, responder
1331            }))) => {
1332                assert_eq!(ssid, Ssid::try_from("foo").unwrap());
1333                assert_eq!(password, "bar".as_bytes().to_vec());
1334
1335                responder.send(Ok(())).expect("failed to send stop AP response");
1336            }
1337        );
1338
1339        // Verify that the client gets the response
1340        assert_matches!(test_values.exec.run_until_stalled(&mut stop_fut), Poll::Ready(Ok(_)));
1341    }
1342
1343    #[test_case(NegativeTestFailureMode::RequestFailure; "request failure")]
1344    #[test_case(NegativeTestFailureMode::OperationFailure; "operation failure")]
1345    #[test_case(NegativeTestFailureMode::ServiceFailure; "service failure")]
1346    #[fuchsia::test(add_test_attr = false)]
1347    fn stop_ap_negative_test(failure_mode: NegativeTestFailureMode) {
1348        let mut test_values = test_setup();
1349
1350        // Stop an AP
1351        let stop_fut = test_values
1352            .iface_manager
1353            .stop_ap(Ssid::try_from("foo").unwrap(), "bar".as_bytes().to_vec());
1354        let mut stop_fut = pin!(stop_fut);
1355        assert_matches!(test_values.exec.run_until_stalled(&mut stop_fut), Poll::Pending);
1356
1357        let service_fut =
1358            iface_manager_api_negative_test(test_values.receiver, failure_mode.clone());
1359        let mut service_fut = pin!(service_fut);
1360
1361        match failure_mode {
1362            NegativeTestFailureMode::RequestFailure => {}
1363            _ => {
1364                // Run the request and the servicing of the request
1365                assert_matches!(test_values.exec.run_until_stalled(&mut stop_fut), Poll::Pending);
1366                assert_matches!(
1367                    test_values.exec.run_until_stalled(&mut service_fut),
1368                    Poll::Ready(())
1369                );
1370            }
1371        }
1372
1373        // Verify that the client gets the response
1374        assert_matches!(test_values.exec.run_until_stalled(&mut stop_fut), Poll::Ready(Err(_)));
1375    }
1376
1377    #[fuchsia::test]
1378    fn test_stop_all_aps_succeeds() {
1379        let mut test_values = test_setup();
1380
1381        // Stop an AP
1382        let stop_fut = test_values.iface_manager.stop_all_aps();
1383        let mut stop_fut = pin!(stop_fut);
1384        assert_matches!(test_values.exec.run_until_stalled(&mut stop_fut), Poll::Pending);
1385
1386        // Verify the service sees the request
1387        let next_message = test_values.receiver.next();
1388        let mut next_message = pin!(next_message);
1389        assert_matches!(
1390            test_values.exec.run_until_stalled(&mut next_message),
1391            Poll::Ready(Some(IfaceManagerRequest::StopAllAps(StopAllApsRequest{
1392                responder
1393            }))) => {
1394                responder.send(Ok(())).expect("failed to send stop AP response");
1395            }
1396        );
1397
1398        // Verify that the client gets the response
1399        assert_matches!(test_values.exec.run_until_stalled(&mut stop_fut), Poll::Ready(Ok(_)));
1400    }
1401
1402    #[test_case(NegativeTestFailureMode::RequestFailure; "request failure")]
1403    #[test_case(NegativeTestFailureMode::OperationFailure; "operation failure")]
1404    #[test_case(NegativeTestFailureMode::ServiceFailure; "service failure")]
1405    #[fuchsia::test(add_test_attr = false)]
1406    fn stop_all_aps_negative_test(failure_mode: NegativeTestFailureMode) {
1407        let mut test_values = test_setup();
1408
1409        // Stop an AP
1410        let stop_fut = test_values.iface_manager.stop_all_aps();
1411        let mut stop_fut = pin!(stop_fut);
1412        assert_matches!(test_values.exec.run_until_stalled(&mut stop_fut), Poll::Pending);
1413
1414        let service_fut =
1415            iface_manager_api_negative_test(test_values.receiver, failure_mode.clone());
1416        let mut service_fut = pin!(service_fut);
1417
1418        match failure_mode {
1419            NegativeTestFailureMode::RequestFailure => {}
1420            _ => {
1421                // Run the request and the servicing of the request
1422                assert_matches!(test_values.exec.run_until_stalled(&mut stop_fut), Poll::Pending);
1423                assert_matches!(
1424                    test_values.exec.run_until_stalled(&mut service_fut),
1425                    Poll::Ready(())
1426                );
1427            }
1428        }
1429
1430        // Verify that the client gets the response
1431        assert_matches!(test_values.exec.run_until_stalled(&mut stop_fut), Poll::Ready(Err(_)));
1432    }
1433
1434    #[fuchsia::test]
1435    fn test_set_country_succeeds() {
1436        let mut test_values = test_setup();
1437
1438        // Set country code
1439        let set_country_fut = test_values.iface_manager.set_country(None);
1440        let mut set_country_fut = pin!(set_country_fut);
1441        assert_matches!(test_values.exec.run_until_stalled(&mut set_country_fut), Poll::Pending);
1442
1443        // Verify the service sees the request
1444        let next_message = test_values.receiver.next();
1445        let mut next_message = pin!(next_message);
1446
1447        assert_matches!(
1448            test_values.exec.run_until_stalled(&mut next_message),
1449            Poll::Ready(Some(IfaceManagerRequest::SetCountry(SetCountryRequest{
1450                country_code: None,
1451                responder
1452            }))) => {
1453                responder.send(Ok(())).expect("failed to send stop AP response");
1454            }
1455        );
1456
1457        // Verify that the client gets the response
1458        assert_matches!(
1459            test_values.exec.run_until_stalled(&mut set_country_fut),
1460            Poll::Ready(Ok(_))
1461        );
1462    }
1463
1464    #[test_case(NegativeTestFailureMode::RequestFailure; "request failure")]
1465    #[test_case(NegativeTestFailureMode::OperationFailure; "operation failure")]
1466    #[test_case(NegativeTestFailureMode::ServiceFailure; "service failure")]
1467    #[fuchsia::test(add_test_attr = false)]
1468    fn set_country_negative_test(failure_mode: NegativeTestFailureMode) {
1469        let mut test_values = test_setup();
1470
1471        // Set country code
1472        let set_country_fut = test_values.iface_manager.set_country(None);
1473        let mut set_country_fut = pin!(set_country_fut);
1474        assert_matches!(test_values.exec.run_until_stalled(&mut set_country_fut), Poll::Pending);
1475        let service_fut =
1476            iface_manager_api_negative_test(test_values.receiver, failure_mode.clone());
1477        let mut service_fut = pin!(service_fut);
1478
1479        match failure_mode {
1480            NegativeTestFailureMode::RequestFailure => {}
1481            _ => {
1482                // Run the request and the servicing of the request
1483                assert_matches!(
1484                    test_values.exec.run_until_stalled(&mut set_country_fut),
1485                    Poll::Pending
1486                );
1487                assert_matches!(
1488                    test_values.exec.run_until_stalled(&mut service_fut),
1489                    Poll::Ready(())
1490                );
1491            }
1492        }
1493
1494        // Verify that the client gets the response
1495        assert_matches!(
1496            test_values.exec.run_until_stalled(&mut set_country_fut),
1497            Poll::Ready(Err(_))
1498        );
1499    }
1500
1501    #[fuchsia::test]
1502    fn test_sme_for_scan() {
1503        let mut exec = fasync::TestExecutor::new();
1504
1505        // Build an SME specifically for scanning.
1506        let (proxy, server_end) = create_proxy::<fidl_sme::ClientSmeMarker>();
1507        let (defect_sender, _defect_receiver) = mpsc::channel(100);
1508        let sme = SmeForScan::new(proxy, 0, defect_sender);
1509        let mut sme_stream = server_end.into_stream();
1510
1511        // Construct a scan request.
1512        let scan_request = fidl_sme::ScanRequest::Active(fidl_sme::ActiveScanRequest {
1513            ssids: vec![vec![]],
1514            channels: vec![],
1515        });
1516
1517        // Issue the scan request.
1518        let scan_result_fut = sme.scan(&scan_request);
1519        let mut scan_result_fut = pin!(scan_result_fut);
1520        assert_matches!(exec.run_until_stalled(&mut scan_result_fut), Poll::Pending);
1521
1522        // Poll the server end of the SME and expect that a scan request has been forwarded.
1523        assert_matches!(
1524            exec.run_until_stalled(&mut sme_stream.next()),
1525            Poll::Ready(Some(Ok(fidl_sme::ClientSmeRequest::Scan {
1526                req, ..
1527            }))) => {
1528                assert_eq!(scan_request, req)
1529            }
1530        );
1531    }
1532
1533    #[fuchsia::test]
1534    fn sme_for_scan_defects() {
1535        let _exec = fasync::TestExecutor::new();
1536
1537        // Build an SME specifically for scanning.
1538        let (proxy, _) = create_proxy::<fidl_sme::ClientSmeMarker>();
1539        let (defect_sender, mut defect_receiver) = mpsc::channel(100);
1540        let iface_id = rand::random::<u16>();
1541        let sme = SmeForScan::new(proxy, iface_id, defect_sender);
1542
1543        sme.log_aborted_scan_defect();
1544        sme.log_failed_scan_defect();
1545        sme.log_empty_scan_defect();
1546
1547        assert_eq!(
1548            defect_receiver.try_next().expect("missing canceled scan error"),
1549            Some(Defect::Iface(IfaceFailure::CanceledScan { iface_id })),
1550        );
1551        assert_eq!(
1552            defect_receiver.try_next().expect("missing failed scan error"),
1553            Some(Defect::Iface(IfaceFailure::FailedScan { iface_id })),
1554        );
1555        assert_eq!(
1556            defect_receiver.try_next().expect("missing empty scan results error"),
1557            Some(Defect::Iface(IfaceFailure::EmptyScanResults { iface_id })),
1558        );
1559    }
1560
1561    #[fuchsia::test]
1562    fn sme_for_scan_timeout() {
1563        let mut exec = fasync::TestExecutor::new_with_fake_time();
1564        exec.set_fake_time(fasync::MonotonicInstant::from_nanos(0));
1565
1566        // Create the SmeForScan
1567        let (proxy, _server) = create_proxy::<fidl_sme::ClientSmeMarker>();
1568        let (defect_sender, mut defect_receiver) = mpsc::channel(100);
1569        let iface_id = rand::random::<u16>();
1570        let sme = SmeForScan::new(proxy, iface_id, defect_sender);
1571
1572        // Issue the scan request.
1573        let scan_request = fidl_sme::ScanRequest::Active(fidl_sme::ActiveScanRequest {
1574            ssids: vec![vec![]],
1575            channels: vec![],
1576        });
1577        let scan_result_fut = sme.scan(&scan_request);
1578        let mut scan_result_fut = pin!(scan_result_fut);
1579        assert_matches!(exec.run_until_stalled(&mut scan_result_fut), Poll::Pending);
1580
1581        // Advance the clock so that the timeout expires.
1582        exec.set_fake_time(fasync::MonotonicInstant::after(
1583            SCAN_TIMEOUT + fasync::MonotonicDuration::from_seconds(1),
1584        ));
1585
1586        // Verify that the future returns and that a defect is logged.
1587        assert_matches!(exec.run_until_stalled(&mut scan_result_fut), Poll::Ready(Err(_)));
1588        assert_eq!(
1589            defect_receiver.try_next().expect("missing empty scan results error"),
1590            Some(Defect::Iface(IfaceFailure::Timeout {
1591                iface_id,
1592                source: telemetry::TimeoutSource::Scan,
1593            })),
1594        );
1595    }
1596
1597    #[fuchsia::test]
1598    fn state_machine_sme_disconnects_successfully() {
1599        let mut exec = fasync::TestExecutor::new();
1600
1601        // Build an SME wrapper.
1602        let (proxy, sme_fut) = create_proxy::<fidl_sme::ClientSmeMarker>();
1603        let (defect_sender, _defect_receiver) = mpsc::channel(100);
1604        let iface_id = rand::random::<u16>();
1605        let sme = SmeForClientStateMachine::new(proxy, iface_id, defect_sender);
1606
1607        // Request a disconnect and run the future until it stalls.
1608        let fut = sme.disconnect(fidl_sme::UserDisconnectReason::FidlStopClientConnectionsRequest);
1609        let mut fut = pin!(fut);
1610        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1611
1612        // Ack the disconnect request.
1613        let mut sme_fut = pin!(sme_fut.into_stream().into_future());
1614        assert_matches!(
1615            poll_sme_req(&mut exec, &mut sme_fut),
1616            Poll::Ready(fidl_sme::ClientSmeRequest::Disconnect{
1617                responder,
1618                reason: fidl_sme::UserDisconnectReason::FidlStopClientConnectionsRequest
1619            }) => {
1620                responder.send().expect("could not send sme response");
1621            }
1622        );
1623
1624        // Verify that the disconnect was successful.
1625        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(Ok(())));
1626    }
1627
1628    #[fuchsia::test]
1629    fn state_machine_sme_fails_to_disconnect() {
1630        let mut exec = fasync::TestExecutor::new();
1631
1632        // Build an SME wrapper.
1633        let (proxy, _) = create_proxy::<fidl_sme::ClientSmeMarker>();
1634        let (defect_sender, _defect_receiver) = mpsc::channel(100);
1635        let iface_id = rand::random::<u16>();
1636        let sme = SmeForClientStateMachine::new(proxy, iface_id, defect_sender);
1637
1638        // Request a disconnect and expect an immediate error return.
1639        let fut = sme.disconnect(fidl_sme::UserDisconnectReason::FidlStopClientConnectionsRequest);
1640        let mut fut = pin!(fut);
1641        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(Err(_)));
1642    }
1643
1644    #[fuchsia::test]
1645    fn state_machine_sme_disconnect_timeout() {
1646        let mut exec = fasync::TestExecutor::new_with_fake_time();
1647        exec.set_fake_time(fasync::MonotonicInstant::from_nanos(0));
1648
1649        // Build an SME wrapper.
1650        let (proxy, _sme_fut) = create_proxy::<fidl_sme::ClientSmeMarker>();
1651        let (defect_sender, mut defect_receiver) = mpsc::channel(100);
1652        let iface_id = rand::random::<u16>();
1653        let sme = SmeForClientStateMachine::new(proxy, iface_id, defect_sender);
1654
1655        // Request a disconnect and run the future until it stalls.
1656        let fut = sme.disconnect(fidl_sme::UserDisconnectReason::FidlStopClientConnectionsRequest);
1657        let mut fut = pin!(fut);
1658        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1659
1660        // Advance the clock beyond the timeout.
1661        exec.set_fake_time(fasync::MonotonicInstant::after(
1662            DISCONNECT_TIMEOUT + fasync::MonotonicDuration::from_seconds(1),
1663        ));
1664
1665        // Verify that the future returns and that a defect is logged.
1666        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(Err(_)));
1667        assert_eq!(
1668            defect_receiver.try_next().expect("missing empty scan results error"),
1669            Some(Defect::Iface(IfaceFailure::Timeout {
1670                iface_id,
1671                source: telemetry::TimeoutSource::Disconnect,
1672            })),
1673        );
1674    }
1675
1676    #[fuchsia::test]
1677    fn state_machine_sme_roam_sends_request() {
1678        let mut exec = fasync::TestExecutor::new();
1679
1680        // Build an SME wrapper.
1681        let (proxy, sme_fut) = create_proxy::<fidl_sme::ClientSmeMarker>();
1682        let (defect_sender, _defect_receiver) = mpsc::channel(100);
1683        let iface_id = rand::random::<u16>();
1684        let sme = SmeForClientStateMachine::new(proxy, iface_id, defect_sender);
1685
1686        // Request a roam via the sme proxy
1687        let roam_request =
1688            fidl_sme::RoamRequest { bss_description: random_fidl_bss_description!() };
1689        sme.roam(&roam_request).unwrap();
1690
1691        // Verify SME gets the request
1692        let mut sme_fut = pin!(sme_fut.into_stream().into_future());
1693        assert_matches!(
1694            poll_sme_req(&mut exec, &mut sme_fut),
1695            Poll::Ready(fidl_sme::ClientSmeRequest::Roam {
1696                req, ..
1697            }) => {
1698                assert_eq!(req, roam_request);
1699            }
1700        );
1701    }
1702
1703    fn generate_connect_request() -> fidl_sme::ConnectRequest {
1704        let connection_selection = generate_connect_selection();
1705        fidl_sme::ConnectRequest {
1706            ssid: connection_selection.target.network.ssid.to_vec(),
1707            bss_description: Sequestered::release(connection_selection.target.bss.bss_description),
1708            multiple_bss_candidates: connection_selection.target.network_has_multiple_bss,
1709            authentication: connection_selection.target.authenticator.clone().into(),
1710            deprecated_scan_type: fidl_fuchsia_wlan_common::ScanType::Active,
1711        }
1712    }
1713
1714    #[fuchsia::test]
1715    fn state_machine_sme_connects_successfully() {
1716        let mut exec = fasync::TestExecutor::new();
1717
1718        // Build an SME wrapper.
1719        let (proxy, sme_fut) = create_proxy::<fidl_sme::ClientSmeMarker>();
1720        let (defect_sender, _defect_receiver) = mpsc::channel(100);
1721        let iface_id = rand::random::<u16>();
1722        let sme = SmeForClientStateMachine::new(proxy, iface_id, defect_sender);
1723
1724        // Request a connection.
1725        let connect_request = generate_connect_request();
1726        let fut = sme.connect(&connect_request);
1727        let mut fut = pin!(fut);
1728        match exec.run_until_stalled(&mut fut) {
1729            Poll::Pending => {}
1730            _ => panic!("connect request should be pending."),
1731        }
1732
1733        // Ack the connect request.
1734        let mut sme_fut = pin!(sme_fut.into_stream().into_future());
1735        assert_matches!(
1736            poll_sme_req(&mut exec, &mut sme_fut),
1737            Poll::Ready(fidl_sme::ClientSmeRequest::Connect{
1738                txn,
1739                ..
1740            }) => {
1741                let (_stream, ctrl) = txn.expect("connect txn unused")
1742                    .into_stream_and_control_handle();
1743                ctrl
1744                    .send_on_connect_result(&fidl_sme::ConnectResult {
1745                        code: fidl_ieee80211::StatusCode::Success,
1746                        is_credential_rejected: false,
1747                        is_reconnect: false,
1748                    })
1749                    .expect("failed to send connection completion");
1750            }
1751        );
1752
1753        // Expect a successful result.
1754        match exec.run_until_stalled(&mut fut) {
1755            Poll::Ready(Ok((result, txn))) => {
1756                assert_eq!(
1757                    result,
1758                    fidl_sme::ConnectResult {
1759                        code: fidl_ieee80211::StatusCode::Success,
1760                        is_credential_rejected: false,
1761                        is_reconnect: false,
1762                    }
1763                );
1764                // This is required or else the test panics on exit with
1765                // "receivers must not outlive their executor".
1766                drop(txn)
1767            }
1768            Poll::Ready(Err(_)) => panic!("connection should be successful"),
1769            Poll::Pending => panic!("connect request should not be pending."),
1770        }
1771    }
1772
1773    #[fuchsia::test]
1774    fn state_machine_sme_connection_failure() {
1775        let mut exec = fasync::TestExecutor::new();
1776
1777        // Build an SME wrapper.
1778        let (proxy, sme_fut) = create_proxy::<fidl_sme::ClientSmeMarker>();
1779        let (defect_sender, _defect_receiver) = mpsc::channel(100);
1780        let iface_id = rand::random::<u16>();
1781        let sme = SmeForClientStateMachine::new(proxy, iface_id, defect_sender);
1782
1783        // Request a connection.
1784        let connect_request = generate_connect_request();
1785        let fut = sme.connect(&connect_request);
1786        let mut fut = pin!(fut);
1787        match exec.run_until_stalled(&mut fut) {
1788            Poll::Pending => {}
1789            _ => panic!("connect request should be pending."),
1790        }
1791
1792        // Ack the connect request.
1793        let mut sme_fut = pin!(sme_fut.into_stream().into_future());
1794        assert_matches!(
1795            poll_sme_req(&mut exec, &mut sme_fut),
1796            Poll::Ready(fidl_sme::ClientSmeRequest::Connect{
1797                txn,
1798                ..
1799            }) => {
1800                let (_stream, ctrl) = txn.expect("connect txn unused")
1801                    .into_stream_and_control_handle();
1802                ctrl
1803                    .send_on_connect_result(&fidl_sme::ConnectResult {
1804                        code: fidl_ieee80211::StatusCode::RefusedReasonUnspecified,
1805                        is_credential_rejected: false,
1806                        is_reconnect: false,
1807                    })
1808                    .expect("failed to send connection completion");
1809            }
1810        );
1811
1812        // Expect a successful result.
1813        match exec.run_until_stalled(&mut fut) {
1814            Poll::Ready(Ok((result, txn))) => {
1815                assert_eq!(
1816                    result,
1817                    fidl_sme::ConnectResult {
1818                        code: fidl_ieee80211::StatusCode::RefusedReasonUnspecified,
1819                        is_credential_rejected: false,
1820                        is_reconnect: false,
1821                    }
1822                );
1823                // This is required or else the test panics on exit with
1824                // "receivers must not outlive their executor".
1825                drop(txn)
1826            }
1827            Poll::Ready(Err(_)) => panic!("connection should be successful"),
1828            Poll::Pending => panic!("connect request should not be pending."),
1829        }
1830    }
1831
1832    #[fuchsia::test]
1833    fn state_machine_sme_connect_request_fails() {
1834        let mut exec = fasync::TestExecutor::new();
1835
1836        // Build an SME wrapper.
1837        let (proxy, _) = create_proxy::<fidl_sme::ClientSmeMarker>();
1838        let (defect_sender, _defect_receiver) = mpsc::channel(100);
1839        let iface_id = rand::random::<u16>();
1840        let sme = SmeForClientStateMachine::new(proxy, iface_id, defect_sender);
1841
1842        // Request a disconnect and expect an immediate error return.
1843        let connect_request = generate_connect_request();
1844        let fut = sme.connect(&connect_request);
1845        let mut fut = pin!(fut);
1846        match exec.run_until_stalled(&mut fut) {
1847            Poll::Ready(Err(_)) => {}
1848            _ => panic!("connect request should have failed."),
1849        }
1850    }
1851
1852    #[fuchsia::test]
1853    fn state_machine_sme_connect_timeout() {
1854        let mut exec = fasync::TestExecutor::new_with_fake_time();
1855        exec.set_fake_time(fasync::MonotonicInstant::from_nanos(0));
1856
1857        // Build an SME wrapper.
1858        let (proxy, _sme_fut) = create_proxy::<fidl_sme::ClientSmeMarker>();
1859        let (defect_sender, mut defect_receiver) = mpsc::channel(100);
1860        let iface_id = rand::random::<u16>();
1861        let sme = SmeForClientStateMachine::new(proxy, iface_id, defect_sender);
1862
1863        // Request a connection and run the future until it stalls.
1864        let connect_request = generate_connect_request();
1865        let fut = sme.connect(&connect_request);
1866        let mut fut = pin!(fut);
1867        match exec.run_until_stalled(&mut fut) {
1868            Poll::Pending => {}
1869            _ => panic!("connect future completed unexpectedly"),
1870        }
1871
1872        // Advance the clock beyond the timeout.
1873        exec.set_fake_time(fasync::MonotonicInstant::after(
1874            CONNECT_TIMEOUT + fasync::MonotonicDuration::from_seconds(1),
1875        ));
1876
1877        // Verify that the future returns and that a defect is logged.
1878        match exec.run_until_stalled(&mut fut) {
1879            Poll::Ready(Err(_)) => {}
1880            Poll::Ready(Ok(_)) => panic!("connect future completed successfully"),
1881            Poll::Pending => panic!("connect future did not complete"),
1882        }
1883        assert_eq!(
1884            defect_receiver.try_next().expect("missing connection timeout"),
1885            Some(Defect::Iface(IfaceFailure::Timeout {
1886                iface_id,
1887                source: telemetry::TimeoutSource::Connect,
1888            })),
1889        );
1890    }
1891
1892    #[fuchsia::test]
1893    fn wait_for_connect_result_error() {
1894        let mut exec = fasync::TestExecutor::new();
1895        let (connect_txn, remote) = create_proxy::<fidl_sme::ConnectTransactionMarker>();
1896        let mut response_stream = connect_txn.take_event_stream();
1897
1898        let fut = wait_for_connect_result(&mut response_stream);
1899
1900        let mut fut = pin!(fut);
1901        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1902
1903        // Drop server end, and verify future completes with error
1904        drop(remote);
1905        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(Err(_)));
1906    }
1907
1908    #[fuchsia::test]
1909    fn wait_for_connect_result_ignores_other_events() {
1910        let mut exec = fasync::TestExecutor::new();
1911        let (connect_txn, remote) = create_proxy::<fidl_sme::ConnectTransactionMarker>();
1912        let request_handle = remote.into_stream().control_handle();
1913        let mut response_stream = connect_txn.take_event_stream();
1914
1915        let fut = wait_for_connect_result(&mut response_stream);
1916
1917        let mut fut = pin!(fut);
1918        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1919
1920        // Send some unexpected response
1921        let ind = fidl_internal::SignalReportIndication { rssi_dbm: -20, snr_db: 25 };
1922        request_handle.send_on_signal_report(&ind).unwrap();
1923
1924        // Future should still be waiting for OnConnectResult event
1925        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1926
1927        // Send expected ConnectResult response
1928        let sme_result = fidl_sme::ConnectResult {
1929            code: fidl_ieee80211::StatusCode::Success,
1930            is_credential_rejected: false,
1931            is_reconnect: false,
1932        };
1933        request_handle.send_on_connect_result(&sme_result).unwrap();
1934        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(Ok(response)) => {
1935            assert_eq!(sme_result, response);
1936        });
1937    }
1938
1939    fn poll_ap_sme_req(
1940        exec: &mut fasync::TestExecutor,
1941        next_sme_req: &mut StreamFuture<fidl_sme::ApSmeRequestStream>,
1942    ) -> Poll<fidl_sme::ApSmeRequest> {
1943        exec.run_until_stalled(next_sme_req).map(|(req, stream)| {
1944            *next_sme_req = stream.into_future();
1945            req.expect("did not expect the SME request stream to end")
1946                .expect("error polling SME request stream")
1947        })
1948    }
1949
1950    #[fuchsia::test]
1951    fn state_machine_sme_starts_ap_successfully() {
1952        let mut exec = fasync::TestExecutor::new();
1953
1954        // Build an SME wrapper.
1955        let (proxy, sme_fut) = create_proxy::<fidl_sme::ApSmeMarker>();
1956        let (defect_sender, _defect_receiver) = mpsc::channel(100);
1957        let iface_id = rand::random::<u16>();
1958        let sme = SmeForApStateMachine::new(proxy, iface_id, defect_sender);
1959
1960        // Start the AP and run the future until it stalls.
1961        let config = fidl_sme::ApConfig::from(create_ap_config());
1962        let fut = sme.start(&config);
1963        let mut fut = pin!(fut);
1964        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1965
1966        // Respond to the start request.
1967        let mut sme_fut = pin!(sme_fut.into_stream().into_future());
1968        assert_matches!(
1969            poll_ap_sme_req(&mut exec, &mut sme_fut),
1970            Poll::Ready(fidl_sme::ApSmeRequest::Start { responder, .. }) => {
1971                responder.send(fidl_sme::StartApResultCode::Success)
1972                    .expect("could not send sme response");
1973            }
1974        );
1975
1976        // Verify that the start response was returned.
1977        assert_matches!(
1978            exec.run_until_stalled(&mut fut),
1979            Poll::Ready(Ok(fidl_sme::StartApResultCode::Success))
1980        );
1981    }
1982
1983    #[fuchsia::test]
1984    fn state_machine_sme_fails_to_request_start_ap() {
1985        let mut exec = fasync::TestExecutor::new();
1986
1987        // Build an SME wrapper.
1988        let (proxy, _) = create_proxy::<fidl_sme::ApSmeMarker>();
1989        let (defect_sender, _defect_receiver) = mpsc::channel(100);
1990        let iface_id = rand::random::<u16>();
1991        let sme = SmeForApStateMachine::new(proxy, iface_id, defect_sender);
1992
1993        // Start the AP and observe an immediate failure.
1994        let config = fidl_sme::ApConfig::from(create_ap_config());
1995        let fut = sme.start(&config);
1996        let mut fut = pin!(fut);
1997        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(Err(_)));
1998    }
1999
2000    #[fuchsia::test]
2001    fn state_machine_sme_start_ap_timeout() {
2002        let mut exec = fasync::TestExecutor::new_with_fake_time();
2003        exec.set_fake_time(fasync::MonotonicInstant::from_nanos(0));
2004
2005        // Build an SME wrapper.
2006        let (proxy, _sme_fut) = create_proxy::<fidl_sme::ApSmeMarker>();
2007        let (defect_sender, mut defect_receiver) = mpsc::channel(100);
2008        let iface_id = rand::random::<u16>();
2009        let sme = SmeForApStateMachine::new(proxy, iface_id, defect_sender);
2010
2011        // Start the AP and run the future until it stalls.
2012        let config = fidl_sme::ApConfig::from(create_ap_config());
2013        let fut = sme.start(&config);
2014        let mut fut = pin!(fut);
2015        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2016
2017        // Advance the clock beyond the timeout.
2018        exec.set_fake_time(fasync::MonotonicInstant::after(
2019            START_AP_TIMEOUT + fasync::MonotonicDuration::from_seconds(1),
2020        ));
2021
2022        // Verify that the future returns and that a defect is logged.
2023        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(Err(_)));
2024        assert_eq!(
2025            defect_receiver.try_next().expect("missing connection timeout"),
2026            Some(Defect::Iface(IfaceFailure::Timeout {
2027                iface_id,
2028                source: telemetry::TimeoutSource::ApStart,
2029            })),
2030        );
2031    }
2032
2033    #[fuchsia::test]
2034    fn state_machine_sme_stops_ap_successfully() {
2035        let mut exec = fasync::TestExecutor::new();
2036
2037        // Build an SME wrapper.
2038        let (proxy, sme_fut) = create_proxy::<fidl_sme::ApSmeMarker>();
2039        let (defect_sender, _defect_receiver) = mpsc::channel(100);
2040        let iface_id = rand::random::<u16>();
2041        let sme = SmeForApStateMachine::new(proxy, iface_id, defect_sender);
2042
2043        // Stop the AP and run the future until it stalls.
2044        let fut = sme.stop();
2045        let mut fut = pin!(fut);
2046        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2047
2048        // Respond to the stop request.
2049        let mut sme_fut = pin!(sme_fut.into_stream().into_future());
2050        assert_matches!(
2051            poll_ap_sme_req(&mut exec, &mut sme_fut),
2052            Poll::Ready(fidl_sme::ApSmeRequest::Stop { responder }) => {
2053                responder.send(fidl_sme::StopApResultCode::Success)
2054                    .expect("could not send sme response");
2055            }
2056        );
2057
2058        // Verify that the start response was returned.
2059        assert_matches!(
2060            exec.run_until_stalled(&mut fut),
2061            Poll::Ready(Ok(fidl_sme::StopApResultCode::Success))
2062        );
2063    }
2064
2065    #[fuchsia::test]
2066    fn state_machine_sme_fails_to_request_stop_ap() {
2067        let mut exec = fasync::TestExecutor::new();
2068
2069        // Build an SME wrapper.
2070        let (proxy, _) = create_proxy::<fidl_sme::ApSmeMarker>();
2071        let (defect_sender, _defect_receiver) = mpsc::channel(100);
2072        let iface_id = rand::random::<u16>();
2073        let sme = SmeForApStateMachine::new(proxy, iface_id, defect_sender);
2074
2075        // Stop the AP and observe an immediate failure.
2076        let fut = sme.stop();
2077        let mut fut = pin!(fut);
2078        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(Err(_)));
2079    }
2080
2081    #[fuchsia::test]
2082    fn state_machine_sme_stop_ap_timeout() {
2083        let mut exec = fasync::TestExecutor::new_with_fake_time();
2084        exec.set_fake_time(fasync::MonotonicInstant::from_nanos(0));
2085
2086        // Build an SME wrapper.
2087        let (proxy, _sme_fut) = create_proxy::<fidl_sme::ApSmeMarker>();
2088        let (defect_sender, mut defect_receiver) = mpsc::channel(100);
2089        let iface_id = rand::random::<u16>();
2090        let sme = SmeForApStateMachine::new(proxy, iface_id, defect_sender);
2091
2092        // Stop the AP and run the future until it stalls.
2093        let fut = sme.stop();
2094        let mut fut = pin!(fut);
2095        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2096
2097        // Advance the clock beyond the timeout.
2098        exec.set_fake_time(fasync::MonotonicInstant::after(
2099            START_AP_TIMEOUT + fasync::MonotonicDuration::from_seconds(1),
2100        ));
2101
2102        // Verify that the future returns and that a defect is logged.
2103        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(Err(_)));
2104        assert_eq!(
2105            defect_receiver.try_next().expect("missing connection timeout"),
2106            Some(Defect::Iface(IfaceFailure::Timeout {
2107                iface_id,
2108                source: telemetry::TimeoutSource::ApStop,
2109            })),
2110        );
2111    }
2112
2113    #[fuchsia::test]
2114    fn state_machine_sme_successfully_queries_ap_status() {
2115        let mut exec = fasync::TestExecutor::new();
2116
2117        // Build an SME wrapper.
2118        let (proxy, sme_fut) = create_proxy::<fidl_sme::ApSmeMarker>();
2119        let (defect_sender, _defect_receiver) = mpsc::channel(100);
2120        let iface_id = rand::random::<u16>();
2121        let sme = SmeForApStateMachine::new(proxy, iface_id, defect_sender);
2122
2123        // Query AP status and run the future until it stalls.
2124        let fut = sme.status();
2125        let mut fut = pin!(fut);
2126        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2127
2128        // Respond to the status request.
2129        let mut sme_fut = pin!(sme_fut.into_stream().into_future());
2130        assert_matches!(
2131            poll_ap_sme_req(&mut exec, &mut sme_fut),
2132            Poll::Ready(fidl_sme::ApSmeRequest::Status{ responder }) => {
2133                let response = fidl_sme::ApStatusResponse { running_ap: None };
2134                responder.send(&response).expect("could not send AP status response");
2135            }
2136        );
2137
2138        // Verify that the status response was returned.
2139        assert_matches!(
2140            exec.run_until_stalled(&mut fut),
2141            Poll::Ready(Ok(fidl_sme::ApStatusResponse { running_ap: None }))
2142        );
2143    }
2144
2145    #[fuchsia::test]
2146    fn state_machine_sme_fails_to_query_ap_status() {
2147        let mut exec = fasync::TestExecutor::new();
2148
2149        // Build an SME wrapper.
2150        let (proxy, _) = create_proxy::<fidl_sme::ApSmeMarker>();
2151        let (defect_sender, _defect_receiver) = mpsc::channel(100);
2152        let iface_id = rand::random::<u16>();
2153        let sme = SmeForApStateMachine::new(proxy, iface_id, defect_sender);
2154
2155        // Query status and observe an immediate failure.
2156        let fut = sme.status();
2157        let mut fut = pin!(fut);
2158        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(Err(_)));
2159    }
2160
2161    #[fuchsia::test]
2162    fn state_machine_sme_query_ap_status_timeout() {
2163        let mut exec = fasync::TestExecutor::new_with_fake_time();
2164        exec.set_fake_time(fasync::MonotonicInstant::from_nanos(0));
2165
2166        // Build an SME wrapper.
2167        let (proxy, _sme_fut) = create_proxy::<fidl_sme::ApSmeMarker>();
2168        let (defect_sender, mut defect_receiver) = mpsc::channel(100);
2169        let iface_id = rand::random::<u16>();
2170        let sme = SmeForApStateMachine::new(proxy, iface_id, defect_sender);
2171
2172        // Query AP status and run the future until it stalls.
2173        let fut = sme.status();
2174        let mut fut = pin!(fut);
2175        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2176
2177        // Advance the clock beyond the timeout.
2178        exec.set_fake_time(fasync::MonotonicInstant::after(
2179            AP_STATUS_TIMEOUT + fasync::MonotonicDuration::from_seconds(1),
2180        ));
2181
2182        // Verify that the future returns and that a defect is logged.
2183        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(Err(_)));
2184        assert_eq!(
2185            defect_receiver.try_next().expect("missing connection timeout"),
2186            Some(Defect::Iface(IfaceFailure::Timeout {
2187                iface_id,
2188                source: telemetry::TimeoutSource::ApStatus,
2189            })),
2190        );
2191    }
2192}