fix(tests): abort server tasks on test cleanup to prevent zombie processes

Store the tokio AbortHandle in TestApp and implement Drop to abort the
spawned server task. Previously the JoinHandle was silently dropped,
leaving server tasks running indefinitely after tests completed.
This commit is contained in:
Jon Seager 2026-02-04 16:37:08 +00:00
parent 3bbcd33933
commit 305bc5f5a5
No known key found for this signature in database

View file

@ -24,6 +24,7 @@ use brewlog::infrastructure::repositories::tokens::SqlTokenRepository;
use brewlog::infrastructure::repositories::users::SqlUserRepository; use brewlog::infrastructure::repositories::users::SqlUserRepository;
use reqwest::Client; use reqwest::Client;
use tokio::net::TcpListener; use tokio::net::TcpListener;
use tokio::task::AbortHandle;
pub struct TestApp { pub struct TestApp {
pub address: String, pub address: String,
@ -40,6 +41,7 @@ pub struct TestApp {
pub auth_token: Option<String>, pub auth_token: Option<String>,
#[allow(dead_code)] #[allow(dead_code)]
pub mock_server: Option<wiremock::MockServer>, pub mock_server: Option<wiremock::MockServer>,
server_handle: AbortHandle,
} }
impl TestApp { impl TestApp {
@ -48,6 +50,12 @@ impl TestApp {
} }
} }
impl Drop for TestApp {
fn drop(&mut self) {
self.server_handle.abort();
}
}
pub async fn spawn_app() -> TestApp { pub async fn spawn_app() -> TestApp {
// Use in-memory SQLite database for testing // Use in-memory SQLite database for testing
let database = Database::connect("sqlite::memory:") let database = Database::connect("sqlite::memory:")
@ -146,11 +154,12 @@ async fn spawn_app_inner(
let address = format!("http://{}", local_addr); let address = format!("http://{}", local_addr);
// Spawn the server in a background task // Spawn the server in a background task
tokio::spawn(async move { let server_handle = tokio::spawn(async move {
axum::serve(listener, app) axum::serve(listener, app)
.await .await
.expect("Server failed to start"); .expect("Server failed to start");
}); })
.abort_handle();
TestApp { TestApp {
address, address,
@ -162,6 +171,7 @@ async fn spawn_app_inner(
token_repo: Some(token_repo), token_repo: Some(token_repo),
auth_token: None, auth_token: None,
mock_server, mock_server,
server_handle,
} }
} }