omaha_client/time/
timers.rs
1use std::time::Duration;
10
11use super::PartialComplexTime;
12
13#[derive(Copy, Clone, Debug, PartialEq, Eq)]
14pub enum ExpectedWait {
15 Until(PartialComplexTime),
16 For(Duration, Duration),
17}
18
19#[derive(Copy, Clone, Debug, PartialEq, Eq)]
20pub enum RequestedWait {
21 Until(PartialComplexTime),
22 For(Duration),
23}
24
25pub use stub::StubTimer;
26
27mod stub {
28 use super::super::*;
29 use futures::future::BoxFuture;
30 use futures::prelude::*;
31
32 pub struct StubTimer;
33 impl Timer for StubTimer {
34 fn wait_until(&mut self, _time: impl Into<PartialComplexTime>) -> BoxFuture<'static, ()> {
36 future::ready(()).boxed()
37 }
38
39 fn wait_for(&mut self, _duration: Duration) -> BoxFuture<'static, ()> {
41 future::ready(()).boxed()
42 }
43 }
44
45 #[cfg(test)]
46 mod tests {
47 use super::*;
48 use futures::executor::block_on;
49 use std::time::Duration;
50
51 #[test]
52 fn test_wait_always_ready() {
53 block_on(StubTimer.wait_until(StandardTimeSource.now() + Duration::from_secs(5555)));
54 block_on(StubTimer.wait_for(Duration::from_secs(5555)));
55 }
56 }
57}
58
59pub use mock::MockTimer;
60
61mod mock {
62 use super::super::*;
63 use super::{ExpectedWait, RequestedWait};
64 use futures::future::BoxFuture;
65 use futures::prelude::*;
66 use std::{cell::RefCell, collections::VecDeque, fmt::Debug, rc::Rc};
67
68 #[derive(Debug)]
70 pub struct MockTimer {
71 expected_waits: VecDeque<ExpectedWait>,
72 requested_waits: Rc<RefCell<Vec<RequestedWait>>>,
73 }
74
75 impl MockTimer {
76 pub fn new() -> Self {
77 MockTimer {
78 expected_waits: VecDeque::new(),
79 requested_waits: Rc::new(RefCell::new(Vec::new())),
80 }
81 }
82
83 pub fn expect_until(&mut self, time: impl Into<PartialComplexTime>) {
85 self.expected_waits
86 .push_back(ExpectedWait::Until(time.into()))
87 }
88
89 pub fn expect_for(&mut self, duration: Duration) {
91 self.expected_waits
92 .push_back(ExpectedWait::For(duration, duration))
93 }
94
95 pub fn expect_for_range(&mut self, min: Duration, max: Duration) {
97 self.expected_waits.push_back(ExpectedWait::For(min, max))
98 }
99
100 fn handle_wait(&mut self, requested: RequestedWait) -> BoxFuture<'static, ()> {
103 if let Some(expected) = self.expected_waits.pop_front() {
104 match (requested, expected) {
105 (RequestedWait::For(duration), ExpectedWait::For(min, max)) => {
106 assert!(
107 duration >= min && duration <= max,
108 "{duration:?} out of range [{min:?}, {max:?}]",
109 );
110 }
111 (RequestedWait::Until(requested), ExpectedWait::Until(expected)) => {
112 assert!(
113 requested == expected,
114 "wait_until() called with wrong time: {requested}, expected {expected}"
115 );
116 }
117 (requested, expected) => {
118 panic!(
119 "Timer called with wrong wait: {requested:?}, expected {expected:?}"
120 );
121 }
122 }
123 self.requested_waits.borrow_mut().push(requested);
124 future::ready(()).boxed()
125 } else {
126 future::pending().boxed()
130 }
131 }
132
133 pub fn get_requested_waits_view(&self) -> Rc<RefCell<Vec<RequestedWait>>> {
134 Rc::clone(&self.requested_waits)
135 }
136 }
137
138 impl Default for MockTimer {
139 fn default() -> Self {
140 Self::new()
141 }
142 }
143
144 impl Timer for MockTimer {
145 fn wait_until(&mut self, time: impl Into<PartialComplexTime>) -> BoxFuture<'static, ()> {
147 self.handle_wait(RequestedWait::Until(time.into()))
148 }
149
150 fn wait_for(&mut self, duration: Duration) -> BoxFuture<'static, ()> {
152 self.handle_wait(RequestedWait::For(duration))
153 }
154 }
155
156 impl Drop for MockTimer {
157 fn drop(&mut self) {
158 assert!(self.expected_waits.is_empty());
160 }
161 }
162
163 #[cfg(test)]
164 mod tests {
165 use super::*;
166 use futures::executor::{block_on, LocalPool};
167 use futures::task::LocalSpawnExt;
168 use std::time::Duration;
169
170 #[test]
171 fn test_wait_until_expected() {
172 let mock_time = MockTimeSource::new_from_now();
173 let time = mock_time.now() + Duration::from_secs(5555);
174
175 let mut timer = MockTimer::new();
176 timer.expect_until(time);
177
178 block_on(timer.wait_until(time));
179 }
180
181 #[test]
182 fn test_wait_for_expected() {
183 let mut timer = MockTimer::new();
184 timer.expect_for(Duration::from_secs(5555));
185
186 block_on(timer.wait_for(Duration::from_secs(5555)));
187 }
188
189 #[test]
190 fn test_wait_for_twice() {
191 let mut timer = MockTimer::new();
192 timer.expect_for(Duration::from_secs(5555));
193 timer.expect_for(Duration::from_secs(6666));
194
195 block_on(async {
196 timer.wait_for(Duration::from_secs(5555)).await;
197 timer.wait_for(Duration::from_secs(6666)).await;
198 });
199 }
200
201 #[test]
202 fn test_wait_for_loop() {
203 let mut timer = MockTimer::new();
204 timer.expect_for(Duration::from_secs(1));
205 timer.expect_for(Duration::from_secs(2));
206 timer.expect_for(Duration::from_secs(3));
207
208 let mut pool = LocalPool::new();
209 pool.spawner()
210 .spawn_local(async move {
211 let mut i = 1;
212 loop {
213 timer.wait_for(Duration::from_secs(i)).await;
214 i += 1;
215 }
216 })
217 .unwrap();
218 pool.run_until_stalled();
219 }
220
221 #[test]
222 fn test_wait_for_expected_duration() {
223 let mut timer = MockTimer::new();
224 timer.expect_for_range(Duration::from_secs(10), Duration::from_secs(20));
225
226 block_on(timer.wait_for(Duration::from_secs(15)));
227 }
228
229 #[test]
230 #[should_panic(expected = "out of range")]
231 fn test_wait_for_expected_duration_out_of_range_low() {
232 let mut timer = MockTimer::new();
233 timer.expect_for_range(Duration::from_secs(10), Duration::from_secs(20));
234
235 block_on(timer.wait_for(Duration::from_secs(3)));
236 }
237
238 #[test]
239 #[should_panic(expected = "out of range")]
240 fn test_wait_for_expected_duration_out_of_range_high() {
241 let mut timer = MockTimer::new();
242 timer.expect_for_range(Duration::from_secs(10), Duration::from_secs(20));
243
244 block_on(timer.wait_for(Duration::from_secs(30)));
245 }
246
247 #[test]
248 #[should_panic(expected = "5555")]
249 fn test_wait_for_wrong_duration() {
250 let mut timer = MockTimer::new();
251 timer.expect_for(Duration::from_secs(5555));
252
253 block_on(timer.wait_for(Duration::from_secs(6666)));
254 }
255
256 #[test]
257 #[should_panic(expected = "is_empty()")]
258 fn test_expect_more_wait_for() {
259 let mut timer = MockTimer::new();
260 timer.expect_for(Duration::from_secs(5555));
261 timer.expect_for(Duration::from_secs(6666));
262
263 block_on(timer.wait_for(Duration::from_secs(5555)));
264 }
265
266 #[test]
267 #[should_panic(expected = "Timer called with wrong wait")]
268 fn test_wait_for_wrong_wait() {
269 let mock_time = MockTimeSource::new_from_now();
270 let time = mock_time.now() + Duration::from_secs(5555);
271
272 let mut timer = MockTimer::new();
273 timer.expect_until(time);
274
275 block_on(timer.wait_for(Duration::from_secs(6666)));
276 }
277 }
278}
279
280pub use blocking::{BlockedTimer, BlockingTimer, InfiniteTimer};
281
282mod blocking {
283 use super::super::*;
284 use super::RequestedWait;
285 use futures::channel::{mpsc, oneshot};
286 use futures::future::BoxFuture;
287 use futures::prelude::*;
288
289 #[derive(Debug)]
291 pub struct BlockingTimer {
292 chan: mpsc::Sender<BlockedTimer>,
293 }
294
295 #[derive(Debug)]
298 pub struct BlockedTimer {
299 wait: RequestedWait,
300 unblock: oneshot::Sender<()>,
301 }
302
303 impl BlockingTimer {
304 pub fn new() -> (Self, mpsc::Receiver<BlockedTimer>) {
306 let (send, recv) = mpsc::channel(0);
307 (Self { chan: send }, recv)
308 }
309
310 fn wait(&mut self, wait: RequestedWait) -> BoxFuture<'static, ()> {
311 let mut chan = self.chan.clone();
312
313 async move {
314 let (send, recv) = oneshot::channel();
315 chan.send(BlockedTimer {
316 wait,
317 unblock: send,
318 })
319 .await
320 .unwrap();
321
322 recv.await.unwrap();
323 }
324 .boxed()
325 }
326 }
327
328 impl BlockedTimer {
329 pub fn requested_wait(&self) -> RequestedWait {
331 self.wait
332 }
333
334 pub fn unblock(self) {
336 self.unblock.send(()).unwrap()
337 }
338 }
339
340 impl Timer for BlockingTimer {
341 fn wait_until(&mut self, time: impl Into<PartialComplexTime>) -> BoxFuture<'static, ()> {
343 self.wait(RequestedWait::Until(time.into()))
344 }
345
346 fn wait_for(&mut self, duration: Duration) -> BoxFuture<'static, ()> {
348 self.wait(RequestedWait::For(duration))
349 }
350 }
351
352 #[derive(Debug)]
354 pub struct InfiniteTimer;
355
356 impl Timer for InfiniteTimer {
357 fn wait_until(&mut self, _time: impl Into<PartialComplexTime>) -> BoxFuture<'static, ()> {
359 future::pending().boxed()
360 }
361
362 fn wait_for(&mut self, _duration: Duration) -> BoxFuture<'static, ()> {
364 future::pending().boxed()
365 }
366 }
367}