From 9705c5d8cf19b7ddb01190f32d4728c9056a41b1 Mon Sep 17 00:00:00 2001 From: github-ops Date: Sun, 21 Jun 2026 10:12:22 +0000 Subject: [PATCH] Wait for test Postgres readiness --- crates/crank-test-support/src/lib.rs | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/crates/crank-test-support/src/lib.rs b/crates/crank-test-support/src/lib.rs index be1c79e..5a45672 100644 --- a/crates/crank-test-support/src/lib.rs +++ b/crates/crank-test-support/src/lib.rs @@ -7,6 +7,7 @@ use sqlx::{Connection, Executor, PgConnection}; use testcontainers::{Container, ImageExt, runners::SyncRunner}; use testcontainers_modules::postgres::Postgres; use tokio::sync::OnceCell; +use tokio::time::{Duration, sleep}; static POSTGRES: OnceCell = OnceCell::const_new(); static CLEANUP_REGISTERED: OnceLock<()> = OnceLock::new(); @@ -24,9 +25,7 @@ pub async fn postgres_database_url() -> &'static str { pub async fn postgres_schema_url(prefix: &str) -> String { let database_url = postgres_database_url().await; let schema = unique_schema_name(prefix); - let mut connection = PgConnection::connect(database_url) - .await - .expect("test PostgreSQL container must accept admin connections"); + let mut connection = connect_admin_with_retry(database_url).await; connection .execute(sqlx::query(&format!("create schema {schema}"))) @@ -36,6 +35,27 @@ pub async fn postgres_schema_url(prefix: &str) -> String { format!("{database_url}?options=-csearch_path%3D{schema}") } +async fn connect_admin_with_retry(database_url: &str) -> PgConnection { + let mut last_error = None; + + for _ in 0..80 { + match PgConnection::connect(database_url).await { + Ok(connection) => return connection, + Err(error) => { + last_error = Some(error); + sleep(Duration::from_millis(250)).await; + } + } + } + + panic!( + "test PostgreSQL container must accept admin connections after readiness wait: {}", + last_error + .map(|error| error.to_string()) + .unwrap_or_else(|| "connection was not attempted".to_owned()) + ); +} + pub fn unique_schema_name(prefix: &str) -> String { let normalized_prefix: String = prefix .chars()