1use crate::access_point::types;
6use crate::mode_management::iface_manager_api::SmeForApStateMachine;
7use crate::mode_management::{Defect, IfaceFailure};
8use crate::telemetry::{TelemetryEvent, TelemetrySender};
9use crate::util::listener::Message::NotifyListeners;
10use crate::util::listener::{
11 ApListenerMessageSender, ApStateUpdate, ApStatesUpdate, ConnectedClientInformation,
12};
13use crate::util::state_machine::{self, ExitReason, IntoStateExt, StateMachineStatusPublisher};
14use anyhow::format_err;
15use fidl_fuchsia_wlan_sme as fidl_sme;
16use fuchsia_async::{self as fasync, DurationExt};
17use fuchsia_inspect::Node as InspectNode;
18use fuchsia_inspect_contrib::inspect_insert;
19use fuchsia_inspect_contrib::log::WriteInspect;
20use fuchsia_sync::Mutex;
21
22use futures::channel::{mpsc, oneshot};
23use futures::future::FutureExt;
24use futures::select;
25use futures::stream::{self, Fuse, FuturesUnordered, StreamExt, TryStreamExt};
26use log::{info, warn};
27use std::borrow::Cow;
28use std::fmt::Debug;
29use std::pin::pin;
30use std::sync::Arc;
31use wlan_common::RadioConfig;
32use wlan_common::channel::{Cbw, Channel};
33
34const AP_STATUS_INTERVAL_SEC: i64 = 10;
35
36const AP_START_RETRY_INTERVAL: i64 = 2;
45const AP_START_MAX_RETRIES: u16 = 6;
46
47type State = state_machine::State<ExitReason>;
48type ReqStream = stream::Fuse<mpsc::Receiver<ManualRequest>>;
49
50pub trait AccessPointApi {
51 fn start(
52 &mut self,
53 request: ApConfig,
54 responder: oneshot::Sender<()>,
55 ) -> Result<(), anyhow::Error>;
56 fn stop(&mut self, responder: oneshot::Sender<()>) -> Result<(), anyhow::Error>;
57 fn exit(&mut self, responder: oneshot::Sender<()>) -> Result<(), anyhow::Error>;
58}
59
60pub struct AccessPoint {
61 req_sender: mpsc::Sender<ManualRequest>,
62}
63
64impl AccessPoint {
65 pub fn new(req_sender: mpsc::Sender<ManualRequest>) -> Self {
66 Self { req_sender }
67 }
68}
69
70impl AccessPointApi for AccessPoint {
71 fn start(
72 &mut self,
73 request: ApConfig,
74 responder: oneshot::Sender<()>,
75 ) -> Result<(), anyhow::Error> {
76 self.req_sender
77 .try_send(ManualRequest::Start((request, responder)))
78 .map_err(|e| format_err!("failed to send start request: {:?}", e))
79 }
80
81 fn stop(&mut self, responder: oneshot::Sender<()>) -> Result<(), anyhow::Error> {
82 self.req_sender
83 .try_send(ManualRequest::Stop(responder))
84 .map_err(|e| format_err!("failed to send stop request: {:?}", e))
85 }
86
87 fn exit(&mut self, responder: oneshot::Sender<()>) -> Result<(), anyhow::Error> {
88 self.req_sender
89 .try_send(ManualRequest::Exit(responder))
90 .map_err(|e| format_err!("failed to send exit request: {:?}", e))
91 }
92}
93
94pub enum ManualRequest {
95 Start((ApConfig, oneshot::Sender<()>)),
96 Stop(oneshot::Sender<()>),
97 Exit(oneshot::Sender<()>),
98}
99
100#[derive(Clone, Debug, Default, PartialEq)]
103pub enum Status {
104 Stopping,
105 #[default]
106 Stopped,
107 Starting,
108 Started {
109 band: types::OperatingBand,
110 channel: u8,
111 mode: types::ConnectivityMode,
112 num_clients: u16,
113 security_type: types::SecurityType,
114 },
115}
116
117impl Status {
118 fn started_from_config(config: &ApConfig) -> Self {
119 Status::Started {
120 band: config.band,
121 channel: config.radio_config.channel.primary,
122 mode: config.mode,
123 num_clients: 0,
124 security_type: config.id.security_type,
125 }
126 }
127
128 fn started_from_sme_update(update: &fidl_sme::Ap, config: &ApConfig) -> Self {
129 Status::Started {
130 band: config.band,
131 channel: update.channel,
132 mode: config.mode,
133 num_clients: update.num_clients,
134 security_type: config.id.security_type,
135 }
136 }
137}
138
139impl WriteInspect for Status {
140 fn write_inspect<'a>(&self, writer: &InspectNode, key: impl Into<Cow<'a, str>>) {
141 match self {
142 Status::Started { band, channel, mode, num_clients, security_type } => {
143 inspect_insert!(writer, var key: {
144 Started: {
145 band: format!("{:?}", band),
146 channel: channel,
147 mode: format!("{:?}", mode),
148 num_clients: num_clients,
149 security_type: format!("{:?}", security_type)
150 }
151 })
152 }
153 other => inspect_insert!(writer, var key: format!("{:?}", other)),
154 }
155 }
156}
157
158#[cfg_attr(test, derive(Debug))]
160#[derive(Clone, PartialEq)]
161pub struct ApConfig {
162 pub id: types::NetworkIdentifier,
163 pub credential: Vec<u8>,
164 pub radio_config: RadioConfig,
165 pub mode: types::ConnectivityMode,
166 pub band: types::OperatingBand,
167}
168
169impl From<ApConfig> for fidl_sme::ApConfig {
170 fn from(config: ApConfig) -> Self {
171 fidl_sme::ApConfig {
172 ssid: config.id.ssid.to_vec(),
173 password: config.credential,
174 radio_cfg: config.radio_config.into(),
175 }
176 }
177}
178
179struct ApStateTrackerInner {
180 state: Option<ApStateUpdate>,
181 sender: ApListenerMessageSender,
182}
183
184impl ApStateTrackerInner {
185 fn send_update(&mut self) -> Result<(), anyhow::Error> {
186 let updates = match self.state.clone() {
187 Some(state) => ApStatesUpdate { access_points: [state].to_vec() },
188 None => ApStatesUpdate { access_points: [].to_vec() },
189 };
190
191 self.sender
192 .clone()
193 .unbounded_send(NotifyListeners(updates))
194 .map_err(|e| format_err!("failed to send state update: {}", e))
195 }
196}
197
198struct ApStateTracker {
199 inner: Mutex<ApStateTrackerInner>,
200}
201
202impl ApStateTracker {
203 fn new(sender: ApListenerMessageSender) -> Self {
204 ApStateTracker { inner: Mutex::new(ApStateTrackerInner { state: None, sender }) }
205 }
206
207 fn reset_state(&self, state: ApStateUpdate) -> Result<(), anyhow::Error> {
208 let mut inner = self.inner.lock();
209 inner.state = Some(state);
210 inner.send_update()
211 }
212
213 fn consume_sme_status_update(
214 &self,
215 cbw: Cbw,
216 band: fidl_fuchsia_wlan_ieee80211::WlanBand,
217 update: fidl_sme::Ap,
218 ) -> Result<(), anyhow::Error> {
219 let mut inner = self.inner.lock();
220
221 if let Some(ref mut state) = inner.state {
222 let channel = Channel::new(update.channel, cbw, band);
223 let frequency = match channel.get_center_freq() {
224 Ok(frequency) => Some(frequency as u32),
225 Err(e) => {
226 info!("failed to convert channel to frequency: {}", e);
227 None
228 }
229 };
230
231 let client_info = Some(ConnectedClientInformation { count: update.num_clients as u8 });
232
233 if frequency != state.frequency || client_info != state.clients {
234 state.frequency = frequency;
235 state.clients = client_info;
236 inner.send_update()?;
237 }
238 }
239
240 Ok(())
241 }
242
243 fn update_operating_state(
244 &self,
245 new_state: types::OperatingState,
246 ) -> Result<(), anyhow::Error> {
247 let mut inner = self.inner.lock();
248
249 if let Some(ref mut state) = inner.state {
251 if state.state != new_state {
252 state.state = new_state;
253 }
254 inner.send_update()?;
255 }
256
257 Ok(())
258 }
259
260 fn set_stopped_state(&self) -> Result<(), anyhow::Error> {
261 let mut inner = self.inner.lock();
262 inner.state = None;
263 inner.send_update()
264 }
265}
266
267struct CommonStateDependencies {
268 iface_id: u16,
269 proxy: SmeForApStateMachine,
270 req_stream: ReqStream,
271 state_tracker: Arc<ApStateTracker>,
272 telemetry_sender: TelemetrySender,
273 defect_sender: mpsc::Sender<Defect>,
274 status_publisher: StateMachineStatusPublisher<Status>,
275}
276
277pub async fn serve(
278 iface_id: u16,
279 proxy: SmeForApStateMachine,
280 sme_event_stream: fidl_sme::ApSmeEventStream,
281 req_stream: Fuse<mpsc::Receiver<ManualRequest>>,
282 message_sender: ApListenerMessageSender,
283 telemetry_sender: TelemetrySender,
284 defect_sender: mpsc::Sender<Defect>,
285 status_publisher: StateMachineStatusPublisher<Status>,
286) {
287 let state_tracker = Arc::new(ApStateTracker::new(message_sender));
288 let deps = CommonStateDependencies {
289 iface_id,
290 proxy,
291 req_stream,
292 state_tracker: state_tracker.clone(),
293 telemetry_sender,
294 defect_sender,
295 status_publisher: status_publisher.clone(),
296 };
297 let state_machine = stopped_state(deps).into_state_machine();
298 let removal_watcher = sme_event_stream.map_ok(|_| ()).try_collect::<()>();
299 select! {
300 state_machine = state_machine.fuse() => {
301 match state_machine {
302 Err(ExitReason(Ok(()))) => info!("AP state machine for iface #{} exited", iface_id),
303 Err(ExitReason(Err(e))) => {
304 info!("AP state machine for iface #{} terminated with an error: {}", iface_id, e)
305 }
306 }
307 },
308 removal_watcher = removal_watcher.fuse() => {
309 match removal_watcher {
310 Ok(()) => info!("AP interface was unexpectedly removed: {}", iface_id),
311 Err(e) => {
312 info!("Error reading from AP SME channel of iface #{}: {}", iface_id, e);
313 }
314 }
315 let _ = state_tracker.update_operating_state(types::OperatingState::Failed);
316 }
317 }
318
319 status_publisher.publish_status(Status::Stopped);
320}
321
322fn perform_manual_request(
323 deps: CommonStateDependencies,
324 req: Option<ManualRequest>,
325) -> Result<State, ExitReason> {
326 match req {
327 Some(ManualRequest::Start((req, responder))) => {
328 Ok(starting_state(deps, req, AP_START_MAX_RETRIES, Some(responder)).into_state())
329 }
330 Some(ManualRequest::Stop(responder)) => Ok(stopping_state(deps, responder).into_state()),
331 Some(ManualRequest::Exit(responder)) => {
332 responder.send(()).unwrap_or(());
333 Err(ExitReason(Ok(())))
334 }
335 None => {
336 deps.state_tracker
340 .update_operating_state(types::OperatingState::Failed)
341 .map_err(|e| ExitReason(Err(e)))?;
342
343 Err(ExitReason(Err(format_err!("The stream of user requests ended unexpectedly"))))
344 }
345 }
346}
347
348fn transition_to_starting(
350 deps: CommonStateDependencies,
351 req: ApConfig,
352 remaining_retries: u16,
353 responder: Option<oneshot::Sender<()>>,
354) -> Result<State, ExitReason> {
355 Ok(starting_state(deps, req, remaining_retries, responder).into_state())
356}
357
358async fn starting_state(
379 mut deps: CommonStateDependencies,
380 req: ApConfig,
381 remaining_retries: u16,
382 responder: Option<oneshot::Sender<()>>,
383) -> Result<State, ExitReason> {
384 deps.status_publisher.publish_status(Status::Starting);
385
386 let stop_result = match deps.proxy.stop().await {
388 Ok(fidl_sme::StopApResultCode::Success) => Ok(()),
389 Ok(code) => Err(format_err!("Unexpected StopApResultCode: {:?}", code)),
390 Err(e) => Err(format_err!("Failed to send a stop command to wlanstack: {}", e)),
391 };
392
393 if stop_result.is_err() {
395 deps.state_tracker
396 .reset_state(ApStateUpdate::new(
397 req.id.clone(),
398 types::OperatingState::Failed,
399 req.mode,
400 req.band,
401 ))
402 .map_err(|e| ExitReason(Err(e)))?;
403
404 stop_result.map_err(|e| ExitReason(Err(e)))?;
405 }
406
407 deps.state_tracker.set_stopped_state().map_err(|e| ExitReason(Err(e)))?;
409
410 if remaining_retries == AP_START_MAX_RETRIES {
412 deps.state_tracker
413 .reset_state(ApStateUpdate::new(
414 req.id.clone(),
415 types::OperatingState::Starting,
416 req.mode,
417 req.band,
418 ))
419 .map_err(|e| ExitReason(Err(e)))?;
420 }
421
422 let ap_config = fidl_sme::ApConfig::from(req.clone());
423 let start_result = match deps.proxy.start(&ap_config).await {
424 Ok(fidl_sme::StartApResultCode::Success) => {
425 deps.telemetry_sender.send(TelemetryEvent::StartApResult(Ok(())));
426 Ok(())
427 }
428 Ok(code) => {
429 deps.telemetry_sender.send(TelemetryEvent::StartApResult(Err(())));
431 if let Err(e) = deps
432 .defect_sender
433 .try_send(Defect::Iface(IfaceFailure::ApStartFailure { iface_id: deps.iface_id }))
434 {
435 warn!("Failed to log AP start defect: {}", e)
436 }
437
438 if remaining_retries > 0 {
443 let mut retry_timer = pin!(fasync::Timer::new(
444 zx::MonotonicDuration::from_seconds(AP_START_RETRY_INTERVAL).after_now(),
445 ));
446
447 select! {
450 () = retry_timer => {
451 return transition_to_starting(
452 deps,
453 req,
454 remaining_retries - 1,
455 responder,
456 );
457 },
458 req = deps.req_stream.next() => {
459 deps.state_tracker
461 .set_stopped_state()
462 .map_err(|e| ExitReason(Err(e)))?;
463 return perform_manual_request(deps, req)
464 }
465 }
466 }
467
468 Err(format_err!("Failed to start AP: {:?}", code))
470 }
471 Err(e) => {
472 Err(format_err!("Failed to send a start command to wlanstack: {}", e))
475 }
476 };
477
478 start_result.map_err(|e| {
479 if let Err(e) = deps.state_tracker.reset_state(ApStateUpdate::new(
481 req.id.clone(),
482 types::OperatingState::Failed,
483 req.mode,
484 req.band,
485 )) {
486 info!("Unable to notify listeners of AP start failure: {:?}", e);
487 }
488 ExitReason(Err(e))
489 })?;
490
491 #[allow(clippy::single_match, reason = "mass allow for https://fxbug.dev/381896734")]
492 match responder {
493 Some(responder) => responder.send(()).unwrap_or(()),
494 None => {}
495 }
496
497 deps.state_tracker
498 .update_operating_state(types::OperatingState::Active)
499 .map_err(|e| ExitReason(Err(e)))?;
500 Ok(started_state(deps, req).into_state())
501}
502
503async fn stopping_state(
515 deps: CommonStateDependencies,
516 responder: oneshot::Sender<()>,
517) -> Result<State, ExitReason> {
518 deps.status_publisher.publish_status(Status::Stopping);
519
520 let result = match deps.proxy.stop().await {
521 Ok(fidl_sme::StopApResultCode::Success) => Ok(()),
522 Ok(code) => Err(format_err!("Unexpected StopApResultCode: {:?}", code)),
523 Err(e) => Err(format_err!("Failed to send a stop command to wlanstack: {}", e)),
524 };
525
526 deps.state_tracker.set_stopped_state().map_err(|e| ExitReason(Err(e)))?;
530 result.map_err(|e| ExitReason(Err(e)))?;
531
532 responder.send(()).unwrap_or(());
534
535 Ok(stopped_state(deps).into_state())
536}
537
538async fn stopped_state(mut deps: CommonStateDependencies) -> Result<State, ExitReason> {
539 deps.status_publisher.publish_status(Status::Stopped);
540
541 loop {
543 let req = deps.req_stream.next().await;
544 match req {
545 Some(ManualRequest::Stop(responder)) => {
547 responder.send(()).unwrap_or(());
548 }
549 other => return perform_manual_request(deps, other),
551 }
552 }
553}
554
555async fn started_state(
556 mut deps: CommonStateDependencies,
557 req: ApConfig,
558) -> Result<State, ExitReason> {
559 deps.status_publisher.publish_status(Status::started_from_config(&req));
560
561 let mut pending_status_req = FuturesUnordered::new();
563 let status_proxy = deps.proxy.clone();
564 pending_status_req.push(async move { status_proxy.status().await }.boxed());
565
566 let mut status_timer =
567 fasync::Interval::new(zx::MonotonicDuration::from_seconds(AP_STATUS_INTERVAL_SEC));
568
569 let cbw = req.radio_config.channel.cbw;
571
572 loop {
573 select! {
574 status_response = pending_status_req.select_next_some() => {
575 let status_response = match status_response {
576 Ok(status_response) => status_response,
577 Err(e) => {
578 deps.state_tracker.update_operating_state(types::OperatingState::Failed)
581 .map_err(|e| { ExitReason(Err(e)) })?;
582
583 return Err(ExitReason(Err(e)));
584 }
585 };
586
587 match status_response.running_ap {
588 Some(sme_state) => {
589 deps.status_publisher
590 .publish_status(Status::started_from_sme_update(&sme_state, &req));
591 deps.state_tracker.consume_sme_status_update(cbw, req.radio_config.channel.band, *sme_state)
592 .map_err(|e| { ExitReason(Err(e)) })?;
593 }
594 None => {
595 deps.state_tracker.update_operating_state(types::OperatingState::Failed)
596 .map_err(|e| { ExitReason(Err(e)) })?;
597
598 return transition_to_starting(
599 deps,
600 req,
601 AP_START_MAX_RETRIES,
602 None,
603 );
604 }
605 }
606 },
607 _ = status_timer.select_next_some() => {
608 if pending_status_req.is_empty() {
609 let status_proxy = deps.proxy.clone();
610 pending_status_req.push(async move {
611 status_proxy.status().await
612 }.boxed());
613 }
614 },
615 manual_req = deps.req_stream.next() => {
616 return perform_manual_request(deps, manual_req)
617 },
618 complete => {
619 panic!("AP state machine terminated unexpectedly");
620 }
621 }
622 }
623}
624
625#[cfg(test)]
626mod tests {
627 use super::*;
628
629 fn new_radio_config() -> RadioConfig {
630 RadioConfig::new(
631 fidl_fuchsia_wlan_ieee80211::WlanPhyType::Ht,
632 Cbw::Cbw20,
633 6,
634 fidl_fuchsia_wlan_ieee80211::WlanBand::TwoGhz,
635 )
636 }
637 use crate::util::listener;
638 use crate::util::state_machine::{StateMachineStatusReader, status_publisher_and_reader};
639 use assert_matches::assert_matches;
640 use fidl::endpoints::create_proxy;
641 use futures::Future;
642 use futures::stream::StreamFuture;
643 use futures::task::Poll;
644 use std::pin::pin;
645
646 struct TestValues {
647 deps: CommonStateDependencies,
648 sme_req_stream: fidl_sme::ApSmeRequestStream,
649 ap_req_sender: mpsc::Sender<ManualRequest>,
650 update_receiver: mpsc::UnboundedReceiver<listener::ApMessage>,
651 telemetry_receiver: mpsc::Receiver<TelemetryEvent>,
652 defect_receiver: mpsc::Receiver<Defect>,
653 status_reader: StateMachineStatusReader<Status>,
654 }
655
656 fn test_setup() -> TestValues {
657 let (ap_req_sender, ap_req_stream) = mpsc::channel(1);
658 let (update_sender, update_receiver) = mpsc::unbounded();
659 let (telemetry_sender, telemetry_receiver) = mpsc::channel(100);
660 let telemetry_sender = TelemetrySender::new(telemetry_sender);
661 let (defect_sender, defect_receiver) = mpsc::channel(100);
662 let (status_publisher, status_reader) = status_publisher_and_reader::<Status>();
663 let (sme_proxy, sme_server) = create_proxy::<fidl_sme::ApSmeMarker>();
664 let sme_req_stream = sme_server.into_stream();
665 let sme_proxy = SmeForApStateMachine::new(sme_proxy, 123, defect_sender.clone());
666
667 let deps = CommonStateDependencies {
668 iface_id: 123,
669 proxy: sme_proxy,
670 req_stream: ap_req_stream.fuse(),
671 state_tracker: Arc::new(ApStateTracker::new(update_sender)),
672 telemetry_sender,
673 defect_sender,
674 status_publisher,
675 };
676
677 TestValues {
678 deps,
679 sme_req_stream,
680 ap_req_sender,
681 update_receiver,
682 telemetry_receiver,
683 defect_receiver,
684 status_reader,
685 }
686 }
687
688 fn create_network_id() -> types::NetworkIdentifier {
689 types::NetworkIdentifier {
690 ssid: types::Ssid::try_from("test_ssid").unwrap(),
691 security_type: types::SecurityType::None,
692 }
693 }
694
695 fn poll_sme_req(
696 exec: &mut fasync::TestExecutor,
697 next_sme_req: &mut StreamFuture<fidl_sme::ApSmeRequestStream>,
698 ) -> Poll<fidl_sme::ApSmeRequest> {
699 exec.run_until_stalled(next_sme_req).map(|(req, stream)| {
700 *next_sme_req = stream.into_future();
701 req.expect("did not expect the SME request stream to end")
702 .expect("error polling SME request stream")
703 })
704 }
705
706 #[allow(clippy::needless_return, reason = "mass allow for https://fxbug.dev/381896734")]
707 async fn run_state_machine(fut: impl Future<Output = Result<State, ExitReason>> + 'static) {
708 let state_machine = fut.into_state_machine();
709 select! {
710 _state_machine = state_machine.fuse() => return,
711 }
712 }
713
714 #[fuchsia::test]
715 fn test_stop_during_started() {
716 let mut exec = fasync::TestExecutor::new();
717 let test_values = test_setup();
718
719 let radio_config = new_radio_config();
720 let req = ApConfig {
721 id: create_network_id(),
722 credential: vec![],
723 radio_config,
724 mode: types::ConnectivityMode::Unrestricted,
725 band: types::OperatingBand::Any,
726 };
727 {
728 let state = ApStateUpdate::new(
729 create_network_id(),
730 types::OperatingState::Starting,
731 types::ConnectivityMode::Unrestricted,
732 types::OperatingBand::Any,
733 );
734 test_values.deps.state_tracker.inner.lock().state = Some(state);
735 }
736
737 let fut = started_state(test_values.deps, req);
739 let fut = run_state_machine(fut);
740 let mut fut = pin!(fut);
741
742 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
743
744 let sme_fut = test_values.sme_req_stream.into_future();
745 let mut sme_fut = pin!(sme_fut);
746
747 assert_matches!(
748 poll_sme_req(&mut exec, &mut sme_fut),
749 Poll::Ready(fidl_sme::ApSmeRequest::Status{ responder }) => {
750 let ap_info = fidl_sme::Ap { ssid: vec![], channel: 0, num_clients: 0 };
751 let response = fidl_sme::ApStatusResponse {
752 running_ap: Some(Box::new(ap_info))
753 };
754 responder.send(&response).expect("could not send AP status response");
755 }
756 );
757
758 let mut ap = AccessPoint::new(test_values.ap_req_sender);
760 let (sender, mut receiver) = oneshot::channel();
761 ap.stop(sender).expect("failed to make stop request");
762
763 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
765 assert_matches!(
766 poll_sme_req(&mut exec, &mut sme_fut),
767 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
768 responder.send(fidl_sme::StopApResultCode::Success).expect("could not send SME stop response");
769 }
770 );
771
772 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
774 assert_matches!(exec.run_until_stalled(&mut receiver), Poll::Ready(Ok(())));
775 }
776
777 #[fuchsia::test]
778 fn test_exit_during_started() {
779 let mut exec = fasync::TestExecutor::new();
780 let test_values = test_setup();
781
782 let radio_config = new_radio_config();
783 let req = ApConfig {
784 id: create_network_id(),
785 credential: vec![],
786 radio_config,
787 mode: types::ConnectivityMode::Unrestricted,
788 band: types::OperatingBand::Any,
789 };
790 {
791 let state = ApStateUpdate::new(
792 create_network_id(),
793 types::OperatingState::Starting,
794 types::ConnectivityMode::Unrestricted,
795 types::OperatingBand::Any,
796 );
797 test_values.deps.state_tracker.inner.lock().state = Some(state);
798 }
799
800 let fut = started_state(test_values.deps, req);
802 let fut = run_state_machine(fut);
803 let mut fut = pin!(fut);
804
805 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
806
807 let sme_fut = test_values.sme_req_stream.into_future();
808 let mut sme_fut = pin!(sme_fut);
809
810 assert_matches!(
811 poll_sme_req(&mut exec, &mut sme_fut),
812 Poll::Ready(fidl_sme::ApSmeRequest::Status{ responder }) => {
813 let ap_info = fidl_sme::Ap { ssid: vec![], channel: 0, num_clients: 0 };
814 let response = fidl_sme::ApStatusResponse {
815 running_ap: Some(Box::new(ap_info))
816 };
817 responder.send(&response).expect("could not send AP status response");
818 }
819 );
820
821 let mut ap = AccessPoint::new(test_values.ap_req_sender);
823 let (sender, mut receiver) = oneshot::channel();
824 ap.exit(sender).expect("failed to make stop request");
825
826 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
828 assert_matches!(exec.run_until_stalled(&mut receiver), Poll::Ready(Ok(())));
829 }
830
831 #[fuchsia::test]
832 fn test_start_during_started() {
833 let mut exec = fasync::TestExecutor::new();
834 let test_values = test_setup();
835
836 let radio_config = new_radio_config();
837 let req = ApConfig {
838 id: create_network_id(),
839 credential: vec![],
840 radio_config,
841 mode: types::ConnectivityMode::Unrestricted,
842 band: types::OperatingBand::Any,
843 };
844 {
845 let state = ApStateUpdate::new(
846 create_network_id(),
847 types::OperatingState::Starting,
848 types::ConnectivityMode::Unrestricted,
849 types::OperatingBand::Any,
850 );
851 test_values.deps.state_tracker.inner.lock().state = Some(state);
852 }
853
854 let fut = started_state(test_values.deps, req);
856 let fut = run_state_machine(fut);
857 let mut fut = pin!(fut);
858
859 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
860
861 let sme_fut = test_values.sme_req_stream.into_future();
862 let mut sme_fut = pin!(sme_fut);
863
864 assert_matches!(
865 poll_sme_req(&mut exec, &mut sme_fut),
866 Poll::Ready(fidl_sme::ApSmeRequest::Status{ responder }) => {
867 let ap_info = fidl_sme::Ap { ssid: vec![], channel: 0, num_clients: 0 };
868 let response = fidl_sme::ApStatusResponse {
869 running_ap: Some(Box::new(ap_info))
870 };
871 responder.send(&response).expect("could not send AP status response");
872 }
873 );
874
875 let mut ap = AccessPoint::new(test_values.ap_req_sender);
877 let (sender, mut receiver) = oneshot::channel();
878 let radio_config = new_radio_config();
879 let req = ApConfig {
880 id: create_network_id(),
881 credential: vec![],
882 radio_config,
883 mode: types::ConnectivityMode::Unrestricted,
884 band: types::OperatingBand::Any,
885 };
886 ap.start(req, sender).expect("failed to make stop request");
887
888 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
890 assert_matches!(
891 poll_sme_req(&mut exec, &mut sme_fut),
892 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
893 responder.send(fidl_sme::StopApResultCode::Success).expect("could not send AP stop response");
894 }
895 );
896
897 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
898 assert_matches!(
899 poll_sme_req(&mut exec, &mut sme_fut),
900 Poll::Ready(fidl_sme::ApSmeRequest::Start{ config: _, responder }) => {
901 responder
902 .send(fidl_sme::StartApResultCode::Success)
903 .expect("could not send AP stop response");
904 }
905 );
906
907 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
909 assert_matches!(exec.run_until_stalled(&mut receiver), Poll::Ready(Ok(())));
910 }
911
912 #[fuchsia::test]
913 fn test_duplicate_status_during_started() {
914 let mut exec = fasync::TestExecutor::new();
915 let test_values = test_setup();
916
917 let radio_config = new_radio_config();
918 let req = ApConfig {
919 id: create_network_id(),
920 credential: vec![],
921 radio_config,
922 mode: types::ConnectivityMode::Unrestricted,
923 band: types::OperatingBand::Any,
924 };
925 {
926 let mut state = ApStateUpdate::new(
927 create_network_id(),
928 types::OperatingState::Starting,
929 types::ConnectivityMode::Unrestricted,
930 types::OperatingBand::Any,
931 );
932 state.frequency = Some(2437);
933 state.clients = Some(ConnectedClientInformation { count: 0 });
934 test_values.deps.state_tracker.inner.lock().state = Some(state);
935 }
936
937 let fut = started_state(test_values.deps, req);
939 let fut = run_state_machine(fut);
940 let mut fut = pin!(fut);
941
942 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
943
944 let sme_fut = test_values.sme_req_stream.into_future();
945 let mut sme_fut = pin!(sme_fut);
946
947 assert_matches!(
948 poll_sme_req(&mut exec, &mut sme_fut),
949 Poll::Ready(fidl_sme::ApSmeRequest::Status{ responder }) => {
950 let ap_info = fidl_sme::Ap { ssid: vec![], channel: 6, num_clients: 0 };
951 let response = fidl_sme::ApStatusResponse {
952 running_ap: Some(Box::new(ap_info))
953 };
954 responder.send(&response).expect("could not send AP status response");
955 }
956 );
957
958 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
960 assert_matches!(
961 exec.run_until_stalled(&mut test_values.update_receiver.into_future()),
962 Poll::Pending
963 );
964 }
965
966 #[fuchsia::test]
967 fn test_new_status_during_started() {
968 let mut exec = fasync::TestExecutor::new();
969 let test_values = test_setup();
970
971 let radio_config = new_radio_config();
972 let req = ApConfig {
973 id: create_network_id(),
974 credential: vec![],
975 radio_config,
976 mode: types::ConnectivityMode::Unrestricted,
977 band: types::OperatingBand::Any,
978 };
979 {
980 let mut state = ApStateUpdate::new(
981 create_network_id(),
982 types::OperatingState::Starting,
983 types::ConnectivityMode::Unrestricted,
984 types::OperatingBand::Any,
985 );
986 state.frequency = Some(0);
987 state.clients = Some(ConnectedClientInformation { count: 0 });
988 test_values.deps.state_tracker.inner.lock().state = Some(state);
989 }
990
991 let fut = started_state(test_values.deps, req);
993 let fut = run_state_machine(fut);
994 let mut fut = pin!(fut);
995
996 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
997
998 assert_matches!(
1000 test_values.status_reader.read_status(),
1001 Ok(Status::Started {
1002 band: types::OperatingBand::Any,
1003 channel: 6,
1004 mode: types::ConnectivityMode::Unrestricted,
1005 num_clients: 0,
1006 security_type: types::SecurityType::None,
1007 })
1008 );
1009
1010 let sme_fut = test_values.sme_req_stream.into_future();
1012 let mut sme_fut = pin!(sme_fut);
1013
1014 assert_matches!(
1015 poll_sme_req(&mut exec, &mut sme_fut),
1016 Poll::Ready(fidl_sme::ApSmeRequest::Status{ responder }) => {
1017 let ap_info = fidl_sme::Ap { ssid: vec![], channel: 1, num_clients: 1 };
1018 let response = fidl_sme::ApStatusResponse {
1019 running_ap: Some(Box::new(ap_info))
1020 };
1021 responder.send(&response).expect("could not send AP status response");
1022 }
1023 );
1024
1025 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1027 assert_matches!(
1028 exec.run_until_stalled(&mut test_values.update_receiver.into_future()),
1029 Poll::Ready((Some(listener::Message::NotifyListeners(updates)), _)) => {
1030 assert!(!updates.access_points.is_empty());
1031 });
1032
1033 assert_matches!(
1035 test_values.status_reader.read_status(),
1036 Ok(Status::Started {
1037 band: types::OperatingBand::Any,
1038 channel: 1,
1039 mode: types::ConnectivityMode::Unrestricted,
1040 num_clients: 1,
1041 security_type: types::SecurityType::None,
1042 })
1043 );
1044 }
1045
1046 #[fuchsia::test]
1047 fn test_sme_failure_during_started() {
1048 let mut exec = fasync::TestExecutor::new();
1049 let mut test_values = test_setup();
1050
1051 drop(test_values.sme_req_stream);
1053
1054 let radio_config = new_radio_config();
1055 let req = ApConfig {
1056 id: create_network_id(),
1057 credential: vec![],
1058 radio_config,
1059 mode: types::ConnectivityMode::Unrestricted,
1060 band: types::OperatingBand::Any,
1061 };
1062 {
1063 let mut state = ApStateUpdate::new(
1064 create_network_id(),
1065 types::OperatingState::Starting,
1066 types::ConnectivityMode::Unrestricted,
1067 types::OperatingBand::Any,
1068 );
1069 state.frequency = Some(0);
1070 state.clients = Some(ConnectedClientInformation { count: 0 });
1071 test_values.deps.state_tracker.inner.lock().state = Some(state);
1072 }
1073
1074 let fut = started_state(test_values.deps, req);
1076 let fut = run_state_machine(fut);
1077 let mut fut = pin!(fut);
1078
1079 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
1081
1082 assert_matches!(
1084 test_values.update_receiver.try_next(),
1085 Ok(Some(listener::Message::NotifyListeners(mut updates))) => {
1086 let update = updates.access_points.pop().expect("no new updates available.");
1087 assert_eq!(update.state, types::OperatingState::Failed);
1088 });
1089 }
1090
1091 #[fuchsia::test]
1092 fn test_stop_while_stopped() {
1093 let mut exec = fasync::TestExecutor::new();
1094 let test_values = test_setup();
1095
1096 let fut = stopped_state(test_values.deps);
1098 let fut = run_state_machine(fut);
1099 let mut fut = pin!(fut);
1100
1101 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1102
1103 let mut ap = AccessPoint::new(test_values.ap_req_sender);
1105 let (sender, mut receiver) = oneshot::channel();
1106 ap.stop(sender).expect("failed to make stop request");
1107
1108 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1110 assert_matches!(exec.run_until_stalled(&mut receiver), Poll::Ready(Ok(())));
1111 }
1112
1113 #[fuchsia::test]
1114 fn test_exit_while_stopped() {
1115 let mut exec = fasync::TestExecutor::new();
1116 let test_values = test_setup();
1117
1118 let fut = stopped_state(test_values.deps);
1120 let fut = run_state_machine(fut);
1121 let mut fut = pin!(fut);
1122
1123 let mut ap = AccessPoint::new(test_values.ap_req_sender);
1125 let (sender, mut receiver) = oneshot::channel();
1126 ap.exit(sender).expect("failed to make stop request");
1127
1128 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
1130 assert_matches!(exec.run_until_stalled(&mut receiver), Poll::Ready(Ok(())));
1131 }
1132
1133 #[fuchsia::test]
1134 fn test_start_while_stopped() {
1135 let mut exec = fasync::TestExecutor::new();
1136 let mut test_values = test_setup();
1137
1138 let fut = stopped_state(test_values.deps);
1140 let fut = run_state_machine(fut);
1141 let mut fut = pin!(fut);
1142
1143 let (sender, mut receiver) = oneshot::channel();
1145 let radio_config = new_radio_config();
1146 let req = ApConfig {
1147 id: create_network_id(),
1148 credential: vec![],
1149 radio_config,
1150 mode: types::ConnectivityMode::Unrestricted,
1151 band: types::OperatingBand::Any,
1152 };
1153
1154 let mut ap = AccessPoint::new(test_values.ap_req_sender);
1155 ap.start(req, sender).expect("failed to make stop request");
1156
1157 let sme_fut = test_values.sme_req_stream.into_future();
1159 let mut sme_fut = pin!(sme_fut);
1160
1161 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1162 assert_matches!(
1163 poll_sme_req(&mut exec, &mut sme_fut),
1164 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
1165 responder.send(fidl_sme::StopApResultCode::Success).expect("could not send AP stop response");
1166 }
1167 );
1168
1169 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1171 assert_matches!(
1172 test_values.update_receiver.try_next(),
1173 Ok(Some(listener::Message::NotifyListeners(updates))) => {
1174 assert!(updates.access_points.is_empty());
1175 });
1176
1177 assert_matches!(
1179 test_values.update_receiver.try_next(),
1180 Ok(Some(listener::Message::NotifyListeners(mut updates))) => {
1181 let update = updates.access_points.pop().expect("no new updates available.");
1182 assert_eq!(update.state, types::OperatingState::Starting);
1183 });
1184
1185 assert_matches!(
1187 poll_sme_req(&mut exec, &mut sme_fut),
1188 Poll::Ready(fidl_sme::ApSmeRequest::Start{ config: _, responder }) => {
1189 responder
1190 .send(fidl_sme::StartApResultCode::Success)
1191 .expect("could not send AP stop response");
1192 }
1193 );
1194
1195 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1197 assert_matches!(exec.run_until_stalled(&mut receiver), Poll::Ready(Ok(())));
1198
1199 assert_matches!(
1201 test_values.update_receiver.try_next(),
1202 Ok(Some(listener::Message::NotifyListeners(mut updates))) => {
1203 let update = updates.access_points.pop().expect("no new updates available.");
1204 assert_eq!(update.state, types::OperatingState::Active);
1205 });
1206 }
1207
1208 #[fuchsia::test]
1209 fn test_exit_while_stopping() {
1210 let mut exec = fasync::TestExecutor::new();
1211 let test_values = test_setup();
1212
1213 let (stop_sender, mut stop_receiver) = oneshot::channel();
1215 let fut = stopping_state(test_values.deps, stop_sender);
1216 let fut = run_state_machine(fut);
1217 let mut fut = pin!(fut);
1218
1219 let mut ap = AccessPoint::new(test_values.ap_req_sender);
1221 let (exit_sender, mut exit_receiver) = oneshot::channel();
1222 ap.exit(exit_sender).expect("failed to make stop request");
1223
1224 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1226 assert_matches!(exec.run_until_stalled(&mut stop_receiver), Poll::Pending);
1227 assert_matches!(exec.run_until_stalled(&mut exit_receiver), Poll::Pending);
1228
1229 let sme_fut = test_values.sme_req_stream.into_future();
1231 let mut sme_fut = pin!(sme_fut);
1232 assert_matches!(
1233 poll_sme_req(&mut exec, &mut sme_fut),
1234 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
1235 responder.send(fidl_sme::StopApResultCode::Success).expect("could not send AP stop response");
1236 }
1237 );
1238 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
1239 assert_matches!(exec.run_until_stalled(&mut stop_receiver), Poll::Ready(Ok(())));
1240 assert_matches!(exec.run_until_stalled(&mut exit_receiver), Poll::Ready(Ok(())));
1241 }
1242
1243 #[fuchsia::test]
1244 fn test_stop_while_stopping() {
1245 let mut exec = fasync::TestExecutor::new();
1246 let mut test_values = test_setup();
1247
1248 let (stop_sender, mut stop_receiver) = oneshot::channel();
1250 let fut = stopping_state(test_values.deps, stop_sender);
1251 let fut = run_state_machine(fut);
1252 let mut fut = pin!(fut);
1253
1254 assert_matches!(&mut test_values.update_receiver.try_next(), Err(_));
1256
1257 let mut ap = AccessPoint::new(test_values.ap_req_sender);
1259 let (second_stop_sender, mut second_stop_receiver) = oneshot::channel();
1260 ap.stop(second_stop_sender).expect("failed to make stop request");
1261
1262 let sme_fut = test_values.sme_req_stream.into_future();
1264 let mut sme_fut = pin!(sme_fut);
1265
1266 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1267 assert_matches!(
1268 poll_sme_req(&mut exec, &mut sme_fut),
1269 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
1270 responder.send(fidl_sme::StopApResultCode::Success).expect("could not send AP stop response");
1271 }
1272 );
1273
1274 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1276 assert_matches!(exec.run_until_stalled(&mut stop_receiver), Poll::Ready(Ok(())));
1277 assert_matches!(exec.run_until_stalled(&mut second_stop_receiver), Poll::Ready(Ok(())));
1278
1279 assert_matches!(
1281 test_values.update_receiver.try_next(),
1282 Ok(Some(listener::Message::NotifyListeners(updates))) => {
1283 assert!(updates.access_points.is_empty());
1284 });
1285 }
1286
1287 #[fuchsia::test]
1288 fn test_start_while_stopping() {
1289 let mut exec = fasync::TestExecutor::new();
1290 let test_values = test_setup();
1291
1292 let (stop_sender, mut stop_receiver) = oneshot::channel();
1294 let fut = stopping_state(test_values.deps, stop_sender);
1295 let fut = run_state_machine(fut);
1296 let mut fut = pin!(fut);
1297
1298 let (start_sender, mut start_receiver) = oneshot::channel();
1300 let radio_config = new_radio_config();
1301 let req = ApConfig {
1302 id: create_network_id(),
1303 credential: vec![],
1304 radio_config,
1305 mode: types::ConnectivityMode::Unrestricted,
1306 band: types::OperatingBand::Any,
1307 };
1308
1309 let mut ap = AccessPoint::new(test_values.ap_req_sender);
1310 ap.start(req, start_sender).expect("failed to make stop request");
1311
1312 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1314 assert_matches!(exec.run_until_stalled(&mut stop_receiver), Poll::Pending);
1315 let sme_fut = test_values.sme_req_stream.into_future();
1316 let mut sme_fut = pin!(sme_fut);
1317 let stop_responder = assert_matches!(
1318 poll_sme_req(&mut exec, &mut sme_fut),
1319 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => responder
1320 );
1321
1322 assert_matches!(poll_sme_req(&mut exec, &mut sme_fut), Poll::Pending);
1324
1325 stop_responder
1327 .send(fidl_sme::StopApResultCode::Success)
1328 .expect("could not send AP stop response");
1329 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1330 assert_matches!(exec.run_until_stalled(&mut stop_receiver), Poll::Ready(Ok(())));
1331
1332 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1334 assert_matches!(
1335 poll_sme_req(&mut exec, &mut sme_fut),
1336 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
1337 responder.send(fidl_sme::StopApResultCode::Success).expect("could not send AP stop response");
1338 }
1339 );
1340
1341 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1343 assert_matches!(
1344 poll_sme_req(&mut exec, &mut sme_fut),
1345 Poll::Ready(fidl_sme::ApSmeRequest::Start{ config: _, responder }) => {
1346 responder
1347 .send(fidl_sme::StartApResultCode::Success)
1348 .expect("could not send AP stop response");
1349 }
1350 );
1351
1352 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1354 assert_matches!(exec.run_until_stalled(&mut start_receiver), Poll::Ready(Ok(())));
1355 }
1356
1357 #[fuchsia::test]
1358 fn test_sme_failure_while_stopping() {
1359 let mut exec = fasync::TestExecutor::new();
1360 let mut test_values = test_setup();
1361
1362 drop(test_values.sme_req_stream);
1364
1365 let (stop_sender, mut stop_receiver) = oneshot::channel();
1367 let fut = stopping_state(test_values.deps, stop_sender);
1368 let fut = run_state_machine(fut);
1369 let mut fut = pin!(fut);
1370
1371 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
1373 assert_matches!(exec.run_until_stalled(&mut stop_receiver), Poll::Ready(Err(_)));
1374
1375 assert_matches!(
1377 test_values.update_receiver.try_next(),
1378 Ok(Some(listener::Message::NotifyListeners(updates))) => {
1379 assert!(updates.access_points.is_empty());
1380 });
1381 }
1382
1383 #[fuchsia::test]
1384 fn test_failed_result_code_while_stopping() {
1385 let mut exec = fasync::TestExecutor::new();
1386 let mut test_values = test_setup();
1387
1388 let (stop_sender, mut stop_receiver) = oneshot::channel();
1390 let fut = stopping_state(test_values.deps, stop_sender);
1391 let fut = run_state_machine(fut);
1392 let mut fut = pin!(fut);
1393
1394 assert_matches!(&mut test_values.update_receiver.try_next(), Err(_));
1396
1397 let sme_fut = test_values.sme_req_stream.into_future();
1399 let mut sme_fut = pin!(sme_fut);
1400
1401 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1402 assert_matches!(
1403 poll_sme_req(&mut exec, &mut sme_fut),
1404 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
1405 responder.send(fidl_sme::StopApResultCode::InternalError).expect("could not send AP stop response");
1406 }
1407 );
1408
1409 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
1411 assert_matches!(exec.run_until_stalled(&mut stop_receiver), Poll::Ready(Err(_)));
1412
1413 assert_matches!(
1415 test_values.update_receiver.try_next(),
1416 Ok(Some(listener::Message::NotifyListeners(updates))) => {
1417 assert!(updates.access_points.is_empty());
1418 });
1419 }
1420
1421 #[fuchsia::test]
1422 fn test_stop_while_starting() {
1423 let mut exec = fasync::TestExecutor::new();
1424 let mut test_values = test_setup();
1425
1426 let (start_sender, mut start_receiver) = oneshot::channel();
1427 let radio_config = new_radio_config();
1428 let req = ApConfig {
1429 id: create_network_id(),
1430 credential: vec![],
1431 radio_config,
1432 mode: types::ConnectivityMode::Unrestricted,
1433 band: types::OperatingBand::Any,
1434 };
1435
1436 let fut = starting_state(test_values.deps, req, 0, Some(start_sender));
1438 let fut = run_state_machine(fut);
1439 let mut fut = pin!(fut);
1440
1441 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1443
1444 let sme_fut = test_values.sme_req_stream.into_future();
1445 let mut sme_fut = pin!(sme_fut);
1446
1447 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1448 assert_matches!(
1449 poll_sme_req(&mut exec, &mut sme_fut),
1450 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
1451 responder.send(fidl_sme::StopApResultCode::Success).expect("could not send AP stop response");
1452 }
1453 );
1454
1455 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1457 let start_responder = assert_matches!(
1458 poll_sme_req(&mut exec, &mut sme_fut),
1459 Poll::Ready(fidl_sme::ApSmeRequest::Start{ config: _, responder }) => {
1460 responder
1461 }
1462 );
1463
1464 let mut ap = AccessPoint::new(test_values.ap_req_sender);
1466 let (stop_sender, mut stop_receiver) = oneshot::channel();
1467 ap.stop(stop_sender).expect("failed to make stop request");
1468
1469 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1471 assert_matches!(poll_sme_req(&mut exec, &mut sme_fut), Poll::Pending);
1472
1473 start_responder
1475 .send(fidl_sme::StartApResultCode::Success)
1476 .expect("could not send SME start response");
1477 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1478 assert_matches!(exec.run_until_stalled(&mut start_receiver), Poll::Ready(Ok(())));
1479
1480 assert_matches!(
1482 poll_sme_req(&mut exec, &mut sme_fut),
1483 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
1484 responder.send(fidl_sme::StopApResultCode::Success).expect("could not send SME stop response");
1485 }
1486 );
1487
1488 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1490 assert_matches!(exec.run_until_stalled(&mut stop_receiver), Poll::Ready(Ok(())));
1491
1492 assert_matches!(
1494 test_values.telemetry_receiver.try_next(),
1495 Ok(Some(TelemetryEvent::StartApResult(Ok(()))))
1496 );
1497 }
1498
1499 #[fuchsia::test]
1500 fn test_start_while_starting() {
1501 let mut exec = fasync::TestExecutor::new();
1502 let mut test_values = test_setup();
1503
1504 let (start_sender, mut start_receiver) = oneshot::channel();
1505 let radio_config = new_radio_config();
1506 let req = ApConfig {
1507 id: create_network_id(),
1508 credential: vec![],
1509 radio_config,
1510 mode: types::ConnectivityMode::Unrestricted,
1511 band: types::OperatingBand::Any,
1512 };
1513
1514 let fut = starting_state(test_values.deps, req, 0, Some(start_sender));
1516 let fut = run_state_machine(fut);
1517 let mut fut = pin!(fut);
1518
1519 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1521
1522 let sme_fut = test_values.sme_req_stream.into_future();
1523 let mut sme_fut = pin!(sme_fut);
1524
1525 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1526 assert_matches!(
1527 poll_sme_req(&mut exec, &mut sme_fut),
1528 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
1529 responder.send(fidl_sme::StopApResultCode::Success).expect("could not send AP stop response");
1530 }
1531 );
1532
1533 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1535 let start_responder = assert_matches!(
1536 poll_sme_req(&mut exec, &mut sme_fut),
1537 Poll::Ready(fidl_sme::ApSmeRequest::Start{ config: _, responder }) => {
1538 responder
1539 }
1540 );
1541
1542 let (second_start_sender, mut second_start_receiver) = oneshot::channel();
1544 let radio_config = new_radio_config();
1545 let req = ApConfig {
1546 id: create_network_id(),
1547 credential: vec![],
1548 radio_config,
1549 mode: types::ConnectivityMode::Unrestricted,
1550 band: types::OperatingBand::Any,
1551 };
1552 let mut ap = AccessPoint::new(test_values.ap_req_sender);
1553 ap.start(req, second_start_sender).expect("failed to make start request");
1554
1555 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1558 assert_matches!(exec.run_until_stalled(&mut start_receiver), Poll::Pending);
1559 assert_matches!(poll_sme_req(&mut exec, &mut sme_fut), Poll::Pending);
1560
1561 start_responder
1563 .send(fidl_sme::StartApResultCode::Success)
1564 .expect("failed to send start response");
1565
1566 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1568 assert_matches!(exec.run_until_stalled(&mut start_receiver), Poll::Ready(Ok(())));
1569 assert_matches!(exec.run_until_stalled(&mut second_start_receiver), Poll::Pending);
1570
1571 assert_matches!(
1574 poll_sme_req(&mut exec, &mut sme_fut),
1575 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
1576 responder.send(fidl_sme::StopApResultCode::Success).expect("could not send SME stop response");
1577 }
1578 );
1579
1580 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1582 assert_matches!(
1583 poll_sme_req(&mut exec, &mut sme_fut),
1584 Poll::Ready(fidl_sme::ApSmeRequest::Start{ config: _, responder }) => {
1585 responder
1586 .send(fidl_sme::StartApResultCode::Success)
1587 .expect("failed to send start response");
1588 }
1589 );
1590
1591 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1593 assert_matches!(exec.run_until_stalled(&mut second_start_receiver), Poll::Ready(Ok(())));
1594
1595 assert_matches!(
1597 test_values.telemetry_receiver.try_next(),
1598 Ok(Some(TelemetryEvent::StartApResult(Ok(()))))
1599 );
1600 }
1601
1602 #[fuchsia::test]
1603 fn test_exit_while_starting() {
1604 let mut exec = fasync::TestExecutor::new();
1605 let mut test_values = test_setup();
1606
1607 let (start_sender, mut start_receiver) = oneshot::channel();
1608 let radio_config = new_radio_config();
1609 let req = ApConfig {
1610 id: create_network_id(),
1611 credential: vec![],
1612 radio_config,
1613 mode: types::ConnectivityMode::Unrestricted,
1614 band: types::OperatingBand::Any,
1615 };
1616
1617 let fut = starting_state(test_values.deps, req, 0, Some(start_sender));
1619 let fut = run_state_machine(fut);
1620 let mut fut = pin!(fut);
1621
1622 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1624
1625 let sme_fut = test_values.sme_req_stream.into_future();
1626 let mut sme_fut = pin!(sme_fut);
1627
1628 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1629 assert_matches!(
1630 poll_sme_req(&mut exec, &mut sme_fut),
1631 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
1632 responder.send(fidl_sme::StopApResultCode::Success).expect("could not send AP stop response");
1633 }
1634 );
1635
1636 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1638 let start_responder = assert_matches!(
1639 poll_sme_req(&mut exec, &mut sme_fut),
1640 Poll::Ready(fidl_sme::ApSmeRequest::Start{ config: _, responder }) => {
1641 responder
1642 }
1643 );
1644
1645 let mut ap = AccessPoint::new(test_values.ap_req_sender);
1647 let (exit_sender, mut exit_receiver) = oneshot::channel();
1648 ap.exit(exit_sender).expect("failed to make stop request");
1649
1650 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1652 assert_matches!(exec.run_until_stalled(&mut start_receiver), Poll::Pending);
1653 assert_matches!(exec.run_until_stalled(&mut exit_receiver), Poll::Pending);
1654
1655 start_responder
1657 .send(fidl_sme::StartApResultCode::Success)
1658 .expect("could not send AP start response");
1659
1660 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
1661 assert_matches!(exec.run_until_stalled(&mut exit_receiver), Poll::Ready(Ok(())));
1662 assert_matches!(exec.run_until_stalled(&mut start_receiver), Poll::Ready(Ok(())));
1663
1664 assert_matches!(
1666 test_values.telemetry_receiver.try_next(),
1667 Ok(Some(TelemetryEvent::StartApResult(Ok(()))))
1668 );
1669 }
1670
1671 #[fuchsia::test]
1672 fn test_sme_breaks_while_starting() {
1673 let mut exec = fasync::TestExecutor::new();
1674 let mut test_values = test_setup();
1675
1676 drop(test_values.sme_req_stream);
1678
1679 let (start_sender, _start_receiver) = oneshot::channel();
1680 let radio_config = new_radio_config();
1681 let req = ApConfig {
1682 id: create_network_id(),
1683 credential: vec![],
1684 radio_config,
1685 mode: types::ConnectivityMode::Unrestricted,
1686 band: types::OperatingBand::Any,
1687 };
1688
1689 let fut = starting_state(test_values.deps, req, 0, Some(start_sender));
1691 let fut = run_state_machine(fut);
1692 let mut fut = pin!(fut);
1693
1694 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
1696
1697 assert_matches!(test_values.telemetry_receiver.try_next(), Ok(None));
1699 }
1700
1701 #[fuchsia::test]
1702 fn test_sme_fails_to_stop_while_starting() {
1703 let mut exec = fasync::TestExecutor::new();
1704 let mut test_values = test_setup();
1705
1706 let (start_sender, _start_receiver) = oneshot::channel();
1707 let radio_config = new_radio_config();
1708 let req = ApConfig {
1709 id: create_network_id(),
1710 credential: vec![],
1711 radio_config,
1712 mode: types::ConnectivityMode::Unrestricted,
1713 band: types::OperatingBand::Any,
1714 };
1715
1716 let fut = starting_state(test_values.deps, req, 0, Some(start_sender));
1718 let fut = run_state_machine(fut);
1719 let mut fut = pin!(fut);
1720
1721 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1723
1724 let sme_fut = test_values.sme_req_stream.into_future();
1725 let mut sme_fut = pin!(sme_fut);
1726
1727 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1728 assert_matches!(
1729 poll_sme_req(&mut exec, &mut sme_fut),
1730 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
1731 responder
1732 .send(fidl_sme::StopApResultCode::TimedOut)
1733 .expect("could not send AP stop response");
1734 }
1735 );
1736
1737 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
1739
1740 assert_matches!(
1742 test_values.update_receiver.try_next(),
1743 Ok(Some(listener::Message::NotifyListeners(mut updates))) => {
1744 let update = updates.access_points.pop().expect("no new updates available.");
1745 assert_eq!(update.state, types::OperatingState::Failed);
1746 });
1747
1748 assert_matches!(test_values.telemetry_receiver.try_next(), Ok(None));
1750 }
1751
1752 #[fuchsia::test]
1753 fn test_sme_fails_to_start_while_starting() {
1754 let mut exec = fasync::TestExecutor::new();
1755 let mut test_values = test_setup();
1756
1757 let (start_sender, mut start_receiver) = oneshot::channel();
1758 let radio_config = new_radio_config();
1759 let req = ApConfig {
1760 id: create_network_id(),
1761 credential: vec![],
1762 radio_config,
1763 mode: types::ConnectivityMode::Unrestricted,
1764 band: types::OperatingBand::Any,
1765 };
1766
1767 let fut = starting_state(test_values.deps, req, AP_START_MAX_RETRIES, Some(start_sender));
1769 let fut = run_state_machine(fut);
1770 let mut fut = pin!(fut);
1771
1772 let sme_fut = test_values.sme_req_stream.into_future();
1774 let mut sme_fut = pin!(sme_fut);
1775
1776 for retry_number in 0..(AP_START_MAX_RETRIES + 1) {
1777 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1779 assert_matches!(
1780 poll_sme_req(&mut exec, &mut sme_fut),
1781 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
1782 responder
1783 .send(fidl_sme::StopApResultCode::Success)
1784 .expect("could not send AP stop response");
1785 }
1786 );
1787
1788 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1790 assert_matches!(
1791 test_values.update_receiver.try_next(),
1792 Ok(Some(listener::Message::NotifyListeners(_)))
1793 );
1794
1795 if retry_number == 0 {
1798 assert_matches!(
1799 test_values.update_receiver.try_next(),
1800 Ok(Some(listener::Message::NotifyListeners(mut updates))) => {
1801 let update = updates.access_points.pop().expect("no new updates available.");
1802 assert_eq!(update.state, types::OperatingState::Starting);
1803 });
1804 } else {
1805 assert_matches!(test_values.update_receiver.try_next(), Err(_));
1806 }
1807
1808 assert_matches!(
1810 poll_sme_req(&mut exec, &mut sme_fut),
1811 Poll::Ready(fidl_sme::ApSmeRequest::Start{ config: _, responder }) => {
1812 responder
1813 .send(fidl_sme::StartApResultCode::TimedOut)
1814 .expect("could not send AP stop response");
1815 }
1816 );
1817
1818 if retry_number < AP_START_MAX_RETRIES {
1819 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1821
1822 assert_matches!(exec.run_until_stalled(&mut start_receiver), Poll::Pending);
1824
1825 assert_matches!(exec.wake_next_timer(), Some(_));
1827 }
1828 }
1829
1830 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
1832
1833 assert_matches!(exec.run_until_stalled(&mut start_receiver), Poll::Ready(Err(_)));
1835
1836 assert_matches!(
1838 test_values.update_receiver.try_next(),
1839 Ok(Some(listener::Message::NotifyListeners(mut updates))) => {
1840 let update = updates.access_points.pop().expect("no new updates available.");
1841 assert_eq!(update.state, types::OperatingState::Failed);
1842 });
1843
1844 assert_matches!(
1846 test_values.telemetry_receiver.try_next(),
1847 Ok(Some(TelemetryEvent::StartApResult(Err(()))))
1848 );
1849
1850 assert_matches!(
1852 test_values.defect_receiver.try_next(),
1853 Ok(Some(Defect::Iface(IfaceFailure::ApStartFailure { .. })))
1854 );
1855 }
1856
1857 #[fuchsia::test]
1858 fn test_stop_after_start_failure() {
1859 let mut exec = fasync::TestExecutor::new();
1860 let mut test_values = test_setup();
1861
1862 let (start_sender, mut start_receiver) = oneshot::channel();
1863 let radio_config = new_radio_config();
1864 let req = ApConfig {
1865 id: create_network_id(),
1866 credential: vec![],
1867 radio_config,
1868 mode: types::ConnectivityMode::Unrestricted,
1869 band: types::OperatingBand::Any,
1870 };
1871
1872 let (stop_sender, mut stop_receiver) = oneshot::channel();
1874 test_values
1875 .ap_req_sender
1876 .try_send(ManualRequest::Stop(stop_sender))
1877 .expect("failed to request AP stop");
1878
1879 let fut = starting_state(test_values.deps, req, AP_START_MAX_RETRIES, Some(start_sender));
1881 let fut = run_state_machine(fut);
1882 let mut fut = pin!(fut);
1883
1884 let sme_fut = test_values.sme_req_stream.into_future();
1886 let mut sme_fut = pin!(sme_fut);
1887
1888 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1890 assert_matches!(
1891 poll_sme_req(&mut exec, &mut sme_fut),
1892 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
1893 responder
1894 .send(fidl_sme::StopApResultCode::Success)
1895 .expect("could not send AP stop response");
1896 }
1897 );
1898
1899 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1901 assert_matches!(
1902 test_values.update_receiver.try_next(),
1903 Ok(Some(listener::Message::NotifyListeners(_)))
1904 );
1905
1906 assert_matches!(
1908 test_values.update_receiver.try_next(),
1909 Ok(Some(listener::Message::NotifyListeners(mut updates))) => {
1910 let update = updates.access_points.pop().expect("no new updates available.");
1911 assert_eq!(update.state, types::OperatingState::Starting);
1912 });
1913
1914 assert_matches!(
1916 poll_sme_req(&mut exec, &mut sme_fut),
1917 Poll::Ready(fidl_sme::ApSmeRequest::Start{ config: _, responder }) => {
1918 responder
1919 .send(fidl_sme::StartApResultCode::TimedOut)
1920 .expect("could not send AP stop response");
1921 }
1922 );
1923
1924 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1928
1929 assert_matches!(
1931 test_values.telemetry_receiver.try_next(),
1932 Ok(Some(TelemetryEvent::StartApResult(Err(()))))
1933 );
1934
1935 assert_matches!(
1937 test_values.defect_receiver.try_next(),
1938 Ok(Some(Defect::Iface(IfaceFailure::ApStartFailure { .. })))
1939 );
1940
1941 assert_matches!(exec.run_until_stalled(&mut start_receiver), Poll::Ready(Err(_)));
1943
1944 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1946 assert_matches!(
1947 poll_sme_req(&mut exec, &mut sme_fut),
1948 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
1949 responder
1950 .send(fidl_sme::StopApResultCode::Success)
1951 .expect("could not send AP stop response");
1952 }
1953 );
1954
1955 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1957
1958 assert_matches!(exec.run_until_stalled(&mut stop_receiver), Poll::Ready(Ok(())));
1960
1961 assert_matches!(
1963 test_values.update_receiver.try_next(),
1964 Ok(Some(listener::Message::NotifyListeners(updates))) => {
1965 assert!(updates.access_points.is_empty());
1966 });
1967 }
1968
1969 #[fuchsia::test]
1970 fn test_start_after_start_failure() {
1971 let mut exec = fasync::TestExecutor::new();
1972 let mut test_values = test_setup();
1973
1974 let (start_sender, mut start_receiver) = oneshot::channel();
1975 let radio_config = new_radio_config();
1976 let req = ApConfig {
1977 id: create_network_id(),
1978 credential: vec![],
1979 radio_config: radio_config.clone(),
1980 mode: types::ConnectivityMode::Unrestricted,
1981 band: types::OperatingBand::Any,
1982 };
1983
1984 let mut requested_id = create_network_id();
1986 requested_id.ssid = types::Ssid::try_from("second_test_ssid").unwrap();
1987
1988 let requested_config = ApConfig {
1989 id: requested_id.clone(),
1990 credential: vec![],
1991 radio_config,
1992 mode: types::ConnectivityMode::Unrestricted,
1993 band: types::OperatingBand::Any,
1994 };
1995
1996 let (start_response_sender, _) = oneshot::channel();
1997 test_values
1998 .ap_req_sender
1999 .try_send(ManualRequest::Start((requested_config, start_response_sender)))
2000 .expect("failed to request AP stop");
2001
2002 let fut = starting_state(test_values.deps, req, AP_START_MAX_RETRIES, Some(start_sender));
2004 let fut = run_state_machine(fut);
2005 let mut fut = pin!(fut);
2006
2007 let sme_fut = test_values.sme_req_stream.into_future();
2009 let mut sme_fut = pin!(sme_fut);
2010
2011 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2013 assert_matches!(
2014 poll_sme_req(&mut exec, &mut sme_fut),
2015 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
2016 responder
2017 .send(fidl_sme::StopApResultCode::Success)
2018 .expect("could not send AP stop response");
2019 }
2020 );
2021
2022 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2024 assert_matches!(
2025 test_values.update_receiver.try_next(),
2026 Ok(Some(listener::Message::NotifyListeners(_)))
2027 );
2028
2029 assert_matches!(
2031 test_values.update_receiver.try_next(),
2032 Ok(Some(listener::Message::NotifyListeners(mut updates))) => {
2033 let update = updates.access_points.pop().expect("no new updates available.");
2034 assert_eq!(update.state, types::OperatingState::Starting);
2035 });
2036
2037 assert_matches!(
2039 poll_sme_req(&mut exec, &mut sme_fut),
2040 Poll::Ready(fidl_sme::ApSmeRequest::Start{ config: _, responder }) => {
2041 responder
2042 .send(fidl_sme::StartApResultCode::TimedOut)
2043 .expect("could not send AP stop response");
2044 }
2045 );
2046
2047 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2051
2052 assert_matches!(
2054 test_values.telemetry_receiver.try_next(),
2055 Ok(Some(TelemetryEvent::StartApResult(Err(()))))
2056 );
2057
2058 assert_matches!(
2060 test_values.defect_receiver.try_next(),
2061 Ok(Some(Defect::Iface(IfaceFailure::ApStartFailure { .. })))
2062 );
2063
2064 assert_matches!(exec.run_until_stalled(&mut start_receiver), Poll::Ready(Err(_)));
2066
2067 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2069 assert_matches!(
2070 poll_sme_req(&mut exec, &mut sme_fut),
2071 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
2072 responder
2073 .send(fidl_sme::StopApResultCode::Success)
2074 .expect("could not send AP stop response");
2075 }
2076 );
2077
2078 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2080 assert_matches!(
2081 poll_sme_req(&mut exec, &mut sme_fut),
2082 Poll::Ready(fidl_sme::ApSmeRequest::Start{ config, responder: _ }) => {
2083 assert_eq!(config.ssid, requested_id.ssid);
2084 }
2085 );
2086 }
2087
2088 #[fuchsia::test]
2089 fn test_exit_after_start_failure() {
2090 let mut exec = fasync::TestExecutor::new();
2091 let mut test_values = test_setup();
2092
2093 let (start_sender, _) = oneshot::channel();
2094 let radio_config = new_radio_config();
2095 let req = ApConfig {
2096 id: create_network_id(),
2097 credential: vec![],
2098 radio_config,
2099 mode: types::ConnectivityMode::Unrestricted,
2100 band: types::OperatingBand::Any,
2101 };
2102
2103 let (exit_sender, mut exit_receiver) = oneshot::channel();
2105 test_values
2106 .ap_req_sender
2107 .try_send(ManualRequest::Exit(exit_sender))
2108 .expect("failed to request AP stop");
2109
2110 let fut = starting_state(test_values.deps, req, AP_START_MAX_RETRIES, Some(start_sender));
2112 let fut = run_state_machine(fut);
2113 let mut fut = pin!(fut);
2114
2115 let sme_fut = test_values.sme_req_stream.into_future();
2117 let mut sme_fut = pin!(sme_fut);
2118
2119 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2121 assert_matches!(
2122 poll_sme_req(&mut exec, &mut sme_fut),
2123 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
2124 responder
2125 .send(fidl_sme::StopApResultCode::Success)
2126 .expect("could not send AP stop response");
2127 }
2128 );
2129
2130 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2132 assert_matches!(
2133 test_values.update_receiver.try_next(),
2134 Ok(Some(listener::Message::NotifyListeners(_)))
2135 );
2136
2137 assert_matches!(
2139 test_values.update_receiver.try_next(),
2140 Ok(Some(listener::Message::NotifyListeners(mut updates))) => {
2141 let update = updates.access_points.pop().expect("no new updates available.");
2142 assert_eq!(update.state, types::OperatingState::Starting);
2143 });
2144
2145 assert_matches!(
2147 poll_sme_req(&mut exec, &mut sme_fut),
2148 Poll::Ready(fidl_sme::ApSmeRequest::Start{ config: _, responder }) => {
2149 responder
2150 .send(fidl_sme::StartApResultCode::TimedOut)
2151 .expect("could not send AP stop response");
2152 }
2153 );
2154
2155 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
2159 assert_matches!(exec.run_until_stalled(&mut exit_receiver), Poll::Ready(Ok(())));
2160
2161 assert_matches!(
2163 test_values.telemetry_receiver.try_next(),
2164 Ok(Some(TelemetryEvent::StartApResult(Err(()))))
2165 );
2166
2167 assert_matches!(
2169 test_values.defect_receiver.try_next(),
2170 Ok(Some(Defect::Iface(IfaceFailure::ApStartFailure { .. })))
2171 );
2172 }
2173
2174 #[fuchsia::test]
2175 fn test_manual_start_causes_starting_notification() {
2176 let mut exec = fasync::TestExecutor::new();
2177 let mut test_values = test_setup();
2178
2179 let radio_config = new_radio_config();
2181 let requested_config = ApConfig {
2182 id: create_network_id(),
2183 credential: vec![],
2184 radio_config,
2185 mode: types::ConnectivityMode::Unrestricted,
2186 band: types::OperatingBand::Any,
2187 };
2188
2189 let (start_response_sender, _) = oneshot::channel();
2190 let manual_request = ManualRequest::Start((requested_config, start_response_sender));
2191
2192 let fut = perform_manual_request(test_values.deps, Some(manual_request));
2193 let fut = run_state_machine(async move { fut });
2194 let mut fut = pin!(fut);
2195 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2196
2197 let sme_fut = test_values.sme_req_stream.into_future();
2199 let mut sme_fut = pin!(sme_fut);
2200
2201 assert_matches!(
2202 poll_sme_req(&mut exec, &mut sme_fut),
2203 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
2204 responder
2205 .send(fidl_sme::StopApResultCode::Success)
2206 .expect("could not send SME stop response");
2207 }
2208 );
2209
2210 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2213 assert_matches!(
2214 test_values.update_receiver.try_next(),
2215 Ok(Some(listener::Message::NotifyListeners(updates))) => {
2216 assert!(updates.access_points.is_empty());
2217 });
2218
2219 assert_matches!(
2220 test_values.update_receiver.try_next(),
2221 Ok(Some(listener::Message::NotifyListeners(mut updates))) => {
2222 let update = updates.access_points.pop().expect("no new updates available.");
2223 assert_eq!(update.state, types::OperatingState::Starting);
2224 });
2225 }
2226
2227 #[fuchsia::test]
2228 fn test_serve_does_not_terminate_right_away() {
2229 let mut exec = fasync::TestExecutor::new();
2230 let test_values = test_setup();
2231 let sme_event_stream = test_values.deps.proxy.take_event_stream();
2232 let sme_fut = test_values.sme_req_stream.into_future();
2233 let mut sme_fut = pin!(sme_fut);
2234
2235 let update_sender = test_values.deps.state_tracker.inner.lock().sender.clone();
2236
2237 let fut = serve(
2238 0,
2239 test_values.deps.proxy,
2240 sme_event_stream,
2241 test_values.deps.req_stream,
2242 update_sender,
2243 test_values.deps.telemetry_sender,
2244 test_values.deps.defect_sender,
2245 test_values.deps.status_publisher,
2246 );
2247 let mut fut = pin!(fut);
2248
2249 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2251 assert_matches!(poll_sme_req(&mut exec, &mut sme_fut), Poll::Pending);
2252 }
2253
2254 #[fuchsia::test]
2255 fn test_no_notification_when_sme_fails_while_stopped() {
2256 let mut exec = fasync::TestExecutor::new();
2257 let test_values = test_setup();
2258 let sme_event_stream = test_values.deps.proxy.take_event_stream();
2259 let update_sender = test_values.deps.state_tracker.inner.lock().sender.clone();
2260
2261 test_values.deps.status_publisher.publish_status(Status::Starting);
2263
2264 let fut = serve(
2265 0,
2266 test_values.deps.proxy,
2267 sme_event_stream,
2268 test_values.deps.req_stream,
2269 update_sender,
2270 test_values.deps.telemetry_sender,
2271 test_values.deps.defect_sender,
2272 test_values.deps.status_publisher.clone(),
2273 );
2274 let mut fut = pin!(fut);
2275
2276 drop(test_values.sme_req_stream);
2278
2279 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
2281
2282 assert_matches!(
2284 exec.run_until_stalled(&mut test_values.update_receiver.into_future()),
2285 Poll::Pending
2286 );
2287
2288 assert_matches!(test_values.status_reader.read_status(), Ok(Status::Stopped));
2290 }
2291
2292 #[fuchsia::test]
2293 fn test_failure_notification_when_configured() {
2294 let mut exec = fasync::TestExecutor::new();
2295 let mut test_values = test_setup();
2296 let sme_event_stream = test_values.deps.proxy.take_event_stream();
2297 let mut sme_fut = Box::pin(test_values.sme_req_stream.into_future());
2298
2299 let update_sender = test_values.deps.state_tracker.inner.lock().sender.clone();
2300 let fut = serve(
2301 0,
2302 test_values.deps.proxy,
2303 sme_event_stream,
2304 test_values.deps.req_stream,
2305 update_sender,
2306 test_values.deps.telemetry_sender,
2307 test_values.deps.defect_sender,
2308 test_values.deps.status_publisher,
2309 );
2310 let mut fut = pin!(fut);
2311
2312 let mut ap = AccessPoint::new(test_values.ap_req_sender);
2314 let (sender, _receiver) = oneshot::channel();
2315 let radio_config = new_radio_config();
2316 let config = ApConfig {
2317 id: create_network_id(),
2318 credential: vec![],
2319 radio_config,
2320 mode: types::ConnectivityMode::Unrestricted,
2321 band: types::OperatingBand::Any,
2322 };
2323 ap.start(config, sender).expect("failed to make start request");
2324
2325 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2327 assert_matches!(
2328 poll_sme_req(&mut exec, &mut sme_fut),
2329 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
2330 responder.send(fidl_sme::StopApResultCode::Success).expect("could not send AP stop response");
2331 }
2332 );
2333
2334 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2335
2336 assert_matches!(
2339 test_values.update_receiver.try_next(),
2340 Ok(Some(listener::Message::NotifyListeners(update))) => {
2341 assert!(update.access_points.is_empty());
2342 }
2343 );
2344 assert_matches!(
2345 test_values.update_receiver.try_next(),
2346 Ok(Some(listener::Message::NotifyListeners(update))) => {
2347 assert_eq!(update.access_points.len(), 1);
2348 assert_eq!(update.access_points[0].state, types::OperatingState::Starting);
2349 }
2350 );
2351
2352 drop(sme_fut);
2354
2355 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
2357
2358 assert_matches!(
2360 test_values.update_receiver.try_next(),
2361 Ok(Some(listener::Message::NotifyListeners(update))) => {
2362 assert_eq!(update.access_points.len(), 1);
2363 assert_eq!(update.access_points[0].state, types::OperatingState::Failed);
2364 }
2365 );
2366 }
2367
2368 #[fuchsia::test]
2369 fn test_state_tracker_reset() {
2370 let _exec = fasync::TestExecutor::new();
2371 let (sender, mut receiver) = mpsc::unbounded();
2372
2373 let state = ApStateTracker::new(sender);
2375 {
2376 assert!(state.inner.lock().state.is_none());
2377 }
2378
2379 assert_matches!(receiver.try_next(), Err(_));
2381
2382 let new_state = ApStateUpdate::new(
2384 create_network_id(),
2385 types::OperatingState::Starting,
2386 types::ConnectivityMode::Unrestricted,
2387 types::OperatingBand::Any,
2388 );
2389 state.reset_state(new_state).expect("failed to reset state");
2390 assert_matches!(state.inner.lock().state.as_ref(), Some(ApStateUpdate {
2391 id: types::NetworkIdentifier {
2392 ssid,
2393 security_type: types::SecurityType::None,
2394 },
2395 state: types::OperatingState::Starting,
2396 mode: Some(types::ConnectivityMode::Unrestricted),
2397 band: Some(types::OperatingBand::Any),
2398 frequency: None,
2399 clients: None,
2400 }) => {
2401 let expected_ssid = types::Ssid::try_from("test_ssid").unwrap();
2402 assert_eq!(ssid, &expected_ssid);
2403 });
2404
2405 assert_matches!(
2407 receiver.try_next(),
2408 Ok(Some(listener::Message::NotifyListeners(ApStatesUpdate { access_points }))) => {
2409 assert_eq!(access_points.len(), 1);
2410
2411 let expected_id = types::NetworkIdentifier {
2412 ssid: types::Ssid::try_from("test_ssid").unwrap(),
2413 security_type: types::SecurityType::None,
2414 };
2415 assert_eq!(access_points[0].id, expected_id);
2416 assert_eq!(access_points[0].state, types::OperatingState::Starting);
2417 assert_eq!(access_points[0].mode, Some(types::ConnectivityMode::Unrestricted));
2418 assert_eq!(access_points[0].band, Some(types::OperatingBand::Any));
2419 assert_eq!(access_points[0].frequency, None);
2420 assert_eq!(access_points[0].clients, None);
2421 }
2422 );
2423 }
2424
2425 #[fuchsia::test]
2426 fn test_state_tracker_consume_sme_update() {
2427 let _exec = fasync::TestExecutor::new();
2428 let (sender, mut receiver) = mpsc::unbounded();
2429 let state = ApStateTracker::new(sender);
2430
2431 let new_state = ApStateUpdate::new(
2433 create_network_id(),
2434 types::OperatingState::Active,
2435 types::ConnectivityMode::Unrestricted,
2436 types::OperatingBand::Any,
2437 );
2438 state.reset_state(new_state).expect("failed to reset state");
2439
2440 assert_matches!(
2442 receiver.try_next(),
2443 Ok(Some(listener::Message::NotifyListeners(ApStatesUpdate { access_points }))
2444 ) => {
2445 assert_eq!(access_points.len(), 1);
2446
2447 let expected_id = types::NetworkIdentifier {
2448 ssid: types::Ssid::try_from("test_ssid").unwrap(),
2449 security_type: types::SecurityType::None,
2450 };
2451 assert_eq!(access_points[0].id, expected_id);
2452 assert_eq!(access_points[0].state, types::OperatingState::Active);
2453 assert_eq!(access_points[0].mode, Some(types::ConnectivityMode::Unrestricted));
2454 assert_eq!(access_points[0].band, Some(types::OperatingBand::Any));
2455 assert_eq!(access_points[0].frequency, None);
2456 assert_eq!(access_points[0].clients, None);
2457 });
2458
2459 let ap_info = fidl_sme::Ap {
2461 ssid: types::Ssid::try_from("test_ssid").unwrap().to_vec(),
2462 channel: 6,
2463 num_clients: 123,
2464 };
2465 state
2466 .consume_sme_status_update(
2467 Cbw::Cbw20,
2468 fidl_fuchsia_wlan_ieee80211::WlanBand::TwoGhz,
2469 ap_info,
2470 )
2471 .expect("failure while updating SME status");
2472
2473 assert_matches!(
2474 receiver.try_next(),
2475 Ok(Some(listener::Message::NotifyListeners(ApStatesUpdate { access_points }))
2476 ) => {
2477 assert_eq!(access_points.len(), 1);
2478
2479 let expected_id = types::NetworkIdentifier {
2480 ssid: types::Ssid::try_from("test_ssid").unwrap(),
2481 security_type: types::SecurityType::None,
2482 };
2483 assert_eq!(access_points[0].id, expected_id);
2484 assert_eq!(access_points[0].state, types::OperatingState::Active);
2485 assert_eq!(access_points[0].mode, Some(types::ConnectivityMode::Unrestricted));
2486 assert_eq!(access_points[0].band, Some(types::OperatingBand::Any));
2487 assert_eq!(access_points[0].frequency, Some(2437));
2488 assert_eq!(access_points[0].clients, Some(ConnectedClientInformation { count: 123 }));
2489 });
2490 }
2491
2492 #[fuchsia::test]
2493 fn test_state_tracker_update_operating_state() {
2494 let _exec = fasync::TestExecutor::new();
2495 let (sender, mut receiver) = mpsc::unbounded();
2496 let state = ApStateTracker::new(sender);
2497
2498 let new_state = ApStateUpdate::new(
2500 create_network_id(),
2501 types::OperatingState::Starting,
2502 types::ConnectivityMode::Unrestricted,
2503 types::OperatingBand::Any,
2504 );
2505 state.reset_state(new_state).expect("failed to reset state");
2506
2507 assert_matches!(
2509 receiver.try_next(),
2510 Ok(Some(listener::Message::NotifyListeners(ApStatesUpdate { access_points }))
2511 ) => {
2512 assert_eq!(access_points.len(), 1);
2513
2514 let expected_id = types::NetworkIdentifier {
2515 ssid: types::Ssid::try_from("test_ssid").unwrap(),
2516 security_type: types::SecurityType::None,
2517 };
2518 assert_eq!(access_points[0].id, expected_id);
2519 assert_eq!(access_points[0].state, types::OperatingState::Starting);
2520 assert_eq!(access_points[0].mode, Some(types::ConnectivityMode::Unrestricted));
2521 assert_eq!(access_points[0].band, Some(types::OperatingBand::Any));
2522 assert_eq!(access_points[0].frequency, None);
2523 assert_eq!(access_points[0].clients, None);
2524 });
2525
2526 state
2528 .update_operating_state(types::OperatingState::Starting)
2529 .expect("failed to send duplicate update.");
2530 assert_matches!(
2531 receiver.try_next(),
2532 Ok(Some(listener::Message::NotifyListeners(ApStatesUpdate { access_points }))
2533 ) => {
2534 assert_eq!(access_points.len(), 1);
2535
2536 let expected_id = types::NetworkIdentifier {
2537 ssid: types::Ssid::try_from("test_ssid").unwrap(),
2538 security_type: types::SecurityType::None,
2539 };
2540 assert_eq!(access_points[0].id, expected_id);
2541 assert_eq!(access_points[0].state, types::OperatingState::Starting);
2542 assert_eq!(access_points[0].mode, Some(types::ConnectivityMode::Unrestricted));
2543 assert_eq!(access_points[0].band, Some(types::OperatingBand::Any));
2544 assert_eq!(access_points[0].frequency, None);
2545 assert_eq!(access_points[0].clients, None);
2546 });
2547
2548 state
2550 .update_operating_state(types::OperatingState::Active)
2551 .expect("failed to send active update.");
2552 assert_matches!(
2553 receiver.try_next(),
2554 Ok(Some(listener::Message::NotifyListeners(ApStatesUpdate { access_points }))
2555 ) => {
2556 assert_eq!(access_points.len(), 1);
2557
2558 let expected_id = types::NetworkIdentifier {
2559 ssid: types::Ssid::try_from("test_ssid").unwrap(),
2560 security_type: types::SecurityType::None,
2561 };
2562 assert_eq!(access_points[0].id, expected_id);
2563 assert_eq!(access_points[0].state, types::OperatingState::Active);
2564 assert_eq!(access_points[0].mode, Some(types::ConnectivityMode::Unrestricted));
2565 assert_eq!(access_points[0].band, Some(types::OperatingBand::Any));
2566 assert_eq!(access_points[0].frequency, None);
2567 assert_eq!(access_points[0].clients, None);
2568 });
2569 }
2570
2571 #[fuchsia::test]
2572 fn test_state_tracker_set_stopped_state() {
2573 let _exec = fasync::TestExecutor::new();
2574 let (sender, mut receiver) = mpsc::unbounded();
2575 let state = ApStateTracker::new(sender);
2576
2577 {
2579 let new_state = ApStateUpdate::new(
2580 create_network_id(),
2581 types::OperatingState::Active,
2582 types::ConnectivityMode::Unrestricted,
2583 types::OperatingBand::Any,
2584 );
2585 state.inner.lock().state = Some(new_state);
2586 }
2587
2588 state.set_stopped_state().expect("failed to send stopped notification");
2591 {
2592 assert!(state.inner.lock().state.is_none());
2593 }
2594
2595 assert_matches!(
2597 receiver.try_next(),
2598 Ok(Some(listener::Message::NotifyListeners(ApStatesUpdate { access_points }))
2599 ) => {
2600 assert!(access_points.is_empty());
2601 });
2602 }
2603
2604 #[fuchsia::test]
2605 fn test_state_tracker_failure_modes() {
2606 let _exec = fasync::TestExecutor::new();
2607 let (sender, receiver) = mpsc::unbounded();
2608 let state = ApStateTracker::new(sender);
2609 {
2610 let new_state = ApStateUpdate::new(
2611 create_network_id(),
2612 types::OperatingState::Active,
2613 types::ConnectivityMode::Unrestricted,
2614 types::OperatingBand::Any,
2615 );
2616 state.inner.lock().state = Some(new_state);
2617 }
2618
2619 drop(receiver);
2623
2624 let _ = state
2625 .update_operating_state(types::OperatingState::Failed)
2626 .expect_err("unexpectedly able to set operating state");
2627 let _ = state
2628 .consume_sme_status_update(
2629 Cbw::Cbw20,
2630 fidl_fuchsia_wlan_ieee80211::WlanBand::TwoGhz,
2631 fidl_sme::Ap {
2632 ssid: types::Ssid::try_from("test_ssid").unwrap().to_vec(),
2633 channel: 6,
2634 num_clients: 123,
2635 },
2636 )
2637 .expect_err("unexpectedly able to update SME status");
2638 let _ = state.set_stopped_state().expect_err("unexpectedly able to set stopped state");
2639 }
2640
2641 #[fuchsia::test]
2642 fn test_state_when_stopping() {
2643 let mut exec = fasync::TestExecutor::new();
2644 let test_values = test_setup();
2645
2646 let (stop_sender, _) = oneshot::channel();
2648 let fut = stopping_state(test_values.deps, stop_sender);
2649 let fut = run_state_machine(fut);
2650 let mut fut = pin!(fut);
2651 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2652
2653 assert_matches!(test_values.status_reader.read_status(), Ok(Status::Stopping));
2655 }
2656
2657 #[fuchsia::test]
2658 fn test_state_when_stopped() {
2659 let mut exec = fasync::TestExecutor::new();
2660 let test_values = test_setup();
2661
2662 test_values.deps.status_publisher.publish_status(Status::Starting);
2664
2665 let fut = stopped_state(test_values.deps);
2667 let fut = run_state_machine(fut);
2668 let mut fut = pin!(fut);
2669 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2670
2671 assert_matches!(test_values.status_reader.read_status(), Ok(Status::Stopped));
2673 }
2674
2675 #[fuchsia::test]
2676 fn test_state_when_starting() {
2677 let mut exec = fasync::TestExecutor::new();
2678 let test_values = test_setup();
2679
2680 let (start_sender, _) = oneshot::channel();
2682 let radio_config = new_radio_config();
2683 let req = ApConfig {
2684 id: create_network_id(),
2685 credential: vec![],
2686 radio_config,
2687 mode: types::ConnectivityMode::Unrestricted,
2688 band: types::OperatingBand::Any,
2689 };
2690 let fut = starting_state(test_values.deps, req, 0, Some(start_sender));
2691 let fut = run_state_machine(fut);
2692 let mut fut = pin!(fut);
2693 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2694
2695 assert_matches!(test_values.status_reader.read_status(), Ok(Status::Starting));
2697 }
2698
2699 #[fuchsia::test]
2700 fn test_state_when_started() {
2701 let mut exec = fasync::TestExecutor::new();
2702 let test_values = test_setup();
2703
2704 let radio_config = new_radio_config();
2706 let req = ApConfig {
2707 id: create_network_id(),
2708 credential: vec![],
2709 radio_config,
2710 mode: types::ConnectivityMode::Unrestricted,
2711 band: types::OperatingBand::Any,
2712 };
2713 let fut = started_state(test_values.deps, req);
2714 let fut = run_state_machine(fut);
2715 let mut fut = pin!(fut);
2716 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2717
2718 assert_matches!(test_values.status_reader.read_status(), Ok(Status::Started { .. }));
2720 }
2721
2722 struct InspectTestValues {
2723 exec: fasync::TestExecutor,
2724 inspector: fuchsia_inspect::Inspector,
2725 _node: fuchsia_inspect::Node,
2726 status_node: fuchsia_inspect_contrib::nodes::BoundedListNode,
2727 }
2728
2729 impl InspectTestValues {
2730 fn new(exec: fasync::TestExecutor) -> Self {
2731 let inspector = fuchsia_inspect::Inspector::default();
2732 let _node = inspector.root().create_child("node");
2733 let status_node =
2734 fuchsia_inspect_contrib::nodes::BoundedListNode::new(_node.clone_weak(), 1);
2735
2736 Self { exec, inspector, _node, status_node }
2737 }
2738
2739 fn log_status(&mut self, status: Status) -> fuchsia_inspect::reader::DiagnosticsHierarchy {
2740 fuchsia_inspect_contrib::inspect_log!(self.status_node, "status" => status);
2741 let read_fut = fuchsia_inspect::reader::read(&self.inspector);
2742 let mut read_fut = pin!(read_fut);
2743 assert_matches!(
2744 self.exec.run_until_stalled(&mut read_fut),
2745 Poll::Ready(Ok(hierarchy)) => hierarchy
2746 )
2747 }
2748 }
2749
2750 #[fuchsia::test]
2751 fn test_stopping_status_inspect_log() {
2752 let exec = fasync::TestExecutor::new_with_fake_time();
2753 let mut test_values = InspectTestValues::new(exec);
2754 let hierarchy = test_values.log_status(Status::Stopping);
2755 diagnostics_assertions::assert_data_tree!(
2756 @executor test_values.exec,
2757 hierarchy,
2758 root: contains {
2759 node: contains {
2760 "0": contains {
2761 status: "Stopping"
2762 }
2763 }
2764 });
2765 }
2766
2767 #[fuchsia::test]
2768 fn test_stopped_status_inspect_log() {
2769 let exec = fasync::TestExecutor::new_with_fake_time();
2770 let mut test_values = InspectTestValues::new(exec);
2771 let hierarchy = test_values.log_status(Status::Stopped);
2772 diagnostics_assertions::assert_data_tree!(
2773 @executor test_values.exec,
2774 hierarchy,
2775 root: contains {
2776 node: contains {
2777 "0": contains {
2778 status: "Stopped"
2779 }
2780 }
2781 });
2782 }
2783
2784 #[fuchsia::test]
2785 fn test_starting_status_inspect_log() {
2786 let exec = fasync::TestExecutor::new_with_fake_time();
2787 let mut test_values = InspectTestValues::new(exec);
2788 let hierarchy = test_values.log_status(Status::Starting);
2789 diagnostics_assertions::assert_data_tree!(
2790 @executor test_values.exec,
2791 hierarchy,
2792 root: contains {
2793 node: contains {
2794 "0": contains {
2795 status: "Starting"
2796 }
2797 }
2798 });
2799 }
2800
2801 #[fuchsia::test]
2802 fn test_started_status_inspect_log() {
2803 let exec = fasync::TestExecutor::new_with_fake_time();
2804 let mut test_values = InspectTestValues::new(exec);
2805 let hierarchy = test_values.log_status(Status::Started {
2806 band: types::OperatingBand::Any,
2807 channel: 1,
2808 mode: types::ConnectivityMode::Unrestricted,
2809 num_clients: 2,
2810 security_type: types::SecurityType::None,
2811 });
2812 diagnostics_assertions::assert_data_tree!(
2813 @executor test_values.exec,
2814 hierarchy,
2815 root: contains {
2816 node: contains {
2817 "0": contains {
2818 status: contains {
2819 Started: {
2820 band: "Any",
2821 channel: 1_u64,
2822 mode: "Unrestricted",
2823 num_clients: 2_u64,
2824 security_type: "None"
2825 }
2826 }
2827 }
2828 }
2829 });
2830 }
2831}