#[cfg(test)]
mod e2e_tests {
use std::process::{Child, Command};
use std::thread;
use std::time::Duration;
struct ProxyTestFixture {
proxy_process: Option<Child>,
port: u16,
token: String,
}
impl ProxyTestFixture {
fn new() -> Self {
let port = 8443;
let token = Self::generate_test_token();
Self {
proxy_process: None,
port,
token,
}
}
fn generate_test_token() -> String {
use std::time::{SystemTime, UNIX_EPOCH};
let payload = serde_json::json!({
"token_id": "test-token-e2e",
"user_id": 1,
"allowed_regions": ["us-east", "eu-west"],
"exp": SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() + 3600,
"iat": SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs(),
});
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl9pZCI6InRlc3QtdG9rZW4tZTJlIiwidXNlcl9pZCI6MSwiYWxsb3dlZF9yZWdpb25zIjpbInVzLWVhc3QiLCJldS13ZXN0Il0sImV4cCI6MTc2MzcyNzcwNSwiaWF0IjoxNzYzNzI0MTA1fQ.RU7SjgZVT3JUH1h1PYhJEhaXDEXym-BW3QsKw3q5D0c".to_string()
}
fn start_proxy(&mut self) -> Result<(), Box<dyn std::error::Error>> {
let child = Command::new("./target/release/probe-proxy")
.env("TLS_CERT_PATH", "/tmp/test-certs/cert.pem")
.env("TLS_KEY_PATH", "/tmp/test-certs/key.pem")
.env("PROXY_PORT", self.port.to_string())
.env("JWT_SECRET", "test_secret_at_least_32_characters!!")
.env("HTTP_PROXY_ENABLED", "true")
.spawn()?;
self.proxy_process = Some(child);
thread::sleep(Duration::from_secs(2));
Ok(())
}
fn stop_proxy(&mut self) {
if let Some(mut child) = self.proxy_process.take() {
let _ = child.kill();
let _ = child.wait();
}
}
}
impl Drop for ProxyTestFixture {
fn drop(&mut self) {
self.stop_proxy();
}
}
#[test]
#[ignore]
fn test_proxy_manual_verification() {
println!("
=== Manual Proxy Test Instructions ===
1. Start the proxy:
TLS_CERT_PATH=/tmp/test-certs/cert.pem \\
TLS_KEY_PATH=/tmp/test-certs/key.pem \\
PROXY_PORT=8443 \\
JWT_SECRET='test_secret_at_least_32_characters!!' \\
HTTP_PROXY_ENABLED=true \\
./target/release/probe-proxy
2. In another terminal, test HTTP GET:
TOKEN='eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl9pZCI6InRlc3QtdG9rZW4tMTIzIiwidXNlcl9pZCI6MSwiYWxsb3dlZF9yZWdpb25zIjpbInVzLWVhc3QiLCJldS13ZXN0Il0sImV4cCI6MTc2MzcyNzcwNSwiaWF0IjoxNzYzNzI0MTA1fQ.RU7SjgZVT3JUH1h1PYhJEhaXDEXym-BW3QsKw3q5D0c'
printf \"GET http://www.google.com/ HTTP/1.1\\r\\n\" \\
\"Host: www.google.com\\r\\n\" \\
\"Proxy-Authorization: Bearer $TOKEN\\r\\n\" \\
\"Connection: close\\r\\n\\r\\n\" | \\
openssl s_client -connect localhost:8443 -quiet 2>&1 | head -20
3. Test HTTP POST:
BODY='{{\"test\":\"data\"}}'
printf \"POST http://httpbin.org/post HTTP/1.1\\r\\n\" \\
\"Host: httpbin.org\\r\\n\" \\
\"Proxy-Authorization: Bearer $TOKEN\\r\\n\" \\
\"Content-Type: application/json\\r\\n\" \\
\"Content-Length: ${{#BODY}}\\r\\n\" \\
\"Connection: close\\r\\n\\r\\n\" \\
\"$BODY\" | \\
openssl s_client -connect localhost:8443 -quiet 2>&1 | head -40
4. Test SSRF protection (should get 403):
printf \"GET http://localhost:22/ HTTP/1.1\\r\\n\" \\
\"Host: localhost\\r\\n\" \\
\"Proxy-Authorization: Bearer $TOKEN\\r\\n\" \\
\"Connection: close\\r\\n\\r\\n\" | \\
openssl s_client -connect localhost:8443 -quiet 2>&1 | head -10
5. Test missing auth (should get 407):
printf \"GET http://www.google.com/ HTTP/1.1\\r\\n\" \\
\"Host: www.google.com\\r\\n\" \\
\"Connection: close\\r\\n\\r\\n\" | \\
openssl s_client -connect localhost:8443 -quiet 2>&1 | head -10
=== Expected Results ===
- Test 2: HTTP 200 OK with Google HTML
- Test 3: HTTP 200 OK with JSON echo from httpbin
- Test 4: HTTP 403 Forbidden (SSRF blocked)
- Test 5: HTTP 407 Proxy Authentication Required
");
}
}
#[cfg(test)]
mod load_tests {
#[test]
#[ignore]
fn generate_load_test_scripts() {
let script_dir = "/tmp/proxy-load-tests";
std::fs::create_dir_all(script_dir).ok();
let script1 = r#"#!/bin/bash
# Load Test Scenario 1: Basic Throughput (10k requests, 100 concurrent)
TOKEN="eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl9pZCI6InRlc3QtdG9rZW4tMTIzIiwidXNlcl9pZCI6MSwiYWxsb3dlZF9yZWdpb25zIjpbInVzLWVhc3QiLCJldS13ZXN0Il0sImV4cCI6MTc2MzcyNzcwNSwiaWF0IjoxNzYzNzI0MTA1fQ.RU7SjgZVT3JUH1h1PYhJEhaXDEXym-BW3QsKw3q5D0c"
echo "=== Load Test 1: Basic Throughput ==="
echo "Requests: 10,000"
echo "Concurrency: 100"
echo "Target: httpbin.org/get"
echo ""
# Note: This requires modifying h2load to support HTTPS proxy
# Or use a tool like wrk with proxy support
echo "Simulating with curl in loop..."
for i in {1..100}; do
(printf "GET http://httpbin.org/get HTTP/1.1\r\nHost: httpbin.org\r\nProxy-Authorization: Bearer $TOKEN\r\nConnection: close\r\n\r\n" | \
openssl s_client -connect localhost:8443 -quiet 2>&1 > /dev/null) &
done
wait
echo "Completed 100 requests"
"#;
let script2 = r#"#!/bin/bash
# Load Test Scenario 2: High Concurrency (1000 concurrent connections)
TOKEN="eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl9pZCI6InRlc3QtdG9rZW4tMTIzIiwidXNlcl9pZCI6MSwiYWxsb3dlZF9yZWdpb25zIjpbInVzLWVhc3QiLCJldS13ZXN0Il0sImV4cCI6MTc2MzcyNzcwNSwiaWF0IjoxNzYzNzI0MTA1fQ.RU7SjgZVT3JUH1h1PYhJEhaXDEXym-BW3QsKw3q5D0c"
echo "=== Load Test 2: High Concurrency ==="
echo "Concurrency: 1000"
echo "Target: httpbin.org/get"
echo ""
# Monitor proxy memory usage
echo "Proxy Memory Usage:"
ps aux | grep probe-proxy | grep -v grep | awk '{print $6 " KB"}'
"#;
let script3 = r#"#!/bin/bash
# Load Test Scenario 3: Large Response Bodies (10MB responses)
TOKEN="eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl9pZCI6InRlc3QtdG9rZW4tMTIzIiwidXNlcl9pZCI6MSwiYWxsb3dlZF9yZWdpb25zIjpbInVzLWVhc3QiLCJldS13ZXN0Il0sImV4cCI6MTc2MzcyNzcwNSwiaWF0IjoxNzYzNzI0MTA1fQ.RU7SjgZVT3JUH1h1PYhJEhaXDEXym-BW3QsKw3q5D0c"
echo "=== Load Test 3: Large Bodies ==="
echo "Body Size: 10MB"
echo "Target: httpbin.org/bytes/10485760"
echo ""
printf "GET http://httpbin.org/bytes/10485760 HTTP/1.1\r\nHost: httpbin.org\r\nProxy-Authorization: Bearer $TOKEN\r\nConnection: close\r\n\r\n" | \
openssl s_client -connect localhost:8443 -quiet 2>&1 | wc -c
echo "Response received and measured"
"#;
std::fs::write(format!("{}/scenario1_throughput.sh", script_dir), script1).ok();
std::fs::write(format!("{}/scenario2_concurrency.sh", script_dir), script2).ok();
std::fs::write(format!("{}/scenario3_large_bodies.sh", script_dir), script3).ok();
println!("Load test scripts generated in: {}", script_dir);
println!("Make executable with: chmod +x {}/*.sh", script_dir);
}
}