Skip to main content

wlancfg_lib/mode_management/
iface_manager_api.rs

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