Test that the server correctly reports missing certificate errors, rejects invalid hostnames, fails gracefully on port conflicts, and starts successfully with multiple virtual hosts configured.
104 lines
3.1 KiB
Rust
104 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("--quiet")
|
|
.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
|
|
);
|
|
}
|