| #![warn(rust_2018_idioms)] |
| #![cfg(feature = "full")] |
| |
| use rand::SeedableRng; |
| use rand::{rngs::StdRng, Rng}; |
| use tokio::time::{self, Duration, Instant, Sleep}; |
| use tokio_test::{assert_elapsed, assert_pending, assert_ready, assert_ready_eq, task}; |
| |
| #[cfg(not(tokio_wasi))] |
| use tokio_test::assert_err; |
| |
| use std::{ |
| future::Future, |
| pin::Pin, |
| task::{Context, Poll}, |
| }; |
| |
| #[tokio::test] |
| async fn pause_time_in_main() { |
| tokio::time::pause(); |
| } |
| |
| #[tokio::test] |
| async fn pause_time_in_task() { |
| let t = tokio::spawn(async { |
| tokio::time::pause(); |
| }); |
| |
| t.await.unwrap(); |
| } |
| |
| #[cfg(all(feature = "full", not(tokio_wasi)))] // Wasi doesn't support threads |
| #[tokio::test(flavor = "multi_thread", worker_threads = 1)] |
| #[should_panic] |
| async fn pause_time_in_main_threads() { |
| tokio::time::pause(); |
| } |
| |
| #[cfg(all(feature = "full", not(tokio_wasi)))] // Wasi doesn't support threads |
| #[tokio::test(flavor = "multi_thread", worker_threads = 1)] |
| async fn pause_time_in_spawn_threads() { |
| let t = tokio::spawn(async { |
| tokio::time::pause(); |
| }); |
| |
| assert_err!(t.await); |
| } |
| |
| #[test] |
| fn paused_time_is_deterministic() { |
| let run_1 = paused_time_stress_run(); |
| let run_2 = paused_time_stress_run(); |
| |
| assert_eq!(run_1, run_2); |
| } |
| |
| #[tokio::main(flavor = "current_thread", start_paused = true)] |
| async fn paused_time_stress_run() -> Vec<Duration> { |
| let mut rng = StdRng::seed_from_u64(1); |
| |
| let mut times = vec![]; |
| let start = Instant::now(); |
| for _ in 0..10_000 { |
| let sleep = rng.gen_range(Duration::from_secs(0)..Duration::from_secs(1)); |
| time::sleep(sleep).await; |
| times.push(start.elapsed()); |
| } |
| |
| times |
| } |
| |
| #[tokio::test(start_paused = true)] |
| async fn advance_after_poll() { |
| time::sleep(ms(1)).await; |
| |
| let start = Instant::now(); |
| |
| let mut sleep = task::spawn(time::sleep_until(start + ms(300))); |
| |
| assert_pending!(sleep.poll()); |
| |
| let before = Instant::now(); |
| time::advance(ms(100)).await; |
| assert_elapsed!(before, ms(100)); |
| |
| assert_pending!(sleep.poll()); |
| } |
| |
| #[tokio::test(start_paused = true)] |
| async fn sleep_no_poll() { |
| let start = Instant::now(); |
| |
| // TODO: Skip this |
| time::advance(ms(1)).await; |
| |
| let mut sleep = task::spawn(time::sleep_until(start + ms(300))); |
| |
| let before = Instant::now(); |
| time::advance(ms(100)).await; |
| assert_elapsed!(before, ms(100)); |
| |
| assert_pending!(sleep.poll()); |
| } |
| |
| enum State { |
| Begin, |
| AwaitingAdvance(Pin<Box<dyn Future<Output = ()>>>), |
| AfterAdvance, |
| } |
| |
| struct Tester { |
| sleep: Pin<Box<Sleep>>, |
| state: State, |
| before: Option<Instant>, |
| poll: bool, |
| } |
| |
| impl Future for Tester { |
| type Output = (); |
| |
| fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { |
| match &mut self.state { |
| State::Begin => { |
| if self.poll { |
| assert_pending!(self.sleep.as_mut().poll(cx)); |
| } |
| self.before = Some(Instant::now()); |
| let advance_fut = Box::pin(time::advance(ms(100))); |
| self.state = State::AwaitingAdvance(advance_fut); |
| self.poll(cx) |
| } |
| State::AwaitingAdvance(ref mut advance_fut) => match advance_fut.as_mut().poll(cx) { |
| Poll::Pending => Poll::Pending, |
| Poll::Ready(()) => { |
| self.state = State::AfterAdvance; |
| self.poll(cx) |
| } |
| }, |
| State::AfterAdvance => { |
| assert_elapsed!(self.before.unwrap(), ms(100)); |
| |
| assert_pending!(self.sleep.as_mut().poll(cx)); |
| |
| Poll::Ready(()) |
| } |
| } |
| } |
| } |
| |
| #[tokio::test(start_paused = true)] |
| async fn sleep_same_task() { |
| let start = Instant::now(); |
| |
| // TODO: Skip this |
| time::advance(ms(1)).await; |
| |
| let sleep = Box::pin(time::sleep_until(start + ms(300))); |
| |
| Tester { |
| sleep, |
| state: State::Begin, |
| before: None, |
| poll: true, |
| } |
| .await; |
| } |
| |
| #[tokio::test(start_paused = true)] |
| async fn sleep_same_task_no_poll() { |
| let start = Instant::now(); |
| |
| // TODO: Skip this |
| time::advance(ms(1)).await; |
| |
| let sleep = Box::pin(time::sleep_until(start + ms(300))); |
| |
| Tester { |
| sleep, |
| state: State::Begin, |
| before: None, |
| poll: false, |
| } |
| .await; |
| } |
| |
| #[tokio::test(start_paused = true)] |
| async fn interval() { |
| let start = Instant::now(); |
| |
| // TODO: Skip this |
| time::advance(ms(1)).await; |
| |
| let mut i = task::spawn(time::interval_at(start, ms(300))); |
| |
| assert_ready_eq!(poll_next(&mut i), start); |
| assert_pending!(poll_next(&mut i)); |
| |
| let before = Instant::now(); |
| time::advance(ms(100)).await; |
| assert_elapsed!(before, ms(100)); |
| assert_pending!(poll_next(&mut i)); |
| |
| let before = Instant::now(); |
| time::advance(ms(200)).await; |
| assert_elapsed!(before, ms(200)); |
| assert_ready_eq!(poll_next(&mut i), start + ms(300)); |
| assert_pending!(poll_next(&mut i)); |
| |
| let before = Instant::now(); |
| time::advance(ms(400)).await; |
| assert_elapsed!(before, ms(400)); |
| assert_ready_eq!(poll_next(&mut i), start + ms(600)); |
| assert_pending!(poll_next(&mut i)); |
| |
| let before = Instant::now(); |
| time::advance(ms(500)).await; |
| assert_elapsed!(before, ms(500)); |
| assert_ready_eq!(poll_next(&mut i), start + ms(900)); |
| assert_ready_eq!(poll_next(&mut i), start + ms(1200)); |
| assert_pending!(poll_next(&mut i)); |
| } |
| |
| #[tokio::test(start_paused = true)] |
| async fn test_time_advance_sub_ms() { |
| let now = Instant::now(); |
| |
| let dur = Duration::from_micros(51_592); |
| time::advance(dur).await; |
| |
| assert_eq!(now.elapsed(), dur); |
| |
| let now = Instant::now(); |
| let dur = Duration::from_micros(1); |
| time::advance(dur).await; |
| |
| assert_eq!(now.elapsed(), dur); |
| } |
| |
| #[tokio::test(start_paused = true)] |
| async fn test_time_advance_3ms_and_change() { |
| let now = Instant::now(); |
| |
| let dur = Duration::from_micros(3_141_592); |
| time::advance(dur).await; |
| |
| assert_eq!(now.elapsed(), dur); |
| |
| let now = Instant::now(); |
| let dur = Duration::from_micros(3_123_456); |
| time::advance(dur).await; |
| |
| assert_eq!(now.elapsed(), dur); |
| } |
| |
| #[tokio::test(start_paused = true)] |
| async fn regression_3710_with_submillis_advance() { |
| let start = Instant::now(); |
| |
| time::advance(Duration::from_millis(1)).await; |
| |
| let mut sleep = task::spawn(time::sleep_until(start + Duration::from_secs(60))); |
| |
| assert_pending!(sleep.poll()); |
| |
| let before = Instant::now(); |
| let dur = Duration::from_micros(51_592); |
| time::advance(dur).await; |
| assert_eq!(before.elapsed(), dur); |
| |
| assert_pending!(sleep.poll()); |
| } |
| |
| #[tokio::test(start_paused = true)] |
| async fn exact_1ms_advance() { |
| let now = Instant::now(); |
| |
| let dur = Duration::from_millis(1); |
| time::advance(dur).await; |
| |
| assert_eq!(now.elapsed(), dur); |
| |
| let now = Instant::now(); |
| let dur = Duration::from_millis(1); |
| time::advance(dur).await; |
| |
| assert_eq!(now.elapsed(), dur); |
| } |
| |
| #[tokio::test(start_paused = true)] |
| async fn advance_once_with_timer() { |
| let mut sleep = task::spawn(time::sleep(Duration::from_millis(1))); |
| assert_pending!(sleep.poll()); |
| |
| time::advance(Duration::from_micros(250)).await; |
| assert_pending!(sleep.poll()); |
| |
| time::advance(Duration::from_micros(1500)).await; |
| |
| assert!(sleep.is_woken()); |
| assert_ready!(sleep.poll()); |
| } |
| |
| #[tokio::test(start_paused = true)] |
| async fn advance_multi_with_timer() { |
| // Round to the nearest ms |
| // time::sleep(Duration::from_millis(1)).await; |
| |
| let mut sleep = task::spawn(time::sleep(Duration::from_millis(1))); |
| assert_pending!(sleep.poll()); |
| |
| time::advance(Duration::from_micros(250)).await; |
| assert_pending!(sleep.poll()); |
| |
| time::advance(Duration::from_micros(250)).await; |
| assert_pending!(sleep.poll()); |
| |
| time::advance(Duration::from_micros(250)).await; |
| assert_pending!(sleep.poll()); |
| |
| time::advance(Duration::from_micros(250)).await; |
| assert!(sleep.is_woken()); |
| assert_ready!(sleep.poll()); |
| } |
| |
| fn poll_next(interval: &mut task::Spawn<time::Interval>) -> Poll<Instant> { |
| interval.enter(|cx, mut interval| interval.poll_tick(cx)) |
| } |
| |
| fn ms(n: u64) -> Duration { |
| Duration::from_millis(n) |
| } |