omaha_client/time/
timers.rs

1// Copyright 2020 The Fuchsia Authors
2//
3// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
4// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
5// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
6// This file may not be copied, modified, or distributed except according to
7// those terms.
8
9use 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        /// Wait until at least one of the given time bounds has been reached.
35        fn wait_until(&mut self, _time: impl Into<PartialComplexTime>) -> BoxFuture<'static, ()> {
36            future::ready(()).boxed()
37        }
38
39        /// Wait for the given duration (from now).
40        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    /// A mocked timer that will assert expected waits, and block forever after it has used them.
69    #[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        /// Expect a wait until the given PartialComplexTime.
84        pub fn expect_until(&mut self, time: impl Into<PartialComplexTime>) {
85            self.expected_waits
86                .push_back(ExpectedWait::Until(time.into()))
87        }
88
89        /// Expect a wait for the given Duration.
90        pub fn expect_for(&mut self, duration: Duration) {
91            self.expected_waits
92                .push_back(ExpectedWait::For(duration, duration))
93        }
94
95        /// Add a new wait to the end of the expected durations.
96        pub fn expect_for_range(&mut self, min: Duration, max: Duration) {
97            self.expected_waits.push_back(ExpectedWait::For(min, max))
98        }
99
100        /// Check that a given Wait was expected.  If no expected waits have been set, then
101        /// do nothing after recording the Wait.
102        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                // No more expected durations left, blocking the Timer forever.
127                // Users of MockTimer are expected to use run_until_stalled()
128                // if timer is used in an infinite loop.
129                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        /// Wait until at least one of the given time bounds has been reached.
146        fn wait_until(&mut self, time: impl Into<PartialComplexTime>) -> BoxFuture<'static, ()> {
147            self.handle_wait(RequestedWait::Until(time.into()))
148        }
149
150        /// Wait for the given duration (from now).
151        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            // Make sure all the expected durations have been waited on.
159            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    /// A mock timer that will notify a channel when creating a timer.
290    #[derive(Debug)]
291    pub struct BlockingTimer {
292        chan: mpsc::Sender<BlockedTimer>,
293    }
294
295    /// An omaha state machine timer waiting to be unblocked. Dropping a BlockedTimer will cause
296    /// the timer to panic.
297    #[derive(Debug)]
298    pub struct BlockedTimer {
299        wait: RequestedWait,
300        unblock: oneshot::Sender<()>,
301    }
302
303    impl BlockingTimer {
304        /// Returns a new BlockingTimer and a channel to receive BlockedTimer instances.
305        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        /// The requested duration of this timer.
330        pub fn requested_wait(&self) -> RequestedWait {
331            self.wait
332        }
333
334        /// Unblock the timer, panicing if it no longer exists.
335        pub fn unblock(self) {
336            self.unblock.send(()).unwrap()
337        }
338    }
339
340    impl Timer for BlockingTimer {
341        /// Wait until at least one of the given time bounds has been reached.
342        fn wait_until(&mut self, time: impl Into<PartialComplexTime>) -> BoxFuture<'static, ()> {
343            self.wait(RequestedWait::Until(time.into()))
344        }
345
346        /// Wait for the given duration (from now).
347        fn wait_for(&mut self, duration: Duration) -> BoxFuture<'static, ()> {
348            self.wait(RequestedWait::For(duration))
349        }
350    }
351
352    /// A mock timer that will block forever.
353    #[derive(Debug)]
354    pub struct InfiniteTimer;
355
356    impl Timer for InfiniteTimer {
357        /// Wait until at least one of the given time bounds has been reached.
358        fn wait_until(&mut self, _time: impl Into<PartialComplexTime>) -> BoxFuture<'static, ()> {
359            future::pending().boxed()
360        }
361
362        /// Wait for the given duration (from now).
363        fn wait_for(&mut self, _duration: Duration) -> BoxFuture<'static, ()> {
364            future::pending().boxed()
365        }
366    }
367}