From 83915acbd113368a5d56862d529cf89b4085dffe Mon Sep 17 00:00:00 2001 From: minhtrannhat Date: Fri, 29 Mar 2024 16:20:53 -0400 Subject: [PATCH] feat(test): use random ports for testing - port is assigned by the OS. --- src/lib.rs | 5 +++-- src/main.rs | 6 +++++- tests/health_check.rs | 16 ++++++++++++---- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 1bff894..733b7e9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,16 +1,17 @@ use actix_web::{web, App, HttpResponse, HttpServer}; use actix_web::dev::Server; +use std::net::TcpListener; async fn healthcheck_route() -> HttpResponse { return HttpResponse::Ok().finish() } -pub fn run() -> Result{ +pub fn run(listener: TcpListener) -> Result{ let server = HttpServer::new(||{ App::new() .route("/health_check", web::get().to(healthcheck_route)) }) - .bind("127.0.0.1:8000")? + .listen(listener)? .run(); Ok(server) diff --git a/src/main.rs b/src/main.rs index 8ea4e9f..5cd6fd8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,12 @@ +use std::net::TcpListener; + use email_newsletter_api::run; #[tokio::main] async fn main() -> Result<(), std::io::Error>{ + let listener = TcpListener::bind("127.0.0.1:8000").expect("Failed to bind to port 8000"); + // Move the error up the call stack // otherwise await for the HttpServer - run()?.await + run(listener)?.await } diff --git a/tests/health_check.rs b/tests/health_check.rs index 9c2690b..5736ad6 100644 --- a/tests/health_check.rs +++ b/tests/health_check.rs @@ -1,24 +1,32 @@ +use std::{fmt::format, net::TcpListener}; // tokio spins up a new async runtime every time // at the beginning of each test case and shutdown at // the end of each test case // the spawn_app() function therefore only survives as long as the runtime #[tokio::test] async fn health_check_works(){ - spawn_app(); + let server_address = spawn_app(); let client = reqwest::Client::new(); - let response = client.get("http://127.0.0.1:8000/health_check").send().await.expect("Failed to execute health_check request."); + let response = client.get(&format!("{}/health_check", &server_address)).send().await.expect("Failed to execute health_check request."); assert!(response.status().is_success()); assert_eq!(Some(0), response.content_length()); } -fn spawn_app() { - let server = email_newsletter_api::run().expect("Failed to bind address"); +fn spawn_app() -> String { + let listener = TcpListener::bind("127.0.0.1:0").expect("Failed to bind to a random port"); + + let port = listener.local_addr().unwrap().port(); + + let server = email_newsletter_api::run(listener).expect("Failed to bind address"); + // run() returns an instance of HttpServer that will run forever. // We don't want this behavior // Therefore we want to spawn our server, run our test logic // and then tear down the entire test suite let _ = tokio::spawn(server); + + format!("http://127.0.0.1:{}", port) }