#[cfg(test)]
mod tests {
use fraiseql_server::middleware::{RateLimitConfig, RateLimiter};
fn create_test_limiter(rps_per_ip: u32, burst_size: u32) -> RateLimiter {
RateLimiter::new(RateLimitConfig {
enabled: true,
rps_per_ip,
rps_per_user: 1000,
burst_size,
cleanup_interval_secs: 300,
trust_proxy_headers: false,
trusted_proxy_cidrs: Vec::new(),
max_buckets: 100_000,
})
}
#[tokio::test]
async fn test_rate_limiter_respects_ip_limit() {
let limiter = create_test_limiter(5, 5);
for i in 0..5 {
let result = limiter.check_ip_limit("192.168.1.1", None).await;
assert!(result.allowed, "Request {} should be allowed within rate limit", i + 1);
}
let result = limiter.check_ip_limit("192.168.1.1", None).await;
assert!(!result.allowed, "Request 6 should exceed rate limit");
}
#[tokio::test]
async fn test_rate_limiter_independent_per_ip() {
let limiter = create_test_limiter(2, 2);
assert!(limiter.check_ip_limit("192.168.1.1", None).await.allowed);
assert!(limiter.check_ip_limit("192.168.1.1", None).await.allowed);
assert!(!limiter.check_ip_limit("192.168.1.1", None).await.allowed);
assert!(limiter.check_ip_limit("192.168.1.2", None).await.allowed);
assert!(limiter.check_ip_limit("192.168.1.2", None).await.allowed);
assert!(!limiter.check_ip_limit("192.168.1.2", None).await.allowed);
}
#[tokio::test]
async fn test_rate_limiter_config_accessible() {
let limiter = create_test_limiter(100, 500);
let config = limiter.config();
assert_eq!(config.rps_per_ip, 100);
assert_eq!(config.burst_size, 500);
assert!(config.enabled);
}
#[tokio::test]
async fn test_rate_limiter_disabled() {
let limiter = RateLimiter::new(RateLimitConfig {
enabled: false,
rps_per_ip: 1,
rps_per_user: 1,
burst_size: 1,
cleanup_interval_secs: 300,
trust_proxy_headers: false,
trusted_proxy_cidrs: Vec::new(),
max_buckets: 100_000,
});
for _ in 0..100 {
assert!(limiter.check_ip_limit("192.168.1.1", None).await.allowed);
}
}
#[tokio::test]
async fn test_rate_limiter_remaining_tokens() {
let limiter = create_test_limiter(10, 10);
let first = limiter.check_ip_limit("192.168.1.1", None).await;
assert!(first.allowed);
assert!(first.remaining < 10.0, "remaining should decrease after first request");
let second = limiter.check_ip_limit("192.168.1.1", None).await;
assert!(second.remaining < first.remaining, "remaining must decrease per request");
}
#[tokio::test]
async fn test_rate_limiter_user_limit() {
let limiter = RateLimiter::new(RateLimitConfig {
enabled: true,
rps_per_ip: 100,
rps_per_user: 3,
burst_size: 3,
cleanup_interval_secs: 300,
trust_proxy_headers: false,
trusted_proxy_cidrs: Vec::new(),
max_buckets: 100_000,
});
assert!(limiter.check_user_limit("user123", None).await.allowed);
assert!(limiter.check_user_limit("user123", None).await.allowed);
assert!(limiter.check_user_limit("user123", None).await.allowed);
assert!(!limiter.check_user_limit("user123", None).await.allowed);
}
#[tokio::test]
async fn test_rate_limiter_independent_users() {
let limiter = RateLimiter::new(RateLimitConfig {
enabled: true,
rps_per_ip: 100,
rps_per_user: 2,
burst_size: 2,
cleanup_interval_secs: 300,
trust_proxy_headers: false,
trusted_proxy_cidrs: Vec::new(),
max_buckets: 100_000,
});
assert!(limiter.check_user_limit("user1", None).await.allowed);
assert!(limiter.check_user_limit("user1", None).await.allowed);
assert!(!limiter.check_user_limit("user1", None).await.allowed);
assert!(limiter.check_user_limit("user2", None).await.allowed);
assert!(limiter.check_user_limit("user2", None).await.allowed);
assert!(!limiter.check_user_limit("user2", None).await.allowed);
}
#[tokio::test]
async fn test_rate_limiter_user_remaining() {
let limiter = RateLimiter::new(RateLimitConfig {
enabled: true,
rps_per_ip: 100,
rps_per_user: 10,
burst_size: 10,
cleanup_interval_secs: 300,
trust_proxy_headers: false,
trusted_proxy_cidrs: Vec::new(),
max_buckets: 100_000,
});
let first = limiter.check_user_limit("user123", None).await;
assert!(first.allowed);
assert!(first.remaining < 10.0, "remaining should decrease after first request");
let second = limiter.check_user_limit("user123", None).await;
assert!(second.remaining < first.remaining, "remaining must decrease per request");
}
#[tokio::test]
async fn test_rate_limiter_cleanup() {
let limiter = create_test_limiter(10, 10);
limiter.check_ip_limit("192.168.1.1", None).await;
limiter.check_ip_limit("192.168.1.2", None).await;
limiter.cleanup().await;
}
#[tokio::test]
async fn test_rate_limiter_burst_capacity() {
let limiter = RateLimiter::new(RateLimitConfig {
enabled: true,
rps_per_ip: 100,
rps_per_user: 100,
burst_size: 5,
cleanup_interval_secs: 300,
trust_proxy_headers: false,
trusted_proxy_cidrs: Vec::new(),
max_buckets: 100_000,
});
for _ in 0..5 {
assert!(limiter.check_ip_limit("192.168.1.1", None).await.allowed);
}
assert!(!limiter.check_ip_limit("192.168.1.1", None).await.allowed);
}
#[test]
fn test_rate_limit_config_defaults() {
let config = RateLimitConfig::default();
assert!(config.enabled);
assert_eq!(config.rps_per_ip, 100);
assert_eq!(config.rps_per_user, 1000);
assert_eq!(config.burst_size, 500);
}
}