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"); let config_content = format!(r#" root = "{}" cert = "{}" key = "{}" hostname = "localhost" bind_host = "127.0.0.1" port = {} max_concurrent_requests = 1 "#, temp_dir.path().join("content").display(), temp_dir.path().join("cert.pem").display(), temp_dir.path().join("key.pem").display(), port); 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("1") // 1 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", port); let handle = std::thread::spawn(move || { std::process::Command::new("python3") .arg("tests/gemini_test_client.py") .arg(url) .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(); // Validation assert!(success_count >= 1, "At least 1 request should succeed, got results: {:?}", results); assert!(rate_limited_count >= 1, "At least 1 request should be rate limited, got results: {:?}", results); assert_eq!(success_count + rate_limited_count, 5, "All requests should get valid responses, got results: {:?}", results); }