windowed_stats/experimental/
testing.rs1use derivative::Derivative;
6use fuchsia_sync::Mutex;
7use std::any::{self, Any};
8use std::collections::HashMap;
9use std::marker::PhantomData;
10use std::sync::Arc;
11
12use crate::experimental::clock::{Timed, Timestamp};
13use crate::experimental::series::interpolation::InterpolationKind;
14use crate::experimental::series::statistic::{FoldError, Metadata, SerialStatistic};
15use crate::experimental::series::{Interpolator, MatrixSampler, SerializedBuffer, TimeMatrix};
16use crate::experimental::serve::{
17 BufferedSampler, InspectSender, InspectedTimeMatrix, ServedTimeMatrix,
18};
19
20type DynamicSample = Box<dyn Any + Send>;
21
22#[derive(Derivative)]
23#[derivative(Debug, PartialEq)]
24pub enum TimeMatrixCall<T> {
25 Fold(Timed<T>),
26 Interpolate(Timestamp),
27}
28
29impl<T> TimeMatrixCall<T> {
30 fn map<U, F>(self, f: F) -> TimeMatrixCall<U>
31 where
32 F: FnOnce(T) -> U,
33 {
34 match self {
35 TimeMatrixCall::Fold(timed) => TimeMatrixCall::Fold(timed.map(f)),
36 TimeMatrixCall::Interpolate(timestamp) => TimeMatrixCall::Interpolate(timestamp),
37 }
38 }
39}
40
41impl<T, E> TimeMatrixCall<Result<T, E>> {
42 fn transpose(self) -> Result<TimeMatrixCall<T>, E> {
43 match self {
44 TimeMatrixCall::Fold(result) => match result.transpose() {
45 Ok(sample) => Ok(TimeMatrixCall::Fold(sample)),
46 Err(error) => Err(error),
47 },
48 TimeMatrixCall::Interpolate(timestamp) => Ok(TimeMatrixCall::Interpolate(timestamp)),
49 }
50 }
51}
52
53#[derive(Debug)]
54pub struct TimeMatrixCallLog {
55 calls: HashMap<String, Vec<TimeMatrixCall<DynamicSample>>>,
56}
57
58impl TimeMatrixCallLog {
59 pub fn drain<T: Any + Send + Clone>(&mut self, name: &str) -> Vec<TimeMatrixCall<T>> {
60 self.calls
61 .remove(name)
62 .unwrap_or_default()
63 .into_iter()
64 .map(|call| call.map(|sample| sample.downcast::<T>().map(|sample| *sample)))
65 .map(TimeMatrixCall::transpose)
66 .collect::<Result<Vec<_>, _>>()
67 .unwrap_or_else(|_| {
68 panic!(
69 "in time matrix \"{}\": failed to downcast dynamic sample of type `{}`",
70 name,
71 any::type_name::<T>()
72 )
73 })
74 }
75
76 pub fn as_hash_map(&self) -> &HashMap<String, Vec<TimeMatrixCall<DynamicSample>>> {
77 &self.calls
78 }
79
80 pub fn is_empty(&self) -> bool {
81 self.calls.is_empty()
82 }
83}
84
85#[derive(Clone)]
86pub struct MockTimeMatrixClient {
87 matrices: Arc<Mutex<Vec<Box<dyn ServedTimeMatrix>>>>,
88 calls: Arc<Mutex<Vec<(String, TimeMatrixCall<DynamicSample>)>>>,
89}
90
91impl MockTimeMatrixClient {
92 pub fn new() -> Self {
93 Self { matrices: Arc::new(Mutex::new(vec![])), calls: Arc::new(Mutex::new(vec![])) }
94 }
95}
96
97impl MockTimeMatrixClient {
98 pub fn fold_buffered_samples(&self) -> TimeMatrixCallLog {
99 for matrix in self.matrices.lock().iter_mut() {
100 matrix.fold_buffered_samples().unwrap();
101 }
102 let mut calls = HashMap::<_, Vec<_>>::new();
103 for (name, call) in self.calls.lock().drain(..) {
104 calls.entry(name).or_default().push(call);
105 }
106 TimeMatrixCallLog { calls }
107 }
108}
109
110impl InspectSender for MockTimeMatrixClient {
111 fn inspect_time_matrix<F, P>(
112 &self,
113 name: impl Into<String>,
114 _matrix: TimeMatrix<F, P>,
115 ) -> InspectedTimeMatrix<F::Sample>
116 where
117 TimeMatrix<F, P>: 'static + MatrixSampler<F::Sample> + Send,
118 Metadata<F>: 'static + Send + Sync,
119 F: SerialStatistic<P>,
120 F::Sample: Send,
121 P: InterpolationKind,
122 {
123 let name = name.into();
124 let (sender, matrix) = BufferedSampler::from_time_matrix(MockTimeMatrix::new(
125 name.clone(),
126 self.calls.clone(),
127 ));
128 self.matrices.lock().push(Box::new(matrix));
129 InspectedTimeMatrix::new(name, sender)
130 }
131
132 fn inspect_time_matrix_with_metadata<F, P>(
133 &self,
134 name: impl Into<String>,
135 matrix: TimeMatrix<F, P>,
136 _metadata: impl Into<Metadata<F>>,
137 ) -> InspectedTimeMatrix<F::Sample>
138 where
139 TimeMatrix<F, P>: 'static + MatrixSampler<F::Sample> + Send,
140 Metadata<F>: 'static + Send + Sync,
141 F: SerialStatistic<P>,
142 F::Sample: Send,
143 P: InterpolationKind,
144 {
145 self.inspect_time_matrix(name, matrix)
146 }
147}
148
149struct MockTimeMatrix<T> {
150 name: String,
151 calls: Arc<Mutex<Vec<(String, TimeMatrixCall<DynamicSample>)>>>,
152 phantom: PhantomData<fn() -> T>,
153}
154
155impl<T> MockTimeMatrix<T> {
156 pub fn new(
157 name: impl Into<String>,
158 calls: Arc<Mutex<Vec<(String, TimeMatrixCall<DynamicSample>)>>>,
159 ) -> Self {
160 MockTimeMatrix { name: name.into(), calls, phantom: PhantomData }
161 }
162}
163
164impl<T> Interpolator for MockTimeMatrix<T> {
165 fn interpolate(&mut self, timestamp: Timestamp) -> Result<(), FoldError> {
166 self.calls.lock().push((self.name.clone(), TimeMatrixCall::Interpolate(timestamp)));
167 Ok(())
168 }
169
170 fn interpolate_and_get_buffers(
171 &mut self,
172 timestamp: Timestamp,
173 ) -> Result<SerializedBuffer, FoldError> {
174 self.interpolate(timestamp)?;
175 Ok(SerializedBuffer { data_semantic: "mock".to_string(), data: vec![] })
176 }
177}
178
179impl<T> MatrixSampler<T> for MockTimeMatrix<T>
180where
181 T: 'static + Send,
182{
183 fn fold(&mut self, sample: Timed<T>) -> Result<(), FoldError> {
184 let sample = sample.map(|v| Box::new(v) as DynamicSample);
185 self.calls.lock().push((self.name.clone(), TimeMatrixCall::Fold(sample)));
186 Ok(())
187 }
188}