mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-08-29 00:00:11 +02:00
timer: move tokio-timer into tokio crate (#1674)
A step towards collapsing Tokio sub crates into a single `tokio` crate (#1318). The `timer` implementation is now provided by the main `tokio` crate. The `timer` functionality may still be excluded from the build by skipping the `timer` feature flag.
This commit is contained in:
@@ -1,17 +1,15 @@
|
||||
#![warn(rust_2018_idioms)]
|
||||
#![cfg(feature = "default")]
|
||||
|
||||
use tokio::runtime::{self, current_thread};
|
||||
use tokio::timer::clock::Clock;
|
||||
use tokio::timer::*;
|
||||
use tokio_timer;
|
||||
use tokio_timer::clock::Clock;
|
||||
|
||||
use std::sync::mpsc;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
struct MockNow(Instant);
|
||||
|
||||
impl tokio_timer::clock::Now for MockNow {
|
||||
impl tokio::timer::clock::Now for MockNow {
|
||||
fn now(&self) -> Instant {
|
||||
self.0
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
use tokio::timer::clock;
|
||||
use tokio::timer::clock::*;
|
||||
|
||||
use std::time::Instant;
|
||||
|
||||
struct ConstNow(Instant);
|
||||
|
||||
impl Now for ConstNow {
|
||||
fn now(&self) -> Instant {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn default_clock() {
|
||||
let a = Instant::now();
|
||||
let b = clock::now();
|
||||
let c = Clock::new().now();
|
||||
|
||||
assert!(a <= b);
|
||||
assert!(b <= c);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn custom_clock() {
|
||||
let now = ConstNow(Instant::now());
|
||||
let clock = Clock::new_with_now(now);
|
||||
|
||||
let a = Instant::now();
|
||||
let b = clock.now();
|
||||
|
||||
assert!(b <= a);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn execution_context() {
|
||||
let now = ConstNow(Instant::now());
|
||||
let clock = Clock::new_with_now(now);
|
||||
|
||||
with_default(&clock, || {
|
||||
let a = Instant::now();
|
||||
let b = clock::now();
|
||||
|
||||
assert!(b <= a);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,538 @@
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
use tokio::timer::delay;
|
||||
use tokio::timer::timer::Handle;
|
||||
use tokio_test::task::MockTask;
|
||||
use tokio_test::{assert_pending, assert_ready, clock};
|
||||
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
#[test]
|
||||
fn immediate_delay() {
|
||||
let mut task = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
// Create `Delay` that elapsed immediately.
|
||||
let mut fut = delay(clock.now());
|
||||
|
||||
// Ready!
|
||||
assert_ready!(task.poll(&mut fut));
|
||||
|
||||
// Turn the timer, it runs for the elapsed time
|
||||
clock.turn_for(ms(1000));
|
||||
|
||||
// The time has not advanced. The `turn` completed immediately.
|
||||
assert_eq!(clock.advanced(), ms(1000));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn delayed_delay_level_0() {
|
||||
let mut task = MockTask::new();
|
||||
|
||||
for &i in &[1, 10, 60] {
|
||||
clock::mock(|clock| {
|
||||
// Create a `Delay` that elapses in the future
|
||||
let mut fut = delay(clock.now() + ms(i));
|
||||
|
||||
// The delay has not elapsed.
|
||||
assert_pending!(task.poll(&mut fut));
|
||||
|
||||
clock.turn();
|
||||
assert_eq!(clock.advanced(), ms(i));
|
||||
|
||||
assert_ready!(task.poll(&mut fut));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub_ms_delayed_delay() {
|
||||
let mut task = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
for _ in 0..5 {
|
||||
let deadline = clock.now() + Duration::from_millis(1) + Duration::new(0, 1);
|
||||
|
||||
let mut fut = delay(deadline);
|
||||
|
||||
assert_pending!(task.poll(&mut fut));
|
||||
|
||||
clock.turn();
|
||||
assert_ready!(task.poll(&mut fut));
|
||||
|
||||
assert!(clock.now() >= deadline);
|
||||
|
||||
clock.advance(Duration::new(0, 1));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn delayed_delay_wrapping_level_0() {
|
||||
let mut task = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
clock.turn_for(ms(5));
|
||||
assert_eq!(clock.advanced(), ms(5));
|
||||
|
||||
let mut fut = delay(clock.now() + ms(60));
|
||||
|
||||
assert_pending!(task.poll(&mut fut));
|
||||
|
||||
clock.turn();
|
||||
assert_eq!(clock.advanced(), ms(64));
|
||||
assert_pending!(task.poll(&mut fut));
|
||||
|
||||
clock.turn();
|
||||
assert_eq!(clock.advanced(), ms(65));
|
||||
|
||||
assert_ready!(task.poll(&mut fut));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn timer_wrapping_with_higher_levels() {
|
||||
let mut task = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
// Set delay to hit level 1
|
||||
let mut s1 = delay(clock.now() + ms(64));
|
||||
assert_pending!(task.poll(&mut s1));
|
||||
|
||||
// Turn a bit
|
||||
clock.turn_for(ms(5));
|
||||
|
||||
// Set timeout such that it will hit level 0, but wrap
|
||||
let mut s2 = delay(clock.now() + ms(60));
|
||||
assert_pending!(task.poll(&mut s2));
|
||||
|
||||
// This should result in s1 firing
|
||||
clock.turn();
|
||||
assert_eq!(clock.advanced(), ms(64));
|
||||
|
||||
assert_ready!(task.poll(&mut s1));
|
||||
assert_pending!(task.poll(&mut s2));
|
||||
|
||||
clock.turn();
|
||||
assert_eq!(clock.advanced(), ms(65));
|
||||
|
||||
assert_ready!(task.poll(&mut s2));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn delay_with_deadline_in_past() {
|
||||
let mut task = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
// Create `Delay` that elapsed immediately.
|
||||
let mut fut = delay(clock.now() - ms(100));
|
||||
|
||||
// Even though the delay expires in the past, it is not ready yet
|
||||
// because the timer must observe it.
|
||||
assert_ready!(task.poll(&mut fut));
|
||||
|
||||
// Turn the timer, it runs for the elapsed time
|
||||
clock.turn_for(ms(1000));
|
||||
|
||||
// The time has not advanced. The `turn` completed immediately.
|
||||
assert_eq!(clock.advanced(), ms(1000));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn delayed_delay_level_1() {
|
||||
let mut task = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
// Create a `Delay` that elapses in the future
|
||||
let mut fut = delay(clock.now() + ms(234));
|
||||
|
||||
// The delay has not elapsed.
|
||||
assert_pending!(task.poll(&mut fut));
|
||||
|
||||
// Turn the timer, this will wake up to cascade the timer down.
|
||||
clock.turn_for(ms(1000));
|
||||
assert_eq!(clock.advanced(), ms(192));
|
||||
|
||||
// The delay has not elapsed.
|
||||
assert_pending!(task.poll(&mut fut));
|
||||
|
||||
// Turn the timer again
|
||||
clock.turn_for(ms(1000));
|
||||
assert_eq!(clock.advanced(), ms(234));
|
||||
|
||||
// The delay has elapsed.
|
||||
assert_ready!(task.poll(&mut fut));
|
||||
});
|
||||
|
||||
clock::mock(|clock| {
|
||||
// Create a `Delay` that elapses in the future
|
||||
let mut fut = delay(clock.now() + ms(234));
|
||||
|
||||
// The delay has not elapsed.
|
||||
assert_pending!(task.poll(&mut fut));
|
||||
|
||||
// Turn the timer with a smaller timeout than the cascade.
|
||||
clock.turn_for(ms(100));
|
||||
assert_eq!(clock.advanced(), ms(100));
|
||||
|
||||
assert_pending!(task.poll(&mut fut));
|
||||
|
||||
// Turn the timer, this will wake up to cascade the timer down.
|
||||
clock.turn_for(ms(1000));
|
||||
assert_eq!(clock.advanced(), ms(192));
|
||||
|
||||
// The delay has not elapsed.
|
||||
assert_pending!(task.poll(&mut fut));
|
||||
|
||||
// Turn the timer again
|
||||
clock.turn_for(ms(1000));
|
||||
assert_eq!(clock.advanced(), ms(234));
|
||||
|
||||
// The delay has elapsed.
|
||||
assert_ready!(task.poll(&mut fut));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn creating_delay_outside_of_context() {
|
||||
let now = Instant::now();
|
||||
|
||||
// This creates a delay outside of the context of a mock timer. This tests
|
||||
// that it will still expire.
|
||||
let mut fut = delay(now + ms(500));
|
||||
let mut task = MockTask::new();
|
||||
|
||||
clock::mock_at(now, |clock| {
|
||||
// This registers the delay with the timer
|
||||
assert_pending!(task.poll(&mut fut));
|
||||
|
||||
// Wait some time... the timer is cascading
|
||||
clock.turn_for(ms(1000));
|
||||
assert_eq!(clock.advanced(), ms(448));
|
||||
|
||||
assert_pending!(task.poll(&mut fut));
|
||||
|
||||
clock.turn_for(ms(1000));
|
||||
assert_eq!(clock.advanced(), ms(500));
|
||||
|
||||
// The delay has elapsed
|
||||
assert_ready!(task.poll(&mut fut));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn concurrently_set_two_timers_second_one_shorter() {
|
||||
let mut t1 = MockTask::new();
|
||||
let mut t2 = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
let mut fut1 = delay(clock.now() + ms(500));
|
||||
let mut fut2 = delay(clock.now() + ms(200));
|
||||
|
||||
// The delay has not elapsed
|
||||
assert_pending!(t1.poll(&mut fut1));
|
||||
assert_pending!(t2.poll(&mut fut2));
|
||||
|
||||
// Delay until a cascade
|
||||
clock.turn();
|
||||
assert_eq!(clock.advanced(), ms(192));
|
||||
|
||||
// Delay until the second timer.
|
||||
clock.turn();
|
||||
assert_eq!(clock.advanced(), ms(200));
|
||||
|
||||
// The shorter delay fires
|
||||
assert_ready!(t2.poll(&mut fut2));
|
||||
assert_pending!(t1.poll(&mut fut1));
|
||||
|
||||
clock.turn();
|
||||
assert_eq!(clock.advanced(), ms(448));
|
||||
|
||||
assert_pending!(t1.poll(&mut fut1));
|
||||
|
||||
// Turn again, this time the time will advance to the second delay
|
||||
clock.turn();
|
||||
assert_eq!(clock.advanced(), ms(500));
|
||||
|
||||
assert_ready!(t1.poll(&mut fut1));
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn short_delay() {
|
||||
let mut task = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
// Create a `Delay` that elapses in the future
|
||||
let mut fut = delay(clock.now() + ms(1));
|
||||
|
||||
// The delay has not elapsed.
|
||||
assert_pending!(task.poll(&mut fut));
|
||||
|
||||
// Turn the timer, but not enough time will go by.
|
||||
clock.turn();
|
||||
|
||||
// The delay has elapsed.
|
||||
assert_ready!(task.poll(&mut fut));
|
||||
|
||||
// The time has advanced to the point of the delay elapsing.
|
||||
assert_eq!(clock.advanced(), ms(1));
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sorta_long_delay() {
|
||||
const MIN_5: u64 = 5 * 60 * 1000;
|
||||
|
||||
let mut task = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
// Create a `Delay` that elapses in the future
|
||||
let mut fut = delay(clock.now() + ms(MIN_5));
|
||||
|
||||
// The delay has not elapsed.
|
||||
assert_pending!(task.poll(&mut fut));
|
||||
|
||||
let cascades = &[262_144, 262_144 + 9 * 4096, 262_144 + 9 * 4096 + 15 * 64];
|
||||
|
||||
for &elapsed in cascades {
|
||||
clock.turn();
|
||||
assert_eq!(clock.advanced(), ms(elapsed));
|
||||
|
||||
assert_pending!(task.poll(&mut fut));
|
||||
}
|
||||
|
||||
clock.turn();
|
||||
assert_eq!(clock.advanced(), ms(MIN_5));
|
||||
|
||||
// The delay has elapsed.
|
||||
assert_ready!(task.poll(&mut fut));
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn very_long_delay() {
|
||||
const MO_5: u64 = 5 * 30 * 24 * 60 * 60 * 1000;
|
||||
|
||||
let mut task = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
// Create a `Delay` that elapses in the future
|
||||
let mut fut = delay(clock.now() + ms(MO_5));
|
||||
|
||||
// The delay has not elapsed.
|
||||
assert_pending!(task.poll(&mut fut));
|
||||
|
||||
let cascades = &[
|
||||
12_884_901_888,
|
||||
12_952_010_752,
|
||||
12_959_875_072,
|
||||
12_959_997_952,
|
||||
];
|
||||
|
||||
for &elapsed in cascades {
|
||||
clock.turn();
|
||||
assert_eq!(clock.advanced(), ms(elapsed));
|
||||
|
||||
assert_pending!(task.poll(&mut fut));
|
||||
}
|
||||
|
||||
// Turn the timer, but not enough time will go by.
|
||||
clock.turn();
|
||||
|
||||
// The time has advanced to the point of the delay elapsing.
|
||||
assert_eq!(clock.advanced(), ms(MO_5));
|
||||
|
||||
// The delay has elapsed.
|
||||
assert_ready!(task.poll(&mut fut));
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn greater_than_max() {
|
||||
const YR_5: u64 = 5 * 365 * 24 * 60 * 60 * 1000;
|
||||
|
||||
let mut task = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
// Create a `Delay` that elapses in the future
|
||||
let mut fut = delay(clock.now() + ms(YR_5));
|
||||
|
||||
assert_pending!(task.poll(&mut fut));
|
||||
|
||||
clock.turn_for(ms(0));
|
||||
|
||||
// boom
|
||||
let _ = task.poll(&mut fut);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unpark_is_delayed() {
|
||||
let mut t1 = MockTask::new();
|
||||
let mut t2 = MockTask::new();
|
||||
let mut t3 = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
let mut fut1 = delay(clock.now() + ms(100));
|
||||
let mut fut2 = delay(clock.now() + ms(101));
|
||||
let mut fut3 = delay(clock.now() + ms(200));
|
||||
|
||||
assert_pending!(t1.poll(&mut fut1));
|
||||
assert_pending!(t2.poll(&mut fut2));
|
||||
assert_pending!(t3.poll(&mut fut3));
|
||||
|
||||
clock.park_for(ms(500));
|
||||
|
||||
assert_eq!(clock.advanced(), ms(500));
|
||||
|
||||
assert_ready!(t1.poll(&mut fut1));
|
||||
assert_ready!(t2.poll(&mut fut2));
|
||||
assert_ready!(t3.poll(&mut fut3));
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_timeout_at_deadline_greater_than_max_timer() {
|
||||
const YR_1: u64 = 365 * 24 * 60 * 60 * 1000;
|
||||
const YR_5: u64 = 5 * YR_1;
|
||||
|
||||
let mut task = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
for _ in 0..5 {
|
||||
clock.turn_for(ms(YR_1));
|
||||
}
|
||||
|
||||
let mut fut = delay(clock.now() + ms(1));
|
||||
assert_pending!(task.poll(&mut fut));
|
||||
|
||||
clock.turn_for(ms(1000));
|
||||
assert_eq!(clock.advanced(), ms(YR_5) + ms(1));
|
||||
|
||||
assert_ready!(task.poll(&mut fut));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reset_future_delay_before_fire() {
|
||||
let mut task = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
let mut fut = delay(clock.now() + ms(100));
|
||||
|
||||
assert_pending!(task.poll(&mut fut));
|
||||
|
||||
fut.reset(clock.now() + ms(200));
|
||||
|
||||
clock.turn();
|
||||
assert_eq!(clock.advanced(), ms(192));
|
||||
|
||||
assert_pending!(task.poll(&mut fut));
|
||||
|
||||
clock.turn();
|
||||
assert_eq!(clock.advanced(), ms(200));
|
||||
|
||||
assert_ready!(task.poll(&mut fut));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reset_past_delay_before_turn() {
|
||||
let mut task = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
let mut fut = delay(clock.now() + ms(100));
|
||||
|
||||
assert_pending!(task.poll(&mut fut));
|
||||
|
||||
fut.reset(clock.now() + ms(80));
|
||||
|
||||
clock.turn();
|
||||
assert_eq!(clock.advanced(), ms(64));
|
||||
|
||||
assert_pending!(task.poll(&mut fut));
|
||||
|
||||
clock.turn();
|
||||
assert_eq!(clock.advanced(), ms(80));
|
||||
|
||||
assert_ready!(task.poll(&mut fut));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reset_past_delay_before_fire() {
|
||||
let mut task = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
let mut fut = delay(clock.now() + ms(100));
|
||||
|
||||
assert_pending!(task.poll(&mut fut));
|
||||
clock.turn_for(ms(10));
|
||||
|
||||
assert_pending!(task.poll(&mut fut));
|
||||
fut.reset(clock.now() + ms(80));
|
||||
|
||||
clock.turn();
|
||||
assert_eq!(clock.advanced(), ms(64));
|
||||
|
||||
assert_pending!(task.poll(&mut fut));
|
||||
|
||||
clock.turn();
|
||||
assert_eq!(clock.advanced(), ms(90));
|
||||
|
||||
assert_ready!(task.poll(&mut fut));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reset_future_delay_after_fire() {
|
||||
let mut task = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
let mut fut = delay(clock.now() + ms(100));
|
||||
|
||||
assert_pending!(task.poll(&mut fut));
|
||||
|
||||
clock.turn_for(ms(1000));
|
||||
assert_eq!(clock.advanced(), ms(64));
|
||||
|
||||
clock.turn();
|
||||
assert_eq!(clock.advanced(), ms(100));
|
||||
|
||||
assert_ready!(task.poll(&mut fut));
|
||||
|
||||
fut.reset(clock.now() + ms(10));
|
||||
assert_pending!(task.poll(&mut fut));
|
||||
|
||||
clock.turn_for(ms(1000));
|
||||
assert_eq!(clock.advanced(), ms(110));
|
||||
|
||||
assert_ready!(task.poll(&mut fut));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn delay_with_default_handle() {
|
||||
let handle = Handle::default();
|
||||
let now = Instant::now();
|
||||
let mut task = MockTask::new();
|
||||
|
||||
let mut fut = handle.delay(now + ms(1));
|
||||
|
||||
clock::mock_at(now, |clock| {
|
||||
assert_pending!(task.poll(&mut fut));
|
||||
|
||||
clock.turn_for(ms(1));
|
||||
|
||||
assert_ready!(task.poll(&mut fut));
|
||||
});
|
||||
}
|
||||
|
||||
fn ms(n: u64) -> Duration {
|
||||
Duration::from_millis(n)
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
use tokio::timer::{Delay, Timer};
|
||||
|
||||
use tokio_executor::current_thread::CurrentThread;
|
||||
use tokio_executor::park::{Park, Unpark, UnparkThread};
|
||||
|
||||
use rand;
|
||||
use rand::Rng;
|
||||
use std::cmp;
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
use std::sync::atomic::Ordering::SeqCst;
|
||||
use std::sync::{Arc, Barrier};
|
||||
use std::task::{Context, Poll};
|
||||
use std::thread;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
struct Signal {
|
||||
rem: AtomicUsize,
|
||||
unpark: UnparkThread,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hammer_complete() {
|
||||
const ITERS: usize = 5;
|
||||
const THREADS: usize = 4;
|
||||
const PER_THREAD: usize = 40;
|
||||
const MIN_DELAY: u64 = 1;
|
||||
const MAX_DELAY: u64 = 5_000;
|
||||
|
||||
for _ in 0..ITERS {
|
||||
let mut timer = Timer::default();
|
||||
let handle = timer.handle();
|
||||
let barrier = Arc::new(Barrier::new(THREADS));
|
||||
|
||||
let done = Arc::new(Signal {
|
||||
rem: AtomicUsize::new(THREADS),
|
||||
unpark: timer.get_park().unpark(),
|
||||
});
|
||||
|
||||
for _ in 0..THREADS {
|
||||
let handle = handle.clone();
|
||||
let barrier = barrier.clone();
|
||||
let done = done.clone();
|
||||
|
||||
thread::spawn(move || {
|
||||
let mut exec = CurrentThread::new();
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
barrier.wait();
|
||||
|
||||
for _ in 0..PER_THREAD {
|
||||
let deadline =
|
||||
Instant::now() + Duration::from_millis(rng.gen_range(MIN_DELAY, MAX_DELAY));
|
||||
let delay = handle.delay(deadline);
|
||||
|
||||
exec.spawn(async move {
|
||||
delay.await;
|
||||
|
||||
let now = Instant::now();
|
||||
assert!(now >= deadline, "deadline greater by {:?}", deadline - now);
|
||||
});
|
||||
}
|
||||
|
||||
// Run the logic
|
||||
exec.run().unwrap();
|
||||
|
||||
if 1 == done.rem.fetch_sub(1, SeqCst) {
|
||||
done.unpark.unpark();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
while done.rem.load(SeqCst) > 0 {
|
||||
timer.turn(None).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hammer_cancel() {
|
||||
const ITERS: usize = 5;
|
||||
const THREADS: usize = 4;
|
||||
const PER_THREAD: usize = 40;
|
||||
const MIN_DELAY: u64 = 1;
|
||||
const MAX_DELAY: u64 = 5_000;
|
||||
|
||||
for _ in 0..ITERS {
|
||||
let mut timer = Timer::default();
|
||||
let handle = timer.handle();
|
||||
let barrier = Arc::new(Barrier::new(THREADS));
|
||||
|
||||
let done = Arc::new(Signal {
|
||||
rem: AtomicUsize::new(THREADS),
|
||||
unpark: timer.get_park().unpark(),
|
||||
});
|
||||
|
||||
for _ in 0..THREADS {
|
||||
let handle = handle.clone();
|
||||
let barrier = barrier.clone();
|
||||
let done = done.clone();
|
||||
|
||||
thread::spawn(move || {
|
||||
let mut exec = CurrentThread::new();
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
barrier.wait();
|
||||
|
||||
for _ in 0..PER_THREAD {
|
||||
let timeout1 = Duration::from_millis(rng.gen_range(MIN_DELAY, MAX_DELAY));
|
||||
let timeout2 = Duration::from_millis(rng.gen_range(MIN_DELAY, MAX_DELAY));
|
||||
|
||||
let deadline = Instant::now() + cmp::min(timeout1, timeout2);
|
||||
|
||||
let delay = handle.delay(Instant::now() + timeout1);
|
||||
let join = handle.timeout(delay, timeout2);
|
||||
|
||||
exec.spawn(async move {
|
||||
let _ = join.await;
|
||||
|
||||
let now = Instant::now();
|
||||
assert!(now >= deadline, "deadline greater by {:?}", deadline - now);
|
||||
});
|
||||
}
|
||||
|
||||
// Run the logic
|
||||
exec.run().unwrap();
|
||||
|
||||
if 1 == done.rem.fetch_sub(1, SeqCst) {
|
||||
done.unpark.unpark();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
while done.rem.load(SeqCst) > 0 {
|
||||
timer.turn(None).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hammer_reset() {
|
||||
const ITERS: usize = 5;
|
||||
const THREADS: usize = 4;
|
||||
const PER_THREAD: usize = 40;
|
||||
const MIN_DELAY: u64 = 1;
|
||||
const MAX_DELAY: u64 = 250;
|
||||
|
||||
for _ in 0..ITERS {
|
||||
let mut timer = Timer::default();
|
||||
let handle = timer.handle();
|
||||
let barrier = Arc::new(Barrier::new(THREADS));
|
||||
|
||||
let done = Arc::new(Signal {
|
||||
rem: AtomicUsize::new(THREADS),
|
||||
unpark: timer.get_park().unpark(),
|
||||
});
|
||||
|
||||
for _ in 0..THREADS {
|
||||
let handle = handle.clone();
|
||||
let barrier = barrier.clone();
|
||||
let done = done.clone();
|
||||
|
||||
thread::spawn(move || {
|
||||
let mut exec = CurrentThread::new();
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
barrier.wait();
|
||||
|
||||
for _ in 0..PER_THREAD {
|
||||
let deadline1 =
|
||||
Instant::now() + Duration::from_millis(rng.gen_range(MIN_DELAY, MAX_DELAY));
|
||||
|
||||
let deadline2 =
|
||||
deadline1 + Duration::from_millis(rng.gen_range(MIN_DELAY, MAX_DELAY));
|
||||
|
||||
let deadline3 =
|
||||
deadline2 + Duration::from_millis(rng.gen_range(MIN_DELAY, MAX_DELAY));
|
||||
|
||||
struct Select {
|
||||
a: Option<Delay>,
|
||||
b: Option<Delay>,
|
||||
}
|
||||
|
||||
impl Future for Select {
|
||||
type Output = Delay;
|
||||
|
||||
fn poll(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
) -> Poll<Self::Output> {
|
||||
let res = Pin::new(self.a.as_mut().unwrap()).poll(cx);
|
||||
|
||||
if res.is_ready() {
|
||||
return Poll::Ready(self.a.take().unwrap());
|
||||
}
|
||||
|
||||
let res = Pin::new(self.b.as_mut().unwrap()).poll(cx);
|
||||
|
||||
if res.is_ready() {
|
||||
return Poll::Ready(self.b.take().unwrap());
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
|
||||
let s = Select {
|
||||
a: Some(handle.delay(deadline1)),
|
||||
b: Some(handle.delay(deadline2)),
|
||||
};
|
||||
|
||||
exec.spawn(async move {
|
||||
let mut delay = s.await;
|
||||
|
||||
let now = Instant::now();
|
||||
assert!(
|
||||
now >= deadline1,
|
||||
"deadline greater by {:?}",
|
||||
deadline1 - now
|
||||
);
|
||||
|
||||
delay.reset(deadline3);
|
||||
delay.await;
|
||||
});
|
||||
}
|
||||
|
||||
// Run the logic
|
||||
exec.run().unwrap();
|
||||
|
||||
if 1 == done.rem.fetch_sub(1, SeqCst) {
|
||||
done.unpark.unpark();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
while done.rem.load(SeqCst) > 0 {
|
||||
timer.turn(None).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
use tokio::timer::*;
|
||||
use tokio_test::task::MockTask;
|
||||
use tokio_test::{assert_pending, assert_ready_eq, clock};
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn interval_zero_duration() {
|
||||
clock::mock(|clock| {
|
||||
let _ = Interval::new(clock.now(), ms(0));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn usage() {
|
||||
let mut task = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
let start = clock.now();
|
||||
let mut int = Interval::new(start, ms(300));
|
||||
|
||||
macro_rules! poll {
|
||||
() => {
|
||||
task.enter(|cx| int.poll_next(cx))
|
||||
};
|
||||
}
|
||||
|
||||
assert_ready_eq!(poll!(), Some(start));
|
||||
assert_pending!(poll!());
|
||||
|
||||
clock.advance(ms(100));
|
||||
assert_pending!(poll!());
|
||||
|
||||
clock.advance(ms(200));
|
||||
assert_ready_eq!(poll!(), Some(start + ms(300)));
|
||||
assert_pending!(poll!());
|
||||
|
||||
clock.advance(ms(400));
|
||||
assert_ready_eq!(poll!(), Some(start + ms(600)));
|
||||
assert_pending!(poll!());
|
||||
|
||||
clock.advance(ms(500));
|
||||
assert_ready_eq!(poll!(), Some(start + ms(900)));
|
||||
assert_ready_eq!(poll!(), Some(start + ms(1200)));
|
||||
assert_pending!(poll!());
|
||||
});
|
||||
}
|
||||
|
||||
fn ms(n: u64) -> Duration {
|
||||
Duration::from_millis(n)
|
||||
}
|
||||
@@ -0,0 +1,401 @@
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
use tokio::timer::*;
|
||||
use tokio_test::task::MockTask;
|
||||
use tokio_test::{assert_ok, assert_pending, assert_ready, clock};
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
macro_rules! poll {
|
||||
($task:ident, $queue:ident) => {
|
||||
$task.enter(|cx| $queue.poll_next(cx))
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! assert_ready_ok {
|
||||
($e:expr) => {{
|
||||
assert_ok!(match assert_ready!($e) {
|
||||
Some(v) => v,
|
||||
None => panic!("None"),
|
||||
})
|
||||
}};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_immediate_delay() {
|
||||
let mut t = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
let mut queue = DelayQueue::new();
|
||||
let _key = queue.insert_at("foo", clock.now());
|
||||
|
||||
let entry = assert_ready_ok!(poll!(t, queue));
|
||||
assert_eq!(*entry.get_ref(), "foo");
|
||||
|
||||
let entry = assert_ready!(poll!(t, queue));
|
||||
assert!(entry.is_none())
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multi_immediate_delays() {
|
||||
let mut t = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
let mut queue = DelayQueue::new();
|
||||
|
||||
let _k = queue.insert_at("1", clock.now());
|
||||
let _k = queue.insert_at("2", clock.now());
|
||||
let _k = queue.insert_at("3", clock.now());
|
||||
|
||||
let mut res = vec![];
|
||||
|
||||
while res.len() < 3 {
|
||||
let entry = assert_ready_ok!(poll!(t, queue));
|
||||
res.push(entry.into_inner());
|
||||
}
|
||||
|
||||
let entry = assert_ready!(poll!(t, queue));
|
||||
assert!(entry.is_none());
|
||||
|
||||
res.sort();
|
||||
|
||||
assert_eq!("1", res[0]);
|
||||
assert_eq!("2", res[1]);
|
||||
assert_eq!("3", res[2]);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_short_delay() {
|
||||
let mut t = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
let mut queue = DelayQueue::new();
|
||||
let _key = queue.insert_at("foo", clock.now() + ms(5));
|
||||
|
||||
assert_pending!(poll!(t, queue));
|
||||
|
||||
clock.turn_for(ms(1));
|
||||
|
||||
assert!(!t.is_woken());
|
||||
|
||||
clock.turn_for(ms(5));
|
||||
|
||||
assert!(t.is_woken());
|
||||
|
||||
let entry = assert_ready_ok!(poll!(t, queue));
|
||||
assert_eq!(*entry.get_ref(), "foo");
|
||||
|
||||
let entry = assert_ready!(poll!(t, queue));
|
||||
assert!(entry.is_none());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multi_delay_at_start() {
|
||||
let long = 262_144 + 9 * 4096;
|
||||
let delays = &[1000, 2, 234, long, 60, 10];
|
||||
|
||||
let mut t = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
let mut queue = DelayQueue::new();
|
||||
|
||||
// Setup the delays
|
||||
for &i in delays {
|
||||
let _key = queue.insert_at(i, clock.now() + ms(i));
|
||||
}
|
||||
|
||||
assert_pending!(poll!(t, queue));
|
||||
assert!(!t.is_woken());
|
||||
|
||||
for elapsed in 0..1200 {
|
||||
clock.turn_for(ms(1));
|
||||
let elapsed = elapsed + 1;
|
||||
|
||||
if delays.contains(&elapsed) {
|
||||
assert!(t.is_woken());
|
||||
assert_ready!(poll!(t, queue));
|
||||
assert_pending!(poll!(t, queue));
|
||||
} else {
|
||||
if t.is_woken() {
|
||||
let cascade = &[192, 960];
|
||||
assert!(cascade.contains(&elapsed), "elapsed={}", elapsed);
|
||||
|
||||
assert_pending!(poll!(t, queue));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_in_past_fires_immediately() {
|
||||
let mut t = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
let mut queue = DelayQueue::new();
|
||||
|
||||
let now = clock.now();
|
||||
|
||||
clock.turn_for(ms(10));
|
||||
|
||||
queue.insert_at("foo", now);
|
||||
|
||||
assert_ready!(poll!(t, queue));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn remove_entry() {
|
||||
let mut t = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
let mut queue = DelayQueue::new();
|
||||
|
||||
let key = queue.insert_at("foo", clock.now() + ms(5));
|
||||
|
||||
assert_pending!(poll!(t, queue));
|
||||
|
||||
let entry = queue.remove(&key);
|
||||
assert_eq!(entry.into_inner(), "foo");
|
||||
|
||||
clock.turn_for(ms(10));
|
||||
|
||||
let entry = assert_ready!(poll!(t, queue));
|
||||
assert!(entry.is_none());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reset_entry() {
|
||||
let mut t = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
let mut queue = DelayQueue::new();
|
||||
|
||||
let now = clock.now();
|
||||
let key = queue.insert_at("foo", now + ms(5));
|
||||
|
||||
assert_pending!(poll!(t, queue));
|
||||
clock.turn_for(ms(1));
|
||||
|
||||
queue.reset_at(&key, now + ms(10));
|
||||
|
||||
assert_pending!(poll!(t, queue));
|
||||
|
||||
clock.turn_for(ms(7));
|
||||
|
||||
assert!(!t.is_woken());
|
||||
|
||||
assert_pending!(poll!(t, queue));
|
||||
|
||||
clock.turn_for(ms(3));
|
||||
|
||||
assert!(t.is_woken());
|
||||
|
||||
let entry = assert_ready_ok!(poll!(t, queue));
|
||||
assert_eq!(*entry.get_ref(), "foo");
|
||||
|
||||
let entry = assert_ready!(poll!(t, queue));
|
||||
assert!(entry.is_none())
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reset_much_later() {
|
||||
let mut t = MockTask::new();
|
||||
|
||||
// Reproduces tokio-rs/tokio#849.
|
||||
clock::mock(|clock| {
|
||||
let mut queue = DelayQueue::new();
|
||||
|
||||
let epoch = clock.now();
|
||||
|
||||
clock.turn_for(ms(1));
|
||||
|
||||
let key = queue.insert_at("foo", epoch + ms(200));
|
||||
|
||||
assert_pending!(poll!(t, queue));
|
||||
|
||||
clock.turn_for(ms(3));
|
||||
|
||||
queue.reset_at(&key, epoch + ms(5));
|
||||
|
||||
clock.turn_for(ms(20));
|
||||
|
||||
assert!(t.is_woken());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reset_twice() {
|
||||
let mut t = MockTask::new();
|
||||
|
||||
// Reproduces tokio-rs/tokio#849.
|
||||
clock::mock(|clock| {
|
||||
let mut queue = DelayQueue::new();
|
||||
|
||||
let epoch = clock.now();
|
||||
|
||||
clock.turn_for(ms(1));
|
||||
|
||||
let key = queue.insert_at("foo", epoch + ms(200));
|
||||
|
||||
assert_pending!(poll!(t, queue));
|
||||
|
||||
clock.turn_for(ms(3));
|
||||
|
||||
queue.reset_at(&key, epoch + ms(50));
|
||||
|
||||
clock.turn_for(ms(20));
|
||||
|
||||
queue.reset_at(&key, epoch + ms(40));
|
||||
|
||||
clock.turn_for(ms(20));
|
||||
|
||||
assert!(t.is_woken());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn remove_expired_item() {
|
||||
clock::mock(|clock| {
|
||||
let mut queue = DelayQueue::new();
|
||||
|
||||
let now = clock.now();
|
||||
|
||||
clock.turn_for(ms(10));
|
||||
|
||||
let key = queue.insert_at("foo", now);
|
||||
|
||||
let entry = queue.remove(&key);
|
||||
assert_eq!(entry.into_inner(), "foo");
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expires_before_last_insert() {
|
||||
let mut t = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
let mut queue = DelayQueue::new();
|
||||
|
||||
let epoch = clock.now();
|
||||
|
||||
queue.insert_at("foo", epoch + ms(10_000));
|
||||
|
||||
// Delay should be set to 8.192s here.
|
||||
assert_pending!(poll!(t, queue));
|
||||
|
||||
// Delay should be set to the delay of the new item here
|
||||
queue.insert_at("bar", epoch + ms(600));
|
||||
|
||||
assert_pending!(poll!(t, queue));
|
||||
|
||||
clock.advance(ms(600));
|
||||
|
||||
assert!(t.is_woken());
|
||||
|
||||
let entry = assert_ready_ok!(poll!(t, queue)).into_inner();
|
||||
assert_eq!(entry, "bar");
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multi_reset() {
|
||||
let mut t = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
let mut queue = DelayQueue::new();
|
||||
|
||||
let epoch = clock.now();
|
||||
|
||||
let foo = queue.insert_at("foo", epoch + ms(200));
|
||||
let bar = queue.insert_at("bar", epoch + ms(250));
|
||||
|
||||
assert_pending!(poll!(t, queue));
|
||||
|
||||
queue.reset_at(&foo, epoch + ms(300));
|
||||
queue.reset_at(&bar, epoch + ms(350));
|
||||
queue.reset_at(&foo, epoch + ms(400));
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expire_first_key_when_reset_to_expire_earlier() {
|
||||
let mut t = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
let mut queue = DelayQueue::new();
|
||||
|
||||
let epoch = clock.now();
|
||||
|
||||
let foo = queue.insert_at("foo", epoch + ms(200));
|
||||
queue.insert_at("bar", epoch + ms(250));
|
||||
|
||||
assert_pending!(poll!(t, queue));
|
||||
|
||||
queue.reset_at(&foo, epoch + ms(100));
|
||||
|
||||
clock.advance(ms(100));
|
||||
|
||||
assert!(t.is_woken());
|
||||
|
||||
let entry = assert_ready_ok!(poll!(t, queue)).into_inner();
|
||||
assert_eq!(entry, "foo");
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expire_second_key_when_reset_to_expire_earlier() {
|
||||
let mut t = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
let mut queue = DelayQueue::new();
|
||||
|
||||
let epoch = clock.now();
|
||||
|
||||
queue.insert_at("foo", epoch + ms(200));
|
||||
let bar = queue.insert_at("bar", epoch + ms(250));
|
||||
|
||||
assert_pending!(poll!(t, queue));
|
||||
|
||||
queue.reset_at(&bar, epoch + ms(100));
|
||||
|
||||
clock.advance(ms(100));
|
||||
|
||||
assert!(t.is_woken());
|
||||
let entry = assert_ready_ok!(poll!(t, queue)).into_inner();
|
||||
assert_eq!(entry, "bar");
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reset_first_expiring_item_to_expire_later() {
|
||||
let mut t = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
let mut queue = DelayQueue::new();
|
||||
|
||||
let epoch = clock.now();
|
||||
|
||||
let foo = queue.insert_at("foo", epoch + ms(200));
|
||||
let _bar = queue.insert_at("bar", epoch + ms(250));
|
||||
|
||||
assert_pending!(poll!(t, queue));
|
||||
|
||||
queue.reset_at(&foo, epoch + ms(300));
|
||||
clock.advance(ms(250));
|
||||
|
||||
assert!(t.is_woken());
|
||||
|
||||
let entry = assert_ready_ok!(poll!(t, queue)).into_inner();
|
||||
assert_eq!(entry, "bar");
|
||||
})
|
||||
}
|
||||
|
||||
fn ms(n: u64) -> Duration {
|
||||
Duration::from_millis(n)
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
#![warn(rust_2018_idioms)]
|
||||
#![cfg(feature = "default")]
|
||||
|
||||
use tokio::prelude::*;
|
||||
use tokio::timer::*;
|
||||
@@ -0,0 +1,67 @@
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
use tokio::sync::mpsc;
|
||||
use tokio::timer::throttle::Throttle;
|
||||
use tokio_test::task::MockTask;
|
||||
use tokio_test::{assert_pending, assert_ready_eq, clock};
|
||||
|
||||
use futures_core::Stream;
|
||||
use std::time::Duration;
|
||||
|
||||
macro_rules! poll {
|
||||
($task:ident, $stream:ident) => {{
|
||||
use std::pin::Pin;
|
||||
$task.enter(|cx| Pin::new(&mut $stream).poll_next(cx))
|
||||
}};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn throttle() {
|
||||
let mut t = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
let (mut tx, rx) = mpsc::unbounded_channel();
|
||||
let mut stream = Throttle::new(rx, ms(1));
|
||||
|
||||
assert_pending!(poll!(t, stream));
|
||||
|
||||
for i in 0..3 {
|
||||
tx.try_send(i).unwrap();
|
||||
}
|
||||
|
||||
for i in 0..3 {
|
||||
assert_ready_eq!(poll!(t, stream), Some(i));
|
||||
assert_pending!(poll!(t, stream));
|
||||
|
||||
clock.advance(ms(1));
|
||||
}
|
||||
|
||||
assert_pending!(poll!(t, stream));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn throttle_dur_0() {
|
||||
let mut t = MockTask::new();
|
||||
|
||||
clock::mock(|_| {
|
||||
let (mut tx, rx) = mpsc::unbounded_channel();
|
||||
let mut stream = Throttle::new(rx, ms(0));
|
||||
|
||||
assert_pending!(poll!(t, stream));
|
||||
|
||||
for i in 0..3 {
|
||||
tx.try_send(i).unwrap();
|
||||
}
|
||||
|
||||
for i in 0..3 {
|
||||
assert_ready_eq!(poll!(t, stream), Some(i));
|
||||
}
|
||||
|
||||
assert_pending!(poll!(t, stream));
|
||||
});
|
||||
}
|
||||
|
||||
fn ms(n: u64) -> Duration {
|
||||
Duration::from_millis(n)
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
use tokio::sync::oneshot;
|
||||
use tokio::timer::*;
|
||||
use tokio_test::task::MockTask;
|
||||
use tokio_test::{
|
||||
assert_err, assert_pending, assert_ready, assert_ready_err, assert_ready_ok, clock,
|
||||
};
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
#[test]
|
||||
fn simultaneous_deadline_future_completion() {
|
||||
let mut t = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
// Create a future that is immediately ready
|
||||
let fut = Box::pin(Timeout::new_at(async {}, clock.now()));
|
||||
|
||||
// Ready!
|
||||
assert_ready_ok!(t.poll(fut));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completed_future_past_deadline() {
|
||||
let mut t = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
// Wrap it with a deadline
|
||||
let fut = Timeout::new_at(async {}, clock.now() - ms(1000));
|
||||
let fut = Box::pin(fut);
|
||||
|
||||
// Ready!
|
||||
assert_ready_ok!(t.poll(fut));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn future_and_deadline_in_future() {
|
||||
let mut t = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
// Not yet complete
|
||||
let (tx, rx) = oneshot::channel();
|
||||
|
||||
// Wrap it with a deadline
|
||||
let mut fut = Timeout::new_at(rx, clock.now() + ms(100));
|
||||
|
||||
assert_pending!(t.poll(&mut fut));
|
||||
|
||||
// Turn the timer, it runs for the elapsed time
|
||||
clock.advance(ms(90));
|
||||
|
||||
assert_pending!(t.poll(&mut fut));
|
||||
|
||||
// Complete the future
|
||||
tx.send(()).unwrap();
|
||||
|
||||
assert_ready_ok!(t.poll(&mut fut)).unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn future_and_timeout_in_future() {
|
||||
let mut t = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
// Not yet complete
|
||||
let (tx, rx) = oneshot::channel();
|
||||
|
||||
// Wrap it with a deadline
|
||||
let mut fut = Timeout::new(rx, ms(100));
|
||||
|
||||
// Ready!
|
||||
assert_pending!(t.poll(&mut fut));
|
||||
|
||||
// Turn the timer, it runs for the elapsed time
|
||||
clock.advance(ms(90));
|
||||
|
||||
assert_pending!(t.poll(&mut fut));
|
||||
|
||||
// Complete the future
|
||||
tx.send(()).unwrap();
|
||||
|
||||
assert_ready_ok!(t.poll(&mut fut)).unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
struct Empty;
|
||||
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
impl Future for Empty {
|
||||
type Output = ();
|
||||
|
||||
fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<()> {
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deadline_now_elapses() {
|
||||
let mut t = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
// Wrap it with a deadline
|
||||
let mut fut = Timeout::new_at(Empty, clock.now());
|
||||
|
||||
assert_ready_err!(t.poll(&mut fut));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deadline_future_elapses() {
|
||||
let mut t = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
// Wrap it with a deadline
|
||||
let mut fut = Timeout::new_at(Empty, clock.now() + ms(300));
|
||||
|
||||
assert_pending!(t.poll(&mut fut));
|
||||
|
||||
clock.advance(ms(300));
|
||||
|
||||
assert_ready_err!(t.poll(&mut fut));
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(feature = "async-traits")]
|
||||
macro_rules! poll {
|
||||
($task:ident, $stream:ident) => {{
|
||||
use futures_core::Stream;
|
||||
$task.enter(|cx| Pin::new(&mut $stream).poll_next(cx))
|
||||
}};
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "async-traits")]
|
||||
fn stream_and_timeout_in_future() {
|
||||
use tokio_sync::mpsc;
|
||||
|
||||
let mut t = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
// Not yet complete
|
||||
let (mut tx, rx) = mpsc::unbounded_channel();
|
||||
|
||||
// Wrap it with a deadline
|
||||
let mut stream = Timeout::new(rx, ms(100));
|
||||
|
||||
// Not ready
|
||||
assert_pending!(poll!(t, stream));
|
||||
|
||||
// Turn the timer, it runs for the elapsed time
|
||||
clock.advance(ms(90));
|
||||
|
||||
assert_pending!(poll!(t, stream));
|
||||
|
||||
// Complete the future
|
||||
tx.try_send(()).unwrap();
|
||||
|
||||
let item = assert_ready!(poll!(t, stream));
|
||||
assert!(item.is_some());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "async-traits")]
|
||||
fn idle_stream_timesout_periodically() {
|
||||
use tokio_sync::mpsc;
|
||||
|
||||
let mut t = MockTask::new();
|
||||
|
||||
clock::mock(|clock| {
|
||||
// Not yet complete
|
||||
let (_tx, rx) = mpsc::unbounded_channel::<()>();
|
||||
|
||||
// Wrap it with a deadline
|
||||
let mut stream = Timeout::new(rx, ms(100));
|
||||
|
||||
// Not ready
|
||||
assert_pending!(poll!(t, stream));
|
||||
|
||||
// Turn the timer, it runs for the elapsed time
|
||||
clock.advance(ms(100));
|
||||
|
||||
let v = assert_ready!(poll!(t, stream)).unwrap();
|
||||
assert_err!(v);
|
||||
|
||||
// Stream's timeout should reset
|
||||
assert_pending!(poll!(t, stream));
|
||||
|
||||
// Turn the timer, it runs for the elapsed time
|
||||
clock.advance(ms(100));
|
||||
let v = assert_ready!(poll!(t, stream)).unwrap();
|
||||
assert_err!(v)
|
||||
});
|
||||
}
|
||||
|
||||
fn ms(n: u64) -> Duration {
|
||||
Duration::from_millis(n)
|
||||
}
|
||||
Reference in New Issue
Block a user