use std::{path::PathBuf, process::Command, time::Duration}; fn repo_root() -> PathBuf { PathBuf::from(env!("CARGO_MANIFEST_DIR")) .parent() .and_then(|p| p.parent()) .expect("api crate should live under repo root") .to_path_buf() } fn docker_enabled() -> bool { std::env::var("CONTROL_TEST_DOCKER") .ok() .is_some_and(|v| v.trim() == "1") } fn compose_file() -> PathBuf { repo_root().join("docker-compose.yml") } #[test] fn minio_docs_bucket_exists_and_credentials_work_in_compose_network() { if !docker_enabled() { eprintln!("skipping: set CONTROL_TEST_DOCKER=1 to enable docker compose tests"); return; } let compose = compose_file(); let up = Command::new("docker") .args(["compose", "-f"]) .arg(&compose) .args(["up", "-d", "minio"]) .status() .expect("failed to run docker compose up minio"); assert!(up.success(), "docker compose up minio failed"); // The `minio-init` service runs `mc` inside the compose network. let out = Command::new("docker") .args(["compose", "-f"]) .arg(&compose) .args([ "run", "--rm", "minio-init", "/bin/sh", "-lc", "mc alias set local http://minio:9000 minioadmin minioadmin && mc ls local/cloudlysis-docs-0 && mc ls local/cloudlysis-docs-1 && mc ls local/cloudlysis-docs-2", ]) .output() .expect("failed to run docker compose run minio-init"); // Best-effort cleanup (keep it short; other docker tests may reuse this env). let _ = Command::new("docker") .args(["compose", "-f"]) .arg(&compose) .args(["down", "-v"]) .status(); assert!( out.status.success(), "minio-init bucket check failed: {}", String::from_utf8_lossy(&out.stderr) ); // `mc ls` prints at least one line when the bucket exists (even if empty it prints the bucket line). let stdout = String::from_utf8_lossy(&out.stdout); assert!( stdout.contains("cloudlysis-docs-0") && stdout.contains("cloudlysis-docs-1") && stdout.contains("cloudlysis-docs-2"), "expected mc ls output to mention bucket: {stdout}" ); // Avoid tests hanging due to docker flakiness. std::thread::sleep(Duration::from_millis(10)); }