diff options
Diffstat (limited to 'third_party/rust/tokio/tests/time_sleep.rs')
-rw-r--r-- | third_party/rust/tokio/tests/time_sleep.rs | 356 |
1 files changed, 356 insertions, 0 deletions
diff --git a/third_party/rust/tokio/tests/time_sleep.rs b/third_party/rust/tokio/tests/time_sleep.rs new file mode 100644 index 0000000000..97cadecb0a --- /dev/null +++ b/third_party/rust/tokio/tests/time_sleep.rs @@ -0,0 +1,356 @@ +#![warn(rust_2018_idioms)] +#![cfg(feature = "full")] + +use std::future::Future; +use std::task::Context; + +use futures::task::noop_waker_ref; + +use tokio::time::{self, Duration, Instant}; +use tokio_test::{assert_elapsed, assert_pending, assert_ready, task}; + +#[tokio::test] +async fn immediate_sleep() { + time::pause(); + + let now = Instant::now(); + + // Ready! + time::sleep_until(now).await; + assert_elapsed!(now, ms(1)); +} + +#[tokio::test] +async fn is_elapsed() { + time::pause(); + + let sleep = time::sleep(Duration::from_millis(10)); + + tokio::pin!(sleep); + + assert!(!sleep.is_elapsed()); + + assert!(futures::poll!(sleep.as_mut()).is_pending()); + + assert!(!sleep.is_elapsed()); + + sleep.as_mut().await; + + assert!(sleep.is_elapsed()); +} + +#[tokio::test] +async fn delayed_sleep_level_0() { + time::pause(); + + for &i in &[1, 10, 60] { + let now = Instant::now(); + let dur = ms(i); + + time::sleep_until(now + dur).await; + + assert_elapsed!(now, dur); + } +} + +#[tokio::test] +async fn sub_ms_delayed_sleep() { + time::pause(); + + for _ in 0..5 { + let now = Instant::now(); + let deadline = now + ms(1) + Duration::new(0, 1); + + time::sleep_until(deadline).await; + + assert_elapsed!(now, ms(1)); + } +} + +#[tokio::test] +async fn delayed_sleep_wrapping_level_0() { + time::pause(); + + time::sleep(ms(5)).await; + + let now = Instant::now(); + time::sleep_until(now + ms(60)).await; + + assert_elapsed!(now, ms(60)); +} + +#[tokio::test] +async fn reset_future_sleep_before_fire() { + time::pause(); + + let now = Instant::now(); + + let mut sleep = task::spawn(Box::pin(time::sleep_until(now + ms(100)))); + assert_pending!(sleep.poll()); + + let mut sleep = sleep.into_inner(); + + sleep.as_mut().reset(Instant::now() + ms(200)); + sleep.await; + + assert_elapsed!(now, ms(200)); +} + +#[tokio::test] +async fn reset_past_sleep_before_turn() { + time::pause(); + + let now = Instant::now(); + + let mut sleep = task::spawn(Box::pin(time::sleep_until(now + ms(100)))); + assert_pending!(sleep.poll()); + + let mut sleep = sleep.into_inner(); + + sleep.as_mut().reset(now + ms(80)); + sleep.await; + + assert_elapsed!(now, ms(80)); +} + +#[tokio::test] +async fn reset_past_sleep_before_fire() { + time::pause(); + + let now = Instant::now(); + + let mut sleep = task::spawn(Box::pin(time::sleep_until(now + ms(100)))); + assert_pending!(sleep.poll()); + + let mut sleep = sleep.into_inner(); + + time::sleep(ms(10)).await; + + sleep.as_mut().reset(now + ms(80)); + sleep.await; + + assert_elapsed!(now, ms(80)); +} + +#[tokio::test] +async fn reset_future_sleep_after_fire() { + time::pause(); + + let now = Instant::now(); + let mut sleep = Box::pin(time::sleep_until(now + ms(100))); + + sleep.as_mut().await; + assert_elapsed!(now, ms(100)); + + sleep.as_mut().reset(now + ms(110)); + sleep.await; + assert_elapsed!(now, ms(110)); +} + +#[tokio::test] +async fn reset_sleep_to_past() { + time::pause(); + + let now = Instant::now(); + + let mut sleep = task::spawn(Box::pin(time::sleep_until(now + ms(100)))); + assert_pending!(sleep.poll()); + + time::sleep(ms(50)).await; + + assert!(!sleep.is_woken()); + + sleep.as_mut().reset(now + ms(40)); + + // TODO: is this required? + //assert!(sleep.is_woken()); + + assert_ready!(sleep.poll()); +} + +#[test] +#[should_panic] +fn creating_sleep_outside_of_context() { + let now = Instant::now(); + + // This creates a delay outside of the context of a mock timer. This tests + // that it will panic. + let _fut = time::sleep_until(now + ms(500)); +} + +#[tokio::test] +async fn greater_than_max() { + const YR_5: u64 = 5 * 365 * 24 * 60 * 60 * 1000; + + time::pause(); + time::sleep_until(Instant::now() + ms(YR_5)).await; +} + +#[tokio::test] +async fn short_sleeps() { + for i in 0..10000 { + if (i % 10) == 0 { + eprintln!("=== {}", i); + } + tokio::time::sleep(std::time::Duration::from_millis(0)).await; + } +} + +#[tokio::test] +async fn multi_long_sleeps() { + tokio::time::pause(); + + for _ in 0..5u32 { + tokio::time::sleep(Duration::from_secs( + // about a year + 365 * 24 * 3600, + )) + .await; + } + + let deadline = tokio::time::Instant::now() + + Duration::from_secs( + // about 10 years + 10 * 365 * 24 * 3600, + ); + + tokio::time::sleep_until(deadline).await; + + assert!(tokio::time::Instant::now() >= deadline); +} + +#[tokio::test] +async fn long_sleeps() { + tokio::time::pause(); + + let deadline = tokio::time::Instant::now() + + Duration::from_secs( + // about 10 years + 10 * 365 * 24 * 3600, + ); + + tokio::time::sleep_until(deadline).await; + + assert!(tokio::time::Instant::now() >= deadline); + assert!(tokio::time::Instant::now() <= deadline + Duration::from_millis(1)); +} + +#[tokio::test] +async fn reset_after_firing() { + let timer = tokio::time::sleep(std::time::Duration::from_millis(1)); + tokio::pin!(timer); + + let deadline = timer.deadline(); + + timer.as_mut().await; + assert_ready!(timer + .as_mut() + .poll(&mut Context::from_waker(noop_waker_ref()))); + timer + .as_mut() + .reset(tokio::time::Instant::now() + std::time::Duration::from_secs(600)); + + assert_ne!(deadline, timer.deadline()); + + assert_pending!(timer + .as_mut() + .poll(&mut Context::from_waker(noop_waker_ref()))); + assert_pending!(timer + .as_mut() + .poll(&mut Context::from_waker(noop_waker_ref()))); +} + +const NUM_LEVELS: usize = 6; +const MAX_DURATION: u64 = (1 << (6 * NUM_LEVELS)) - 1; + +#[tokio::test] +async fn exactly_max() { + time::pause(); + time::sleep(ms(MAX_DURATION)).await; +} + +#[tokio::test] +async fn no_out_of_bounds_close_to_max() { + time::pause(); + time::sleep(ms(MAX_DURATION - 1)).await; +} + +fn ms(n: u64) -> Duration { + Duration::from_millis(n) +} + +#[tokio::test] +async fn drop_after_reschedule_at_new_scheduled_time() { + use futures::poll; + + tokio::time::pause(); + + let start = tokio::time::Instant::now(); + + let mut a = Box::pin(tokio::time::sleep(Duration::from_millis(5))); + let mut b = Box::pin(tokio::time::sleep(Duration::from_millis(5))); + let mut c = Box::pin(tokio::time::sleep(Duration::from_millis(10))); + + let _ = poll!(&mut a); + let _ = poll!(&mut b); + let _ = poll!(&mut c); + + b.as_mut().reset(start + Duration::from_millis(10)); + a.await; + + drop(b); +} + +#[tokio::test] +async fn drop_from_wake() { + use std::future::Future; + use std::pin::Pin; + use std::sync::atomic::{AtomicBool, Ordering}; + use std::sync::{Arc, Mutex}; + use std::task::Context; + + let panicked = Arc::new(AtomicBool::new(false)); + let list: Arc<Mutex<Vec<Pin<Box<tokio::time::Sleep>>>>> = Arc::new(Mutex::new(Vec::new())); + + let arc_wake = Arc::new(DropWaker(panicked.clone(), list.clone())); + let arc_wake = futures::task::waker(arc_wake); + + tokio::time::pause(); + + let mut lock = list.lock().unwrap(); + + for _ in 0..100 { + let mut timer = Box::pin(tokio::time::sleep(Duration::from_millis(10))); + + let _ = timer.as_mut().poll(&mut Context::from_waker(&arc_wake)); + + lock.push(timer); + } + + drop(lock); + + tokio::time::sleep(Duration::from_millis(11)).await; + + assert!( + !panicked.load(Ordering::SeqCst), + "panicked when dropping timers" + ); + + #[derive(Clone)] + struct DropWaker( + Arc<AtomicBool>, + Arc<Mutex<Vec<Pin<Box<tokio::time::Sleep>>>>>, + ); + + impl futures::task::ArcWake for DropWaker { + fn wake_by_ref(arc_self: &Arc<Self>) { + let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + *arc_self.1.lock().expect("panic in lock") = Vec::new() + })); + + if result.is_err() { + arc_self.0.store(true, Ordering::SeqCst); + } + } + } +} |