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