#[cfg(test)]
mod tests {
use crate::helpers::*;
#[test]
fn first_request_always_allowed() {
let (limiter, _clock) = setup_limiter(1.0, 1.0, 0.0);
assert_request_allowed(&limiter, "client1");
}
#[test]
fn rate_limiting_blocks_rapid_requests() {
let (limiter, clock) = setup_limiter(1.0, 0.0, 0.0); let client = "client1";
assert_request_allowed(&limiter, client);
assert_request_denied(&limiter, client);
clock.set_time(0.5);
assert_request_denied(&limiter, client);
let decision = advance_time_and_request(&limiter, &clock, 0.5, client);
assert!(decision.allowed);
assert_request_denied(&limiter, client);
}
#[test]
fn burst_allowance_works() {
let clock = TestClock::new(0.0);
let config = FluxLimiterConfig::new(1.0, 3.0); let limiter = FluxLimiter::with_config(config, clock.clone()).unwrap();
let client = "client1";
assert!(limiter.check_request(client).unwrap().allowed);
assert!(limiter.check_request(client).unwrap().allowed);
assert!(limiter.check_request(client).unwrap().allowed);
assert!(limiter.check_request(client).unwrap().allowed);
assert!(!limiter.check_request(client).unwrap().allowed);
clock.set_time(1.0);
assert!(limiter.check_request(client).unwrap().allowed);
assert!(!limiter.check_request(client).unwrap().allowed);
}
#[test]
fn multiple_clients_independent() {
let clock = TestClock::new(0.0);
let config = FluxLimiterConfig::new(1.0, 0.0); let limiter = FluxLimiter::with_config(config, clock.clone()).unwrap();
assert!(limiter.check_request("client1").unwrap().allowed);
assert!(limiter.check_request("client2").unwrap().allowed);
assert!(!limiter.check_request("client1").unwrap().allowed);
assert!(!limiter.check_request("client2").unwrap().allowed);
clock.set_time(1.0);
assert!(limiter.check_request("client1").unwrap().allowed);
assert!(limiter.check_request("client2").unwrap().allowed);
assert!(!limiter.check_request("client1").unwrap().allowed);
assert!(limiter.check_request("client3").unwrap().allowed);
}
#[test]
fn time_progression_allows_requests() {
let clock = TestClock::new(0.0);
let config = FluxLimiterConfig::new(2.0, 0.0); let limiter = FluxLimiter::with_config(config, clock.clone()).unwrap();
let client = "client1";
assert!(limiter.check_request(client).unwrap().allowed);
assert!(!limiter.check_request(client).unwrap().allowed);
clock.set_time(0.25);
assert!(!limiter.check_request(client).unwrap().allowed);
clock.set_time(0.5);
assert!(limiter.check_request(client).unwrap().allowed);
assert!(!limiter.check_request(client).unwrap().allowed);
clock.set_time(1.0);
assert!(limiter.check_request(client).unwrap().allowed);
clock.set_time(10.0);
assert!(limiter.check_request(client).unwrap().allowed);
}
#[test]
fn test_clock_advances_time() {
let clock = TestClock::new(5.0);
assert_eq!(clock.time_as_f64(), 5.0);
clock.advance(2.5);
assert_eq!(clock.time_as_f64(), 7.5);
clock.set_time(0.0);
assert_eq!(clock.time_as_f64(), 0.0);
}
#[test]
fn accessor_methods_work() {
let clock = TestClock::new(0.0);
let config = FluxLimiterConfig::new(10.0, 5.0);
let limiter = FluxLimiter::<String, _>::with_config(config, clock).unwrap();
assert_eq!(limiter.rate(), 10.0);
assert_eq!(limiter.burst(), 5.0);
}
#[test]
fn nanosecond_precision() {
let clock = TestClock::new(0.0);
let config = FluxLimiterConfig::new(1_000_000.0, 0.0); let limiter = FluxLimiter::with_config(config, clock.clone()).unwrap();
let client = "client1";
let decision = limiter.check_request(client).expect("Clock should work");
assert!(decision.allowed);
assert!(
!limiter
.check_request(client)
.expect("Clock should work")
.allowed
);
clock.advance(0.000001);
assert!(
limiter
.check_request(client)
.expect("Clock should work")
.allowed
);
}
}