Skip to main content

wlan_telemetry/processors/
sme_timeout.rs

1// Copyright 2025 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::util::cobalt_logger::{FilteredCobaltLogger, log_cobalt_batch};
6use cobalt_client::traits::AsEventCode;
7use fidl_fuchsia_metrics::{MetricEvent, MetricEventPayload};
8use std::sync::Arc;
9
10use wlan_legacy_metrics_registry as metrics;
11
12#[derive(Copy, Clone, Debug, PartialEq, Eq)]
13pub enum TimeoutSource {
14    Scan,
15    Connect,
16    Disconnect,
17    ClientStatus,
18    WmmStatus,
19    ApStart,
20    ApStop,
21    ApStatus,
22    GetIfaceStats,
23    GetHistogramStats,
24}
25
26impl TimeoutSource {
27    fn to_metric_dimension(self) -> metrics::SmeOperationTimeoutMetricDimensionStalledOperation {
28        use metrics::SmeOperationTimeoutMetricDimensionStalledOperation::*;
29        match self {
30            Self::Scan => Scan_,
31            Self::Connect => Connect_,
32            Self::Disconnect => Disconnect_,
33            Self::ClientStatus => ClientStatus_,
34            Self::WmmStatus => WmmStatus_,
35            Self::ApStart => ApStart_,
36            Self::ApStop => ApStop_,
37            Self::ApStatus => ApStatus_,
38            Self::GetIfaceStats => GetCounterStats_,
39            Self::GetHistogramStats => GetHistogramStats_,
40        }
41    }
42}
43
44pub struct SmeTimeoutLogger {
45    cobalt_proxy: Arc<FilteredCobaltLogger>,
46}
47
48impl SmeTimeoutLogger {
49    pub fn new(cobalt_proxy: Arc<FilteredCobaltLogger>) -> Self {
50        Self { cobalt_proxy }
51    }
52
53    pub async fn handle_sme_timeout_event(&self, source: TimeoutSource) {
54        let metric_events = vec![
55            MetricEvent {
56                metric_id: metrics::SME_OPERATION_TIMEOUT_2_METRIC_ID,
57                event_codes: vec![],
58                payload: MetricEventPayload::Count(1),
59            },
60            MetricEvent {
61                metric_id: metrics::SME_OPERATION_TIMEOUT_METRIC_ID,
62                event_codes: vec![source.to_metric_dimension().as_event_code()],
63                payload: MetricEventPayload::Count(1),
64            },
65        ];
66        log_cobalt_batch!(self.cobalt_proxy, &metric_events, "handle_sme_timeout_event");
67    }
68}
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73    use crate::testing::{TestHelper, setup_test};
74    use futures::task::Poll;
75    use std::pin::pin;
76    use test_case::test_case;
77
78    fn run_handle_sme_timeout_event(
79        test_helper: &mut TestHelper,
80        sme_timeout_logger: &SmeTimeoutLogger,
81        source: TimeoutSource,
82    ) {
83        let mut test_fut = pin!(sme_timeout_logger.handle_sme_timeout_event(source));
84        assert_eq!(
85            test_helper.run_until_stalled_drain_cobalt_events(&mut test_fut),
86            Poll::Ready(())
87        );
88    }
89
90    #[test_case(
91        TimeoutSource::Scan,
92        metrics::SmeOperationTimeoutMetricDimensionStalledOperation::Scan_ ;
93        "log scan timeout"
94    )]
95    #[test_case(
96        TimeoutSource::Connect,
97        metrics::SmeOperationTimeoutMetricDimensionStalledOperation::Connect_ ;
98        "log connect"
99    )]
100    #[test_case(
101        TimeoutSource::Disconnect,
102        metrics::SmeOperationTimeoutMetricDimensionStalledOperation::Disconnect_ ;
103        "log disconnect timeout"
104    )]
105    #[test_case(
106        TimeoutSource::ClientStatus,
107        metrics::SmeOperationTimeoutMetricDimensionStalledOperation::ClientStatus_ ;
108        "log client status timeout"
109    )]
110    #[test_case(
111        TimeoutSource::WmmStatus,
112        metrics::SmeOperationTimeoutMetricDimensionStalledOperation::WmmStatus_ ;
113        "log WMM status timeout"
114    )]
115    #[test_case(
116        TimeoutSource::ApStart,
117        metrics::SmeOperationTimeoutMetricDimensionStalledOperation::ApStart_ ;
118        "log AP start timeout"
119    )]
120    #[test_case(
121        TimeoutSource::ApStop,
122        metrics::SmeOperationTimeoutMetricDimensionStalledOperation::ApStop_ ;
123        "log Ap stop timeout"
124    )]
125    #[test_case(
126        TimeoutSource::ApStatus,
127        metrics::SmeOperationTimeoutMetricDimensionStalledOperation::ApStatus_ ;
128        "log AP status timeout"
129    )]
130    #[test_case(
131        TimeoutSource::GetIfaceStats,
132        metrics::SmeOperationTimeoutMetricDimensionStalledOperation::GetCounterStats_ ;
133        "log iface stats timeout"
134    )]
135    #[test_case(
136        TimeoutSource::GetHistogramStats,
137        metrics::SmeOperationTimeoutMetricDimensionStalledOperation::GetHistogramStats_ ;
138        "log histogram stats timeout"
139    )]
140    #[fuchsia::test(add_test_attr = false)]
141    fn test_handle_sme_timeout_event_with_source(
142        source: TimeoutSource,
143        expected_dimension: metrics::SmeOperationTimeoutMetricDimensionStalledOperation,
144    ) {
145        let mut test_helper = setup_test();
146        let sme_timeout_logger = SmeTimeoutLogger::new(test_helper.filtered_cobalt_logger());
147
148        run_handle_sme_timeout_event(&mut test_helper, &sme_timeout_logger, source);
149
150        let metrics_2 = test_helper.get_logged_metrics(metrics::SME_OPERATION_TIMEOUT_2_METRIC_ID);
151        assert_eq!(metrics_2.len(), 1);
152        assert_eq!(metrics_2[0].payload, MetricEventPayload::Count(1));
153
154        let metrics = test_helper.get_logged_metrics(metrics::SME_OPERATION_TIMEOUT_METRIC_ID);
155        assert_eq!(metrics.len(), 1);
156        assert_eq!(metrics[0].payload, MetricEventPayload::Count(1));
157        assert_eq!(metrics[0].event_codes, vec![expected_dimension.as_event_code()]);
158    }
159}