#![allow(clippy::expect_used)]
use std::time::SystemTime;
use assert2::{check, let_assert};
use rstest::rstest;
use tokio::task::JoinSet;
use tracing::{debug, info};
use rustainers::images::{GenericImage, Minio, Mongo, Mosquitto, Nats, Postgres, Redis};
use rustainers::runner::{RunOption, Runner};
use rustainers::{ExposedPort, ImageName, Port, WaitStrategy};
mod common;
pub use self::common::*;
#[rstest]
#[tokio::test]
async fn test_image_postgres(runner: &Runner) -> anyhow::Result<()> {
let options = RunOption::builder().with_remove(true).build();
let image = Postgres::default();
let container = runner.start_with_options(image, options).await?;
debug!("Started {container}");
container.url().await?;
Ok(())
}
#[rstest]
#[tokio::test]
async fn test_postgres_build_config(runner: &Runner) -> anyhow::Result<()> {
let options = RunOption::builder().with_remove(true).build();
let image = Postgres::default().with_port(ExposedPort::fixed(Port::new(5432), Port::new(5432)));
let container = runner.start_with_options(image, options).await?;
debug!("Started {container}");
let result = container.config().await.expect("config");
check!(result == "host=127.0.0.1 user=postgres password=passwd port=5432 dbname=postgres");
let result = container.url().await.expect("url");
check!(result == "postgresql://postgres:passwd@127.0.0.1:5432/postgres");
Ok(())
}
#[rstest]
#[tokio::test]
async fn test_image_minio(runner: &Runner) -> anyhow::Result<()> {
let options = RunOption::builder().with_remove(true).build();
let image = Minio::default();
let container = runner.start_with_options(image, options).await?;
debug!("Started {container}");
container.endpoint().await?;
container.console_endpoint().await?;
Ok(())
}
#[rstest]
#[tokio::test]
async fn test_minio_endpoint(runner: &Runner) -> anyhow::Result<()> {
let options = RunOption::builder().with_remove(true).build();
let image = Minio::default().with_port(ExposedPort::fixed(Port::new(9000), Port::new(9124)));
let container = runner.start_with_options(image, options).await?;
debug!("Started {container}");
let result = container.endpoint().await;
let_assert!(Ok(endpoint) = result);
check!(endpoint == "http://127.0.0.1:9124");
Ok(())
}
#[rstest]
#[tokio::test]
async fn test_image_redis(runner: &Runner) -> anyhow::Result<()> {
let options = RunOption::builder().with_remove(true).build();
let image = Redis::default();
let container = runner.start_with_options(image, options).await?;
debug!("Started {container}");
container.endpoint().await?;
Ok(())
}
#[rstest]
#[tokio::test]
async fn test_redis_endpoint(runner: &Runner) -> anyhow::Result<()> {
let options = RunOption::builder().with_remove(true).build();
let image = Redis::default().with_port(ExposedPort::fixed(Port::new(6379), Port::new(9125)));
let container = runner.start_with_options(image, options).await?;
debug!("Started {container}");
let result = container.endpoint().await;
let_assert!(Ok(endpoint) = result);
check!(endpoint == "redis://127.0.0.1:9125");
Ok(())
}
#[rstest]
#[tokio::test]
async fn test_image_nats(runner: &Runner) -> anyhow::Result<()> {
let options = RunOption::builder().with_remove(true).build();
let image = Nats::default();
let container = runner.start_with_options(image, options).await?;
debug!("Started {container}");
container.client_endpoint().await?;
Ok(())
}
#[rstest]
#[tokio::test]
async fn test_nats_client_endpoint(runner: &Runner) -> anyhow::Result<()> {
let options = RunOption::builder()
.with_remove(true)
.with_name("test_nats_client_endpoint")
.build();
let image =
Nats::default().with_client_port(ExposedPort::fixed(Port::new(8333), Port::new(8333)));
let container = runner.start_with_options(image, options).await?;
debug!("Started {container}");
let result = container.client_endpoint().await;
let_assert!(Ok(endpoint) = result);
check!(endpoint == "nats://127.0.0.1:8333");
Ok(())
}
#[rstest]
#[tokio::test]
async fn test_nats_monitoring_endpoint(runner: &Runner) -> anyhow::Result<()> {
let options = RunOption::builder()
.with_remove(true)
.with_name("test_nats_monitoring_endpoint")
.build();
let image =
Nats::default().with_monitoring_port(ExposedPort::fixed(Port::new(8666), Port::new(8666)));
let container = runner.start_with_options(image, options).await?;
debug!("Started {container}");
let result = container.monitoring_endpoint().await;
let_assert!(Ok(endpoint) = result);
check!(endpoint == "http://127.0.0.1:8666");
Ok(())
}
#[rstest]
#[tokio::test]
async fn test_nats_cluster_endpoint(runner: &Runner) -> anyhow::Result<()> {
let options = RunOption::builder()
.with_name("test_nats_cluster_endpoint")
.with_remove(true)
.build();
let image =
Nats::default().with_cluster_port(ExposedPort::fixed(Port::new(8777), Port::new(8777)));
let container = runner.start_with_options(image, options).await?;
debug!("Started {container}");
let result = container.cluster_endpoint().await;
let_assert!(Ok(endpoint) = result);
check!(endpoint == "nats-route://127.0.0.1:8777");
Ok(())
}
#[rstest]
#[tokio::test]
async fn test_image_mongo(runner: &Runner) -> anyhow::Result<()> {
let options = RunOption::builder().with_remove(true).build();
let image = Mongo::default();
let container = runner.start_with_options(image, options).await?;
debug!("Started {container}");
container.endpoint().await?;
Ok(())
}
#[rstest]
#[tokio::test]
async fn test_mongo_endpoint(runner: &Runner) -> anyhow::Result<()> {
let options = RunOption::builder().with_remove(true).build();
let image = Mongo::default().with_port(ExposedPort::fixed(Port::new(27017), Port::new(9126)));
let container = runner.start_with_options(image, options).await?;
debug!("Started {container}");
let result = container.endpoint().await;
let_assert!(Ok(endpoint) = result);
check!(endpoint == "mongodb://127.0.0.1:9126");
Ok(())
}
#[rstest]
#[tokio::test]
async fn test_run_in_multiple_tasks(runner: &Runner) -> anyhow::Result<()> {
if let Runner::Podman(_) = &runner {
return Ok(());
}
let start = SystemTime::now();
let mut set = JoinSet::new();
let size = 20;
for id in 0..size {
let img = Redis::default();
let runner = runner.clone();
set.spawn(async move {
let container = runner.start(img).await.expect("container started");
(id, container)
});
}
let mut finished = vec![false; size];
#[allow(clippy::indexing_slicing)]
while let Some(Ok((id, container))) = set.join_next().await {
info!("Container #{id} {container:#?}");
finished[id] = true;
}
let duration = start.elapsed()?;
for (id, value) in finished.iter().enumerate() {
check!(*value == true, "Task #{id} not finished");
}
info!("Took {}s", duration.as_secs_f32());
Ok(())
}
#[rstest]
#[tokio::test]
async fn test_mosquitto_endpoint(runner: &Runner) -> anyhow::Result<()> {
let options = RunOption::builder().with_remove(true).build();
let image =
Mosquitto::default().with_port(ExposedPort::fixed(Port::new(6379), Port::new(9127)));
let container = runner.start_with_options(image, options).await?;
debug!("Started {container}");
let result = container.endpoint().await;
let_assert!(Ok(endpoint) = result);
check!(endpoint == "mqtt://127.0.0.1:9127");
Ok(())
}
#[rstest]
#[tokio::test]
async fn test_generic_image(runner: &Runner) -> anyhow::Result<()> {
let options = RunOption::builder().with_remove(true).build();
let name = ImageName::new("docker.io/nginx");
let mut nginx = GenericImage::new(name);
let container_port = 80;
nginx.add_port_mapping(container_port);
nginx.set_wait_strategy(WaitStrategy::http("/"));
let container = runner.start_with_options(nginx, options).await?;
debug!("Started {container}");
let host_port = container.host_port(container_port).await;
let_assert!(Ok(_) = host_port);
Ok(())
}