测试套件完成后清理测试容器 Postgres 容器

问题描述 投票:0回答:1

我正在尝试编写一个实现,以重新使用 Postgres Testcontainer 进行一系列用 Rust 编写的测试。

该结构体定义如下:

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)
    }
}

当前的测试实现使用

lazy_static
创建容器并将其提供给所有测试:

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?; 
    ...
}

这非常有效,除了我正在努力确定如何在完成后停止容器。我如何编写清理方法,或者如何重新编写实现以考虑使用后容器的清理?

我尝试使用

impl Drop for PostgresTestContainer
来停止容器,但没有成功并且经过大量研究后我了解到静态对象不会调用
drop

谢谢!

rust containers testcontainers
1个回答
0
投票

我查看了 cafce25 的推荐,虽然

#[custom_test_frameworks]
看起来很有希望,但我不想使用不稳定的 Rust。

我决定使用我在这篇文章中看到的解决方案。 首先,我在testcontainer创建方法中添加了一个参数:

pub async fn create(ctn_name: Uuid) -> anyhow::Result<Self> {
    // Create the postgres container and return
    let ctn = Postgres::default()
        .with_user(USER_NAME)
        .with_password(PASSWORD)
        .with_container_name(ctn_name)
        .start().await?;

    Ok(Self { ctn })
}

然后,我创建了一个辅助方法:

pub fn stop_active_container(name: &str) {
    Command::new("docker")
        .arg("rm")
        .arg("-f")
        .arg(&name)
        .status()
        .unwrap();
}

然后我结合使用这两种方法以及

ctor
板条箱来处理创建和销毁。

lazy_static! {
    static ref CTN_ID: Uuid = Uuid::new_v4();
    static ref CTN: AsyncOnce<PostgresTestContainer> = AsyncOnce::new(async { PostgresTestContainer::create(CTN_ID.clone()).await.unwrap() });
    ...
}
...
#[dtor]
fn cleanup() {
    docker_helpers::stop_active_container(CTN_ID.clone());
}

我真的不喜欢这个解决方案,因为它依赖于从命令行调用 Docker,但看起来它可以正常工作。

很高兴看到 Rust 在未来开发其测试工具。拥有设置和拆卸方法将是一个很棒的补充!

© www.soinside.com 2019 - 2024. All rights reserved.