use docker_wrapper::prerequisites::ensure_docker;
use docker_wrapper::{BakeCommand, DockerCommand};
use std::fs;
use tempfile::TempDir;
async fn ensure_docker_or_skip() {
match ensure_docker().await {
Ok(_) => {}
Err(_) => {
println!("Docker not available - skipping bake integration test");
}
}
}
fn create_test_bake_files() -> Result<TempDir, Box<dyn std::error::Error>> {
let temp_dir = TempDir::new()?;
let compose_content = r#"version: '3.8'
services:
web:
build:
context: .
dockerfile: Dockerfile.web
ports:
- "8080:80"
api:
build:
context: .
dockerfile: Dockerfile.api
ports:
- "3000:3000"
"#;
let bake_hcl_content = r#"group "default" {
targets = ["web", "api"]
}
target "web" {
dockerfile = "Dockerfile.web"
tags = ["myapp/web:latest"]
platforms = ["linux/amd64"]
}
target "api" {
dockerfile = "Dockerfile.api"
tags = ["myapp/api:latest"]
platforms = ["linux/amd64"]
}
"#;
let dockerfile_web = r#"FROM nginx:alpine
COPY . /usr/share/nginx/html
"#;
let dockerfile_api = r#"FROM node:alpine
WORKDIR /app
COPY . .
CMD ["node", "server.js"]
"#;
fs::write(temp_dir.path().join("docker-compose.yml"), compose_content)?;
fs::write(temp_dir.path().join("docker-bake.hcl"), bake_hcl_content)?;
fs::write(temp_dir.path().join("Dockerfile.web"), dockerfile_web)?;
fs::write(temp_dir.path().join("Dockerfile.api"), dockerfile_api)?;
fs::write(temp_dir.path().join("index.html"), "<h1>Test App</h1>")?;
Ok(temp_dir)
}
#[tokio::test]
async fn test_bake_prerequisites_validation() {
match ensure_docker().await {
Ok(info) => {
println!("Bake: Prerequisites OK - Docker {}", info.version.version);
assert!(!info.version.version.is_empty());
}
Err(e) => {
println!("Bake: Prerequisites failed (expected in some CI): {e}");
}
}
}
#[tokio::test]
async fn test_bake_command_builder() {
let bake_cmd = BakeCommand::new()
.file("docker-compose.yml")
.file("custom-bake.hcl")
.target("web")
.target("api")
.builder("mybuilder")
.set("web.platform", "linux/amd64,linux/arm64")
.push()
.no_cache()
.progress("plain");
let args = bake_cmd.build_command_args();
assert!(args.contains(&"--file".to_string()));
assert!(args.contains(&"docker-compose.yml".to_string()));
assert!(args.contains(&"custom-bake.hcl".to_string()));
assert!(args.contains(&"--builder".to_string()));
assert!(args.contains(&"mybuilder".to_string()));
assert!(args.contains(&"--set".to_string()));
assert!(args.contains(&"web.platform=linux/amd64,linux/arm64".to_string()));
assert!(args.contains(&"--push".to_string()));
assert!(args.contains(&"--no-cache".to_string()));
assert!(args.contains(&"--progress".to_string()));
assert!(args.contains(&"plain".to_string()));
assert!(args.contains(&"web".to_string()));
assert!(args.contains(&"api".to_string()));
assert_eq!(bake_cmd.target_count(), 2);
assert_eq!(bake_cmd.get_targets(), &["web", "api"]);
assert_eq!(
bake_cmd.get_files(),
&["docker-compose.yml", "custom-bake.hcl"]
);
assert!(bake_cmd.is_push_enabled());
assert!(!bake_cmd.is_load_enabled());
assert!(!bake_cmd.is_dry_run());
println!("Bake: Command builder validation passed");
}
#[tokio::test]
async fn test_bake_basic_command() {
ensure_docker_or_skip().await;
let bake_cmd = BakeCommand::new().print();
match bake_cmd.execute().await {
Ok(output) => {
println!("Bake: Basic command test passed");
assert!(output.success || !output.stderr_is_empty());
}
Err(e) => {
println!("Bake: Basic command test failed (may be expected): {e}");
}
}
}
#[tokio::test]
async fn test_bake_with_compose_file() {
ensure_docker_or_skip().await;
let temp_dir = match create_test_bake_files() {
Ok(dir) => dir,
Err(e) => {
println!("Bake: Could not create test files: {e}");
return;
}
};
let compose_file = temp_dir.path().join("docker-compose.yml");
let bake_cmd = BakeCommand::new()
.file(compose_file.to_string_lossy())
.print();
match bake_cmd.execute().await {
Ok(output) => {
println!("Bake: Compose file test passed");
assert!(output.success);
if !output.stdout_is_empty() {
let stdout = output.stdout.to_lowercase();
assert!(
stdout.contains("web") || stdout.contains("api") || stdout.contains("target")
);
}
}
Err(e) => {
println!("Bake: Compose file test failed (may be expected): {e}");
}
}
}
#[tokio::test]
async fn test_bake_with_hcl_file() {
ensure_docker_or_skip().await;
let temp_dir = match create_test_bake_files() {
Ok(dir) => dir,
Err(e) => {
println!("Bake: Could not create test files: {e}");
return;
}
};
let bake_file = temp_dir.path().join("docker-bake.hcl");
let bake_cmd = BakeCommand::new().file(bake_file.to_string_lossy()).print();
match bake_cmd.execute().await {
Ok(output) => {
println!("Bake: HCL file test passed");
assert!(output.success);
if !output.stdout_is_empty() {
let stdout = output.stdout.to_lowercase();
assert!(
stdout.contains("web") || stdout.contains("api") || stdout.contains("target")
);
}
}
Err(e) => {
println!("Bake: HCL file test failed (may be expected): {e}");
}
}
}
#[tokio::test]
async fn test_bake_list_targets() {
ensure_docker_or_skip().await;
let temp_dir = match create_test_bake_files() {
Ok(dir) => dir,
Err(e) => {
println!("Bake: Could not create test files: {e}");
return;
}
};
let bake_file = temp_dir.path().join("docker-bake.hcl");
let bake_cmd = BakeCommand::new()
.file(bake_file.to_string_lossy())
.list("targets");
match bake_cmd.execute().await {
Ok(output) => {
println!("Bake: List targets test passed");
assert!(output.success);
if !output.stdout_is_empty() {
let stdout = output.stdout;
assert!(stdout.contains("web") || stdout.contains("api"));
}
}
Err(e) => {
println!("Bake: List targets test failed (may be expected): {e}");
}
}
}
#[tokio::test]
async fn test_bake_check_mode() {
ensure_docker_or_skip().await;
let temp_dir = match create_test_bake_files() {
Ok(dir) => dir,
Err(e) => {
println!("Bake: Could not create test files: {e}");
return;
}
};
let compose_file = temp_dir.path().join("docker-compose.yml");
let bake_cmd = BakeCommand::new()
.file(compose_file.to_string_lossy())
.check();
match bake_cmd.execute().await {
Ok(output) => {
println!("Bake: Check mode test passed");
assert!(output.success);
}
Err(e) => {
println!("Bake: Check mode test failed (may be expected): {e}");
}
}
}
#[tokio::test]
async fn test_bake_with_specific_targets() {
ensure_docker_or_skip().await;
let temp_dir = match create_test_bake_files() {
Ok(dir) => dir,
Err(e) => {
println!("Bake: Could not create test files: {e}");
return;
}
};
let bake_file = temp_dir.path().join("docker-bake.hcl");
let bake_cmd = BakeCommand::new()
.file(bake_file.to_string_lossy())
.target("web")
.print();
match bake_cmd.execute().await {
Ok(output) => {
println!("Bake: Specific targets test passed");
assert!(output.success);
if !output.stdout_is_empty() {
let stdout = output.stdout.to_lowercase();
assert!(stdout.contains("web"));
}
}
Err(e) => {
println!("Bake: Specific targets test failed (may be expected): {e}");
}
}
}
#[tokio::test]
async fn test_bake_with_set_overrides() {
ensure_docker_or_skip().await;
let temp_dir = match create_test_bake_files() {
Ok(dir) => dir,
Err(e) => {
println!("Bake: Could not create test files: {e}");
return;
}
};
let bake_file = temp_dir.path().join("docker-bake.hcl");
let bake_cmd = BakeCommand::new()
.file(bake_file.to_string_lossy())
.set("web.tags", "myapp/web:test")
.print();
match bake_cmd.execute().await {
Ok(output) => {
println!("Bake: Set overrides test passed");
assert!(output.success);
}
Err(e) => {
println!("Bake: Set overrides test failed (may be expected): {e}");
}
}
}
#[tokio::test]
async fn test_bake_progress_modes() {
ensure_docker_or_skip().await;
let bake_cmd = BakeCommand::new().progress("plain").print();
match bake_cmd.execute().await {
Ok(output) => {
println!("Bake: Progress modes test passed");
assert!(output.success || !output.stderr_is_empty());
}
Err(e) => {
println!("Bake: Progress modes test failed (may be expected): {e}");
}
}
}
#[tokio::test]
async fn test_bake_debug_mode() {
ensure_docker_or_skip().await;
let bake_cmd = BakeCommand::new().debug().print();
match bake_cmd.execute().await {
Ok(output) => {
println!("Bake: Debug mode test passed");
assert!(output.success || !output.stderr_is_empty());
}
Err(e) => {
println!("Bake: Debug mode test failed (may be expected): {e}");
}
}
}
#[tokio::test]
async fn test_bake_metadata_file() {
ensure_docker_or_skip().await;
let temp_dir = match create_test_bake_files() {
Ok(dir) => dir,
Err(e) => {
println!("Bake: Could not create test files: {e}");
return;
}
};
let compose_file = temp_dir.path().join("docker-compose.yml");
let metadata_file = temp_dir.path().join("metadata.json");
let bake_cmd = BakeCommand::new()
.file(compose_file.to_string_lossy())
.metadata_file(metadata_file.to_string_lossy())
.print();
match bake_cmd.execute().await {
Ok(output) => {
println!("Bake: Metadata file test passed");
assert!(output.success);
}
Err(e) => {
println!("Bake: Metadata file test failed (may be expected): {e}");
}
}
}
#[tokio::test]
async fn test_bake_extensibility() {
let mut bake_cmd = BakeCommand::new();
bake_cmd
.arg("--experimental-feature")
.arg("value")
.args(vec!["--custom", "option"]);
println!("Bake: Extensibility test passed");
}