198 lines
5.6 KiB
Rust
198 lines
5.6 KiB
Rust
mod common;
|
|
|
|
use common::*;
|
|
use rustproxy::RustProxy;
|
|
use rustproxy_config::RustProxyOptions;
|
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
|
use tokio::net::TcpStream;
|
|
|
|
#[tokio::test]
|
|
async fn test_tcp_forward_echo() {
|
|
let backend_port = next_port();
|
|
let proxy_port = next_port();
|
|
|
|
// Start echo backend
|
|
let _backend = start_echo_server(backend_port).await;
|
|
|
|
// Configure proxy
|
|
let options = RustProxyOptions {
|
|
routes: vec![make_test_route(proxy_port, None, "127.0.0.1", backend_port)],
|
|
..Default::default()
|
|
};
|
|
|
|
let mut proxy = RustProxy::new(options).unwrap();
|
|
proxy.start().await.unwrap();
|
|
|
|
// Wait for proxy to be ready
|
|
assert!(wait_for_port(proxy_port, 2000).await, "Proxy port not ready");
|
|
|
|
// Connect and send data
|
|
let result = with_timeout(async {
|
|
let mut stream = TcpStream::connect(format!("127.0.0.1:{}", proxy_port))
|
|
.await
|
|
.unwrap();
|
|
stream.write_all(b"hello world").await.unwrap();
|
|
|
|
let mut buf = vec![0u8; 1024];
|
|
let n = stream.read(&mut buf).await.unwrap();
|
|
String::from_utf8_lossy(&buf[..n]).to_string()
|
|
}, 5)
|
|
.await
|
|
.unwrap();
|
|
|
|
assert_eq!(result, "hello world");
|
|
|
|
proxy.stop().await.unwrap();
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_tcp_forward_large_payload() {
|
|
let backend_port = next_port();
|
|
let proxy_port = next_port();
|
|
|
|
let _backend = start_echo_server(backend_port).await;
|
|
|
|
let options = RustProxyOptions {
|
|
routes: vec![make_test_route(proxy_port, None, "127.0.0.1", backend_port)],
|
|
..Default::default()
|
|
};
|
|
|
|
let mut proxy = RustProxy::new(options).unwrap();
|
|
proxy.start().await.unwrap();
|
|
assert!(wait_for_port(proxy_port, 2000).await);
|
|
|
|
let result = with_timeout(async {
|
|
let mut stream = TcpStream::connect(format!("127.0.0.1:{}", proxy_port))
|
|
.await
|
|
.unwrap();
|
|
|
|
// Send 1MB of data
|
|
let data = vec![b'A'; 1_000_000];
|
|
stream.write_all(&data).await.unwrap();
|
|
stream.shutdown().await.unwrap();
|
|
|
|
// Read all back
|
|
let mut received = Vec::new();
|
|
stream.read_to_end(&mut received).await.unwrap();
|
|
received.len()
|
|
}, 10)
|
|
.await
|
|
.unwrap();
|
|
|
|
assert_eq!(result, 1_000_000);
|
|
|
|
proxy.stop().await.unwrap();
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_tcp_forward_multiple_connections() {
|
|
let backend_port = next_port();
|
|
let proxy_port = next_port();
|
|
|
|
let _backend = start_echo_server(backend_port).await;
|
|
|
|
let options = RustProxyOptions {
|
|
routes: vec![make_test_route(proxy_port, None, "127.0.0.1", backend_port)],
|
|
..Default::default()
|
|
};
|
|
|
|
let mut proxy = RustProxy::new(options).unwrap();
|
|
proxy.start().await.unwrap();
|
|
assert!(wait_for_port(proxy_port, 2000).await);
|
|
|
|
let result = with_timeout(async {
|
|
let mut handles = Vec::new();
|
|
for i in 0..10 {
|
|
let port = proxy_port;
|
|
handles.push(tokio::spawn(async move {
|
|
let mut stream = TcpStream::connect(format!("127.0.0.1:{}", port))
|
|
.await
|
|
.unwrap();
|
|
let msg = format!("connection-{}", i);
|
|
stream.write_all(msg.as_bytes()).await.unwrap();
|
|
|
|
let mut buf = vec![0u8; 1024];
|
|
let n = stream.read(&mut buf).await.unwrap();
|
|
String::from_utf8_lossy(&buf[..n]).to_string()
|
|
}));
|
|
}
|
|
|
|
let mut results = Vec::new();
|
|
for handle in handles {
|
|
results.push(handle.await.unwrap());
|
|
}
|
|
results
|
|
}, 10)
|
|
.await
|
|
.unwrap();
|
|
|
|
assert_eq!(result.len(), 10);
|
|
for (i, r) in result.iter().enumerate() {
|
|
assert_eq!(r, &format!("connection-{}", i));
|
|
}
|
|
|
|
proxy.stop().await.unwrap();
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_tcp_forward_backend_unreachable() {
|
|
let proxy_port = next_port();
|
|
let dead_port = next_port(); // No server on this port
|
|
|
|
let options = RustProxyOptions {
|
|
routes: vec![make_test_route(proxy_port, None, "127.0.0.1", dead_port)],
|
|
..Default::default()
|
|
};
|
|
|
|
let mut proxy = RustProxy::new(options).unwrap();
|
|
proxy.start().await.unwrap();
|
|
assert!(wait_for_port(proxy_port, 2000).await);
|
|
|
|
// Connection should complete (proxy accepts it) but data should not flow
|
|
let result = with_timeout(async {
|
|
let stream = TcpStream::connect(format!("127.0.0.1:{}", proxy_port)).await;
|
|
stream.is_ok()
|
|
}, 5)
|
|
.await
|
|
.unwrap();
|
|
|
|
assert!(result, "Should be able to connect to proxy even if backend is down");
|
|
|
|
proxy.stop().await.unwrap();
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_tcp_forward_bidirectional() {
|
|
let backend_port = next_port();
|
|
let proxy_port = next_port();
|
|
|
|
// Start a prefix echo server to verify data flows in both directions
|
|
let _backend = start_prefix_echo_server(backend_port, "REPLY:").await;
|
|
|
|
let options = RustProxyOptions {
|
|
routes: vec![make_test_route(proxy_port, None, "127.0.0.1", backend_port)],
|
|
..Default::default()
|
|
};
|
|
|
|
let mut proxy = RustProxy::new(options).unwrap();
|
|
proxy.start().await.unwrap();
|
|
assert!(wait_for_port(proxy_port, 2000).await);
|
|
|
|
let result = with_timeout(async {
|
|
let mut stream = TcpStream::connect(format!("127.0.0.1:{}", proxy_port))
|
|
.await
|
|
.unwrap();
|
|
stream.write_all(b"test data").await.unwrap();
|
|
|
|
let mut buf = vec![0u8; 1024];
|
|
let n = stream.read(&mut buf).await.unwrap();
|
|
String::from_utf8_lossy(&buf[..n]).to_string()
|
|
}, 5)
|
|
.await
|
|
.unwrap();
|
|
|
|
assert_eq!(result, "REPLY:test data");
|
|
|
|
proxy.stop().await.unwrap();
|
|
}
|