use super::*;
fn sched_with_clock() -> (DeadlineScheduler<&'static str, TestClock>, ()) {
(
DeadlineScheduler::new(64, TestClock::new(), Duration::from_millis(1)),
(),
)
}
#[test]
fn tick_nanos_reflects_the_configured_resolution() {
let s: DeadlineScheduler<&'static str, TestClock> =
DeadlineScheduler::new(64, TestClock::new(), Duration::from_millis(1));
assert_eq!(s.tick_nanos(), 1_000_000);
}
#[test]
fn schedule_after_fires_after_elapsed_time() {
let (mut s, _) = sched_with_clock();
s.schedule_after(Duration::from_millis(3), "a");
assert!(s.poll().is_empty());
s.clock.advance(Duration::from_millis(2));
assert!(s.poll().is_empty());
s.clock.advance(Duration::from_millis(1));
assert_eq!(s.poll(), vec!["a"]);
}
#[test]
fn schedule_at_with_absolute_deadline_fires_when_clock_passes_it() {
let mut s = DeadlineScheduler::new(64, TestClock::new(), Duration::from_millis(1));
let when = s.clock.now_nanos() + Duration::from_millis(5).as_nanos() as u64;
s.schedule_at(when, "five");
s.clock.advance(Duration::from_millis(4));
assert!(s.poll().is_empty());
s.clock.advance(Duration::from_millis(1));
assert_eq!(s.poll(), vec!["five"]);
}
#[test]
fn schedule_at_in_the_past_fires_on_next_tick() {
let mut s = DeadlineScheduler::new(64, TestClock::new(), Duration::from_millis(1));
s.clock.advance(Duration::from_secs(10));
let id = s.schedule_at(0, "stale");
s.clock.advance(Duration::from_millis(1));
assert_eq!(s.poll(), vec!["stale"]);
assert!(!s.cancel(id));
}
#[test]
fn cancel_removes_before_fire() {
let (mut s, _) = sched_with_clock();
let id = s.schedule_after(Duration::from_millis(3), "doomed");
assert!(s.cancel(id));
s.clock.advance(Duration::from_millis(10));
assert!(s.poll().is_empty());
}
#[test]
fn poll_with_no_clock_movement_is_idempotent() {
let (mut s, _) = sched_with_clock();
s.schedule_after(Duration::from_millis(2), "a");
assert!(s.poll().is_empty());
assert!(s.poll().is_empty());
s.clock.advance(Duration::from_millis(2));
let first = s.poll();
let second = s.poll();
assert_eq!(first, vec!["a"]);
assert!(second.is_empty(), "second poll must not refire");
}
#[test]
fn sub_tick_delay_rounds_up_to_one_tick() {
let mut s = DeadlineScheduler::new(64, TestClock::new(), Duration::from_millis(1));
s.schedule_after(Duration::from_micros(500), "a");
s.clock.advance(Duration::from_millis(1));
assert_eq!(s.poll(), vec!["a"]);
}
#[test]
fn many_deadlines_fire_in_order() {
let mut s = DeadlineScheduler::new(64, TestClock::new(), Duration::from_millis(1));
for i in 1u32..=10 {
s.schedule_after(Duration::from_millis(i as u64), i);
}
for i in 1u32..=10 {
s.clock.advance(Duration::from_millis(1));
assert_eq!(s.poll(), vec![i]);
}
}
#[test]
fn monotonic_clock_default_does_not_panic() {
let c = MonotonicClock::new();
let a = c.now_nanos();
let b = c.now_nanos();
assert!(b >= a);
}
#[test]
fn monotonic_clock_default_origin_lazily_initialises() {
let c = MonotonicClock::default();
let a = c.now_nanos();
let b = c.now_nanos();
let d = c.now_nanos();
assert!(b >= a);
assert!(d >= b);
let t = TestClock::default();
assert_eq!(t.now_nanos(), 0);
t.advance(Duration::from_nanos(7));
assert_eq!(t.now_nanos(), 7);
}
#[test]
fn idle_timeout_is_bumped_by_reschedule_rather_than_re_armed() {
let clock = TestClock::new();
let mut s: DeadlineScheduler<&'static str, TestClock> =
DeadlineScheduler::new(256, clock, Duration::from_millis(1));
let id = s.schedule_after(Duration::from_millis(10), "SESSION-IDLE");
assert_eq!(s.pending(), 1);
assert!(!s.is_empty());
s.clock.advance(Duration::from_millis(6));
assert!(s.poll().is_empty());
assert!(s.reschedule_after(id, Duration::from_millis(10)));
s.clock.advance(Duration::from_millis(9));
assert!(s.poll().is_empty(), "the bumped deadline has not arrived");
s.clock.advance(Duration::from_millis(1));
assert_eq!(s.poll(), vec!["SESSION-IDLE"]);
assert!(s.is_empty());
}
#[test]
fn reschedule_at_moves_an_absolute_deadline_and_drain_empties_the_layer() {
let clock = TestClock::new();
let mut s: DeadlineScheduler<u32, TestClock> =
DeadlineScheduler::new(256, clock, Duration::from_millis(1));
let id = s.schedule_at(Duration::from_millis(20).as_nanos() as u64, 1);
assert!(s.reschedule_at(id, Duration::from_millis(3).as_nanos() as u64));
s.clock.advance(Duration::from_millis(3));
assert_eq!(s.poll(), vec![1]);
assert!(!s.reschedule_at(id, 0), "a fired deadline cannot be moved");
s.schedule_after(Duration::from_millis(5), 2);
s.schedule_after(Duration::from_millis(9), 3);
let mut left = s.drain();
left.sort();
assert_eq!(left, vec![2, 3]);
assert_eq!(s.pending(), 0);
}