tokio01_test/
clock.rs

1//! A mocked clock for use with `tokio_timer` based futures.
2//!
3//! # Example
4//!
5//! ```
6//! # #[macro_use] extern crate tokio01_test;
7//! # extern crate futures;
8//! # extern crate tokio_timer;
9//! # use tokio01_test::clock;
10//! # use tokio_timer::Delay;
11//! # use std::time::Duration;
12//! # use futures::Future;
13//! clock::mock(|handle| {
14//!     let mut delay = Delay::new(handle.now() + Duration::from_secs(1));
15//!
16//!     assert_not_ready!(delay.poll());
17//!
18//!     handle.advance(Duration::from_secs(1));
19//!
20//!     assert_ready!(delay.poll());
21//! });
22//! ```
23
24use futures::{future::lazy, Future};
25use std::marker::PhantomData;
26use std::rc::Rc;
27use std::sync::{Arc, Mutex};
28use std::time::{Duration, Instant};
29use tokio_executor::park::{Park, Unpark};
30use tokio_timer::clock::{Clock, Now};
31use tokio_timer::Timer;
32
33/// Run the provided closure with a `MockClock` that starts at the current time.
34pub fn mock<F, R>(f: F) -> R
35where
36    F: FnOnce(&mut Handle) -> R,
37{
38    let mut mock = MockClock::new();
39    mock.enter(f)
40}
41
42/// Run the provided closure with a `MockClock` that starts at the provided `Instant`.
43pub fn mock_at<F, R>(instant: Instant, f: F) -> R
44where
45    F: FnOnce(&mut Handle) -> R,
46{
47    let mut mock = MockClock::with_instant(instant);
48    mock.enter(f)
49}
50
51/// Mock clock for use with `tokio-timer` futures.
52///
53/// A mock timer that is able to advance and wake after a
54/// certain duration.
55#[derive(Debug)]
56pub struct MockClock {
57    time: MockTime,
58    clock: Clock,
59}
60
61/// A handle to the `MockClock`.
62#[derive(Debug)]
63pub struct Handle {
64    timer: Timer<MockPark>,
65    time: MockTime,
66}
67
68type Inner = Arc<Mutex<State>>;
69
70#[derive(Debug, Clone)]
71struct MockTime {
72    inner: Inner,
73    _pd: PhantomData<Rc<()>>,
74}
75
76#[derive(Debug)]
77struct MockNow {
78    inner: Inner,
79}
80
81#[derive(Debug)]
82struct MockPark {
83    inner: Inner,
84    _pd: PhantomData<Rc<()>>,
85}
86
87#[derive(Debug)]
88struct MockUnpark {
89    inner: Inner,
90}
91
92#[derive(Debug)]
93struct State {
94    base: Instant,
95    advance: Duration,
96    unparked: bool,
97    park_for: Option<Duration>,
98}
99
100impl MockClock {
101    /// Create a new `MockClock` with the current time.
102    pub fn new() -> Self {
103        MockClock::with_instant(Instant::now())
104    }
105
106    /// Create a `MockClock` with its current time at a duration from now
107    ///
108    /// This will create a clock with `Instant::now() + duration` as the current time.
109    pub fn with_duration(duration: Duration) -> Self {
110        let instant = Instant::now() + duration;
111        MockClock::with_instant(instant)
112    }
113
114    /// Create a `MockClock` that sets its current time as the `Instant` provided.
115    pub fn with_instant(instant: Instant) -> Self {
116        let time = MockTime::new(instant);
117        let clock = Clock::new_with_now(time.mock_now());
118
119        MockClock { time, clock }
120    }
121
122    /// Enter the `MockClock` context.
123    pub fn enter<F, R>(&mut self, f: F) -> R
124    where
125        F: FnOnce(&mut Handle) -> R,
126    {
127        let mut enter = ::tokio_executor::enter().unwrap();
128
129        ::tokio_timer::clock::with_default(&self.clock, &mut enter, |enter| {
130            let park = self.time.mock_park();
131            let timer = Timer::new(park);
132            let handle = timer.handle();
133            let time = self.time.clone();
134
135            ::tokio_timer::with_default(&handle, enter, |_| {
136                let mut handle = Handle::new(timer, time);
137                lazy(|| Ok::<_, ()>(f(&mut handle))).wait().unwrap()
138            })
139        })
140    }
141}
142
143impl Handle {
144    pub(self) fn new(timer: Timer<MockPark>, time: MockTime) -> Self {
145        Handle { timer, time }
146    }
147
148    /// Turn the internal timer and mock park for the provided duration.
149    pub fn turn(&mut self, duration: Option<Duration>) {
150        self.timer.turn(duration).unwrap();
151    }
152
153    /// Advance the `MockClock` by the provided duration.
154    pub fn advance(&mut self, duration: Duration) {
155        let inner = self.timer.get_park().inner.clone();
156        let deadline = inner.lock().unwrap().now() + duration;
157
158        while inner.lock().unwrap().now() < deadline {
159            let dur = deadline - inner.lock().unwrap().now();
160            self.turn(Some(dur));
161        }
162    }
163
164    /// Get the currently mocked time
165    pub fn now(&mut self) -> Instant {
166        self.time.now()
167    }
168}
169
170impl MockTime {
171    pub(crate) fn new(now: Instant) -> MockTime {
172        let state = State {
173            base: now,
174            advance: Duration::default(),
175            unparked: false,
176            park_for: None,
177        };
178
179        MockTime {
180            inner: Arc::new(Mutex::new(state)),
181            _pd: PhantomData,
182        }
183    }
184
185    pub(crate) fn mock_now(&self) -> MockNow {
186        let inner = self.inner.clone();
187        MockNow { inner }
188    }
189
190    pub(crate) fn mock_park(&self) -> MockPark {
191        let inner = self.inner.clone();
192        MockPark {
193            inner,
194            _pd: PhantomData,
195        }
196    }
197
198    pub(crate) fn now(&self) -> Instant {
199        self.inner.lock().unwrap().now()
200    }
201}
202
203impl State {
204    fn now(&self) -> Instant {
205        self.base + self.advance
206    }
207
208    fn advance(&mut self, duration: Duration) {
209        self.advance += duration;
210    }
211}
212
213impl Park for MockPark {
214    type Unpark = MockUnpark;
215    type Error = ();
216
217    fn unpark(&self) -> Self::Unpark {
218        let inner = self.inner.clone();
219        MockUnpark { inner }
220    }
221
222    fn park(&mut self) -> Result<(), Self::Error> {
223        let mut inner = self.inner.lock().map_err(|_| ())?;
224
225        let duration = inner.park_for.take().expect("call park_for first");
226
227        inner.advance(duration);
228        Ok(())
229    }
230
231    fn park_timeout(&mut self, duration: Duration) -> Result<(), Self::Error> {
232        let mut inner = self.inner.lock().unwrap();
233
234        if let Some(duration) = inner.park_for.take() {
235            inner.advance(duration);
236        } else {
237            inner.advance(duration);
238        }
239
240        Ok(())
241    }
242}
243
244impl Unpark for MockUnpark {
245    fn unpark(&self) {
246        if let Ok(mut inner) = self.inner.lock() {
247            inner.unparked = true;
248        }
249    }
250}
251
252impl Now for MockNow {
253    fn now(&self) -> Instant {
254        self.inner.lock().unwrap().now()
255    }
256}