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