use crate::RateLimiter;
use std::time::{Duration, SystemTime};
const LIMIT_COUNT: usize = 5;
const LIMIT_DURATION: Duration = Duration::from_secs(10);
const LIMIT_DURATION_SHORT: Duration = Duration::from_millis(250);
#[test]
fn test_get_wait_duration_empty() {
let mut limiter = RateLimiter::new(LIMIT_COUNT, LIMIT_DURATION);
let wait = limiter.get_wait_duration();
print_duration("Wait", wait);
assert!(wait.is_none());
}
#[test]
fn test_get_wait_duration_available() {
let mut limiter = RateLimiter::new(LIMIT_COUNT, LIMIT_DURATION);
let now = SystemTime::now();
for _ in 0..(LIMIT_COUNT - 1) {
limiter.requests.push_back(now);
}
let wait = limiter.get_wait_duration();
print_duration("Wait", wait);
assert!(wait.is_none());
}
#[test]
fn test_get_wait_duration_full() {
let mut limiter = RateLimiter::new(LIMIT_COUNT, LIMIT_DURATION);
let now = SystemTime::now();
for _ in 0..LIMIT_COUNT {
limiter.requests.push_back(now);
}
let wait = limiter.get_wait_duration();
print_duration("Wait", wait);
assert!(wait.is_some());
assert!(approximately_equals(
wait.unwrap(),
LIMIT_DURATION,
Duration::from_millis(100)
));
}
#[test]
fn test_execute_available() {
let mut limiter = RateLimiter::new(LIMIT_COUNT, LIMIT_DURATION);
let now = SystemTime::now();
for _ in 0..(LIMIT_COUNT - 1) {
limiter.requests.push_back(now);
}
let now = SystemTime::now();
let wait = limiter.execute();
let elapsed = now.elapsed().expect("elapsed should not fail");
print_duration("Wait", wait);
print_duration("Elapsed", Some(elapsed));
assert!(wait.is_none());
assert!(approximately_equals(
elapsed,
Duration::from_secs(0),
Duration::from_millis(50)
));
}
#[test]
fn test_execute_full() {
let mut limiter = RateLimiter::new(LIMIT_COUNT, LIMIT_DURATION_SHORT);
let now = SystemTime::now();
for _ in 0..LIMIT_COUNT {
limiter.requests.push_back(now);
}
let now = SystemTime::now();
let wait = limiter.execute();
let elapsed = now.elapsed().expect("elapsed should not fail");
print_duration("Wait", wait);
print_duration("Elapsed", Some(elapsed));
assert!(wait.is_some());
assert!(approximately_equals(
wait.unwrap(),
LIMIT_DURATION_SHORT,
Duration::from_millis(50)
));
assert!(approximately_equals(
elapsed,
LIMIT_DURATION_SHORT,
Duration::from_millis(50)
));
}
fn approximately_equals(d1: Duration, d2: Duration, tolerance: Duration) -> bool {
if d1 > d2 {
d1.checked_sub(d2).unwrap() <= tolerance
} else {
d2.checked_sub(d1).unwrap() <= tolerance
}
}
fn print_duration(name: &str, duration: Option<Duration>) {
if let Some(duration) = duration {
println!("{name} duration: {:.3} seconds", duration.as_secs_f64());
} else {
println!("{name} duration: None");
}
}