Skip to content

Commit

Permalink
Multi server test
Browse files Browse the repository at this point in the history
  • Loading branch information
antoniosarosi committed Jan 22, 2023
1 parent 42255cc commit fd67690
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 2 deletions.
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! RXH is a reverse proxy, load balancer and static files server.
#![feature(ptr_from_ref)]
#![feature(is_some_and)]

Expand Down
5 changes: 5 additions & 0 deletions src/task/master.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,11 @@ impl Master {

first_error.unwrap_or(Ok(()))
}

/// Returns all the listening sockets.
pub fn sockets(&self) -> Vec<SocketAddr> {
self.states.iter().map(|(addr, _)| *addr).collect()
}
}

async fn log_state_updates(addr: SocketAddr, mut state: watch::Receiver<State>) {
Expand Down
51 changes: 50 additions & 1 deletion tests/proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use crate::util::{
spawn_backend_server,
spawn_backends_with_request_counters,
spawn_client,
spawn_master,
spawn_reverse_proxy,
spawn_reverse_proxy_with_controllers,
},
Expand Down Expand Up @@ -244,7 +245,7 @@ async fn load_balancing() {
}

#[tokio::test]
async fn serve_files() {
async fn static_files() {
let html = r#"
<!DOCTYPE html>
<html lang="en">
Expand Down Expand Up @@ -275,3 +276,51 @@ async fn serve_files() {
assert_eq!(parts.status, http::StatusCode::OK);
assert_eq!(body, html.as_bytes());
}

#[tokio::test]
async fn client_receives_404_if_file_not_found() {
let dir = tempfile::tempdir().unwrap();

let (addr, _) = spawn_reverse_proxy(config::files::serve(dir.path().to_str().unwrap()));

ping_tcp_server(addr).await;

let doesnt_exist = ["/test.html", "/styles.css", "/app.js"];

for file in doesnt_exist {
let (parts, body) = send_http_request(addr, request::empty_with_uri(file)).await;
assert_eq!(parts.status, http::StatusCode::NOT_FOUND);
assert!(body.starts_with(b"HTTP 404 NOT FOUND"));
}
}

#[tokio::test]
async fn multi_server() {
let dir = tempfile::tempdir().unwrap();
let mut file = tokio::fs::File::create(dir.path().join("test.txt"))
.await
.unwrap();
file.write(b"Hello World File").await.unwrap();

let (server_addr, _) = spawn_backend_server(service_fn(|_| async {
Ok(Response::new(Full::<Bytes>::from("Hello World Response")))
}));

let config = rxh::config::Config {
servers: vec![
config::proxy::single_backend_with_uri(server_addr, "/api"),
config::files::serve(dir.path().to_str().unwrap()),
],
};

let (sockets, _) = spawn_master(config);

ping_all(&sockets).await;

let (_, api_req_body) = send_http_request(sockets[0], request::empty_with_uri("/api")).await;
let (_, file_req_body) =
send_http_request(sockets[1], request::empty_with_uri("/test.txt")).await;

assert_eq!(api_req_body, &"Hello World Response");
assert_eq!(file_req_body, &"Hello World File");
}
16 changes: 15 additions & 1 deletion tests/util/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ pub fn spawn_reverse_proxy(config: rxh::config::Server) -> (SocketAddr, JoinHand
(addr, handle)
}

/// Starts an RXH reverse proxy server in the background with the given config.
/// Starts an RXH reverse proxy server in the background with the given config
/// and provides access to shutdown trigger and state updates.
pub fn spawn_reverse_proxy_with_controllers(
config: rxh::config::Server,
) -> (
Expand All @@ -130,6 +131,18 @@ pub fn spawn_reverse_proxy_with_controllers(
(addr, handle, || tx.send(()).unwrap(), state)
}

/// Launches a master task in the background. TODO: Provide shutdown trigger
/// like [`spawn_reverse_proxy_with_controllers`].
pub fn spawn_master(config: rxh::config::Config) -> (Vec<SocketAddr>, JoinHandle<()>) {
let master = rxh::Master::init(config).unwrap();
let sockets = master.sockets();
let handle = tokio::task::spawn(async move {
master.run().await.unwrap();
});

(sockets, handle)
}

/// Provides an HTTP client that spawns a connection object in the background
/// to manage request transmissions.
pub async fn http_client<B: AsyncBody>(stream: TcpStream) -> SendRequest<B> {
Expand All @@ -156,6 +169,7 @@ where
(parts, body.collect().await.unwrap().to_bytes())
}

/// Sends an HTTP request from a random socket to the given address.
pub async fn send_http_request<B>(to: SocketAddr, req: Request<B>) -> (http::response::Parts, Bytes)
where
B: AsyncBody,
Expand Down
1 change: 1 addition & 0 deletions tests/util/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ impl Service<Request<Incoming>> for RequestInterceptor {
.await
.unwrap();

// TODO: Make response customizable.
Ok(Response::new(Full::<Bytes>::from("Hello world")))
})
}
Expand Down

0 comments on commit fd67690

Please sign in to comment.