#![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(target_os = "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(target_os = "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_attr(panic = "abort", ignore)] #[cfg(all(feature = "full", not(target_os = "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 { 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>>), AfterAdvance, } struct Tester { sleep: Pin>, state: State, before: Option, poll: bool, } impl Future for Tester { type Output = (); fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 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) -> Poll { interval.enter(|cx, mut interval| interval.poll_tick(cx)) } fn ms(n: u64) -> Duration { Duration::from_millis(n) }