- Remove custom logging module and init_logging function - Update main.rs to use tracing_subscriber with EnvFilter - Remove log_level from global config structure - Update documentation and tests to use RUST_LOG - Format long lines in config.rs and test files for better readability
103 lines
3.1 KiB
Rust
103 lines
3.1 KiB
Rust
mod common;
|
|
|
|
#[test]
|
|
fn test_rate_limiting_with_concurrent_requests() {
|
|
let temp_dir = common::setup_test_environment();
|
|
let port = 1967 + (std::process::id() % 1000) as u16;
|
|
|
|
// Create config with rate limiting enabled
|
|
let config_path = temp_dir.path().join("config.toml");
|
|
|
|
// Use existing content directory and cert files from setup_test_environment
|
|
let root_dir = temp_dir.path().join("content");
|
|
let cert_path = temp_dir.path().join("cert.pem");
|
|
let key_path = temp_dir.path().join("key.pem");
|
|
|
|
let config_content = format!(
|
|
r#"
|
|
bind_host = "127.0.0.1"
|
|
port = {}
|
|
max_concurrent_requests = 1
|
|
|
|
["localhost"]
|
|
root = "{}"
|
|
cert = "{}"
|
|
key = "{}"
|
|
"#,
|
|
port,
|
|
root_dir.display(),
|
|
cert_path.display(),
|
|
key_path.display()
|
|
);
|
|
std::fs::write(&config_path, config_content).unwrap();
|
|
|
|
// Start server binary with test delay to simulate processing time
|
|
let mut server_process = std::process::Command::new(env!("CARGO_BIN_EXE_pollux"))
|
|
.arg("--config")
|
|
.arg(&config_path)
|
|
.arg("--test-processing-delay")
|
|
.arg("3") // 3 second delay per request
|
|
.spawn()
|
|
.expect("Failed to start server");
|
|
|
|
// Wait for server to start
|
|
std::thread::sleep(std::time::Duration::from_millis(500));
|
|
|
|
// Spawn 5 concurrent client processes
|
|
let mut handles = vec![];
|
|
for _ in 0..5 {
|
|
let url = format!("gemini://localhost/test.gmi");
|
|
let handle = std::thread::spawn(move || {
|
|
std::process::Command::new("python3")
|
|
.arg("tests/gemini_test_client.py")
|
|
.arg(url)
|
|
.env("GEMINI_PORT", &port.to_string())
|
|
.env("RATE_LIMIT_TEST", "true")
|
|
.output()
|
|
});
|
|
handles.push(handle);
|
|
}
|
|
|
|
// Collect results
|
|
let mut results = vec![];
|
|
for handle in handles {
|
|
let output = handle.join().unwrap().unwrap();
|
|
let status = String::from_utf8(output.stdout).unwrap();
|
|
results.push(status.trim().to_string());
|
|
}
|
|
|
|
// Kill server
|
|
let _ = server_process.kill();
|
|
|
|
// Analyze results
|
|
let success_count = results.iter().filter(|r| r.starts_with("20")).count();
|
|
let rate_limited_count = results.iter().filter(|r| r.starts_with("41")).count();
|
|
|
|
// Debug output
|
|
tracing::debug!("Test results: {:?}", results);
|
|
tracing::debug!(
|
|
"Success: {}, Rate limited: {}",
|
|
success_count,
|
|
rate_limited_count
|
|
);
|
|
|
|
// Strict validation - rate limiting must work deterministically with delay
|
|
assert_eq!(
|
|
success_count, 1,
|
|
"Expected exactly 1 successful request with limit=1, got {}. Results: {:?}",
|
|
success_count, results
|
|
);
|
|
assert_eq!(
|
|
rate_limited_count, 4,
|
|
"Expected exactly 4 rate limited requests with limit=1, got {}. Results: {:?}",
|
|
rate_limited_count, results
|
|
);
|
|
|
|
// Verify all requests received valid responses
|
|
assert_eq!(
|
|
success_count + rate_limited_count,
|
|
5,
|
|
"All 5 requests should receive responses. Results: {:?}",
|
|
results
|
|
);
|
|
}
|