I’m attempting to write an implementation for re-using a Postgres Testcontainer for a series of tests written in Rust.
The struct is defined as follows:
use sea_orm::{ConnectOptions, DatabaseConnection, SqlxPostgresConnector};
use std::process::Command;
use testcontainers::runners::AsyncRunner;
use testcontainers::ContainerAsync;
use testcontainers_modules::postgres::Postgres;
use tokio::runtime::Runtime;
use uuid::Uuid;
const USER_NAME: &'static str = "<USERNAME>";
const PASSWORD: &'static str = "<PASSWORD>";
pub struct PostgresTestContainer {
ctn: ContainerAsync<Postgres>,
}
impl PostgresTestContainer {
pub async fn create() -> anyhow::Result<Self> {
// Create the postgres container and return
let ctn = Postgres::default()
.with_user(USER_NAME)
.with_password(PASSWORD)
.start()
.await?;
Ok(Self { ctn })
}
pub async fn new_db(&self) -> anyhow::Result<DatabaseConnection> {
// Expose and provide a port to localhost
let host_port = self.ctn.get_host_port_ipv4(5432).await?;
let db_name = Uuid::new_v4().to_string();
// Create the database url using the host port
let db_url = format!("postgres://{USER_NAME}:{PASSWORD}@localhost:{host_port}/{db_name}");
let db = SqlxPostgresConnector::connect(ConnectOptions::new(&db_url)).await?;
Ok(db)
}
}
The current test implementation uses lazy_static
to create the container and provide it for all tests:
lazy_static! {
static ref CTN: AsyncOnce<PostgresTestContainer> =
AsyncOnce::new(async { PostgresTestContainer::create().await.expect("Could not create postgres container" });
...
}
#[tokio::test]
async fn login_with_correct_pwd_returns_tokens() -> Result<(), anyhow::Error> {
let db = CTN.get().await.new_db().await?;
...
}
This works great, except I’m struggling to determine how I can stop the container after completion. How could I write a cleanup method, or how can re-write the implementation to consider cleanup of the container after use?
I attempted to use impl Drop for PostgresTestContainer
to stop the container, but after no success and a fair deal of research I learned that static objects don’t call drop
.
Thanks!