use docker_wrapper::prerequisites::ensure_docker;
use docker_wrapper::{DockerCommand, PushCommand};
async fn ensure_docker_or_skip() {
match ensure_docker().await {
Ok(_) => {}
Err(_) => {
println!("Docker not available - skipping push integration test");
}
}
}
async fn can_reach_registry() -> bool {
match tokio::process::Command::new("ping")
.args(["-c", "1", "registry-1.docker.io"])
.output()
.await
{
Ok(output) => output.status.success(),
Err(_) => false,
}
}
async fn has_local_registry() -> bool {
match tokio::process::Command::new("curl")
.args(["-s", "http://localhost:5000/v2/"])
.output()
.await
{
Ok(output) => output.status.success(),
Err(_) => false,
}
}
#[tokio::test]
async fn test_push_prerequisites_validation() {
match ensure_docker().await {
Ok(info) => {
println!("Push: Prerequisites OK - Docker {}", info.version.version);
assert!(!info.version.version.is_empty());
}
Err(e) => {
println!("Push: Prerequisites failed (expected in some CI): {e}");
}
}
}
#[tokio::test]
async fn test_push_command_builder() {
let push_cmd = PushCommand::new("myregistry.com/myapp:v1.0")
.all_tags()
.platform("linux/amd64")
.quiet()
.disable_content_trust();
let args = push_cmd.build_command_args();
assert!(args.contains(&"--all-tags".to_string()));
assert!(args.contains(&"--platform".to_string()));
assert!(args.contains(&"linux/amd64".to_string()));
assert!(args.contains(&"--quiet".to_string()));
assert!(args.contains(&"--disable-content-trust".to_string()));
assert!(args.contains(&"myregistry.com/myapp:v1.0".to_string()));
assert_eq!(args.last(), Some(&"myregistry.com/myapp:v1.0".to_string()));
assert_eq!(push_cmd.get_image(), "myregistry.com/myapp:v1.0");
assert!(push_cmd.is_all_tags());
assert!(push_cmd.is_quiet());
assert!(push_cmd.is_content_trust_disabled());
assert_eq!(push_cmd.get_platform(), Some("linux/amd64"));
println!("Push: Command builder validation passed");
}
#[tokio::test]
async fn test_push_nonexistent_image() {
ensure_docker_or_skip().await;
let push_cmd = PushCommand::new("nonexistent/invalid-image:no-such-tag");
match push_cmd.execute().await {
Ok(output) => {
println!("Push: Nonexistent image unexpectedly succeeded");
assert!(!output.success);
}
Err(e) => {
println!("Push: Nonexistent image correctly failed: {e}");
let error_msg = e.to_string().to_lowercase();
assert!(
error_msg.contains("no such image")
|| error_msg.contains("not found")
|| error_msg.contains("does not exist")
|| error_msg.contains("repository does not exist")
|| error_msg.contains("failed")
|| error_msg.contains("error")
);
}
}
}
#[tokio::test]
async fn test_push_to_localhost_registry() {
ensure_docker_or_skip().await;
if !has_local_registry().await {
println!("Push: No local registry available - skipping localhost test");
return;
}
let push_cmd = PushCommand::new("localhost:5000/test:latest");
match push_cmd.execute().await {
Ok(output) => {
println!("Push: Localhost registry test passed");
if output.success {
println!("Successfully pushed to local registry");
}
}
Err(e) => {
println!("Push: Localhost registry test failed (may be expected): {e}");
}
}
}
#[tokio::test]
async fn test_push_with_quiet_mode() {
ensure_docker_or_skip().await;
let push_cmd = PushCommand::new("test/nonexistent:latest").quiet();
match push_cmd.execute().await {
Ok(output) => {
println!("Push: Quiet mode test completed");
assert!(!output.success);
}
Err(e) => {
println!("Push: Quiet mode test failed as expected: {e}");
}
}
}
#[tokio::test]
async fn test_push_with_platform() {
ensure_docker_or_skip().await;
let push_cmd = PushCommand::new("test/nonexistent:latest").platform("linux/amd64");
match push_cmd.execute().await {
Ok(output) => {
println!("Push: Platform test completed");
assert!(!output.success);
}
Err(e) => {
println!("Push: Platform test failed as expected: {e}");
}
}
}
#[tokio::test]
async fn test_push_disable_content_trust() {
ensure_docker_or_skip().await;
let push_cmd = PushCommand::new("test/nonexistent:latest").disable_content_trust();
match push_cmd.execute().await {
Ok(output) => {
println!("Push: Disable content trust test completed");
assert!(!output.success);
}
Err(e) => {
println!("Push: Disable content trust test failed as expected: {e}");
}
}
}
#[tokio::test]
async fn test_push_all_tags() {
ensure_docker_or_skip().await;
let push_cmd = PushCommand::new("test/nonexistent").all_tags();
match push_cmd.execute().await {
Ok(output) => {
println!("Push: All tags test completed");
assert!(!output.success);
}
Err(e) => {
println!("Push: All tags test failed as expected: {e}");
}
}
}
#[tokio::test]
async fn test_push_registry_formats() {
let test_cases = vec![
("myapp:latest", vec!["push", "myapp:latest"]),
("username/myapp:v1.0", vec!["push", "username/myapp:v1.0"]),
(
"registry.com/myapp:latest",
vec!["push", "registry.com/myapp:latest"],
),
(
"registry.com:5000/namespace/myapp:v2.0",
vec!["push", "registry.com:5000/namespace/myapp:v2.0"],
),
(
"localhost:5000/test:dev",
vec!["push", "localhost:5000/test:dev"],
),
];
for (image, expected_args) in test_cases {
let push_cmd = PushCommand::new(image);
let args = push_cmd.build_command_args();
assert_eq!(args, expected_args);
assert_eq!(push_cmd.get_image(), image);
}
println!("Push: Registry formats validation test passed");
}
#[tokio::test]
async fn test_push_authentication_required() {
ensure_docker_or_skip().await;
if !can_reach_registry().await {
println!("Push: Cannot reach registry - skipping authentication test");
return;
}
let push_cmd = PushCommand::new("dockerusername/nonexistent:test");
match push_cmd.execute().await {
Ok(output) => {
println!("Push: Authentication test completed");
assert!(!output.success);
}
Err(e) => {
println!("Push: Authentication test failed as expected: {e}");
let error_msg = e.to_string().to_lowercase();
assert!(
error_msg.contains("authentication")
|| error_msg.contains("unauthorized")
|| error_msg.contains("denied")
|| error_msg.contains("no such image")
|| error_msg.contains("not found")
);
}
}
}
#[tokio::test]
async fn test_push_multiple_options() {
ensure_docker_or_skip().await;
let push_cmd = PushCommand::new("test/nonexistent:latest")
.quiet()
.disable_content_trust()
.platform("linux/amd64");
match push_cmd.execute().await {
Ok(output) => {
println!("Push: Multiple options test completed");
assert!(!output.success);
}
Err(e) => {
println!("Push: Multiple options test failed as expected: {e}");
}
}
}
#[tokio::test]
async fn test_push_error_handling() {
ensure_docker_or_skip().await;
let push_cmd = PushCommand::new("");
match push_cmd.execute().await {
Ok(output) => {
println!("Push: Empty image name unexpectedly succeeded");
assert!(!output.success);
}
Err(e) => {
println!("Push: Empty image name correctly failed: {e}");
}
}
}
#[tokio::test]
async fn test_push_extensibility() {
let mut push_cmd = PushCommand::new("myapp");
push_cmd
.arg("--experimental-feature")
.arg("value")
.args(vec!["--custom", "option"]);
println!("Push: Extensibility test passed");
}
#[tokio::test]
async fn test_push_command_validation() {
let test_cases = vec![
("myapp:latest", false, false, None, false),
("myapp", true, false, None, false),
("myapp:v1.0", false, true, Some("linux/amd64"), true),
(
"registry.com/myapp:stable",
false,
false,
Some("linux/arm64"),
false,
),
];
for (image, all_tags, disable_trust, platform, quiet) in test_cases {
let mut push_cmd = PushCommand::new(image);
if all_tags {
push_cmd = push_cmd.all_tags();
}
if disable_trust {
push_cmd = push_cmd.disable_content_trust();
}
if let Some(p) = platform {
push_cmd = push_cmd.platform(p);
}
if quiet {
push_cmd = push_cmd.quiet();
}
let args = push_cmd.build_command_args();
assert_eq!(args.last(), Some(&image.to_string()));
assert_eq!(push_cmd.get_image(), image);
assert_eq!(push_cmd.is_all_tags(), all_tags);
assert_eq!(push_cmd.is_quiet(), quiet);
assert_eq!(push_cmd.is_content_trust_disabled(), disable_trust);
if let Some(p) = platform {
assert_eq!(push_cmd.get_platform(), Some(p));
} else {
assert_eq!(push_cmd.get_platform(), None);
}
}
println!("Push: Command validation test passed");
}