#[cfg(test)] mod tests { use crate::process::CommandResult; use crate::virt::buildah::BuildahError; use std::sync::Mutex; use lazy_static::lazy_static; // Create a test-specific implementation of the containers module functions // that we can use to verify the correct arguments are passed lazy_static! { static ref LAST_COMMAND: Mutex> = Mutex::new(Vec::new()); static ref SHOULD_FAIL: Mutex = Mutex::new(false); } fn reset_test_state() { let mut cmd = LAST_COMMAND.lock().unwrap(); cmd.clear(); let mut fail = SHOULD_FAIL.lock().unwrap(); *fail = false; } fn set_should_fail(fail: bool) { let mut should_fail = SHOULD_FAIL.lock().unwrap(); *should_fail = fail; } fn get_last_command() -> Vec { let cmd = LAST_COMMAND.lock().unwrap(); cmd.clone() } // Test-specific implementation of execute_buildah_command fn test_execute_buildah_command(args: &[&str]) -> Result { // Record the command { let mut cmd = LAST_COMMAND.lock().unwrap(); cmd.clear(); for arg in args { cmd.push(arg.to_string()); } } // Check if we should fail let should_fail = { let fail = SHOULD_FAIL.lock().unwrap(); *fail }; if should_fail { Err(BuildahError::CommandFailed("Command failed".to_string())) } else { Ok(CommandResult { stdout: "mock stdout".to_string(), stderr: "".to_string(), success: true, code: 0, }) } } // Test implementations of the container functions fn test_from(image: &str) -> Result { test_execute_buildah_command(&["from", image]) } fn test_run(container: &str, command: &str) -> Result { test_execute_buildah_command(&["run", container, "sh", "-c", command]) } fn test_bah_run_with_isolation(container: &str, command: &str, isolation: &str) -> Result { test_execute_buildah_command(&["run", "--isolation", isolation, container, "sh", "-c", command]) } fn test_bah_copy(container: &str, source: &str, dest: &str) -> Result { test_execute_buildah_command(&["copy", container, source, dest]) } fn test_bah_add(container: &str, source: &str, dest: &str) -> Result { test_execute_buildah_command(&["add", container, source, dest]) } fn test_bah_commit(container: &str, image_name: &str) -> Result { test_execute_buildah_command(&["commit", container, image_name]) } fn test_bah_remove(container: &str) -> Result { test_execute_buildah_command(&["rm", container]) } fn test_bah_list() -> Result { test_execute_buildah_command(&["containers"]) } fn test_bah_build(tag: Option<&str>, context_dir: &str, file: &str, isolation: Option<&str>) -> Result { let mut args = Vec::new(); args.push("build"); if let Some(tag_value) = tag { args.push("-t"); args.push(tag_value); } if let Some(isolation_value) = isolation { args.push("--isolation"); args.push(isolation_value); } args.push("-f"); args.push(file); args.push(context_dir); test_execute_buildah_command(&args) } // Tests for each function #[test] fn test_from_function() { reset_test_state(); let image = "alpine:latest"; let result = test_from(image); assert!(result.is_ok()); let cmd = get_last_command(); assert_eq!(cmd, vec!["from", "alpine:latest"]); } #[test] fn test_run_function() { reset_test_state(); let container = "my-container"; let command = "echo hello"; // Test without isolation let result = test_run(container, command); assert!(result.is_ok()); let cmd = get_last_command(); assert_eq!(cmd, vec!["run", "my-container", "sh", "-c", "echo hello"]); } #[test] fn test_bah_run_with_isolation_function() { reset_test_state(); let container = "my-container"; let command = "echo hello"; let isolation = "chroot"; let result = test_bah_run_with_isolation(container, command, isolation); assert!(result.is_ok()); let cmd = get_last_command(); assert_eq!(cmd, vec!["run", "--isolation", "chroot", "my-container", "sh", "-c", "echo hello"]); } #[test] fn test_bah_copy_function() { reset_test_state(); let container = "my-container"; let source = "/local/path"; let dest = "/container/path"; let result = test_bah_copy(container, source, dest); assert!(result.is_ok()); let cmd = get_last_command(); assert_eq!(cmd, vec!["copy", "my-container", "/local/path", "/container/path"]); } #[test] fn test_bah_add_function() { reset_test_state(); let container = "my-container"; let source = "/local/path"; let dest = "/container/path"; let result = test_bah_add(container, source, dest); assert!(result.is_ok()); let cmd = get_last_command(); assert_eq!(cmd, vec!["add", "my-container", "/local/path", "/container/path"]); } #[test] fn test_bah_commit_function() { reset_test_state(); let container = "my-container"; let image_name = "my-image:latest"; let result = test_bah_commit(container, image_name); assert!(result.is_ok()); let cmd = get_last_command(); assert_eq!(cmd, vec!["commit", "my-container", "my-image:latest"]); } #[test] fn test_bah_remove_function() { reset_test_state(); let container = "my-container"; let result = test_bah_remove(container); assert!(result.is_ok()); let cmd = get_last_command(); assert_eq!(cmd, vec!["rm", "my-container"]); } #[test] fn test_bah_list_function() { reset_test_state(); let result = test_bah_list(); assert!(result.is_ok()); let cmd = get_last_command(); assert_eq!(cmd, vec!["containers"]); } #[test] fn test_bah_build_function() { reset_test_state(); // Test with tag, context directory, file, and no isolation let result = test_bah_build(Some("my-app:latest"), ".", "Dockerfile", None); assert!(result.is_ok()); let cmd = get_last_command(); assert_eq!(cmd, vec!["build", "-t", "my-app:latest", "-f", "Dockerfile", "."]); // Test with tag, context directory, file, and isolation let result = test_bah_build(Some("my-app:latest"), ".", "Dockerfile.custom", Some("chroot")); assert!(result.is_ok()); let cmd = get_last_command(); assert_eq!(cmd, vec!["build", "-t", "my-app:latest", "--isolation", "chroot", "-f", "Dockerfile.custom", "."]); // Test with just context directory and file let result = test_bah_build(None, ".", "Dockerfile", None); assert!(result.is_ok()); let cmd = get_last_command(); assert_eq!(cmd, vec!["build", "-f", "Dockerfile", "."]); } #[test] fn test_error_handling() { reset_test_state(); set_should_fail(true); let image = "alpine:latest"; let result = test_from(image); assert!(result.is_err()); match result { Err(BuildahError::CommandFailed(msg)) => { assert_eq!(msg, "Command failed"); }, _ => panic!("Expected CommandFailed error"), } } }