mod common;
use bollard::container::ListContainersOptions;
use common::{is_docker_running, with_docker_cleanup};
use docktopus::DockerBuilder;
use docktopus::config::{DockerCommand, DockerfileConfig};
use futures_util::TryStreamExt;
use std::collections::HashMap;
use std::time::Duration;
#[tokio::test]
async fn test_dockerfile_deployment() -> color_eyre::Result<()> {
with_docker_cleanup(|test_id| {
Box::pin(async move {
if !is_docker_running() {
println!("Skipping test: Docker is not running");
return Ok(());
}
let builder = DockerBuilder::new().await?;
let network_name = format!("test-network-{}", test_id);
let mut network_labels = HashMap::new();
network_labels.insert("test_id".to_string(), test_id.to_string());
builder
.create_network_with_retry(
&network_name,
3,
Duration::from_secs(2),
Some(network_labels),
)
.await?;
println!("Pulling alpine image...");
builder
.client()
.create_image(
Some(bollard::image::CreateImageOptions {
from_image: "alpine",
tag: "latest",
..Default::default()
}),
None,
None,
)
.try_collect::<Vec<_>>()
.await?;
println!("Image pull complete");
let config = DockerfileConfig {
base_image: "alpine:latest".to_string(),
commands: vec![
DockerCommand::Run {
command: "echo 'test' > /test.txt".to_string(),
},
DockerCommand::Label {
labels: {
let mut labels = HashMap::new();
labels.insert("test_id".to_string(), test_id.to_string());
labels
},
},
DockerCommand::Cmd {
command: vec!["sleep".to_string(), "30".to_string()], },
],
};
let tag = format!("test-dockerfile-{}", test_id);
println!("Building image with tag: {}", tag);
let container_id = builder
.deploy_dockerfile(&config, &tag, None, None, Some(network_name.clone()), None)
.await?;
println!("Container created with ID: {}", container_id);
tokio::time::sleep(Duration::from_millis(100)).await;
let mut filters = std::collections::HashMap::new();
filters.insert("id".to_string(), vec![container_id.clone()]);
filters.insert("label".to_string(), vec![format!("test_id={}", test_id)]);
let mut retries = 5;
let mut container_running = false;
while retries > 0 {
println!("Checking container state, attempt {}", 6 - retries);
if let Ok(containers) = builder
.client()
.list_containers(Some(ListContainersOptions {
all: true,
filters: filters.clone(),
..Default::default()
}))
.await
{
if containers.is_empty() {
println!("No containers found matching filters");
} else {
println!("Container found and running");
container_running = true;
break;
}
} else {
println!("Error listing containers");
}
retries -= 1;
tokio::time::sleep(Duration::from_millis(500)).await;
}
if !container_running {
println!("Container not found with filters. Checking container inspect...");
if let Ok(inspect) = builder
.client()
.inspect_container(&container_id, None)
.await
{
println!("Container inspect result: {:?}", inspect);
} else {
println!("Failed to inspect container");
}
}
assert!(container_running, "Container should be running");
Ok(())
})
})
.await
}