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