mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-01-17 02:10:07 +00:00
327 lines
7.9 KiB
Rust
327 lines
7.9 KiB
Rust
#![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)
|
|
}
|