diff --git a/tokio-test/src/macros.rs b/tokio-test/src/macros.rs index 299bd7759..7ca73451f 100644 --- a/tokio-test/src/macros.rs +++ b/tokio-test/src/macros.rs @@ -259,3 +259,37 @@ macro_rules! assert_err { } }}; } + +/// Asserts that an exact duration has elapsed since since the start instant ±1ms. +/// +/// ```rust +/// use tokio::time::{self, Instant}; +/// use std::time::Duration; +/// use tokio_test::assert_elapsed; +/// # async fn test_time_passed() { +/// +/// let start = Instant::now(); +/// let dur = Duration::from_millis(50); +/// time::sleep(dur).await; +/// assert_elapsed!(start, dur); +/// # } +/// ``` +/// +/// This 1ms buffer is required because Tokio's hashed-wheel timer has finite time resolution and +/// will not always sleep for the exact interval. +#[macro_export] +macro_rules! assert_elapsed { + ($start:expr, $dur:expr) => {{ + let elapsed = $start.elapsed(); + // type ascription improves compiler error when wrong type is passed + let lower: std::time::Duration = $dur; + + // Handles ms rounding + assert!( + elapsed >= lower && elapsed <= lower + std::time::Duration::from_millis(1), + "actual = {:?}, expected = {:?}", + elapsed, + lower + ); + }}; +} diff --git a/tokio/tests/time_pause.rs b/tokio/tests/time_pause.rs index 835db12f0..d1834af21 100644 --- a/tokio/tests/time_pause.rs +++ b/tokio/tests/time_pause.rs @@ -4,7 +4,7 @@ use rand::SeedableRng; use rand::{rngs::StdRng, Rng}; use tokio::time::{self, Duration, Instant, Sleep}; -use tokio_test::{assert_err, assert_pending, assert_ready_eq, task}; +use tokio_test::{assert_elapsed, assert_err, assert_pending, assert_ready_eq, task}; use std::{ future::Future, @@ -12,21 +12,6 @@ use std::{ task::{Context, Poll}, }; -macro_rules! assert_elapsed { - ($now:expr, $ms:expr) => {{ - let elapsed = $now.elapsed(); - let lower = ms($ms); - - // Handles ms rounding - assert!( - elapsed >= lower && elapsed <= lower + ms(1), - "actual = {:?}, expected = {:?}", - elapsed, - lower - ); - }}; -} - #[tokio::test] async fn pause_time_in_main() { tokio::time::pause(); @@ -91,7 +76,7 @@ async fn advance_after_poll() { let before = Instant::now(); time::advance(ms(100)).await; - assert_elapsed!(before, 100); + assert_elapsed!(before, ms(100)); assert_pending!(sleep.poll()); } @@ -107,7 +92,7 @@ async fn sleep_no_poll() { let before = Instant::now(); time::advance(ms(100)).await; - assert_elapsed!(before, 100); + assert_elapsed!(before, ms(100)); assert_pending!(sleep.poll()); } @@ -147,7 +132,7 @@ impl Future for Tester { } }, State::AfterAdvance => { - assert_elapsed!(self.before.unwrap(), 100); + assert_elapsed!(self.before.unwrap(), ms(100)); assert_pending!(self.sleep.as_mut().poll(cx)); @@ -207,24 +192,24 @@ async fn interval() { let before = Instant::now(); time::advance(ms(100)).await; - assert_elapsed!(before, 100); + assert_elapsed!(before, ms(100)); assert_pending!(poll_next(&mut i)); let before = Instant::now(); time::advance(ms(200)).await; - assert_elapsed!(before, 200); + 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, 400); + 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, 500); + 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)); diff --git a/tokio/tests/time_sleep.rs b/tokio/tests/time_sleep.rs index 27362581d..9c04d22b1 100644 --- a/tokio/tests/time_sleep.rs +++ b/tokio/tests/time_sleep.rs @@ -7,22 +7,7 @@ use std::task::Context; use futures::task::noop_waker_ref; use tokio::time::{self, Duration, Instant}; -use tokio_test::{assert_pending, assert_ready, task}; - -macro_rules! assert_elapsed { - ($now:expr, $ms:expr) => {{ - let elapsed = $now.elapsed(); - let lower = ms($ms); - - // Handles ms rounding - assert!( - elapsed >= lower && elapsed <= lower + ms(1), - "actual = {:?}, expected = {:?}", - elapsed, - lower - ); - }}; -} +use tokio_test::{assert_elapsed, assert_pending, assert_ready, task}; #[tokio::test] async fn immediate_sleep() { @@ -32,7 +17,7 @@ async fn immediate_sleep() { // Ready! time::sleep_until(now).await; - assert_elapsed!(now, 0); + assert_elapsed!(now, ms(1)); } #[tokio::test] @@ -60,10 +45,11 @@ async fn delayed_sleep_level_0() { for &i in &[1, 10, 60] { let now = Instant::now(); + let dur = ms(i); - time::sleep_until(now + ms(i)).await; + time::sleep_until(now + dur).await; - assert_elapsed!(now, i); + assert_elapsed!(now, dur); } } @@ -77,7 +63,7 @@ async fn sub_ms_delayed_sleep() { time::sleep_until(deadline).await; - assert_elapsed!(now, 1); + assert_elapsed!(now, ms(1)); } } @@ -90,7 +76,7 @@ async fn delayed_sleep_wrapping_level_0() { let now = Instant::now(); time::sleep_until(now + ms(60)).await; - assert_elapsed!(now, 60); + assert_elapsed!(now, ms(60)); } #[tokio::test] @@ -107,7 +93,7 @@ async fn reset_future_sleep_before_fire() { sleep.as_mut().reset(Instant::now() + ms(200)); sleep.await; - assert_elapsed!(now, 200); + assert_elapsed!(now, ms(200)); } #[tokio::test] @@ -124,7 +110,7 @@ async fn reset_past_sleep_before_turn() { sleep.as_mut().reset(now + ms(80)); sleep.await; - assert_elapsed!(now, 80); + assert_elapsed!(now, ms(80)); } #[tokio::test] @@ -143,7 +129,7 @@ async fn reset_past_sleep_before_fire() { sleep.as_mut().reset(now + ms(80)); sleep.await; - assert_elapsed!(now, 80); + assert_elapsed!(now, ms(80)); } #[tokio::test] @@ -154,11 +140,11 @@ async fn reset_future_sleep_after_fire() { let mut sleep = Box::pin(time::sleep_until(now + ms(100))); sleep.as_mut().await; - assert_elapsed!(now, 100); + assert_elapsed!(now, ms(100)); sleep.as_mut().reset(now + ms(110)); sleep.await; - assert_elapsed!(now, 110); + assert_elapsed!(now, ms(110)); } #[tokio::test]