diff options
Diffstat (limited to 'third_party/rust/tokio/tests/time_pause.rs')
-rw-r--r-- | third_party/rust/tokio/tests/time_pause.rs | 326 |
1 files changed, 326 insertions, 0 deletions
diff --git a/third_party/rust/tokio/tests/time_pause.rs b/third_party/rust/tokio/tests/time_pause.rs new file mode 100644 index 0000000000..02e050a2dc --- /dev/null +++ b/third_party/rust/tokio/tests/time_pause.rs @@ -0,0 +1,326 @@ +#![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_err, assert_pending, assert_ready, assert_ready_eq, task}; + +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(); +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[should_panic] +async fn pause_time_in_main_threads() { + tokio::time::pause(); +} + +#[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) +} |