mirror of
https://github.com/telemt/telemt.git
synced 2026-04-19 03:24:10 +03:00
Refactor and enhance tests for proxy and relay functionality
- Renamed test functions in `client_tls_clienthello_truncation_adversarial_tests.rs` to remove "but_leaks" suffix for clarity. - Added new tests in `direct_relay_business_logic_tests.rs` to validate business logic for data center resolution and scope hints. - Introduced tests in `direct_relay_common_mistakes_tests.rs` to cover common mistakes in direct relay configurations. - Added security tests in `direct_relay_security_tests.rs` to ensure proper handling of symlink and parent swap scenarios. - Created `direct_relay_subtle_adversarial_tests.rs` to stress test concurrent logging and validate scope hint behavior. - Implemented `relay_quota_lock_pressure_adversarial_tests.rs` to test quota lock behavior under high contention and stress. - Updated `relay_security_tests.rs` to include quota lock contention tests ensuring proper behavior under concurrent access. - Introduced `ip_tracker_hotpath_adversarial_tests.rs` to validate the performance and correctness of the IP tracking logic under various scenarios.
This commit is contained in:
168
src/tests/ip_tracker_hotpath_adversarial_tests.rs
Normal file
168
src/tests/ip_tracker_hotpath_adversarial_tests.rs
Normal file
@@ -0,0 +1,168 @@
|
||||
use std::net::{IpAddr, Ipv4Addr};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::config::UserMaxUniqueIpsMode;
|
||||
use crate::ip_tracker::UserIpTracker;
|
||||
|
||||
fn ip_from_idx(idx: u32) -> IpAddr {
|
||||
IpAddr::V4(Ipv4Addr::new(10, ((idx >> 16) & 0xff) as u8, ((idx >> 8) & 0xff) as u8, (idx & 0xff) as u8))
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn hotpath_empty_drain_is_idempotent() {
|
||||
let tracker = UserIpTracker::new();
|
||||
for _ in 0..128 {
|
||||
tracker.drain_cleanup_queue().await;
|
||||
}
|
||||
assert_eq!(tracker.get_active_ip_count("none").await, 0);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn hotpath_batch_cleanup_drain_clears_all_active_entries() {
|
||||
let tracker = UserIpTracker::new();
|
||||
tracker.set_user_limit("u", 100).await;
|
||||
|
||||
for idx in 0..32 {
|
||||
let ip = ip_from_idx(idx);
|
||||
tracker.check_and_add("u", ip).await.unwrap();
|
||||
tracker.enqueue_cleanup("u".to_string(), ip);
|
||||
}
|
||||
|
||||
tracker.drain_cleanup_queue().await;
|
||||
assert_eq!(tracker.get_active_ip_count("u").await, 0);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
|
||||
async fn hotpath_parallel_enqueue_and_drain_does_not_deadlock() {
|
||||
let tracker = Arc::new(UserIpTracker::new());
|
||||
tracker.set_user_limit("p", 64).await;
|
||||
|
||||
let mut tasks = Vec::new();
|
||||
for worker in 0..32u32 {
|
||||
let t = tracker.clone();
|
||||
tasks.push(tokio::spawn(async move {
|
||||
let ip = ip_from_idx(1_000 + worker);
|
||||
for _ in 0..64 {
|
||||
let _ = t.check_and_add("p", ip).await;
|
||||
t.enqueue_cleanup("p".to_string(), ip);
|
||||
t.drain_cleanup_queue().await;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
for task in tasks {
|
||||
tokio::time::timeout(Duration::from_secs(3), task)
|
||||
.await
|
||||
.expect("worker must not deadlock")
|
||||
.expect("worker task must not panic");
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
|
||||
async fn hotpath_parallel_unique_ip_limit_never_exceeds_cap() {
|
||||
let tracker = Arc::new(UserIpTracker::new());
|
||||
tracker.set_user_limit("limit", 5).await;
|
||||
|
||||
let mut tasks = Vec::new();
|
||||
for idx in 0..64u32 {
|
||||
let t = tracker.clone();
|
||||
tasks.push(tokio::spawn(async move { t.check_and_add("limit", ip_from_idx(idx)).await.is_ok() }));
|
||||
}
|
||||
|
||||
let mut admitted = 0usize;
|
||||
for task in tasks {
|
||||
if task.await.expect("task must not panic") {
|
||||
admitted += 1;
|
||||
}
|
||||
}
|
||||
|
||||
assert!(admitted <= 5, "admitted unique IPs must not exceed configured cap");
|
||||
assert!(tracker.get_active_ip_count("limit").await <= 5);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn hotpath_repeated_same_ip_counter_balances_to_zero() {
|
||||
let tracker = UserIpTracker::new();
|
||||
tracker.set_user_limit("same", 1).await;
|
||||
let ip = ip_from_idx(77);
|
||||
|
||||
for _ in 0..512 {
|
||||
tracker.check_and_add("same", ip).await.unwrap();
|
||||
}
|
||||
for _ in 0..512 {
|
||||
tracker.remove_ip("same", ip).await;
|
||||
}
|
||||
|
||||
assert_eq!(tracker.get_active_ip_count("same").await, 0);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn hotpath_light_fuzz_mixed_operations_preserve_limit_invariants() {
|
||||
let tracker = UserIpTracker::new();
|
||||
tracker.set_user_limit("fuzz", 4).await;
|
||||
|
||||
let mut state: u64 = 0xA55A_5AA5_D15C_B00B;
|
||||
for _ in 0..4_000 {
|
||||
state ^= state << 7;
|
||||
state ^= state >> 9;
|
||||
state ^= state << 8;
|
||||
|
||||
let ip = ip_from_idx((state as u32) % 8);
|
||||
match state & 0x3 {
|
||||
0 | 1 => {
|
||||
let _ = tracker.check_and_add("fuzz", ip).await;
|
||||
}
|
||||
_ => {
|
||||
tracker.remove_ip("fuzz", ip).await;
|
||||
}
|
||||
}
|
||||
|
||||
assert!(
|
||||
tracker.get_active_ip_count("fuzz").await <= 4,
|
||||
"active count must stay within configured cap"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn hotpath_multi_user_churn_keeps_isolation() {
|
||||
let tracker = UserIpTracker::new();
|
||||
tracker.set_user_limit("u1", 2).await;
|
||||
tracker.set_user_limit("u2", 3).await;
|
||||
|
||||
for idx in 0..200u32 {
|
||||
let ip1 = ip_from_idx(idx % 5);
|
||||
let ip2 = ip_from_idx(100 + (idx % 7));
|
||||
let _ = tracker.check_and_add("u1", ip1).await;
|
||||
let _ = tracker.check_and_add("u2", ip2).await;
|
||||
if idx % 2 == 0 {
|
||||
tracker.remove_ip("u1", ip1).await;
|
||||
}
|
||||
if idx % 3 == 0 {
|
||||
tracker.remove_ip("u2", ip2).await;
|
||||
}
|
||||
}
|
||||
|
||||
assert!(tracker.get_active_ip_count("u1").await <= 2);
|
||||
assert!(tracker.get_active_ip_count("u2").await <= 3);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn hotpath_time_window_expiry_allows_new_ip_after_window() {
|
||||
let tracker = UserIpTracker::new();
|
||||
tracker.set_user_limit("tw", 1).await;
|
||||
tracker
|
||||
.set_limit_policy(UserMaxUniqueIpsMode::TimeWindow, 1)
|
||||
.await;
|
||||
|
||||
let ip1 = ip_from_idx(901);
|
||||
let ip2 = ip_from_idx(902);
|
||||
|
||||
tracker.check_and_add("tw", ip1).await.unwrap();
|
||||
tracker.remove_ip("tw", ip1).await;
|
||||
assert!(tracker.check_and_add("tw", ip2).await.is_err());
|
||||
|
||||
tokio::time::sleep(Duration::from_millis(1_100)).await;
|
||||
assert!(tracker.check_and_add("tw", ip2).await.is_ok());
|
||||
}
|
||||
Reference in New Issue
Block a user