mock_metrics/
lib.rs
1use fidl_fuchsia_metrics::{self as fidl, MetricEvent};
6use fuchsia_async as fasync;
7use fuchsia_sync::Mutex;
8use futures::TryStreamExt as _;
9use std::sync::Arc;
10use std::time::Duration;
11
12pub struct MockMetricEventLogger {
13 cobalt_events: Mutex<Vec<MetricEvent>>,
14}
15
16impl MockMetricEventLogger {
17 fn new() -> Self {
18 Self { cobalt_events: Mutex::new(vec![]) }
19 }
20
21 pub fn clone_metric_events(&self) -> Vec<MetricEvent> {
22 self.cobalt_events.lock().clone()
23 }
24
25 async fn run_logger(self: Arc<Self>, mut stream: fidl::MetricEventLoggerRequestStream) {
26 while let Some(event) = stream.try_next().await.unwrap() {
27 match event {
28 fidl::MetricEventLoggerRequest::LogMetricEvents { events, responder } => {
29 self.cobalt_events.lock().extend(events);
30 let _ = responder.send(Ok(()));
31 }
32 _ => {
33 panic!("unhandled MetricEventLogger method {event:?}");
34 }
35 }
36 }
37 }
38}
39
40pub struct MockMetricEventLoggerFactory {
41 loggers: Mutex<Vec<Arc<MockMetricEventLogger>>>,
42 project_id: u32,
43}
44
45impl MockMetricEventLoggerFactory {
46 #[allow(clippy::new_without_default)]
47 pub fn new() -> Self {
48 Self::with_id(cobalt_sw_delivery_registry::PROJECT_ID)
49 }
50
51 pub fn with_id(id: u32) -> Self {
52 Self { loggers: Mutex::new(vec![]), project_id: id }
53 }
54
55 pub fn clone_loggers(&self) -> Vec<Arc<MockMetricEventLogger>> {
56 self.loggers.lock().clone()
57 }
58
59 pub async fn run_logger_factory(
60 self: Arc<Self>,
61 mut stream: fidl::MetricEventLoggerFactoryRequestStream,
62 ) {
63 while let Some(event) = stream.try_next().await.unwrap() {
64 match event {
65 fidl::MetricEventLoggerFactoryRequest::CreateMetricEventLogger {
66 project_spec,
67 logger,
68 responder,
69 } => {
70 assert_eq!(project_spec.project_id, Some(self.project_id));
71 let mock_logger = Arc::new(MockMetricEventLogger::new());
72 self.loggers.lock().push(mock_logger.clone());
73 fasync::Task::spawn(mock_logger.run_logger(logger.into_stream())).detach();
74 let _ = responder.send(Ok(()));
75 }
76 _ => {
77 panic!("unhandled MetricEventLoggerFactory method: {event:?}");
78 }
79 }
80 }
81 }
82
83 pub async fn wait_for_at_least_n_events_with_metric_id(
84 &self,
85 n: usize,
86 id: u32,
87 ) -> Vec<MetricEvent> {
88 loop {
89 let events: Vec<MetricEvent> = self
90 .loggers
91 .lock()
92 .iter()
93 .flat_map(|logger| logger.cobalt_events.lock().clone())
94 .filter(|MetricEvent { metric_id, .. }| *metric_id == id)
95 .collect();
96 if events.len() >= n {
97 return events;
98 }
99 fasync::Timer::new(Duration::from_millis(10)).await;
100 }
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107 use ::fidl::endpoints::create_proxy_and_stream;
108 use fidl_fuchsia_metrics::ProjectSpec;
109
110 #[fasync::run_singlethreaded(test)]
111 async fn test_mock_metrics() {
112 let mock = Arc::new(MockMetricEventLoggerFactory::new());
113 let (factory, stream) = create_proxy_and_stream::<fidl::MetricEventLoggerFactoryMarker>();
114
115 let task = fasync::Task::spawn(Arc::clone(&mock).run_logger_factory(stream));
116
117 let (logger, server_end) = ::fidl::endpoints::create_proxy();
118 factory
119 .create_metric_event_logger(
120 &ProjectSpec {
121 project_id: Some(cobalt_sw_delivery_registry::PROJECT_ID),
122 ..Default::default()
123 },
124 server_end,
125 )
126 .await
127 .unwrap()
128 .unwrap();
129 drop(factory);
130 task.await;
131
132 let events = &[MetricEvent {
133 metric_id: 42,
134 event_codes: vec![],
135 payload: fidl::MetricEventPayload::Count(0),
136 }];
137 logger.log_metric_events(events).await.unwrap().unwrap();
138 let mock_events = mock.wait_for_at_least_n_events_with_metric_id(1, 42).await;
139 assert_eq!(mock_events, events);
140 }
141}