mod common;
use bollard::query_parameters::{
CreateImageOptionsBuilder, InspectContainerOptions, ListContainersOptionsBuilder,
};
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.clone());
builder
.create_network_with_retry(
&network_name,
3,
Duration::from_secs(2),
Some(network_labels),
)
.await?;
println!("Pulling alpine image...");
let create_opts = CreateImageOptionsBuilder::default()
.from_image("alpine")
.tag("latest")
.build();
builder
.client()
.create_image(Some(create_opts), 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.clone());
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: HashMap<String, Vec<String>> = 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);
let list_opts = ListContainersOptionsBuilder::default()
.all(true)
.filters(&filters)
.build();
if let Ok(containers) = builder.client().list_containers(Some(list_opts)).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::<InspectContainerOptions>)
.await
{
println!("Container inspect result: {:?}", inspect);
} else {
println!("Failed to inspect container");
}
}
assert!(container_running, "Container should be running");
Ok(())
})
})
.await
}