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