use docker_wrapper::prerequisites::ensure_docker;
use docker_wrapper::{DockerCommand, PsCommand, RunCommand};
use std::time::Duration;
use tokio::time::sleep;
async fn ensure_docker_or_skip() {
match ensure_docker().await {
Ok(_) => {}
Err(_) => {
println!("Docker not available - skipping ps integration test");
}
}
}
async fn start_test_containers() -> Result<Vec<String>, Box<dyn std::error::Error>> {
let mut container_ids = Vec::new();
let run_cmd1 = RunCommand::new("alpine:latest")
.name("ps-test-container-1")
.detach()
.cmd(vec!["sleep".to_string(), "30".to_string()]);
let container_id1 = run_cmd1.execute().await?;
container_ids.push(container_id1.as_str().to_string());
let run_cmd2 = RunCommand::new("alpine:latest")
.name("ps-test-container-2")
.detach()
.env("TEST_ENV", "integration")
.cmd(vec!["sleep".to_string(), "30".to_string()]);
let container_id2 = run_cmd2.execute().await?;
container_ids.push(container_id2.as_str().to_string());
sleep(Duration::from_millis(1000)).await;
Ok(container_ids)
}
async fn cleanup_test_containers(container_names: &[&str]) {
for name in container_names {
let _ = tokio::process::Command::new("docker")
.args(["stop", name])
.output()
.await;
let _ = tokio::process::Command::new("docker")
.args(["rm", name])
.output()
.await;
}
}
#[tokio::test]
async fn test_ps_list_running_containers() {
ensure_docker_or_skip().await;
match start_test_containers().await {
Ok(_) => {
let ps_cmd = PsCommand::new();
match ps_cmd.execute().await {
Ok(output) => {
println!("PS: List running containers test passed");
assert!(output.success());
assert!(!output.stdout_is_empty());
let _count = output.container_count();
}
Err(e) => {
println!("PS: List running containers test failed (may be expected): {e}");
}
}
cleanup_test_containers(&["ps-test-container-1", "ps-test-container-2"]).await;
}
Err(e) => {
println!("PS: Could not start test containers: {e}");
}
}
}
#[tokio::test]
async fn test_ps_list_all_containers() {
ensure_docker_or_skip().await;
match start_test_containers().await {
Ok(_) => {
let _ = tokio::process::Command::new("docker")
.args(["stop", "ps-test-container-1"])
.output()
.await;
sleep(Duration::from_millis(500)).await;
let ps_cmd = PsCommand::new().all();
match ps_cmd.execute().await {
Ok(output) => {
println!("PS: List all containers test passed");
assert!(output.success());
assert!(!output.stdout_is_empty());
let output_text = output.stdout.to_lowercase();
assert!(
output_text.contains("ps-test-container") || output.container_count() > 0
);
}
Err(e) => {
println!("PS: List all containers test failed (may be expected): {e}");
}
}
cleanup_test_containers(&["ps-test-container-1", "ps-test-container-2"]).await;
}
Err(e) => {
println!("PS: Could not start test containers: {e}");
}
}
}
#[tokio::test]
async fn test_ps_quiet_mode() {
ensure_docker_or_skip().await;
match start_test_containers().await {
Ok(_) => {
let ps_cmd = PsCommand::new().quiet();
match ps_cmd.execute().await {
Ok(output) => {
println!("PS: Quiet mode test passed");
assert!(output.success());
if !output.stdout_is_empty() {
let ids = output.container_ids();
assert!(!ids.is_empty());
for id in ids {
assert!(id.len() >= 12); assert!(id.chars().all(|c| c.is_ascii_hexdigit()));
}
}
}
Err(e) => {
println!("PS: Quiet mode test failed (may be expected): {e}");
}
}
cleanup_test_containers(&["ps-test-container-1", "ps-test-container-2"]).await;
}
Err(e) => {
println!("PS: Could not start test containers: {e}");
}
}
}
#[tokio::test]
async fn test_ps_with_filters() {
ensure_docker_or_skip().await;
match start_test_containers().await {
Ok(_) => {
let ps_cmd = PsCommand::new().filter("name=ps-test-container-1").all();
match ps_cmd.execute().await {
Ok(output) => {
println!("PS: Filter test passed");
assert!(output.success());
if !output.stdout_is_empty() {
let output_text = output.stdout.to_lowercase();
assert!(output_text.contains("ps-test-container-1"));
assert!(!output_text.contains("ps-test-container-2"));
}
}
Err(e) => {
println!("PS: Filter test failed (may be expected): {e}");
}
}
cleanup_test_containers(&["ps-test-container-1", "ps-test-container-2"]).await;
}
Err(e) => {
println!("PS: Could not start test containers: {e}");
}
}
}
#[tokio::test]
async fn test_ps_json_format() {
ensure_docker_or_skip().await;
match start_test_containers().await {
Ok(_) => {
let ps_cmd = PsCommand::new().format_json();
match ps_cmd.execute().await {
Ok(output) => {
println!("PS: JSON format test passed");
assert!(output.success());
if !output.stdout_is_empty() {
let stdout = output.stdout.trim();
if !stdout.is_empty() {
for line in stdout.lines() {
let json_result = serde_json::from_str::<serde_json::Value>(line);
assert!(
json_result.is_ok(),
"Each line should be valid JSON: {line}"
);
}
}
}
}
Err(e) => {
println!("PS: JSON format test failed (may be expected): {e}");
}
}
cleanup_test_containers(&["ps-test-container-1", "ps-test-container-2"]).await;
}
Err(e) => {
println!("PS: Could not start test containers: {e}");
}
}
}
#[tokio::test]
async fn test_ps_latest_container() {
ensure_docker_or_skip().await;
match start_test_containers().await {
Ok(_) => {
let ps_cmd = PsCommand::new().latest().all();
match ps_cmd.execute().await {
Ok(output) => {
println!("PS: Latest container test passed");
assert!(output.success());
if !output.stdout_is_empty() {
let lines: Vec<&str> = output.stdout.lines().collect();
assert!(!lines.is_empty());
}
}
Err(e) => {
println!("PS: Latest container test failed (may be expected): {e}");
}
}
cleanup_test_containers(&["ps-test-container-1", "ps-test-container-2"]).await;
}
Err(e) => {
println!("PS: Could not start test containers: {e}");
}
}
}
#[tokio::test]
async fn test_ps_with_size() {
ensure_docker_or_skip().await;
match start_test_containers().await {
Ok(_) => {
let ps_cmd = PsCommand::new().size();
match ps_cmd.execute().await {
Ok(output) => {
println!("PS: Size option test passed");
assert!(output.success());
if !output.stdout_is_empty() {
let output_text = output.stdout.to_lowercase();
assert!(
output_text.contains("size")
|| output_text.contains("kb")
|| output_text.contains("mb")
|| output_text.contains("b")
);
}
}
Err(e) => {
println!("PS: Size option test failed (may be expected): {e}");
}
}
cleanup_test_containers(&["ps-test-container-1", "ps-test-container-2"]).await;
}
Err(e) => {
println!("PS: Could not start test containers: {e}");
}
}
}
#[tokio::test]
async fn test_ps_command_builder() {
let complex_ps = PsCommand::new()
.all()
.filter("status=running")
.filter("name=web")
.format_json()
.no_trunc()
.size()
.quiet();
let args = complex_ps.build_command_args();
assert!(args.contains(&"--all".to_string()));
assert!(args.contains(&"--filter".to_string()));
assert!(args.contains(&"status=running".to_string()));
assert!(args.contains(&"name=web".to_string()));
assert!(args.contains(&"--format".to_string()));
assert!(args.contains(&"json".to_string()));
assert!(args.contains(&"--no-trunc".to_string()));
assert!(args.contains(&"--size".to_string()));
assert!(args.contains(&"--quiet".to_string()));
println!("PS: Command builder validation passed");
}
#[tokio::test]
async fn test_ps_prerequisites_validation() {
match ensure_docker().await {
Ok(info) => {
let version = &info.version.version;
println!("PS: Prerequisites OK - Docker {version}");
assert!(!info.version.version.is_empty());
}
Err(e) => {
println!("PS: Prerequisites failed (expected in some CI): {e}");
}
}
}
#[tokio::test]
async fn test_ps_no_containers() {
ensure_docker_or_skip().await;
let ps_cmd = PsCommand::new()
.filter("name=nonexistent-container-name-12345")
.all();
match ps_cmd.execute().await {
Ok(output) => {
println!("PS: No containers test passed");
assert!(output.success());
assert_eq!(output.container_count(), 0);
if !output.stdout_is_empty() {
let lines: Vec<&str> = output.stdout.lines().collect();
assert!(lines.len() <= 1); }
}
Err(e) => {
println!("PS: No containers test failed (may be expected): {e}");
}
}
}