omaha_client/time/
timers.rs1use 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.push_back(ExpectedWait::Until(time.into()))
86 }
87
88 pub fn expect_for(&mut self, duration: Duration) {
90 self.expected_waits.push_back(ExpectedWait::For(duration, duration))
91 }
92
93 pub fn expect_for_range(&mut self, min: Duration, max: Duration) {
95 self.expected_waits.push_back(ExpectedWait::For(min, max))
96 }
97
98 fn handle_wait(&mut self, requested: RequestedWait) -> BoxFuture<'static, ()> {
101 if let Some(expected) = self.expected_waits.pop_front() {
102 match (requested, expected) {
103 (RequestedWait::For(duration), ExpectedWait::For(min, max)) => {
104 assert!(
105 duration >= min && duration <= max,
106 "{duration:?} out of range [{min:?}, {max:?}]",
107 );
108 }
109 (RequestedWait::Until(requested), ExpectedWait::Until(expected)) => {
110 assert!(
111 requested == expected,
112 "wait_until() called with wrong time: {requested}, expected {expected}"
113 );
114 }
115 (requested, expected) => {
116 panic!(
117 "Timer called with wrong wait: {requested:?}, expected {expected:?}"
118 );
119 }
120 }
121 self.requested_waits.borrow_mut().push(requested);
122 future::ready(()).boxed()
123 } else {
124 future::pending().boxed()
128 }
129 }
130
131 pub fn get_requested_waits_view(&self) -> Rc<RefCell<Vec<RequestedWait>>> {
132 Rc::clone(&self.requested_waits)
133 }
134 }
135
136 impl Default for MockTimer {
137 fn default() -> Self {
138 Self::new()
139 }
140 }
141
142 impl Timer for MockTimer {
143 fn wait_until(&mut self, time: impl Into<PartialComplexTime>) -> BoxFuture<'static, ()> {
145 self.handle_wait(RequestedWait::Until(time.into()))
146 }
147
148 fn wait_for(&mut self, duration: Duration) -> BoxFuture<'static, ()> {
150 self.handle_wait(RequestedWait::For(duration))
151 }
152 }
153
154 impl Drop for MockTimer {
155 fn drop(&mut self) {
156 assert!(self.expected_waits.is_empty());
158 }
159 }
160
161 #[cfg(test)]
162 mod tests {
163 use super::*;
164 use futures::executor::{LocalPool, block_on};
165 use futures::task::LocalSpawnExt;
166 use std::time::Duration;
167
168 #[test]
169 fn test_wait_until_expected() {
170 let mock_time = MockTimeSource::new_from_now();
171 let time = mock_time.now() + Duration::from_secs(5555);
172
173 let mut timer = MockTimer::new();
174 timer.expect_until(time);
175
176 block_on(timer.wait_until(time));
177 }
178
179 #[test]
180 fn test_wait_for_expected() {
181 let mut timer = MockTimer::new();
182 timer.expect_for(Duration::from_secs(5555));
183
184 block_on(timer.wait_for(Duration::from_secs(5555)));
185 }
186
187 #[test]
188 fn test_wait_for_twice() {
189 let mut timer = MockTimer::new();
190 timer.expect_for(Duration::from_secs(5555));
191 timer.expect_for(Duration::from_secs(6666));
192
193 block_on(async {
194 timer.wait_for(Duration::from_secs(5555)).await;
195 timer.wait_for(Duration::from_secs(6666)).await;
196 });
197 }
198
199 #[test]
200 fn test_wait_for_loop() {
201 let mut timer = MockTimer::new();
202 timer.expect_for(Duration::from_secs(1));
203 timer.expect_for(Duration::from_secs(2));
204 timer.expect_for(Duration::from_secs(3));
205
206 let mut pool = LocalPool::new();
207 pool.spawner()
208 .spawn_local(async move {
209 let mut i = 1;
210 loop {
211 timer.wait_for(Duration::from_secs(i)).await;
212 i += 1;
213 }
214 })
215 .unwrap();
216 pool.run_until_stalled();
217 }
218
219 #[test]
220 fn test_wait_for_expected_duration() {
221 let mut timer = MockTimer::new();
222 timer.expect_for_range(Duration::from_secs(10), Duration::from_secs(20));
223
224 block_on(timer.wait_for(Duration::from_secs(15)));
225 }
226
227 #[test]
228 #[should_panic(expected = "out of range")]
229 fn test_wait_for_expected_duration_out_of_range_low() {
230 let mut timer = MockTimer::new();
231 timer.expect_for_range(Duration::from_secs(10), Duration::from_secs(20));
232
233 block_on(timer.wait_for(Duration::from_secs(3)));
234 }
235
236 #[test]
237 #[should_panic(expected = "out of range")]
238 fn test_wait_for_expected_duration_out_of_range_high() {
239 let mut timer = MockTimer::new();
240 timer.expect_for_range(Duration::from_secs(10), Duration::from_secs(20));
241
242 block_on(timer.wait_for(Duration::from_secs(30)));
243 }
244
245 #[test]
246 #[should_panic(expected = "5555")]
247 fn test_wait_for_wrong_duration() {
248 let mut timer = MockTimer::new();
249 timer.expect_for(Duration::from_secs(5555));
250
251 block_on(timer.wait_for(Duration::from_secs(6666)));
252 }
253
254 #[test]
255 #[should_panic(expected = "is_empty()")]
256 fn test_expect_more_wait_for() {
257 let mut timer = MockTimer::new();
258 timer.expect_for(Duration::from_secs(5555));
259 timer.expect_for(Duration::from_secs(6666));
260
261 block_on(timer.wait_for(Duration::from_secs(5555)));
262 }
263
264 #[test]
265 #[should_panic(expected = "Timer called with wrong wait")]
266 fn test_wait_for_wrong_wait() {
267 let mock_time = MockTimeSource::new_from_now();
268 let time = mock_time.now() + Duration::from_secs(5555);
269
270 let mut timer = MockTimer::new();
271 timer.expect_until(time);
272
273 block_on(timer.wait_for(Duration::from_secs(6666)));
274 }
275 }
276}
277
278pub use blocking::{BlockedTimer, BlockingTimer, InfiniteTimer};
279
280mod blocking {
281 use super::super::*;
282 use super::RequestedWait;
283 use futures::channel::{mpsc, oneshot};
284 use futures::future::BoxFuture;
285 use futures::prelude::*;
286
287 #[derive(Debug)]
289 pub struct BlockingTimer {
290 chan: mpsc::Sender<BlockedTimer>,
291 }
292
293 #[derive(Debug)]
296 pub struct BlockedTimer {
297 wait: RequestedWait,
298 unblock: oneshot::Sender<()>,
299 }
300
301 impl BlockingTimer {
302 pub fn new() -> (Self, mpsc::Receiver<BlockedTimer>) {
304 let (send, recv) = mpsc::channel(0);
305 (Self { chan: send }, recv)
306 }
307
308 fn wait(&mut self, wait: RequestedWait) -> BoxFuture<'static, ()> {
309 let mut chan = self.chan.clone();
310
311 async move {
312 let (send, recv) = oneshot::channel();
313 chan.send(BlockedTimer { wait, unblock: send }).await.unwrap();
314
315 recv.await.unwrap();
316 }
317 .boxed()
318 }
319 }
320
321 impl BlockedTimer {
322 pub fn requested_wait(&self) -> RequestedWait {
324 self.wait
325 }
326
327 pub fn unblock(self) {
329 self.unblock.send(()).unwrap()
330 }
331 }
332
333 impl Timer for BlockingTimer {
334 fn wait_until(&mut self, time: impl Into<PartialComplexTime>) -> BoxFuture<'static, ()> {
336 self.wait(RequestedWait::Until(time.into()))
337 }
338
339 fn wait_for(&mut self, duration: Duration) -> BoxFuture<'static, ()> {
341 self.wait(RequestedWait::For(duration))
342 }
343 }
344
345 #[derive(Debug)]
347 pub struct InfiniteTimer;
348
349 impl Timer for InfiniteTimer {
350 fn wait_until(&mut self, _time: impl Into<PartialComplexTime>) -> BoxFuture<'static, ()> {
352 future::pending().boxed()
353 }
354
355 fn wait_for(&mut self, _duration: Duration) -> BoxFuture<'static, ()> {
357 future::pending().boxed()
358 }
359 }
360}