#![allow(deprecated)]
macro_rules! test {
($name:ident($now:pat_param) $body:block) => {
#[test]
fn $name() {
fn f<
T: crate::Time<Duration=std::time::Duration>
+ Copy
+ std::ops::Add<std::time::Duration, Output=T>
+ std::ops::AddAssign<std::time::Duration>
>($now: T)
$body
f(std::time::UNIX_EPOCH);
f(std::time::Instant::now());
#[cfg(feature="tokio")] f(tokio::time::Instant::now());
}
};
}
test!(test_rate_limit_fresh(now) {
let cfg = crate::Config::new(std::time::Duration::from_secs(1), 10);
assert!(crate::Tracker::full().simplify_at(&cfg, now));
assert_eq!(
crate::Tracker::full().acquire_at(&cfg, 11, now),
Err(crate::Denied::TooBig));
let mut t = crate::Tracker::full();
assert_eq!(t.capacity_at(&cfg, now), 10);
assert_eq!(t.acquire_at(&cfg, 1, now), Ok(()));
assert_eq!(t.capacity_at(&cfg, now), 9);
let mut t = crate::Tracker::full();
assert_eq!(t.capacity_at(&cfg, now), 10);
assert_eq!(t.acquire_at(&cfg, 8, now), Ok(()));
assert_eq!(t.capacity_at(&cfg, now), 2);
});
test!(test_rate_limit_slow(mut now) {
let cfg = crate::Config::new(std::time::Duration::from_secs(1), 10);
let mut t = crate::Tracker::full();
assert_eq!(t.capacity_at(&cfg, now), 10);
assert_eq!(t.acquire_at(&cfg, 1, now), Ok(()));
assert_eq!(t.capacity_at(&cfg, now), 9);
now += std::time::Duration::from_secs(10);
assert_eq!(t.capacity_at(&cfg, now), 10);
assert_eq!(t.acquire_at(&cfg, 1, now), Ok(()));
assert_eq!(t.capacity_at(&cfg, now), 9);
now += std::time::Duration::from_secs(10);
assert_eq!(t.capacity_at(&cfg, now), 10);
assert_eq!(t.acquire_at(&cfg, 1, now), Ok(()));
assert_eq!(t.capacity_at(&cfg, now), 9);
});
test!(test_rate_limit_active_capacity(now) {
let cfg = crate::Config::new(std::time::Duration::from_secs(1), 10);
let mut t = crate::Tracker::full();
assert_eq!(t.acquire_at(&cfg, 4, now), Ok(()));
assert!(!t.simplify_at(&cfg, now));
assert_eq!(t.capacity_at(&cfg, now), 6);
assert_eq!(t.capacity_at(&cfg, now + std::time::Duration::from_secs(1)), 7);
assert_eq!(t.capacity_at(&cfg, now + std::time::Duration::from_secs(2)), 8);
assert_eq!(t.capacity_at(&cfg, now + std::time::Duration::from_secs(3)), 9);
assert_eq!(t.capacity_at(&cfg, now + std::time::Duration::from_secs(4)), 10);
assert_eq!(t.capacity_at(&cfg, now + std::time::Duration::from_secs(5)), 10);
assert_eq!(t.capacity_at(&cfg, now + std::time::Duration::from_secs(50)), 10);
});
test!(test_with_capacity(now) {
let cfg = crate::Config::new(std::time::Duration::from_secs(1), 10);
let t = crate::Tracker::with_capacity_at(&cfg, 5, now);
assert_eq!(t.capacity_at(&cfg, now), 5);
assert_eq!(t.clone().acquire_at(&cfg, 5, now), Ok(()));
assert_eq!(
t.clone().acquire_at(&cfg, 6, now),
Err(crate::Denied::TooEarly(crate::TooEarly{
next: now + std::time::Duration::from_secs(1),
})));
let t = crate::Tracker::with_capacity_at(&cfg, 0, now);
assert_eq!(t.capacity_at(&cfg, now), 0);
assert_eq!(
t.clone().acquire_at(&cfg, 1, now),
Err(crate::Denied::TooEarly(crate::TooEarly{
next: now + std::time::Duration::from_secs(1),
})));
let t = crate::Tracker::with_capacity_at(&cfg, 10, now);
assert_eq!(t, crate::Tracker::Full{ overfull: 0 });
let t = crate::Tracker::with_capacity_at(&cfg, 11, now);
assert_eq!(t, crate::Tracker::Full{ overfull: 1 });
let t = crate::Tracker::with_capacity_at(&cfg, 201, now);
assert_eq!(t, crate::Tracker::Full{ overfull: 191 });
});
test!(test_with_limited_capacity(now) {
let cfg = crate::Config::new(std::time::Duration::from_secs(1), 10);
let t = crate::Tracker::with_limited_capacity_at(&cfg, 5, now);
assert_eq!(t.capacity_at(&cfg, now), 5);
assert_eq!(t.clone().acquire_at(&cfg, 5, now), Ok(()));
assert_eq!(
t.clone().acquire_at(&cfg, 6, now),
Err(crate::Denied::TooEarly(crate::TooEarly{
next: now + std::time::Duration::from_secs(1),
})));
let t = crate::Tracker::with_limited_capacity_at(&cfg, 0, now);
assert_eq!(t.capacity_at(&cfg, now), 0);
assert_eq!(
t.clone().acquire_at(&cfg, 1, now),
Err(crate::Denied::TooEarly(crate::TooEarly{
next: now + std::time::Duration::from_secs(1),
})));
let t = crate::Tracker::with_limited_capacity_at(&cfg, 10, now);
assert_eq!(t, crate::Tracker::Full{ overfull: 0 });
let t = crate::Tracker::with_limited_capacity_at(&cfg, 11, now);
assert_eq!(t, crate::Tracker::Full{ overfull: 0 });
let t = crate::Tracker::with_limited_capacity_at(&cfg, 201, now);
assert_eq!(t, crate::Tracker::Full{ overfull: 0 });
});
test!(test_rate_limit_acquire_range_zero(now) {
let cfg = crate::Config::new(std::time::Duration::from_secs(1), 10);
let mut t = crate::Tracker::full();
assert_eq!(t.acquire_range_at(&cfg, 0..=0, now), Ok(0));
assert_eq!(t.acquire_range_at(&cfg, 0..=1, now), Ok(1));
#[allow(clippy::reversed_empty_ranges)] {
assert_eq!(t.acquire_range_at(&cfg, 2..=1, now), Err(crate::Denied::EmptyRequest));
}
assert_eq!(t.acquire_range_at(&cfg, 0..=100, now), Ok(9));
assert_eq!(t.capacity_at(&cfg, now), 0);
assert_eq!(t.acquire_range_at(&cfg, 0..=0, now), Ok(0));
assert_eq!(t.acquire_range_at(&cfg, 0..=10, now), Ok(0));
#[allow(clippy::reversed_empty_ranges)] {
assert_eq!(t.acquire_range_at(&cfg, 2..=1, now), Err(crate::Denied::EmptyRequest));
}
});
test!(test_rate_limit_active_acquire(now) {
let cfg = crate::Config::new(std::time::Duration::from_secs(1), 10);
let mut base = crate::Tracker::full();
assert_eq!(base.acquire_at(&cfg, 4, now), Ok(()));
assert_eq!(base.capacity_at(&cfg, now), 6);
let base = base;
let mut t = base.clone();
assert_eq!(
t.acquire_at(&cfg, 2, now),
Ok(()));
assert_eq!(t.capacity_at(&cfg, now), 4);
let mut t = base.clone();
assert_eq!(
t.acquire_at(&cfg, 6, now),
Ok(()));
assert_eq!(t.capacity_at(&cfg, now), 0);
assert_eq!(
t.acquire_at(&cfg, 0, now),
Ok(()));
let mut t = base.clone();
assert_eq!(
t.acquire_at(&cfg, 7, now),
Err(crate::Denied::TooEarly(crate::TooEarly{
next: now + std::time::Duration::from_secs(1),
})));
assert_eq!(
t.acquire_at(&cfg, 7, now + std::time::Duration::from_secs(1)),
Ok(()));
let mut t = base.clone();
assert_eq!(
t.acquire_at(&cfg, 10, now),
Err(crate::Denied::TooEarly(crate::TooEarly{
next: now + std::time::Duration::from_secs(4),
})));
assert_eq!(
t.acquire_at(&cfg, 10, now + std::time::Duration::from_secs(4)),
Ok(()));
});
test!(test_rate_limit_acquire_up_to(mut now) {
let cfg = crate::Config::new(std::time::Duration::from_secs(1), 10);
let mut base = crate::Tracker::full();
assert_eq!(base.acquire_up_to_at_2(&cfg, 40, now), Ok(10));
assert_eq!(base.capacity_at(&cfg, now), 0);
assert_eq!(
base.acquire_up_to_at_2(&cfg, 1, now),
Err(crate::Denied::TooEarly(crate::TooEarly{
next: now + std::time::Duration::from_secs(1),
})));
assert_eq!(
base.acquire_up_to_at_2(&cfg, 2, now),
Err(crate::Denied::TooEarly(crate::TooEarly{
next: now + std::time::Duration::from_secs(1),
})));
assert_eq!(
base.acquire_up_to_at_2(&cfg, 0, now),
Ok(0));
now += std::time::Duration::from_secs(4);
assert_eq!(base.capacity_at(&cfg, now), 4);
assert_eq!(base.acquire_up_to_at_2(&cfg, 2, now), Ok(2));
assert_eq!(base.acquire_up_to_at_2(&cfg, 4, now), Ok(2));
now += std::time::Duration::from_secs(4);
assert_eq!(base.capacity_at(&cfg, now), 4);
assert_eq!(base.acquire_up_to_at_2(&cfg, 5, now), Ok(4));
now += std::time::Duration::from_secs(20);
assert_eq!(base.capacity_at(&cfg, now), 10);
assert_eq!(base.acquire_up_to_at_2(&cfg, 200, now), Ok(10));
});
test!(test_acquire_overflow(now) {
let cfg = crate::Config::new(std::time::Duration::from_secs(1000 * 365 * 24 * 3600), 1_000_000_000);
let mut base = crate::Tracker::full();
assert_eq!(base.acquire_up_to_at_2(&cfg, 1, now), Ok(1));
});
test!(test_force_acquire(mut now) {
let cfg = crate::Config::new(std::time::Duration::from_secs(1), 10);
let mut t = crate::Tracker::full();
t.force_acquire_at(&cfg, 5, now);
assert_eq!(t.capacity_at(&cfg, now), 5);
t.add_capacity_at(&cfg, 20, now);
t.force_acquire_at(&cfg, 10, now);
assert_eq!(t.capacity_at(&cfg, now), 15);
t.force_acquire_at(&cfg, 6, now);
assert_eq!(t.capacity_at(&cfg, now), 9);
now += std::time::Duration::from_millis(500);
t.force_acquire_at(&cfg, 4, now);
assert_eq!(t.capacity_at(&cfg, now), 5);
now += std::time::Duration::from_millis(500);
assert_eq!(t.capacity_at(&cfg, now), 6);
t.force_acquire_at(&cfg, 5, now);
assert_eq!(t.capacity_at(&cfg, now), 1);
t.force_acquire_at(&cfg, 5, now);
assert_eq!(t.capacity_at(&cfg, now), 0);
assert_eq!(
t.acquire_at(&cfg, 1, now),
Err(crate::Denied::TooEarly(crate::TooEarly{
next: now + std::time::Duration::from_secs(5),
})));
assert_eq!(
t.acquire_at(&cfg, 4, now),
Err(crate::Denied::TooEarly(crate::TooEarly{
next: now + std::time::Duration::from_secs(8),
})));
now += std::time::Duration::from_secs(4);
assert_eq!(t.capacity_at(&cfg, now), 0);
assert_eq!(
t.acquire_at(&cfg, 1, now),
Err(crate::Denied::TooEarly(crate::TooEarly{
next: now + std::time::Duration::from_secs(1),
})));
assert_eq!(
t.acquire_at(&cfg, 3, now),
Err(crate::Denied::TooEarly(crate::TooEarly{
next: now + std::time::Duration::from_secs(3),
})));
t.force_acquire_at(&cfg, 5, now);
assert_eq!(t.capacity_at(&cfg, now), 0);
assert_eq!(
t.acquire_at(&cfg, 1, now),
Err(crate::Denied::TooEarly(crate::TooEarly{
next: now + std::time::Duration::from_secs(6),
})));
now += std::time::Duration::from_secs(6);
assert_eq!(t.capacity_at(&cfg, now), 1);
assert_eq!(
t.acquire_at(&cfg, 1, now),
Ok(()));
});
test!(test_add_capacity(mut now) {
let cfg = crate::Config::new(std::time::Duration::from_secs(1), 10);
let mut base = crate::Tracker::new_at(now);
assert_eq!(base.capacity_at(&cfg, now), 0);
now += std::time::Duration::from_millis(500);
base.add_capacity_at(&cfg, 4, now);
assert_eq!(base.capacity_at(&cfg, now), 4);
now += std::time::Duration::from_millis(500);
assert_eq!(base.capacity_at(&cfg, now), 5);
now += std::time::Duration::from_millis(500);
base.add_capacity_at(&cfg, 5, now);
assert_eq!(base.capacity_at(&cfg, now), 10);
assert_eq!(base.acquire_at(&cfg, 1, now), Ok(()));
now += std::time::Duration::from_millis(500);
assert_eq!(base.capacity_at(&cfg, now), 9);
now += std::time::Duration::from_millis(500);
assert_eq!(base.capacity_at(&cfg, now), 10);
assert_eq!(base.acquire_at(&cfg, 4, now), Ok(()));
base.add_capacity_at(&cfg, 10, now);
assert_eq!(base.capacity_at(&cfg, now), 16);
base.add_capacity_at(&cfg, 1, now);
assert_eq!(base.capacity_at(&cfg, now), 17);
});
test!(test_add_capacity_overflow(now) {
let cfg = crate::Config::new(std::time::Duration::from_secs(1), 3_000_000_000);
let mut t = crate::Tracker::overfull(3_000_000_000);
assert_eq!(t.capacity_at(&cfg, now), u32::MAX);
t.add_capacity_at(&cfg, 3_000_000_000, now);
assert_eq!(t.capacity_at(&cfg, now), u32::MAX);
});
test!(test_add_capacity_stale(mut now) {
let cfg = crate::Config::new(std::time::Duration::from_secs(1), 10);
let mut t = crate::Tracker::empty_at(now);
now += std::time::Duration::from_secs(20);
assert_eq!(t.capacity_at(&cfg, now), 10);
t.add_capacity_at(&cfg, 4, now);
assert_eq!(t.capacity_at(&cfg, now), 14);
});
test!(test_add_limited_capacity(mut now) {
let cfg = crate::Config::new(std::time::Duration::from_secs(1), 10);
let mut base = crate::Tracker::empty_at(now);
assert_eq!(base.capacity_at(&cfg, now), 0);
now += std::time::Duration::from_millis(500);
base.add_limited_capacity_at(&cfg, 4, now);
assert_eq!(base.capacity_at(&cfg, now), 4);
now += std::time::Duration::from_millis(500);
assert_eq!(base.capacity_at(&cfg, now), 5);
now += std::time::Duration::from_millis(500);
base.add_limited_capacity_at(&cfg, 5, now);
assert_eq!(base.capacity_at(&cfg, now), 10);
assert_eq!(base.acquire_at(&cfg, 1, now), Ok(()));
now += std::time::Duration::from_millis(500);
assert_eq!(base.capacity_at(&cfg, now), 9);
now += std::time::Duration::from_millis(500);
assert_eq!(base.capacity_at(&cfg, now), 10);
assert_eq!(base.acquire_at(&cfg, 4, now), Ok(()));
base.add_limited_capacity_at(&cfg, 10, now);
assert_eq!(base.capacity_at(&cfg, now), 10);
base.add_limited_capacity_at(&cfg, 1, now);
assert_eq!(base.capacity_at(&cfg, now), 10);
base.add_capacity_at(&cfg, 1, now);
assert_eq!(base.capacity_at(&cfg, now), 11);
base.add_limited_capacity_at(&cfg, 1, now);
assert_eq!(base.capacity_at(&cfg, now), 11);
});
test!(test_overfull(mut now) {
let cfg = crate::Config::new(std::time::Duration::from_secs(1), 10);
let mut base = crate::Tracker::overfull(10);
assert_eq!(base.capacity_at(&cfg, now), 20);
assert!(!base.simplify_at(&cfg, now));
assert_eq!(base.capacity_at(&cfg, now), 20);
assert_eq!(
base.acquire_at(&cfg, 30, now),
Err(crate::Denied::TooBig));
assert_eq!(base.acquire_up_to_at_2(&cfg, 40, now), Ok(20));
assert_eq!(base.capacity_at(&cfg, now), 0);
now += std::time::Duration::from_secs(4);
assert_eq!(base.capacity_at(&cfg, now), 4);
now += std::time::Duration::from_secs(10);
assert_eq!(base.capacity_at(&cfg, now), 10);
});
test!(test_unlimited(mut now) {
let cfg = crate::Config::new(std::time::Duration::from_secs(1), 10);
let mut base = crate::Tracker::unlimited();
assert_eq!(base.capacity_at(&cfg, now), u32::MAX);
assert_eq!(base.acquire_range_at(&cfg, 0..=u32::MAX, now), Ok(u32::MAX));
assert_eq!(base.acquire_range_at(&cfg, 10..=u32::MAX, now), Ok(u32::MAX));
assert_eq!(base.acquire_range_at(&cfg, u32::MAX..=u32::MAX, now), Ok(u32::MAX));
assert_eq!(base.capacity_at(&cfg, now), u32::MAX);
assert!(!base.simplify_at(&cfg, now));
assert_eq!(base.capacity_at(&cfg, now), u32::MAX);
now += std::time::Duration::from_secs(4);
assert_eq!(base.capacity_at(&cfg, now), u32::MAX);
assert_eq!(base.acquire_range_at(&cfg, 0..=u32::MAX, now), Ok(u32::MAX));
assert_eq!(base.acquire_range_at(&cfg, 10..=u32::MAX, now), Ok(u32::MAX));
assert_eq!(base.acquire_range_at(&cfg, u32::MAX..=u32::MAX, now), Ok(u32::MAX));
assert_eq!(base.capacity_at(&cfg, now), u32::MAX);
});
test!(test_negative_capacity(mut now) {
let cfg = crate::Config::new(std::time::Duration::from_secs(1), 10);
let mut t = crate::Tracker::empty_at(now + std::time::Duration::from_secs(100));
assert_eq!(t.capacity_at(&cfg, now), 0);
assert!(!t.simplify_at(&cfg, now));
assert_eq!(
t.acquire_at(&cfg, 1, now),
Err(crate::Denied::TooEarly(crate::TooEarly {
next: now + std::time::Duration::from_secs(101),
})));
now += std::time::Duration::from_secs(100);
assert_eq!(t.capacity_at(&cfg, now), 0);
assert!(!t.simplify_at(&cfg, now));
assert_eq!(
t.acquire_at(&cfg, 1, now),
Err(crate::Denied::TooEarly(crate::TooEarly {
next: now + std::time::Duration::from_secs(1),
})));
now += std::time::Duration::from_secs(1);
assert_eq!(t.capacity_at(&cfg, now), 1);
assert_eq!(t.acquire_at(&cfg, 1, now), Ok(()));
});
test!(test_simplify(mut now) {
let cfg = crate::Config::new(std::time::Duration::from_secs(1), 10);
let mut base = crate::Tracker::overfull(10);
assert_eq!(base.capacity_at(&cfg, now), 20);
assert!(!base.simplify_at(&cfg, now));
assert_eq!(base.capacity_at(&cfg, now), 20);
assert_eq!(base.acquire_at(&cfg, 10, now), Ok(()));
assert_eq!(base.capacity_at(&cfg, now), 10);
assert!(base.simplify_at(&cfg, now));
assert_eq!(base.capacity_at(&cfg, now), 10);
assert_eq!(base.acquire_at(&cfg, 1, now), Ok(()));
assert_eq!(base.capacity_at(&cfg, now), 9);
assert!(!base.simplify_at(&cfg, now));
assert_eq!(base.capacity_at(&cfg, now), 9);
now += std::time::Duration::from_secs(1);
assert_eq!(base.capacity_at(&cfg, now), 10);
assert!(base.simplify_at(&cfg, now));
assert_eq!(base.capacity_at(&cfg, now), 10);
});
test!(test_disabled_full(now) {
let cfg = crate::Config::disabled();
let mut t = crate::Tracker::full();
assert_eq!(t.capacity_at(&cfg, now), 0);
assert_eq!(t.acquire_at(&cfg, 1, now), Err(crate::Denied::TooBig));
assert!(t.simplify_at(&cfg, now));
t.force_acquire_at(&cfg, 1, now);
assert_eq!(t.capacity_at(&cfg, now), 0);
assert_eq!(t.capacity_at(&cfg, now + std::time::Duration::from_secs(1000 * 365 * 24 * 3600)), 0);
assert_eq!(t.acquire_at(&cfg, 1, now), Err(crate::Denied::TooBig));
assert!(t.simplify_at(&cfg, now));
});
test!(test_disabled_empty(now) {
let cfg = crate::Config::disabled();
let mut t = crate::Tracker::empty_at(now);
assert_eq!(t.capacity_at(&cfg, now), 0);
assert_eq!(t.acquire_at(&cfg, 1, now), Err(crate::Denied::TooBig));
assert!(t.simplify_at(&cfg, now));
t.force_acquire_at(&cfg, 1, now);
assert_eq!(t.capacity_at(&cfg, now), 0);
assert_eq!(t.acquire_at(&cfg, 1, now), Err(crate::Denied::TooBig));
assert!(t.simplify_at(&cfg, now));
});
test!(test_disabled_overfull(now) {
let cfg = crate::Config::disabled();
let mut t = crate::Tracker::overfull(10);
assert_eq!(t.capacity_at(&cfg, now), 10);
assert_eq!(t.acquire_at(&cfg, 3, now), Ok(()));
assert_eq!(t.capacity_at(&cfg, now), 7);
assert!(!t.simplify_at(&cfg, now));
assert_eq!(t.acquire_at(&cfg, 8, now), Err(crate::Denied::TooBig));
assert_eq!(
t.acquire_at(&cfg, 8, now + std::time::Duration::from_secs(1000 * 365 * 24 * 3600)),
Err(crate::Denied::TooBig),
);
assert_eq!(t.acquire_at(&cfg, 6, now), Ok(()));
t.force_acquire_at(&cfg, 3, now);
assert_eq!(t.capacity_at(&cfg, now), 0);
assert!(t.simplify_at(&cfg, now));
});
test!(test_disabled_acquire_range(mut now) {
let cfg = crate::Config::disabled();
let mut t = crate::Tracker::default();
assert_eq!(t.capacity_at(&cfg, now), 0);
assert_eq!(t.acquire_range_at(&cfg, 0..=3, now), Ok(0));
now += std::time::Duration::from_secs(1);
assert_eq!(t.acquire_range_at(&cfg, 0..=3, now), Ok(0));
assert_eq!(t.acquire_range_at(&cfg, 0..=1, now), Ok(0));
now += std::time::Duration::from_secs(100);
assert_eq!(t.acquire_range_at(&cfg, 0..=3, now), Ok(0));
assert_eq!(t.acquire_range_at(&cfg, 0..=1, now), Ok(0));
assert!(t.simplify_at(&cfg, now));
});
test!(test_disabled_acquire_up_to(now) {
let cfg = crate::Config::disabled();
let mut t = crate::Tracker::default();
assert_eq!(t.acquire_up_to_at_2(&cfg, 1, now), Err(crate::Denied::TooBig));
});
test!(test_disabled_add_capacity(mut now) {
let cfg = crate::Config::disabled();
let mut t = crate::Tracker::empty_at(now);
now += std::time::Duration::from_secs(1);
t.force_acquire_at(&cfg, 3, now);
now += std::time::Duration::from_secs(1);
t.add_capacity_at(&cfg, 4, now);
});