use std::sync::atomic::{AtomicU64, Ordering};
use axum_test::{TestServer, transport_layer::IntoTransportLayer};
use eyre::Context;
use sqlx::{Connection as _, Executor as _, PgConnection};
use testcontainers_modules::{
postgres::Postgres,
testcontainers::{ContainerAsync, runners::AsyncRunner as _},
};
use tokio::sync::OnceCell;
use crate::postgres::SanitizedSchema;
pub use axum_test;
#[allow(
clippy::missing_panics_doc,
reason = "synthesized schema is always valid"
)]
pub fn next_test_schema() -> SanitizedSchema {
static SCHEMA_COUNTER: AtomicU64 = AtomicU64::new(0);
let n = SCHEMA_COUNTER.fetch_add(1, Ordering::Relaxed);
format!("test_{n}")
.parse()
.expect("synthesized schema is always valid")
}
pub async fn postgres_testcontainer() -> eyre::Result<(ContainerAsync<Postgres>, String)> {
let postgres_container = Postgres::default().start().await?;
let connection_string = format!(
"postgres://postgres:postgres@{}:{}/postgres",
postgres_container.get_host().await?,
postgres_container.get_host_port_ipv4(5432).await?
);
Ok((postgres_container, connection_string))
}
pub async fn shared_postgres_testcontainer() -> eyre::Result<&'static str> {
static SHARED_PG: OnceCell<(ContainerAsync<Postgres>, String)> = OnceCell::const_new();
let shared = SHARED_PG
.get_or_try_init(|| async {
let (container, connection_string) = postgres_testcontainer().await?;
eyre::Ok((container, connection_string))
})
.await?;
Ok(&shared.1)
}
pub fn random_port() -> eyre::Result<u16> {
reserve_port::ReservedPort::random_permanently_reserved().context("while reserving port")
}
pub fn test_server<A: IntoTransportLayer>(app: A) -> (TestServer, String) {
let server = TestServer::builder().http_transport().build(app);
let url = server
.server_address()
.expect("test server with http transport has address")
.to_string()
.trim_end_matches('/')
.to_string();
(server, url)
}
pub async fn open_pg_connection(
connection_string: &str,
schema: &SanitizedSchema,
) -> eyre::Result<PgConnection> {
let mut conn = PgConnection::connect(connection_string)
.await
.context("while opening PgConnection")?;
conn.execute(format!("CREATE SCHEMA IF NOT EXISTS \"{schema}\"").as_ref())
.await
.context("TestUtils: cannot create schema")?;
conn.execute(format!("SET search_path TO \"{schema}\"").as_ref())
.await
.context("TestUtils: cannot set search path of connection")?;
Ok(conn)
}