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 update: fidl_sme::Ap,
217 ) -> Result<(), anyhow::Error> {
218 let mut inner = self.inner.lock();
219
220 if let Some(ref mut state) = inner.state {
221 let channel = Channel::new(update.channel, cbw);
222 let frequency = match channel.get_center_freq() {
223 Ok(frequency) => Some(frequency as u32),
224 Err(e) => {
225 info!("failed to convert channel to frequency: {}", e);
226 None
227 }
228 };
229
230 let client_info = Some(ConnectedClientInformation { count: update.num_clients as u8 });
231
232 if frequency != state.frequency || client_info != state.clients {
233 state.frequency = frequency;
234 state.clients = client_info;
235 inner.send_update()?;
236 }
237 }
238
239 Ok(())
240 }
241
242 fn update_operating_state(
243 &self,
244 new_state: types::OperatingState,
245 ) -> Result<(), anyhow::Error> {
246 let mut inner = self.inner.lock();
247
248 if let Some(ref mut state) = inner.state {
250 if state.state != new_state {
251 state.state = new_state;
252 }
253 inner.send_update()?;
254 }
255
256 Ok(())
257 }
258
259 fn set_stopped_state(&self) -> Result<(), anyhow::Error> {
260 let mut inner = self.inner.lock();
261 inner.state = None;
262 inner.send_update()
263 }
264}
265
266struct CommonStateDependencies {
267 iface_id: u16,
268 proxy: SmeForApStateMachine,
269 req_stream: ReqStream,
270 state_tracker: Arc<ApStateTracker>,
271 telemetry_sender: TelemetrySender,
272 defect_sender: mpsc::Sender<Defect>,
273 status_publisher: StateMachineStatusPublisher<Status>,
274}
275
276pub async fn serve(
277 iface_id: u16,
278 proxy: SmeForApStateMachine,
279 sme_event_stream: fidl_sme::ApSmeEventStream,
280 req_stream: Fuse<mpsc::Receiver<ManualRequest>>,
281 message_sender: ApListenerMessageSender,
282 telemetry_sender: TelemetrySender,
283 defect_sender: mpsc::Sender<Defect>,
284 status_publisher: StateMachineStatusPublisher<Status>,
285) {
286 let state_tracker = Arc::new(ApStateTracker::new(message_sender));
287 let deps = CommonStateDependencies {
288 iface_id,
289 proxy,
290 req_stream,
291 state_tracker: state_tracker.clone(),
292 telemetry_sender,
293 defect_sender,
294 status_publisher: status_publisher.clone(),
295 };
296 let state_machine = stopped_state(deps).into_state_machine();
297 let removal_watcher = sme_event_stream.map_ok(|_| ()).try_collect::<()>();
298 select! {
299 state_machine = state_machine.fuse() => {
300 match state_machine {
301 Err(ExitReason(Ok(()))) => info!("AP state machine for iface #{} exited", iface_id),
302 Err(ExitReason(Err(e))) => {
303 info!("AP state machine for iface #{} terminated with an error: {}", iface_id, e)
304 }
305 }
306 },
307 removal_watcher = removal_watcher.fuse() => {
308 match removal_watcher {
309 Ok(()) => info!("AP interface was unexpectedly removed: {}", iface_id),
310 Err(e) => {
311 info!("Error reading from AP SME channel of iface #{}: {}", iface_id, e);
312 }
313 }
314 let _ = state_tracker.update_operating_state(types::OperatingState::Failed);
315 }
316 }
317
318 status_publisher.publish_status(Status::Stopped);
319}
320
321fn perform_manual_request(
322 deps: CommonStateDependencies,
323 req: Option<ManualRequest>,
324) -> Result<State, ExitReason> {
325 match req {
326 Some(ManualRequest::Start((req, responder))) => {
327 Ok(starting_state(deps, req, AP_START_MAX_RETRIES, Some(responder)).into_state())
328 }
329 Some(ManualRequest::Stop(responder)) => Ok(stopping_state(deps, responder).into_state()),
330 Some(ManualRequest::Exit(responder)) => {
331 responder.send(()).unwrap_or(());
332 Err(ExitReason(Ok(())))
333 }
334 None => {
335 deps.state_tracker
339 .update_operating_state(types::OperatingState::Failed)
340 .map_err(|e| ExitReason(Err(e)))?;
341
342 Err(ExitReason(Err(format_err!("The stream of user requests ended unexpectedly"))))
343 }
344 }
345}
346
347fn transition_to_starting(
349 deps: CommonStateDependencies,
350 req: ApConfig,
351 remaining_retries: u16,
352 responder: Option<oneshot::Sender<()>>,
353) -> Result<State, ExitReason> {
354 Ok(starting_state(deps, req, remaining_retries, responder).into_state())
355}
356
357async fn starting_state(
378 mut deps: CommonStateDependencies,
379 req: ApConfig,
380 remaining_retries: u16,
381 responder: Option<oneshot::Sender<()>>,
382) -> Result<State, ExitReason> {
383 deps.status_publisher.publish_status(Status::Starting);
384
385 let stop_result = match deps.proxy.stop().await {
387 Ok(fidl_sme::StopApResultCode::Success) => Ok(()),
388 Ok(code) => Err(format_err!("Unexpected StopApResultCode: {:?}", code)),
389 Err(e) => Err(format_err!("Failed to send a stop command to wlanstack: {}", e)),
390 };
391
392 if stop_result.is_err() {
394 deps.state_tracker
395 .reset_state(ApStateUpdate::new(
396 req.id.clone(),
397 types::OperatingState::Failed,
398 req.mode,
399 req.band,
400 ))
401 .map_err(|e| ExitReason(Err(e)))?;
402
403 stop_result.map_err(|e| ExitReason(Err(e)))?;
404 }
405
406 deps.state_tracker.set_stopped_state().map_err(|e| ExitReason(Err(e)))?;
408
409 if remaining_retries == AP_START_MAX_RETRIES {
411 deps.state_tracker
412 .reset_state(ApStateUpdate::new(
413 req.id.clone(),
414 types::OperatingState::Starting,
415 req.mode,
416 req.band,
417 ))
418 .map_err(|e| ExitReason(Err(e)))?;
419 }
420
421 let ap_config = fidl_sme::ApConfig::from(req.clone());
422 let start_result = match deps.proxy.start(&ap_config).await {
423 Ok(fidl_sme::StartApResultCode::Success) => {
424 deps.telemetry_sender.send(TelemetryEvent::StartApResult(Ok(())));
425 Ok(())
426 }
427 Ok(code) => {
428 deps.telemetry_sender.send(TelemetryEvent::StartApResult(Err(())));
430 if let Err(e) = deps
431 .defect_sender
432 .try_send(Defect::Iface(IfaceFailure::ApStartFailure { iface_id: deps.iface_id }))
433 {
434 warn!("Failed to log AP start defect: {}", e)
435 }
436
437 if remaining_retries > 0 {
442 let mut retry_timer = pin!(fasync::Timer::new(
443 zx::MonotonicDuration::from_seconds(AP_START_RETRY_INTERVAL).after_now(),
444 ));
445
446 select! {
449 () = retry_timer => {
450 return transition_to_starting(
451 deps,
452 req,
453 remaining_retries - 1,
454 responder,
455 );
456 },
457 req = deps.req_stream.next() => {
458 deps.state_tracker
460 .set_stopped_state()
461 .map_err(|e| ExitReason(Err(e)))?;
462 return perform_manual_request(deps, req)
463 }
464 }
465 }
466
467 Err(format_err!("Failed to start AP: {:?}", code))
469 }
470 Err(e) => {
471 Err(format_err!("Failed to send a start command to wlanstack: {}", e))
474 }
475 };
476
477 start_result.map_err(|e| {
478 if let Err(e) = deps.state_tracker.reset_state(ApStateUpdate::new(
480 req.id.clone(),
481 types::OperatingState::Failed,
482 req.mode,
483 req.band,
484 )) {
485 info!("Unable to notify listeners of AP start failure: {:?}", e);
486 }
487 ExitReason(Err(e))
488 })?;
489
490 #[allow(clippy::single_match, reason = "mass allow for https://fxbug.dev/381896734")]
491 match responder {
492 Some(responder) => responder.send(()).unwrap_or(()),
493 None => {}
494 }
495
496 deps.state_tracker
497 .update_operating_state(types::OperatingState::Active)
498 .map_err(|e| ExitReason(Err(e)))?;
499 Ok(started_state(deps, req).into_state())
500}
501
502async fn stopping_state(
514 deps: CommonStateDependencies,
515 responder: oneshot::Sender<()>,
516) -> Result<State, ExitReason> {
517 deps.status_publisher.publish_status(Status::Stopping);
518
519 let result = match deps.proxy.stop().await {
520 Ok(fidl_sme::StopApResultCode::Success) => Ok(()),
521 Ok(code) => Err(format_err!("Unexpected StopApResultCode: {:?}", code)),
522 Err(e) => Err(format_err!("Failed to send a stop command to wlanstack: {}", e)),
523 };
524
525 deps.state_tracker.set_stopped_state().map_err(|e| ExitReason(Err(e)))?;
529 result.map_err(|e| ExitReason(Err(e)))?;
530
531 responder.send(()).unwrap_or(());
533
534 Ok(stopped_state(deps).into_state())
535}
536
537async fn stopped_state(mut deps: CommonStateDependencies) -> Result<State, ExitReason> {
538 deps.status_publisher.publish_status(Status::Stopped);
539
540 loop {
542 let req = deps.req_stream.next().await;
543 match req {
544 Some(ManualRequest::Stop(responder)) => {
546 responder.send(()).unwrap_or(());
547 }
548 other => return perform_manual_request(deps, other),
550 }
551 }
552}
553
554async fn started_state(
555 mut deps: CommonStateDependencies,
556 req: ApConfig,
557) -> Result<State, ExitReason> {
558 deps.status_publisher.publish_status(Status::started_from_config(&req));
559
560 let mut pending_status_req = FuturesUnordered::new();
562 let status_proxy = deps.proxy.clone();
563 pending_status_req.push(async move { status_proxy.status().await }.boxed());
564
565 let mut status_timer =
566 fasync::Interval::new(zx::MonotonicDuration::from_seconds(AP_STATUS_INTERVAL_SEC));
567
568 let cbw = req.radio_config.channel.cbw;
570
571 loop {
572 select! {
573 status_response = pending_status_req.select_next_some() => {
574 let status_response = match status_response {
575 Ok(status_response) => status_response,
576 Err(e) => {
577 deps.state_tracker.update_operating_state(types::OperatingState::Failed)
580 .map_err(|e| { ExitReason(Err(e)) })?;
581
582 return Err(ExitReason(Err(e)));
583 }
584 };
585
586 match status_response.running_ap {
587 Some(sme_state) => {
588 deps.status_publisher
589 .publish_status(Status::started_from_sme_update(&sme_state, &req));
590 deps.state_tracker.consume_sme_status_update(cbw, *sme_state)
591 .map_err(|e| { ExitReason(Err(e)) })?;
592 }
593 None => {
594 deps.state_tracker.update_operating_state(types::OperatingState::Failed)
595 .map_err(|e| { ExitReason(Err(e)) })?;
596
597 return transition_to_starting(
598 deps,
599 req,
600 AP_START_MAX_RETRIES,
601 None,
602 );
603 }
604 }
605 },
606 _ = status_timer.select_next_some() => {
607 if pending_status_req.is_empty() {
608 let status_proxy = deps.proxy.clone();
609 pending_status_req.push(async move {
610 status_proxy.status().await
611 }.boxed());
612 }
613 },
614 manual_req = deps.req_stream.next() => {
615 return perform_manual_request(deps, manual_req)
616 },
617 complete => {
618 panic!("AP state machine terminated unexpectedly");
619 }
620 }
621 }
622}
623
624#[cfg(test)]
625mod tests {
626 use super::*;
627 use crate::util::listener;
628 use crate::util::state_machine::{StateMachineStatusReader, status_publisher_and_reader};
629 use assert_matches::assert_matches;
630 use fidl::endpoints::create_proxy;
631 use futures::Future;
632 use futures::stream::StreamFuture;
633 use futures::task::Poll;
634 use std::pin::pin;
635
636 struct TestValues {
637 deps: CommonStateDependencies,
638 sme_req_stream: fidl_sme::ApSmeRequestStream,
639 ap_req_sender: mpsc::Sender<ManualRequest>,
640 update_receiver: mpsc::UnboundedReceiver<listener::ApMessage>,
641 telemetry_receiver: mpsc::Receiver<TelemetryEvent>,
642 defect_receiver: mpsc::Receiver<Defect>,
643 status_reader: StateMachineStatusReader<Status>,
644 }
645
646 fn test_setup() -> TestValues {
647 let (ap_req_sender, ap_req_stream) = mpsc::channel(1);
648 let (update_sender, update_receiver) = mpsc::unbounded();
649 let (telemetry_sender, telemetry_receiver) = mpsc::channel(100);
650 let telemetry_sender = TelemetrySender::new(telemetry_sender);
651 let (defect_sender, defect_receiver) = mpsc::channel(100);
652 let (status_publisher, status_reader) = status_publisher_and_reader::<Status>();
653 let (sme_proxy, sme_server) = create_proxy::<fidl_sme::ApSmeMarker>();
654 let sme_req_stream = sme_server.into_stream();
655 let sme_proxy = SmeForApStateMachine::new(sme_proxy, 123, defect_sender.clone());
656
657 let deps = CommonStateDependencies {
658 iface_id: 123,
659 proxy: sme_proxy,
660 req_stream: ap_req_stream.fuse(),
661 state_tracker: Arc::new(ApStateTracker::new(update_sender)),
662 telemetry_sender,
663 defect_sender,
664 status_publisher,
665 };
666
667 TestValues {
668 deps,
669 sme_req_stream,
670 ap_req_sender,
671 update_receiver,
672 telemetry_receiver,
673 defect_receiver,
674 status_reader,
675 }
676 }
677
678 fn create_network_id() -> types::NetworkIdentifier {
679 types::NetworkIdentifier {
680 ssid: types::Ssid::try_from("test_ssid").unwrap(),
681 security_type: types::SecurityType::None,
682 }
683 }
684
685 fn poll_sme_req(
686 exec: &mut fasync::TestExecutor,
687 next_sme_req: &mut StreamFuture<fidl_sme::ApSmeRequestStream>,
688 ) -> Poll<fidl_sme::ApSmeRequest> {
689 exec.run_until_stalled(next_sme_req).map(|(req, stream)| {
690 *next_sme_req = stream.into_future();
691 req.expect("did not expect the SME request stream to end")
692 .expect("error polling SME request stream")
693 })
694 }
695
696 #[allow(clippy::needless_return, reason = "mass allow for https://fxbug.dev/381896734")]
697 async fn run_state_machine(fut: impl Future<Output = Result<State, ExitReason>> + 'static) {
698 let state_machine = fut.into_state_machine();
699 select! {
700 _state_machine = state_machine.fuse() => return,
701 }
702 }
703
704 #[fuchsia::test]
705 fn test_stop_during_started() {
706 let mut exec = fasync::TestExecutor::new();
707 let test_values = test_setup();
708
709 let radio_config =
710 RadioConfig::new(fidl_fuchsia_wlan_ieee80211::WlanPhyType::Ht, Cbw::Cbw20, 6);
711 let req = ApConfig {
712 id: create_network_id(),
713 credential: vec![],
714 radio_config,
715 mode: types::ConnectivityMode::Unrestricted,
716 band: types::OperatingBand::Any,
717 };
718 {
719 let state = ApStateUpdate::new(
720 create_network_id(),
721 types::OperatingState::Starting,
722 types::ConnectivityMode::Unrestricted,
723 types::OperatingBand::Any,
724 );
725 test_values.deps.state_tracker.inner.lock().state = Some(state);
726 }
727
728 let fut = started_state(test_values.deps, req);
730 let fut = run_state_machine(fut);
731 let mut fut = pin!(fut);
732
733 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
734
735 let sme_fut = test_values.sme_req_stream.into_future();
736 let mut sme_fut = pin!(sme_fut);
737
738 assert_matches!(
739 poll_sme_req(&mut exec, &mut sme_fut),
740 Poll::Ready(fidl_sme::ApSmeRequest::Status{ responder }) => {
741 let ap_info = fidl_sme::Ap { ssid: vec![], channel: 0, num_clients: 0 };
742 let response = fidl_sme::ApStatusResponse {
743 running_ap: Some(Box::new(ap_info))
744 };
745 responder.send(&response).expect("could not send AP status response");
746 }
747 );
748
749 let mut ap = AccessPoint::new(test_values.ap_req_sender);
751 let (sender, mut receiver) = oneshot::channel();
752 ap.stop(sender).expect("failed to make stop request");
753
754 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
756 assert_matches!(
757 poll_sme_req(&mut exec, &mut sme_fut),
758 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
759 responder.send(fidl_sme::StopApResultCode::Success).expect("could not send SME stop response");
760 }
761 );
762
763 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
765 assert_matches!(exec.run_until_stalled(&mut receiver), Poll::Ready(Ok(())));
766 }
767
768 #[fuchsia::test]
769 fn test_exit_during_started() {
770 let mut exec = fasync::TestExecutor::new();
771 let test_values = test_setup();
772
773 let radio_config =
774 RadioConfig::new(fidl_fuchsia_wlan_ieee80211::WlanPhyType::Ht, Cbw::Cbw20, 6);
775 let req = ApConfig {
776 id: create_network_id(),
777 credential: vec![],
778 radio_config,
779 mode: types::ConnectivityMode::Unrestricted,
780 band: types::OperatingBand::Any,
781 };
782 {
783 let state = ApStateUpdate::new(
784 create_network_id(),
785 types::OperatingState::Starting,
786 types::ConnectivityMode::Unrestricted,
787 types::OperatingBand::Any,
788 );
789 test_values.deps.state_tracker.inner.lock().state = Some(state);
790 }
791
792 let fut = started_state(test_values.deps, req);
794 let fut = run_state_machine(fut);
795 let mut fut = pin!(fut);
796
797 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
798
799 let sme_fut = test_values.sme_req_stream.into_future();
800 let mut sme_fut = pin!(sme_fut);
801
802 assert_matches!(
803 poll_sme_req(&mut exec, &mut sme_fut),
804 Poll::Ready(fidl_sme::ApSmeRequest::Status{ responder }) => {
805 let ap_info = fidl_sme::Ap { ssid: vec![], channel: 0, num_clients: 0 };
806 let response = fidl_sme::ApStatusResponse {
807 running_ap: Some(Box::new(ap_info))
808 };
809 responder.send(&response).expect("could not send AP status response");
810 }
811 );
812
813 let mut ap = AccessPoint::new(test_values.ap_req_sender);
815 let (sender, mut receiver) = oneshot::channel();
816 ap.exit(sender).expect("failed to make stop request");
817
818 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
820 assert_matches!(exec.run_until_stalled(&mut receiver), Poll::Ready(Ok(())));
821 }
822
823 #[fuchsia::test]
824 fn test_start_during_started() {
825 let mut exec = fasync::TestExecutor::new();
826 let test_values = test_setup();
827
828 let radio_config =
829 RadioConfig::new(fidl_fuchsia_wlan_ieee80211::WlanPhyType::Ht, Cbw::Cbw20, 6);
830 let req = ApConfig {
831 id: create_network_id(),
832 credential: vec![],
833 radio_config,
834 mode: types::ConnectivityMode::Unrestricted,
835 band: types::OperatingBand::Any,
836 };
837 {
838 let state = ApStateUpdate::new(
839 create_network_id(),
840 types::OperatingState::Starting,
841 types::ConnectivityMode::Unrestricted,
842 types::OperatingBand::Any,
843 );
844 test_values.deps.state_tracker.inner.lock().state = Some(state);
845 }
846
847 let fut = started_state(test_values.deps, req);
849 let fut = run_state_machine(fut);
850 let mut fut = pin!(fut);
851
852 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
853
854 let sme_fut = test_values.sme_req_stream.into_future();
855 let mut sme_fut = pin!(sme_fut);
856
857 assert_matches!(
858 poll_sme_req(&mut exec, &mut sme_fut),
859 Poll::Ready(fidl_sme::ApSmeRequest::Status{ responder }) => {
860 let ap_info = fidl_sme::Ap { ssid: vec![], channel: 0, num_clients: 0 };
861 let response = fidl_sme::ApStatusResponse {
862 running_ap: Some(Box::new(ap_info))
863 };
864 responder.send(&response).expect("could not send AP status response");
865 }
866 );
867
868 let mut ap = AccessPoint::new(test_values.ap_req_sender);
870 let (sender, mut receiver) = oneshot::channel();
871 let radio_config =
872 RadioConfig::new(fidl_fuchsia_wlan_ieee80211::WlanPhyType::Ht, Cbw::Cbw20, 6);
873 let req = ApConfig {
874 id: create_network_id(),
875 credential: vec![],
876 radio_config,
877 mode: types::ConnectivityMode::Unrestricted,
878 band: types::OperatingBand::Any,
879 };
880 ap.start(req, sender).expect("failed to make stop request");
881
882 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
884 assert_matches!(
885 poll_sme_req(&mut exec, &mut sme_fut),
886 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
887 responder.send(fidl_sme::StopApResultCode::Success).expect("could not send AP stop response");
888 }
889 );
890
891 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
892 assert_matches!(
893 poll_sme_req(&mut exec, &mut sme_fut),
894 Poll::Ready(fidl_sme::ApSmeRequest::Start{ config: _, responder }) => {
895 responder
896 .send(fidl_sme::StartApResultCode::Success)
897 .expect("could not send AP stop response");
898 }
899 );
900
901 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
903 assert_matches!(exec.run_until_stalled(&mut receiver), Poll::Ready(Ok(())));
904 }
905
906 #[fuchsia::test]
907 fn test_duplicate_status_during_started() {
908 let mut exec = fasync::TestExecutor::new();
909 let test_values = test_setup();
910
911 let radio_config =
912 RadioConfig::new(fidl_fuchsia_wlan_ieee80211::WlanPhyType::Ht, Cbw::Cbw20, 6);
913 let req = ApConfig {
914 id: create_network_id(),
915 credential: vec![],
916 radio_config,
917 mode: types::ConnectivityMode::Unrestricted,
918 band: types::OperatingBand::Any,
919 };
920 {
921 let mut state = ApStateUpdate::new(
922 create_network_id(),
923 types::OperatingState::Starting,
924 types::ConnectivityMode::Unrestricted,
925 types::OperatingBand::Any,
926 );
927 state.frequency = Some(2437);
928 state.clients = Some(ConnectedClientInformation { count: 0 });
929 test_values.deps.state_tracker.inner.lock().state = Some(state);
930 }
931
932 let fut = started_state(test_values.deps, req);
934 let fut = run_state_machine(fut);
935 let mut fut = pin!(fut);
936
937 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
938
939 let sme_fut = test_values.sme_req_stream.into_future();
940 let mut sme_fut = pin!(sme_fut);
941
942 assert_matches!(
943 poll_sme_req(&mut exec, &mut sme_fut),
944 Poll::Ready(fidl_sme::ApSmeRequest::Status{ responder }) => {
945 let ap_info = fidl_sme::Ap { ssid: vec![], channel: 6, num_clients: 0 };
946 let response = fidl_sme::ApStatusResponse {
947 running_ap: Some(Box::new(ap_info))
948 };
949 responder.send(&response).expect("could not send AP status response");
950 }
951 );
952
953 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
955 assert_matches!(
956 exec.run_until_stalled(&mut test_values.update_receiver.into_future()),
957 Poll::Pending
958 );
959 }
960
961 #[fuchsia::test]
962 fn test_new_status_during_started() {
963 let mut exec = fasync::TestExecutor::new();
964 let test_values = test_setup();
965
966 let radio_config =
967 RadioConfig::new(fidl_fuchsia_wlan_ieee80211::WlanPhyType::Ht, Cbw::Cbw20, 6);
968 let req = ApConfig {
969 id: create_network_id(),
970 credential: vec![],
971 radio_config,
972 mode: types::ConnectivityMode::Unrestricted,
973 band: types::OperatingBand::Any,
974 };
975 {
976 let mut state = ApStateUpdate::new(
977 create_network_id(),
978 types::OperatingState::Starting,
979 types::ConnectivityMode::Unrestricted,
980 types::OperatingBand::Any,
981 );
982 state.frequency = Some(0);
983 state.clients = Some(ConnectedClientInformation { count: 0 });
984 test_values.deps.state_tracker.inner.lock().state = Some(state);
985 }
986
987 let fut = started_state(test_values.deps, req);
989 let fut = run_state_machine(fut);
990 let mut fut = pin!(fut);
991
992 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
993
994 assert_matches!(
996 test_values.status_reader.read_status(),
997 Ok(Status::Started {
998 band: types::OperatingBand::Any,
999 channel: 6,
1000 mode: types::ConnectivityMode::Unrestricted,
1001 num_clients: 0,
1002 security_type: types::SecurityType::None,
1003 })
1004 );
1005
1006 let sme_fut = test_values.sme_req_stream.into_future();
1008 let mut sme_fut = pin!(sme_fut);
1009
1010 assert_matches!(
1011 poll_sme_req(&mut exec, &mut sme_fut),
1012 Poll::Ready(fidl_sme::ApSmeRequest::Status{ responder }) => {
1013 let ap_info = fidl_sme::Ap { ssid: vec![], channel: 1, num_clients: 1 };
1014 let response = fidl_sme::ApStatusResponse {
1015 running_ap: Some(Box::new(ap_info))
1016 };
1017 responder.send(&response).expect("could not send AP status response");
1018 }
1019 );
1020
1021 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1023 assert_matches!(
1024 exec.run_until_stalled(&mut test_values.update_receiver.into_future()),
1025 Poll::Ready((Some(listener::Message::NotifyListeners(updates)), _)) => {
1026 assert!(!updates.access_points.is_empty());
1027 });
1028
1029 assert_matches!(
1031 test_values.status_reader.read_status(),
1032 Ok(Status::Started {
1033 band: types::OperatingBand::Any,
1034 channel: 1,
1035 mode: types::ConnectivityMode::Unrestricted,
1036 num_clients: 1,
1037 security_type: types::SecurityType::None,
1038 })
1039 );
1040 }
1041
1042 #[fuchsia::test]
1043 fn test_sme_failure_during_started() {
1044 let mut exec = fasync::TestExecutor::new();
1045 let mut test_values = test_setup();
1046
1047 drop(test_values.sme_req_stream);
1049
1050 let radio_config =
1051 RadioConfig::new(fidl_fuchsia_wlan_ieee80211::WlanPhyType::Ht, Cbw::Cbw20, 6);
1052 let req = ApConfig {
1053 id: create_network_id(),
1054 credential: vec![],
1055 radio_config,
1056 mode: types::ConnectivityMode::Unrestricted,
1057 band: types::OperatingBand::Any,
1058 };
1059 {
1060 let mut state = ApStateUpdate::new(
1061 create_network_id(),
1062 types::OperatingState::Starting,
1063 types::ConnectivityMode::Unrestricted,
1064 types::OperatingBand::Any,
1065 );
1066 state.frequency = Some(0);
1067 state.clients = Some(ConnectedClientInformation { count: 0 });
1068 test_values.deps.state_tracker.inner.lock().state = Some(state);
1069 }
1070
1071 let fut = started_state(test_values.deps, req);
1073 let fut = run_state_machine(fut);
1074 let mut fut = pin!(fut);
1075
1076 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
1078
1079 assert_matches!(
1081 test_values.update_receiver.try_next(),
1082 Ok(Some(listener::Message::NotifyListeners(mut updates))) => {
1083 let update = updates.access_points.pop().expect("no new updates available.");
1084 assert_eq!(update.state, types::OperatingState::Failed);
1085 });
1086 }
1087
1088 #[fuchsia::test]
1089 fn test_stop_while_stopped() {
1090 let mut exec = fasync::TestExecutor::new();
1091 let test_values = test_setup();
1092
1093 let fut = stopped_state(test_values.deps);
1095 let fut = run_state_machine(fut);
1096 let mut fut = pin!(fut);
1097
1098 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1099
1100 let mut ap = AccessPoint::new(test_values.ap_req_sender);
1102 let (sender, mut receiver) = oneshot::channel();
1103 ap.stop(sender).expect("failed to make stop request");
1104
1105 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1107 assert_matches!(exec.run_until_stalled(&mut receiver), Poll::Ready(Ok(())));
1108 }
1109
1110 #[fuchsia::test]
1111 fn test_exit_while_stopped() {
1112 let mut exec = fasync::TestExecutor::new();
1113 let test_values = test_setup();
1114
1115 let fut = stopped_state(test_values.deps);
1117 let fut = run_state_machine(fut);
1118 let mut fut = pin!(fut);
1119
1120 let mut ap = AccessPoint::new(test_values.ap_req_sender);
1122 let (sender, mut receiver) = oneshot::channel();
1123 ap.exit(sender).expect("failed to make stop request");
1124
1125 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
1127 assert_matches!(exec.run_until_stalled(&mut receiver), Poll::Ready(Ok(())));
1128 }
1129
1130 #[fuchsia::test]
1131 fn test_start_while_stopped() {
1132 let mut exec = fasync::TestExecutor::new();
1133 let mut test_values = test_setup();
1134
1135 let fut = stopped_state(test_values.deps);
1137 let fut = run_state_machine(fut);
1138 let mut fut = pin!(fut);
1139
1140 let (sender, mut receiver) = oneshot::channel();
1142 let radio_config =
1143 RadioConfig::new(fidl_fuchsia_wlan_ieee80211::WlanPhyType::Ht, Cbw::Cbw20, 6);
1144 let req = ApConfig {
1145 id: create_network_id(),
1146 credential: vec![],
1147 radio_config,
1148 mode: types::ConnectivityMode::Unrestricted,
1149 band: types::OperatingBand::Any,
1150 };
1151
1152 let mut ap = AccessPoint::new(test_values.ap_req_sender);
1153 ap.start(req, sender).expect("failed to make stop request");
1154
1155 let sme_fut = test_values.sme_req_stream.into_future();
1157 let mut sme_fut = pin!(sme_fut);
1158
1159 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1160 assert_matches!(
1161 poll_sme_req(&mut exec, &mut sme_fut),
1162 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
1163 responder.send(fidl_sme::StopApResultCode::Success).expect("could not send AP stop response");
1164 }
1165 );
1166
1167 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1169 assert_matches!(
1170 test_values.update_receiver.try_next(),
1171 Ok(Some(listener::Message::NotifyListeners(updates))) => {
1172 assert!(updates.access_points.is_empty());
1173 });
1174
1175 assert_matches!(
1177 test_values.update_receiver.try_next(),
1178 Ok(Some(listener::Message::NotifyListeners(mut updates))) => {
1179 let update = updates.access_points.pop().expect("no new updates available.");
1180 assert_eq!(update.state, types::OperatingState::Starting);
1181 });
1182
1183 assert_matches!(
1185 poll_sme_req(&mut exec, &mut sme_fut),
1186 Poll::Ready(fidl_sme::ApSmeRequest::Start{ config: _, responder }) => {
1187 responder
1188 .send(fidl_sme::StartApResultCode::Success)
1189 .expect("could not send AP stop response");
1190 }
1191 );
1192
1193 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1195 assert_matches!(exec.run_until_stalled(&mut receiver), Poll::Ready(Ok(())));
1196
1197 assert_matches!(
1199 test_values.update_receiver.try_next(),
1200 Ok(Some(listener::Message::NotifyListeners(mut updates))) => {
1201 let update = updates.access_points.pop().expect("no new updates available.");
1202 assert_eq!(update.state, types::OperatingState::Active);
1203 });
1204 }
1205
1206 #[fuchsia::test]
1207 fn test_exit_while_stopping() {
1208 let mut exec = fasync::TestExecutor::new();
1209 let test_values = test_setup();
1210
1211 let (stop_sender, mut stop_receiver) = oneshot::channel();
1213 let fut = stopping_state(test_values.deps, stop_sender);
1214 let fut = run_state_machine(fut);
1215 let mut fut = pin!(fut);
1216
1217 let mut ap = AccessPoint::new(test_values.ap_req_sender);
1219 let (exit_sender, mut exit_receiver) = oneshot::channel();
1220 ap.exit(exit_sender).expect("failed to make stop request");
1221
1222 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1224 assert_matches!(exec.run_until_stalled(&mut stop_receiver), Poll::Pending);
1225 assert_matches!(exec.run_until_stalled(&mut exit_receiver), Poll::Pending);
1226
1227 let sme_fut = test_values.sme_req_stream.into_future();
1229 let mut sme_fut = pin!(sme_fut);
1230 assert_matches!(
1231 poll_sme_req(&mut exec, &mut sme_fut),
1232 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
1233 responder.send(fidl_sme::StopApResultCode::Success).expect("could not send AP stop response");
1234 }
1235 );
1236 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
1237 assert_matches!(exec.run_until_stalled(&mut stop_receiver), Poll::Ready(Ok(())));
1238 assert_matches!(exec.run_until_stalled(&mut exit_receiver), Poll::Ready(Ok(())));
1239 }
1240
1241 #[fuchsia::test]
1242 fn test_stop_while_stopping() {
1243 let mut exec = fasync::TestExecutor::new();
1244 let mut test_values = test_setup();
1245
1246 let (stop_sender, mut stop_receiver) = oneshot::channel();
1248 let fut = stopping_state(test_values.deps, stop_sender);
1249 let fut = run_state_machine(fut);
1250 let mut fut = pin!(fut);
1251
1252 assert_matches!(&mut test_values.update_receiver.try_next(), Err(_));
1254
1255 let mut ap = AccessPoint::new(test_values.ap_req_sender);
1257 let (second_stop_sender, mut second_stop_receiver) = oneshot::channel();
1258 ap.stop(second_stop_sender).expect("failed to make stop request");
1259
1260 let sme_fut = test_values.sme_req_stream.into_future();
1262 let mut sme_fut = pin!(sme_fut);
1263
1264 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1265 assert_matches!(
1266 poll_sme_req(&mut exec, &mut sme_fut),
1267 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
1268 responder.send(fidl_sme::StopApResultCode::Success).expect("could not send AP stop response");
1269 }
1270 );
1271
1272 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1274 assert_matches!(exec.run_until_stalled(&mut stop_receiver), Poll::Ready(Ok(())));
1275 assert_matches!(exec.run_until_stalled(&mut second_stop_receiver), Poll::Ready(Ok(())));
1276
1277 assert_matches!(
1279 test_values.update_receiver.try_next(),
1280 Ok(Some(listener::Message::NotifyListeners(updates))) => {
1281 assert!(updates.access_points.is_empty());
1282 });
1283 }
1284
1285 #[fuchsia::test]
1286 fn test_start_while_stopping() {
1287 let mut exec = fasync::TestExecutor::new();
1288 let test_values = test_setup();
1289
1290 let (stop_sender, mut stop_receiver) = oneshot::channel();
1292 let fut = stopping_state(test_values.deps, stop_sender);
1293 let fut = run_state_machine(fut);
1294 let mut fut = pin!(fut);
1295
1296 let (start_sender, mut start_receiver) = oneshot::channel();
1298 let radio_config =
1299 RadioConfig::new(fidl_fuchsia_wlan_ieee80211::WlanPhyType::Ht, Cbw::Cbw20, 6);
1300 let req = ApConfig {
1301 id: create_network_id(),
1302 credential: vec![],
1303 radio_config,
1304 mode: types::ConnectivityMode::Unrestricted,
1305 band: types::OperatingBand::Any,
1306 };
1307
1308 let mut ap = AccessPoint::new(test_values.ap_req_sender);
1309 ap.start(req, start_sender).expect("failed to make stop request");
1310
1311 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1313 assert_matches!(exec.run_until_stalled(&mut stop_receiver), Poll::Pending);
1314 let sme_fut = test_values.sme_req_stream.into_future();
1315 let mut sme_fut = pin!(sme_fut);
1316 let stop_responder = assert_matches!(
1317 poll_sme_req(&mut exec, &mut sme_fut),
1318 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => responder
1319 );
1320
1321 assert_matches!(poll_sme_req(&mut exec, &mut sme_fut), Poll::Pending);
1323
1324 stop_responder
1326 .send(fidl_sme::StopApResultCode::Success)
1327 .expect("could not send AP stop response");
1328 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1329 assert_matches!(exec.run_until_stalled(&mut stop_receiver), Poll::Ready(Ok(())));
1330
1331 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1333 assert_matches!(
1334 poll_sme_req(&mut exec, &mut sme_fut),
1335 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
1336 responder.send(fidl_sme::StopApResultCode::Success).expect("could not send AP stop response");
1337 }
1338 );
1339
1340 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1342 assert_matches!(
1343 poll_sme_req(&mut exec, &mut sme_fut),
1344 Poll::Ready(fidl_sme::ApSmeRequest::Start{ config: _, responder }) => {
1345 responder
1346 .send(fidl_sme::StartApResultCode::Success)
1347 .expect("could not send AP stop response");
1348 }
1349 );
1350
1351 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1353 assert_matches!(exec.run_until_stalled(&mut start_receiver), Poll::Ready(Ok(())));
1354 }
1355
1356 #[fuchsia::test]
1357 fn test_sme_failure_while_stopping() {
1358 let mut exec = fasync::TestExecutor::new();
1359 let mut test_values = test_setup();
1360
1361 drop(test_values.sme_req_stream);
1363
1364 let (stop_sender, mut stop_receiver) = oneshot::channel();
1366 let fut = stopping_state(test_values.deps, stop_sender);
1367 let fut = run_state_machine(fut);
1368 let mut fut = pin!(fut);
1369
1370 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
1372 assert_matches!(exec.run_until_stalled(&mut stop_receiver), Poll::Ready(Err(_)));
1373
1374 assert_matches!(
1376 test_values.update_receiver.try_next(),
1377 Ok(Some(listener::Message::NotifyListeners(updates))) => {
1378 assert!(updates.access_points.is_empty());
1379 });
1380 }
1381
1382 #[fuchsia::test]
1383 fn test_failed_result_code_while_stopping() {
1384 let mut exec = fasync::TestExecutor::new();
1385 let mut test_values = test_setup();
1386
1387 let (stop_sender, mut stop_receiver) = oneshot::channel();
1389 let fut = stopping_state(test_values.deps, stop_sender);
1390 let fut = run_state_machine(fut);
1391 let mut fut = pin!(fut);
1392
1393 assert_matches!(&mut test_values.update_receiver.try_next(), Err(_));
1395
1396 let sme_fut = test_values.sme_req_stream.into_future();
1398 let mut sme_fut = pin!(sme_fut);
1399
1400 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1401 assert_matches!(
1402 poll_sme_req(&mut exec, &mut sme_fut),
1403 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
1404 responder.send(fidl_sme::StopApResultCode::InternalError).expect("could not send AP stop response");
1405 }
1406 );
1407
1408 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
1410 assert_matches!(exec.run_until_stalled(&mut stop_receiver), Poll::Ready(Err(_)));
1411
1412 assert_matches!(
1414 test_values.update_receiver.try_next(),
1415 Ok(Some(listener::Message::NotifyListeners(updates))) => {
1416 assert!(updates.access_points.is_empty());
1417 });
1418 }
1419
1420 #[fuchsia::test]
1421 fn test_stop_while_starting() {
1422 let mut exec = fasync::TestExecutor::new();
1423 let mut test_values = test_setup();
1424
1425 let (start_sender, mut start_receiver) = oneshot::channel();
1426 let radio_config =
1427 RadioConfig::new(fidl_fuchsia_wlan_ieee80211::WlanPhyType::Ht, Cbw::Cbw20, 6);
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 =
1506 RadioConfig::new(fidl_fuchsia_wlan_ieee80211::WlanPhyType::Ht, Cbw::Cbw20, 6);
1507 let req = ApConfig {
1508 id: create_network_id(),
1509 credential: vec![],
1510 radio_config,
1511 mode: types::ConnectivityMode::Unrestricted,
1512 band: types::OperatingBand::Any,
1513 };
1514
1515 let fut = starting_state(test_values.deps, req, 0, Some(start_sender));
1517 let fut = run_state_machine(fut);
1518 let mut fut = pin!(fut);
1519
1520 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1522
1523 let sme_fut = test_values.sme_req_stream.into_future();
1524 let mut sme_fut = pin!(sme_fut);
1525
1526 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1527 assert_matches!(
1528 poll_sme_req(&mut exec, &mut sme_fut),
1529 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
1530 responder.send(fidl_sme::StopApResultCode::Success).expect("could not send AP stop response");
1531 }
1532 );
1533
1534 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1536 let start_responder = assert_matches!(
1537 poll_sme_req(&mut exec, &mut sme_fut),
1538 Poll::Ready(fidl_sme::ApSmeRequest::Start{ config: _, responder }) => {
1539 responder
1540 }
1541 );
1542
1543 let (second_start_sender, mut second_start_receiver) = oneshot::channel();
1545 let radio_config =
1546 RadioConfig::new(fidl_fuchsia_wlan_ieee80211::WlanPhyType::Ht, Cbw::Cbw20, 6);
1547 let req = ApConfig {
1548 id: create_network_id(),
1549 credential: vec![],
1550 radio_config,
1551 mode: types::ConnectivityMode::Unrestricted,
1552 band: types::OperatingBand::Any,
1553 };
1554 let mut ap = AccessPoint::new(test_values.ap_req_sender);
1555 ap.start(req, second_start_sender).expect("failed to make start request");
1556
1557 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1560 assert_matches!(exec.run_until_stalled(&mut start_receiver), Poll::Pending);
1561 assert_matches!(poll_sme_req(&mut exec, &mut sme_fut), Poll::Pending);
1562
1563 start_responder
1565 .send(fidl_sme::StartApResultCode::Success)
1566 .expect("failed to send start response");
1567
1568 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1570 assert_matches!(exec.run_until_stalled(&mut start_receiver), Poll::Ready(Ok(())));
1571 assert_matches!(exec.run_until_stalled(&mut second_start_receiver), Poll::Pending);
1572
1573 assert_matches!(
1576 poll_sme_req(&mut exec, &mut sme_fut),
1577 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
1578 responder.send(fidl_sme::StopApResultCode::Success).expect("could not send SME stop response");
1579 }
1580 );
1581
1582 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1584 assert_matches!(
1585 poll_sme_req(&mut exec, &mut sme_fut),
1586 Poll::Ready(fidl_sme::ApSmeRequest::Start{ config: _, responder }) => {
1587 responder
1588 .send(fidl_sme::StartApResultCode::Success)
1589 .expect("failed to send start response");
1590 }
1591 );
1592
1593 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1595 assert_matches!(exec.run_until_stalled(&mut second_start_receiver), Poll::Ready(Ok(())));
1596
1597 assert_matches!(
1599 test_values.telemetry_receiver.try_next(),
1600 Ok(Some(TelemetryEvent::StartApResult(Ok(()))))
1601 );
1602 }
1603
1604 #[fuchsia::test]
1605 fn test_exit_while_starting() {
1606 let mut exec = fasync::TestExecutor::new();
1607 let mut test_values = test_setup();
1608
1609 let (start_sender, mut start_receiver) = oneshot::channel();
1610 let radio_config =
1611 RadioConfig::new(fidl_fuchsia_wlan_ieee80211::WlanPhyType::Ht, Cbw::Cbw20, 6);
1612 let req = ApConfig {
1613 id: create_network_id(),
1614 credential: vec![],
1615 radio_config,
1616 mode: types::ConnectivityMode::Unrestricted,
1617 band: types::OperatingBand::Any,
1618 };
1619
1620 let fut = starting_state(test_values.deps, req, 0, Some(start_sender));
1622 let fut = run_state_machine(fut);
1623 let mut fut = pin!(fut);
1624
1625 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1627
1628 let sme_fut = test_values.sme_req_stream.into_future();
1629 let mut sme_fut = pin!(sme_fut);
1630
1631 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1632 assert_matches!(
1633 poll_sme_req(&mut exec, &mut sme_fut),
1634 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
1635 responder.send(fidl_sme::StopApResultCode::Success).expect("could not send AP stop response");
1636 }
1637 );
1638
1639 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1641 let start_responder = assert_matches!(
1642 poll_sme_req(&mut exec, &mut sme_fut),
1643 Poll::Ready(fidl_sme::ApSmeRequest::Start{ config: _, responder }) => {
1644 responder
1645 }
1646 );
1647
1648 let mut ap = AccessPoint::new(test_values.ap_req_sender);
1650 let (exit_sender, mut exit_receiver) = oneshot::channel();
1651 ap.exit(exit_sender).expect("failed to make stop request");
1652
1653 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1655 assert_matches!(exec.run_until_stalled(&mut start_receiver), Poll::Pending);
1656 assert_matches!(exec.run_until_stalled(&mut exit_receiver), Poll::Pending);
1657
1658 start_responder
1660 .send(fidl_sme::StartApResultCode::Success)
1661 .expect("could not send AP start response");
1662
1663 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
1664 assert_matches!(exec.run_until_stalled(&mut exit_receiver), Poll::Ready(Ok(())));
1665 assert_matches!(exec.run_until_stalled(&mut start_receiver), Poll::Ready(Ok(())));
1666
1667 assert_matches!(
1669 test_values.telemetry_receiver.try_next(),
1670 Ok(Some(TelemetryEvent::StartApResult(Ok(()))))
1671 );
1672 }
1673
1674 #[fuchsia::test]
1675 fn test_sme_breaks_while_starting() {
1676 let mut exec = fasync::TestExecutor::new();
1677 let mut test_values = test_setup();
1678
1679 drop(test_values.sme_req_stream);
1681
1682 let (start_sender, _start_receiver) = oneshot::channel();
1683 let radio_config =
1684 RadioConfig::new(fidl_fuchsia_wlan_ieee80211::WlanPhyType::Ht, Cbw::Cbw20, 6);
1685 let req = ApConfig {
1686 id: create_network_id(),
1687 credential: vec![],
1688 radio_config,
1689 mode: types::ConnectivityMode::Unrestricted,
1690 band: types::OperatingBand::Any,
1691 };
1692
1693 let fut = starting_state(test_values.deps, req, 0, Some(start_sender));
1695 let fut = run_state_machine(fut);
1696 let mut fut = pin!(fut);
1697
1698 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
1700
1701 assert_matches!(test_values.telemetry_receiver.try_next(), Ok(None));
1703 }
1704
1705 #[fuchsia::test]
1706 fn test_sme_fails_to_stop_while_starting() {
1707 let mut exec = fasync::TestExecutor::new();
1708 let mut test_values = test_setup();
1709
1710 let (start_sender, _start_receiver) = oneshot::channel();
1711 let radio_config =
1712 RadioConfig::new(fidl_fuchsia_wlan_ieee80211::WlanPhyType::Ht, Cbw::Cbw20, 6);
1713 let req = ApConfig {
1714 id: create_network_id(),
1715 credential: vec![],
1716 radio_config,
1717 mode: types::ConnectivityMode::Unrestricted,
1718 band: types::OperatingBand::Any,
1719 };
1720
1721 let fut = starting_state(test_values.deps, req, 0, Some(start_sender));
1723 let fut = run_state_machine(fut);
1724 let mut fut = pin!(fut);
1725
1726 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1728
1729 let sme_fut = test_values.sme_req_stream.into_future();
1730 let mut sme_fut = pin!(sme_fut);
1731
1732 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1733 assert_matches!(
1734 poll_sme_req(&mut exec, &mut sme_fut),
1735 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
1736 responder
1737 .send(fidl_sme::StopApResultCode::TimedOut)
1738 .expect("could not send AP stop response");
1739 }
1740 );
1741
1742 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
1744
1745 assert_matches!(
1747 test_values.update_receiver.try_next(),
1748 Ok(Some(listener::Message::NotifyListeners(mut updates))) => {
1749 let update = updates.access_points.pop().expect("no new updates available.");
1750 assert_eq!(update.state, types::OperatingState::Failed);
1751 });
1752
1753 assert_matches!(test_values.telemetry_receiver.try_next(), Ok(None));
1755 }
1756
1757 #[fuchsia::test]
1758 fn test_sme_fails_to_start_while_starting() {
1759 let mut exec = fasync::TestExecutor::new();
1760 let mut test_values = test_setup();
1761
1762 let (start_sender, mut start_receiver) = oneshot::channel();
1763 let radio_config =
1764 RadioConfig::new(fidl_fuchsia_wlan_ieee80211::WlanPhyType::Ht, Cbw::Cbw20, 6);
1765 let req = ApConfig {
1766 id: create_network_id(),
1767 credential: vec![],
1768 radio_config,
1769 mode: types::ConnectivityMode::Unrestricted,
1770 band: types::OperatingBand::Any,
1771 };
1772
1773 let fut = starting_state(test_values.deps, req, AP_START_MAX_RETRIES, Some(start_sender));
1775 let fut = run_state_machine(fut);
1776 let mut fut = pin!(fut);
1777
1778 let sme_fut = test_values.sme_req_stream.into_future();
1780 let mut sme_fut = pin!(sme_fut);
1781
1782 for retry_number in 0..(AP_START_MAX_RETRIES + 1) {
1783 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1785 assert_matches!(
1786 poll_sme_req(&mut exec, &mut sme_fut),
1787 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
1788 responder
1789 .send(fidl_sme::StopApResultCode::Success)
1790 .expect("could not send AP stop response");
1791 }
1792 );
1793
1794 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1796 assert_matches!(
1797 test_values.update_receiver.try_next(),
1798 Ok(Some(listener::Message::NotifyListeners(_)))
1799 );
1800
1801 if retry_number == 0 {
1804 assert_matches!(
1805 test_values.update_receiver.try_next(),
1806 Ok(Some(listener::Message::NotifyListeners(mut updates))) => {
1807 let update = updates.access_points.pop().expect("no new updates available.");
1808 assert_eq!(update.state, types::OperatingState::Starting);
1809 });
1810 } else {
1811 assert_matches!(test_values.update_receiver.try_next(), Err(_));
1812 }
1813
1814 assert_matches!(
1816 poll_sme_req(&mut exec, &mut sme_fut),
1817 Poll::Ready(fidl_sme::ApSmeRequest::Start{ config: _, responder }) => {
1818 responder
1819 .send(fidl_sme::StartApResultCode::TimedOut)
1820 .expect("could not send AP stop response");
1821 }
1822 );
1823
1824 if retry_number < AP_START_MAX_RETRIES {
1825 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1827
1828 assert_matches!(exec.run_until_stalled(&mut start_receiver), Poll::Pending);
1830
1831 assert_matches!(exec.wake_next_timer(), Some(_));
1833 }
1834 }
1835
1836 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
1838
1839 assert_matches!(exec.run_until_stalled(&mut start_receiver), Poll::Ready(Err(_)));
1841
1842 assert_matches!(
1844 test_values.update_receiver.try_next(),
1845 Ok(Some(listener::Message::NotifyListeners(mut updates))) => {
1846 let update = updates.access_points.pop().expect("no new updates available.");
1847 assert_eq!(update.state, types::OperatingState::Failed);
1848 });
1849
1850 assert_matches!(
1852 test_values.telemetry_receiver.try_next(),
1853 Ok(Some(TelemetryEvent::StartApResult(Err(()))))
1854 );
1855
1856 assert_matches!(
1858 test_values.defect_receiver.try_next(),
1859 Ok(Some(Defect::Iface(IfaceFailure::ApStartFailure { .. })))
1860 );
1861 }
1862
1863 #[fuchsia::test]
1864 fn test_stop_after_start_failure() {
1865 let mut exec = fasync::TestExecutor::new();
1866 let mut test_values = test_setup();
1867
1868 let (start_sender, mut start_receiver) = oneshot::channel();
1869 let radio_config =
1870 RadioConfig::new(fidl_fuchsia_wlan_ieee80211::WlanPhyType::Ht, Cbw::Cbw20, 6);
1871 let req = ApConfig {
1872 id: create_network_id(),
1873 credential: vec![],
1874 radio_config,
1875 mode: types::ConnectivityMode::Unrestricted,
1876 band: types::OperatingBand::Any,
1877 };
1878
1879 let (stop_sender, mut stop_receiver) = oneshot::channel();
1881 test_values
1882 .ap_req_sender
1883 .try_send(ManualRequest::Stop(stop_sender))
1884 .expect("failed to request AP stop");
1885
1886 let fut = starting_state(test_values.deps, req, AP_START_MAX_RETRIES, Some(start_sender));
1888 let fut = run_state_machine(fut);
1889 let mut fut = pin!(fut);
1890
1891 let sme_fut = test_values.sme_req_stream.into_future();
1893 let mut sme_fut = pin!(sme_fut);
1894
1895 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1897 assert_matches!(
1898 poll_sme_req(&mut exec, &mut sme_fut),
1899 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
1900 responder
1901 .send(fidl_sme::StopApResultCode::Success)
1902 .expect("could not send AP stop response");
1903 }
1904 );
1905
1906 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1908 assert_matches!(
1909 test_values.update_receiver.try_next(),
1910 Ok(Some(listener::Message::NotifyListeners(_)))
1911 );
1912
1913 assert_matches!(
1915 test_values.update_receiver.try_next(),
1916 Ok(Some(listener::Message::NotifyListeners(mut updates))) => {
1917 let update = updates.access_points.pop().expect("no new updates available.");
1918 assert_eq!(update.state, types::OperatingState::Starting);
1919 });
1920
1921 assert_matches!(
1923 poll_sme_req(&mut exec, &mut sme_fut),
1924 Poll::Ready(fidl_sme::ApSmeRequest::Start{ config: _, responder }) => {
1925 responder
1926 .send(fidl_sme::StartApResultCode::TimedOut)
1927 .expect("could not send AP stop response");
1928 }
1929 );
1930
1931 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1935
1936 assert_matches!(
1938 test_values.telemetry_receiver.try_next(),
1939 Ok(Some(TelemetryEvent::StartApResult(Err(()))))
1940 );
1941
1942 assert_matches!(
1944 test_values.defect_receiver.try_next(),
1945 Ok(Some(Defect::Iface(IfaceFailure::ApStartFailure { .. })))
1946 );
1947
1948 assert_matches!(exec.run_until_stalled(&mut start_receiver), Poll::Ready(Err(_)));
1950
1951 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1953 assert_matches!(
1954 poll_sme_req(&mut exec, &mut sme_fut),
1955 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
1956 responder
1957 .send(fidl_sme::StopApResultCode::Success)
1958 .expect("could not send AP stop response");
1959 }
1960 );
1961
1962 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
1964
1965 assert_matches!(exec.run_until_stalled(&mut stop_receiver), Poll::Ready(Ok(())));
1967
1968 assert_matches!(
1970 test_values.update_receiver.try_next(),
1971 Ok(Some(listener::Message::NotifyListeners(updates))) => {
1972 assert!(updates.access_points.is_empty());
1973 });
1974 }
1975
1976 #[fuchsia::test]
1977 fn test_start_after_start_failure() {
1978 let mut exec = fasync::TestExecutor::new();
1979 let mut test_values = test_setup();
1980
1981 let (start_sender, mut start_receiver) = oneshot::channel();
1982 let radio_config =
1983 RadioConfig::new(fidl_fuchsia_wlan_ieee80211::WlanPhyType::Ht, Cbw::Cbw20, 6);
1984 let req = ApConfig {
1985 id: create_network_id(),
1986 credential: vec![],
1987 radio_config: radio_config.clone(),
1988 mode: types::ConnectivityMode::Unrestricted,
1989 band: types::OperatingBand::Any,
1990 };
1991
1992 let mut requested_id = create_network_id();
1994 requested_id.ssid = types::Ssid::try_from("second_test_ssid").unwrap();
1995
1996 let requested_config = ApConfig {
1997 id: requested_id.clone(),
1998 credential: vec![],
1999 radio_config,
2000 mode: types::ConnectivityMode::Unrestricted,
2001 band: types::OperatingBand::Any,
2002 };
2003
2004 let (start_response_sender, _) = oneshot::channel();
2005 test_values
2006 .ap_req_sender
2007 .try_send(ManualRequest::Start((requested_config, start_response_sender)))
2008 .expect("failed to request AP stop");
2009
2010 let fut = starting_state(test_values.deps, req, AP_START_MAX_RETRIES, Some(start_sender));
2012 let fut = run_state_machine(fut);
2013 let mut fut = pin!(fut);
2014
2015 let sme_fut = test_values.sme_req_stream.into_future();
2017 let mut sme_fut = pin!(sme_fut);
2018
2019 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2021 assert_matches!(
2022 poll_sme_req(&mut exec, &mut sme_fut),
2023 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
2024 responder
2025 .send(fidl_sme::StopApResultCode::Success)
2026 .expect("could not send AP stop response");
2027 }
2028 );
2029
2030 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2032 assert_matches!(
2033 test_values.update_receiver.try_next(),
2034 Ok(Some(listener::Message::NotifyListeners(_)))
2035 );
2036
2037 assert_matches!(
2039 test_values.update_receiver.try_next(),
2040 Ok(Some(listener::Message::NotifyListeners(mut updates))) => {
2041 let update = updates.access_points.pop().expect("no new updates available.");
2042 assert_eq!(update.state, types::OperatingState::Starting);
2043 });
2044
2045 assert_matches!(
2047 poll_sme_req(&mut exec, &mut sme_fut),
2048 Poll::Ready(fidl_sme::ApSmeRequest::Start{ config: _, responder }) => {
2049 responder
2050 .send(fidl_sme::StartApResultCode::TimedOut)
2051 .expect("could not send AP stop response");
2052 }
2053 );
2054
2055 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2059
2060 assert_matches!(
2062 test_values.telemetry_receiver.try_next(),
2063 Ok(Some(TelemetryEvent::StartApResult(Err(()))))
2064 );
2065
2066 assert_matches!(
2068 test_values.defect_receiver.try_next(),
2069 Ok(Some(Defect::Iface(IfaceFailure::ApStartFailure { .. })))
2070 );
2071
2072 assert_matches!(exec.run_until_stalled(&mut start_receiver), Poll::Ready(Err(_)));
2074
2075 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2077 assert_matches!(
2078 poll_sme_req(&mut exec, &mut sme_fut),
2079 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
2080 responder
2081 .send(fidl_sme::StopApResultCode::Success)
2082 .expect("could not send AP stop response");
2083 }
2084 );
2085
2086 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2088 assert_matches!(
2089 poll_sme_req(&mut exec, &mut sme_fut),
2090 Poll::Ready(fidl_sme::ApSmeRequest::Start{ config, responder: _ }) => {
2091 assert_eq!(config.ssid, requested_id.ssid);
2092 }
2093 );
2094 }
2095
2096 #[fuchsia::test]
2097 fn test_exit_after_start_failure() {
2098 let mut exec = fasync::TestExecutor::new();
2099 let mut test_values = test_setup();
2100
2101 let (start_sender, _) = oneshot::channel();
2102 let radio_config =
2103 RadioConfig::new(fidl_fuchsia_wlan_ieee80211::WlanPhyType::Ht, Cbw::Cbw20, 6);
2104 let req = ApConfig {
2105 id: create_network_id(),
2106 credential: vec![],
2107 radio_config,
2108 mode: types::ConnectivityMode::Unrestricted,
2109 band: types::OperatingBand::Any,
2110 };
2111
2112 let (exit_sender, mut exit_receiver) = oneshot::channel();
2114 test_values
2115 .ap_req_sender
2116 .try_send(ManualRequest::Exit(exit_sender))
2117 .expect("failed to request AP stop");
2118
2119 let fut = starting_state(test_values.deps, req, AP_START_MAX_RETRIES, Some(start_sender));
2121 let fut = run_state_machine(fut);
2122 let mut fut = pin!(fut);
2123
2124 let sme_fut = test_values.sme_req_stream.into_future();
2126 let mut sme_fut = pin!(sme_fut);
2127
2128 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2130 assert_matches!(
2131 poll_sme_req(&mut exec, &mut sme_fut),
2132 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
2133 responder
2134 .send(fidl_sme::StopApResultCode::Success)
2135 .expect("could not send AP stop response");
2136 }
2137 );
2138
2139 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2141 assert_matches!(
2142 test_values.update_receiver.try_next(),
2143 Ok(Some(listener::Message::NotifyListeners(_)))
2144 );
2145
2146 assert_matches!(
2148 test_values.update_receiver.try_next(),
2149 Ok(Some(listener::Message::NotifyListeners(mut updates))) => {
2150 let update = updates.access_points.pop().expect("no new updates available.");
2151 assert_eq!(update.state, types::OperatingState::Starting);
2152 });
2153
2154 assert_matches!(
2156 poll_sme_req(&mut exec, &mut sme_fut),
2157 Poll::Ready(fidl_sme::ApSmeRequest::Start{ config: _, responder }) => {
2158 responder
2159 .send(fidl_sme::StartApResultCode::TimedOut)
2160 .expect("could not send AP stop response");
2161 }
2162 );
2163
2164 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
2168 assert_matches!(exec.run_until_stalled(&mut exit_receiver), Poll::Ready(Ok(())));
2169
2170 assert_matches!(
2172 test_values.telemetry_receiver.try_next(),
2173 Ok(Some(TelemetryEvent::StartApResult(Err(()))))
2174 );
2175
2176 assert_matches!(
2178 test_values.defect_receiver.try_next(),
2179 Ok(Some(Defect::Iface(IfaceFailure::ApStartFailure { .. })))
2180 );
2181 }
2182
2183 #[fuchsia::test]
2184 fn test_manual_start_causes_starting_notification() {
2185 let mut exec = fasync::TestExecutor::new();
2186 let mut test_values = test_setup();
2187
2188 let radio_config =
2190 RadioConfig::new(fidl_fuchsia_wlan_ieee80211::WlanPhyType::Ht, Cbw::Cbw20, 6);
2191 let requested_config = ApConfig {
2192 id: create_network_id(),
2193 credential: vec![],
2194 radio_config,
2195 mode: types::ConnectivityMode::Unrestricted,
2196 band: types::OperatingBand::Any,
2197 };
2198
2199 let (start_response_sender, _) = oneshot::channel();
2200 let manual_request = ManualRequest::Start((requested_config, start_response_sender));
2201
2202 let fut = perform_manual_request(test_values.deps, Some(manual_request));
2203 let fut = run_state_machine(async move { fut });
2204 let mut fut = pin!(fut);
2205 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2206
2207 let sme_fut = test_values.sme_req_stream.into_future();
2209 let mut sme_fut = pin!(sme_fut);
2210
2211 assert_matches!(
2212 poll_sme_req(&mut exec, &mut sme_fut),
2213 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
2214 responder
2215 .send(fidl_sme::StopApResultCode::Success)
2216 .expect("could not send SME stop response");
2217 }
2218 );
2219
2220 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2223 assert_matches!(
2224 test_values.update_receiver.try_next(),
2225 Ok(Some(listener::Message::NotifyListeners(updates))) => {
2226 assert!(updates.access_points.is_empty());
2227 });
2228
2229 assert_matches!(
2230 test_values.update_receiver.try_next(),
2231 Ok(Some(listener::Message::NotifyListeners(mut updates))) => {
2232 let update = updates.access_points.pop().expect("no new updates available.");
2233 assert_eq!(update.state, types::OperatingState::Starting);
2234 });
2235 }
2236
2237 #[fuchsia::test]
2238 fn test_serve_does_not_terminate_right_away() {
2239 let mut exec = fasync::TestExecutor::new();
2240 let test_values = test_setup();
2241 let sme_event_stream = test_values.deps.proxy.take_event_stream();
2242 let sme_fut = test_values.sme_req_stream.into_future();
2243 let mut sme_fut = pin!(sme_fut);
2244
2245 let update_sender = test_values.deps.state_tracker.inner.lock().sender.clone();
2246
2247 let fut = serve(
2248 0,
2249 test_values.deps.proxy,
2250 sme_event_stream,
2251 test_values.deps.req_stream,
2252 update_sender,
2253 test_values.deps.telemetry_sender,
2254 test_values.deps.defect_sender,
2255 test_values.deps.status_publisher,
2256 );
2257 let mut fut = pin!(fut);
2258
2259 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2261 assert_matches!(poll_sme_req(&mut exec, &mut sme_fut), Poll::Pending);
2262 }
2263
2264 #[fuchsia::test]
2265 fn test_no_notification_when_sme_fails_while_stopped() {
2266 let mut exec = fasync::TestExecutor::new();
2267 let test_values = test_setup();
2268 let sme_event_stream = test_values.deps.proxy.take_event_stream();
2269 let update_sender = test_values.deps.state_tracker.inner.lock().sender.clone();
2270
2271 test_values.deps.status_publisher.publish_status(Status::Starting);
2273
2274 let fut = serve(
2275 0,
2276 test_values.deps.proxy,
2277 sme_event_stream,
2278 test_values.deps.req_stream,
2279 update_sender,
2280 test_values.deps.telemetry_sender,
2281 test_values.deps.defect_sender,
2282 test_values.deps.status_publisher.clone(),
2283 );
2284 let mut fut = pin!(fut);
2285
2286 drop(test_values.sme_req_stream);
2288
2289 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
2291
2292 assert_matches!(
2294 exec.run_until_stalled(&mut test_values.update_receiver.into_future()),
2295 Poll::Pending
2296 );
2297
2298 assert_matches!(test_values.status_reader.read_status(), Ok(Status::Stopped));
2300 }
2301
2302 #[fuchsia::test]
2303 fn test_failure_notification_when_configured() {
2304 let mut exec = fasync::TestExecutor::new();
2305 let mut test_values = test_setup();
2306 let sme_event_stream = test_values.deps.proxy.take_event_stream();
2307 let mut sme_fut = Box::pin(test_values.sme_req_stream.into_future());
2308
2309 let update_sender = test_values.deps.state_tracker.inner.lock().sender.clone();
2310 let fut = serve(
2311 0,
2312 test_values.deps.proxy,
2313 sme_event_stream,
2314 test_values.deps.req_stream,
2315 update_sender,
2316 test_values.deps.telemetry_sender,
2317 test_values.deps.defect_sender,
2318 test_values.deps.status_publisher,
2319 );
2320 let mut fut = pin!(fut);
2321
2322 let mut ap = AccessPoint::new(test_values.ap_req_sender);
2324 let (sender, _receiver) = oneshot::channel();
2325 let radio_config =
2326 RadioConfig::new(fidl_fuchsia_wlan_ieee80211::WlanPhyType::Ht, Cbw::Cbw20, 6);
2327 let config = ApConfig {
2328 id: create_network_id(),
2329 credential: vec![],
2330 radio_config,
2331 mode: types::ConnectivityMode::Unrestricted,
2332 band: types::OperatingBand::Any,
2333 };
2334 ap.start(config, sender).expect("failed to make start request");
2335
2336 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2338 assert_matches!(
2339 poll_sme_req(&mut exec, &mut sme_fut),
2340 Poll::Ready(fidl_sme::ApSmeRequest::Stop{ responder }) => {
2341 responder.send(fidl_sme::StopApResultCode::Success).expect("could not send AP stop response");
2342 }
2343 );
2344
2345 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2346
2347 assert_matches!(
2350 test_values.update_receiver.try_next(),
2351 Ok(Some(listener::Message::NotifyListeners(update))) => {
2352 assert!(update.access_points.is_empty());
2353 }
2354 );
2355 assert_matches!(
2356 test_values.update_receiver.try_next(),
2357 Ok(Some(listener::Message::NotifyListeners(update))) => {
2358 assert_eq!(update.access_points.len(), 1);
2359 assert_eq!(update.access_points[0].state, types::OperatingState::Starting);
2360 }
2361 );
2362
2363 drop(sme_fut);
2365
2366 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
2368
2369 assert_matches!(
2371 test_values.update_receiver.try_next(),
2372 Ok(Some(listener::Message::NotifyListeners(update))) => {
2373 assert_eq!(update.access_points.len(), 1);
2374 assert_eq!(update.access_points[0].state, types::OperatingState::Failed);
2375 }
2376 );
2377 }
2378
2379 #[fuchsia::test]
2380 fn test_state_tracker_reset() {
2381 let _exec = fasync::TestExecutor::new();
2382 let (sender, mut receiver) = mpsc::unbounded();
2383
2384 let state = ApStateTracker::new(sender);
2386 {
2387 assert!(state.inner.lock().state.is_none());
2388 }
2389
2390 assert_matches!(receiver.try_next(), Err(_));
2392
2393 let new_state = ApStateUpdate::new(
2395 create_network_id(),
2396 types::OperatingState::Starting,
2397 types::ConnectivityMode::Unrestricted,
2398 types::OperatingBand::Any,
2399 );
2400 state.reset_state(new_state).expect("failed to reset state");
2401 assert_matches!(state.inner.lock().state.as_ref(), Some(ApStateUpdate {
2402 id: types::NetworkIdentifier {
2403 ssid,
2404 security_type: types::SecurityType::None,
2405 },
2406 state: types::OperatingState::Starting,
2407 mode: Some(types::ConnectivityMode::Unrestricted),
2408 band: Some(types::OperatingBand::Any),
2409 frequency: None,
2410 clients: None,
2411 }) => {
2412 let expected_ssid = types::Ssid::try_from("test_ssid").unwrap();
2413 assert_eq!(ssid, &expected_ssid);
2414 });
2415
2416 assert_matches!(
2418 receiver.try_next(),
2419 Ok(Some(listener::Message::NotifyListeners(ApStatesUpdate { access_points }))) => {
2420 assert_eq!(access_points.len(), 1);
2421
2422 let expected_id = types::NetworkIdentifier {
2423 ssid: types::Ssid::try_from("test_ssid").unwrap(),
2424 security_type: types::SecurityType::None,
2425 };
2426 assert_eq!(access_points[0].id, expected_id);
2427 assert_eq!(access_points[0].state, types::OperatingState::Starting);
2428 assert_eq!(access_points[0].mode, Some(types::ConnectivityMode::Unrestricted));
2429 assert_eq!(access_points[0].band, Some(types::OperatingBand::Any));
2430 assert_eq!(access_points[0].frequency, None);
2431 assert_eq!(access_points[0].clients, None);
2432 }
2433 );
2434 }
2435
2436 #[fuchsia::test]
2437 fn test_state_tracker_consume_sme_update() {
2438 let _exec = fasync::TestExecutor::new();
2439 let (sender, mut receiver) = mpsc::unbounded();
2440 let state = ApStateTracker::new(sender);
2441
2442 let new_state = ApStateUpdate::new(
2444 create_network_id(),
2445 types::OperatingState::Active,
2446 types::ConnectivityMode::Unrestricted,
2447 types::OperatingBand::Any,
2448 );
2449 state.reset_state(new_state).expect("failed to reset state");
2450
2451 assert_matches!(
2453 receiver.try_next(),
2454 Ok(Some(listener::Message::NotifyListeners(ApStatesUpdate { access_points }))
2455 ) => {
2456 assert_eq!(access_points.len(), 1);
2457
2458 let expected_id = types::NetworkIdentifier {
2459 ssid: types::Ssid::try_from("test_ssid").unwrap(),
2460 security_type: types::SecurityType::None,
2461 };
2462 assert_eq!(access_points[0].id, expected_id);
2463 assert_eq!(access_points[0].state, types::OperatingState::Active);
2464 assert_eq!(access_points[0].mode, Some(types::ConnectivityMode::Unrestricted));
2465 assert_eq!(access_points[0].band, Some(types::OperatingBand::Any));
2466 assert_eq!(access_points[0].frequency, None);
2467 assert_eq!(access_points[0].clients, None);
2468 });
2469
2470 let ap_info = fidl_sme::Ap {
2472 ssid: types::Ssid::try_from("test_ssid").unwrap().to_vec(),
2473 channel: 6,
2474 num_clients: 123,
2475 };
2476 state
2477 .consume_sme_status_update(Cbw::Cbw20, ap_info)
2478 .expect("failure while updating SME status");
2479
2480 assert_matches!(
2481 receiver.try_next(),
2482 Ok(Some(listener::Message::NotifyListeners(ApStatesUpdate { access_points }))
2483 ) => {
2484 assert_eq!(access_points.len(), 1);
2485
2486 let expected_id = types::NetworkIdentifier {
2487 ssid: types::Ssid::try_from("test_ssid").unwrap(),
2488 security_type: types::SecurityType::None,
2489 };
2490 assert_eq!(access_points[0].id, expected_id);
2491 assert_eq!(access_points[0].state, types::OperatingState::Active);
2492 assert_eq!(access_points[0].mode, Some(types::ConnectivityMode::Unrestricted));
2493 assert_eq!(access_points[0].band, Some(types::OperatingBand::Any));
2494 assert_eq!(access_points[0].frequency, Some(2437));
2495 assert_eq!(access_points[0].clients, Some(ConnectedClientInformation { count: 123 }));
2496 });
2497 }
2498
2499 #[fuchsia::test]
2500 fn test_state_tracker_update_operating_state() {
2501 let _exec = fasync::TestExecutor::new();
2502 let (sender, mut receiver) = mpsc::unbounded();
2503 let state = ApStateTracker::new(sender);
2504
2505 let new_state = ApStateUpdate::new(
2507 create_network_id(),
2508 types::OperatingState::Starting,
2509 types::ConnectivityMode::Unrestricted,
2510 types::OperatingBand::Any,
2511 );
2512 state.reset_state(new_state).expect("failed to reset state");
2513
2514 assert_matches!(
2516 receiver.try_next(),
2517 Ok(Some(listener::Message::NotifyListeners(ApStatesUpdate { access_points }))
2518 ) => {
2519 assert_eq!(access_points.len(), 1);
2520
2521 let expected_id = types::NetworkIdentifier {
2522 ssid: types::Ssid::try_from("test_ssid").unwrap(),
2523 security_type: types::SecurityType::None,
2524 };
2525 assert_eq!(access_points[0].id, expected_id);
2526 assert_eq!(access_points[0].state, types::OperatingState::Starting);
2527 assert_eq!(access_points[0].mode, Some(types::ConnectivityMode::Unrestricted));
2528 assert_eq!(access_points[0].band, Some(types::OperatingBand::Any));
2529 assert_eq!(access_points[0].frequency, None);
2530 assert_eq!(access_points[0].clients, None);
2531 });
2532
2533 state
2535 .update_operating_state(types::OperatingState::Starting)
2536 .expect("failed to send duplicate update.");
2537 assert_matches!(
2538 receiver.try_next(),
2539 Ok(Some(listener::Message::NotifyListeners(ApStatesUpdate { access_points }))
2540 ) => {
2541 assert_eq!(access_points.len(), 1);
2542
2543 let expected_id = types::NetworkIdentifier {
2544 ssid: types::Ssid::try_from("test_ssid").unwrap(),
2545 security_type: types::SecurityType::None,
2546 };
2547 assert_eq!(access_points[0].id, expected_id);
2548 assert_eq!(access_points[0].state, types::OperatingState::Starting);
2549 assert_eq!(access_points[0].mode, Some(types::ConnectivityMode::Unrestricted));
2550 assert_eq!(access_points[0].band, Some(types::OperatingBand::Any));
2551 assert_eq!(access_points[0].frequency, None);
2552 assert_eq!(access_points[0].clients, None);
2553 });
2554
2555 state
2557 .update_operating_state(types::OperatingState::Active)
2558 .expect("failed to send active update.");
2559 assert_matches!(
2560 receiver.try_next(),
2561 Ok(Some(listener::Message::NotifyListeners(ApStatesUpdate { access_points }))
2562 ) => {
2563 assert_eq!(access_points.len(), 1);
2564
2565 let expected_id = types::NetworkIdentifier {
2566 ssid: types::Ssid::try_from("test_ssid").unwrap(),
2567 security_type: types::SecurityType::None,
2568 };
2569 assert_eq!(access_points[0].id, expected_id);
2570 assert_eq!(access_points[0].state, types::OperatingState::Active);
2571 assert_eq!(access_points[0].mode, Some(types::ConnectivityMode::Unrestricted));
2572 assert_eq!(access_points[0].band, Some(types::OperatingBand::Any));
2573 assert_eq!(access_points[0].frequency, None);
2574 assert_eq!(access_points[0].clients, None);
2575 });
2576 }
2577
2578 #[fuchsia::test]
2579 fn test_state_tracker_set_stopped_state() {
2580 let _exec = fasync::TestExecutor::new();
2581 let (sender, mut receiver) = mpsc::unbounded();
2582 let state = ApStateTracker::new(sender);
2583
2584 {
2586 let new_state = ApStateUpdate::new(
2587 create_network_id(),
2588 types::OperatingState::Active,
2589 types::ConnectivityMode::Unrestricted,
2590 types::OperatingBand::Any,
2591 );
2592 state.inner.lock().state = Some(new_state);
2593 }
2594
2595 state.set_stopped_state().expect("failed to send stopped notification");
2598 {
2599 assert!(state.inner.lock().state.is_none());
2600 }
2601
2602 assert_matches!(
2604 receiver.try_next(),
2605 Ok(Some(listener::Message::NotifyListeners(ApStatesUpdate { access_points }))
2606 ) => {
2607 assert!(access_points.is_empty());
2608 });
2609 }
2610
2611 #[fuchsia::test]
2612 fn test_state_tracker_failure_modes() {
2613 let _exec = fasync::TestExecutor::new();
2614 let (sender, receiver) = mpsc::unbounded();
2615 let state = ApStateTracker::new(sender);
2616 {
2617 let new_state = ApStateUpdate::new(
2618 create_network_id(),
2619 types::OperatingState::Active,
2620 types::ConnectivityMode::Unrestricted,
2621 types::OperatingBand::Any,
2622 );
2623 state.inner.lock().state = Some(new_state);
2624 }
2625
2626 drop(receiver);
2630
2631 let _ = state
2632 .update_operating_state(types::OperatingState::Failed)
2633 .expect_err("unexpectedly able to set operating state");
2634 let _ = state
2635 .consume_sme_status_update(
2636 Cbw::Cbw20,
2637 fidl_sme::Ap {
2638 ssid: types::Ssid::try_from("test_ssid").unwrap().to_vec(),
2639 channel: 6,
2640 num_clients: 123,
2641 },
2642 )
2643 .expect_err("unexpectedly able to update SME status");
2644 let _ = state.set_stopped_state().expect_err("unexpectedly able to set stopped state");
2645 }
2646
2647 #[fuchsia::test]
2648 fn test_state_when_stopping() {
2649 let mut exec = fasync::TestExecutor::new();
2650 let test_values = test_setup();
2651
2652 let (stop_sender, _) = oneshot::channel();
2654 let fut = stopping_state(test_values.deps, stop_sender);
2655 let fut = run_state_machine(fut);
2656 let mut fut = pin!(fut);
2657 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2658
2659 assert_matches!(test_values.status_reader.read_status(), Ok(Status::Stopping));
2661 }
2662
2663 #[fuchsia::test]
2664 fn test_state_when_stopped() {
2665 let mut exec = fasync::TestExecutor::new();
2666 let test_values = test_setup();
2667
2668 test_values.deps.status_publisher.publish_status(Status::Starting);
2670
2671 let fut = stopped_state(test_values.deps);
2673 let fut = run_state_machine(fut);
2674 let mut fut = pin!(fut);
2675 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2676
2677 assert_matches!(test_values.status_reader.read_status(), Ok(Status::Stopped));
2679 }
2680
2681 #[fuchsia::test]
2682 fn test_state_when_starting() {
2683 let mut exec = fasync::TestExecutor::new();
2684 let test_values = test_setup();
2685
2686 let (start_sender, _) = oneshot::channel();
2688 let radio_config =
2689 RadioConfig::new(fidl_fuchsia_wlan_ieee80211::WlanPhyType::Ht, Cbw::Cbw20, 6);
2690 let req = ApConfig {
2691 id: create_network_id(),
2692 credential: vec![],
2693 radio_config,
2694 mode: types::ConnectivityMode::Unrestricted,
2695 band: types::OperatingBand::Any,
2696 };
2697 let fut = starting_state(test_values.deps, req, 0, Some(start_sender));
2698 let fut = run_state_machine(fut);
2699 let mut fut = pin!(fut);
2700 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2701
2702 assert_matches!(test_values.status_reader.read_status(), Ok(Status::Starting));
2704 }
2705
2706 #[fuchsia::test]
2707 fn test_state_when_started() {
2708 let mut exec = fasync::TestExecutor::new();
2709 let test_values = test_setup();
2710
2711 let radio_config =
2713 RadioConfig::new(fidl_fuchsia_wlan_ieee80211::WlanPhyType::Ht, Cbw::Cbw20, 6);
2714 let req = ApConfig {
2715 id: create_network_id(),
2716 credential: vec![],
2717 radio_config,
2718 mode: types::ConnectivityMode::Unrestricted,
2719 band: types::OperatingBand::Any,
2720 };
2721 let fut = started_state(test_values.deps, req);
2722 let fut = run_state_machine(fut);
2723 let mut fut = pin!(fut);
2724 assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
2725
2726 assert_matches!(test_values.status_reader.read_status(), Ok(Status::Started { .. }));
2728 }
2729
2730 struct InspectTestValues {
2731 exec: fasync::TestExecutor,
2732 inspector: fuchsia_inspect::Inspector,
2733 _node: fuchsia_inspect::Node,
2734 status_node: fuchsia_inspect_contrib::nodes::BoundedListNode,
2735 }
2736
2737 impl InspectTestValues {
2738 fn new(exec: fasync::TestExecutor) -> Self {
2739 let inspector = fuchsia_inspect::Inspector::default();
2740 let _node = inspector.root().create_child("node");
2741 let status_node =
2742 fuchsia_inspect_contrib::nodes::BoundedListNode::new(_node.clone_weak(), 1);
2743
2744 Self { exec, inspector, _node, status_node }
2745 }
2746
2747 fn log_status(&mut self, status: Status) -> fuchsia_inspect::reader::DiagnosticsHierarchy {
2748 fuchsia_inspect_contrib::inspect_log!(self.status_node, "status" => status);
2749 let read_fut = fuchsia_inspect::reader::read(&self.inspector);
2750 let mut read_fut = pin!(read_fut);
2751 assert_matches!(
2752 self.exec.run_until_stalled(&mut read_fut),
2753 Poll::Ready(Ok(hierarchy)) => hierarchy
2754 )
2755 }
2756 }
2757
2758 #[fuchsia::test]
2759 fn test_stopping_status_inspect_log() {
2760 let exec = fasync::TestExecutor::new_with_fake_time();
2761 let mut test_values = InspectTestValues::new(exec);
2762 let hierarchy = test_values.log_status(Status::Stopping);
2763 diagnostics_assertions::assert_data_tree!(
2764 @executor test_values.exec,
2765 hierarchy,
2766 root: contains {
2767 node: contains {
2768 "0": contains {
2769 status: "Stopping"
2770 }
2771 }
2772 });
2773 }
2774
2775 #[fuchsia::test]
2776 fn test_stopped_status_inspect_log() {
2777 let exec = fasync::TestExecutor::new_with_fake_time();
2778 let mut test_values = InspectTestValues::new(exec);
2779 let hierarchy = test_values.log_status(Status::Stopped);
2780 diagnostics_assertions::assert_data_tree!(
2781 @executor test_values.exec,
2782 hierarchy,
2783 root: contains {
2784 node: contains {
2785 "0": contains {
2786 status: "Stopped"
2787 }
2788 }
2789 });
2790 }
2791
2792 #[fuchsia::test]
2793 fn test_starting_status_inspect_log() {
2794 let exec = fasync::TestExecutor::new_with_fake_time();
2795 let mut test_values = InspectTestValues::new(exec);
2796 let hierarchy = test_values.log_status(Status::Starting);
2797 diagnostics_assertions::assert_data_tree!(
2798 @executor test_values.exec,
2799 hierarchy,
2800 root: contains {
2801 node: contains {
2802 "0": contains {
2803 status: "Starting"
2804 }
2805 }
2806 });
2807 }
2808
2809 #[fuchsia::test]
2810 fn test_started_status_inspect_log() {
2811 let exec = fasync::TestExecutor::new_with_fake_time();
2812 let mut test_values = InspectTestValues::new(exec);
2813 let hierarchy = test_values.log_status(Status::Started {
2814 band: types::OperatingBand::Any,
2815 channel: 1,
2816 mode: types::ConnectivityMode::Unrestricted,
2817 num_clients: 2,
2818 security_type: types::SecurityType::None,
2819 });
2820 diagnostics_assertions::assert_data_tree!(
2821 @executor test_values.exec,
2822 hierarchy,
2823 root: contains {
2824 node: contains {
2825 "0": contains {
2826 status: contains {
2827 Started: {
2828 band: "Any",
2829 channel: 1_u64,
2830 mode: "Unrestricted",
2831 num_clients: 2_u64,
2832 security_type: "None"
2833 }
2834 }
2835 }
2836 }
2837 });
2838 }
2839}