diff --git a/examples/buildah.rs b/examples/buildah.rs index f26fb39..344c64a 100644 --- a/examples/buildah.rs +++ b/examples/buildah.rs @@ -19,50 +19,51 @@ pub fn run_buildah_example() -> Result<(), BuildahError> { // Step 2: Run a command in the container println!("\n=== Installing nginx in container ==="); - let install_result = buildah::run(container_id, "dnf install -y nginx")?; + let install_result = buildah::run(container_id, "dnf install -y nginx").unwrap(); + println!("{:#?}", install_result); println!("Installation output: {}", install_result.stdout); - // Step 3: Copy a file into the container - println!("\n=== Copying configuration file to container ==="); - // Note: This would require an actual file to exist - // buildah::copy(container_id, "./nginx.conf", "/etc/nginx/nginx.conf")?; - println!("For a real example, you would copy a configuration file here"); + // // Step 3: Copy a file into the container + // println!("\n=== Copying configuration file to container ==="); + // // Note: This would require an actual file to exist + // buildah::copy(container_id, "./example.conf", "/etc/example.conf")?; + // println!("For a real example, you would copy a configuration file here"); - // Step 4: Configure container metadata - println!("\n=== Configuring container metadata ==="); - let mut config_options = HashMap::new(); - config_options.insert("port".to_string(), "80".to_string()); - config_options.insert("label".to_string(), "maintainer=example@example.com".to_string()); - config_options.insert("entrypoint".to_string(), "/usr/sbin/nginx".to_string()); + // // Step 4: Configure container metadata + // println!("\n=== Configuring container metadata ==="); + // let mut config_options = HashMap::new(); + // config_options.insert("port".to_string(), "80".to_string()); + // config_options.insert("label".to_string(), "maintainer=example@example.com".to_string()); + // config_options.insert("entrypoint".to_string(), "/usr/sbin/nginx".to_string()); - buildah::config(container_id, config_options)?; - println!("Container configured"); + // buildah::config(container_id, config_options)?; + // println!("Container configured"); - // Step 5: Commit the container to create a new image - println!("\n=== Committing container to create image ==="); - let image_name = "my-nginx:latest"; - buildah::image_commit(container_id, image_name, Some("docker"), true, true)?; - println!("Created image: {}", image_name); + // // Step 5: Commit the container to create a new image + // println!("\n=== Committing container to create image ==="); + // let image_name = "my-nginx:latest"; + // buildah::image_commit(container_id, image_name, Some("docker"), true, true)?; + // println!("Created image: {}", image_name); - // Step 6: List images to verify our new image exists - println!("\n=== Listing images ==="); - let images = buildah::images()?; - println!("Found {} images:", images.len()); - for image in images { - println!(" ID: {}", image.id); - println!(" Names: {}", image.names.join(", ")); - println!(" Size: {}", image.size); - println!(" Created: {}", image.created); - println!(); - } + // // Step 6: List images to verify our new image exists + // println!("\n=== Listing images ==="); + // let images = buildah::images()?; + // println!("Found {} images:", images.len()); + // for image in images { + // println!(" ID: {}", image.id); + // println!(" Names: {}", image.names.join(", ")); + // println!(" Size: {}", image.size); + // println!(" Created: {}", image.created); + // println!(); + // } - // Step 7: Clean up (optional in a real workflow) - println!("\n=== Cleaning up ==="); - println!("In a real workflow, you might want to keep the image"); - println!("To remove the image, you would run:"); - println!("buildah::image_remove(\"{}\")", image_name); + // // Step 7: Clean up (optional in a real workflow) + // println!("\n=== Cleaning up ==="); + // println!("In a real workflow, you might want to keep the image"); + // println!("To remove the image, you would run:"); + // println!("buildah::image_remove(\"{}\")", image_name); - println!("\nBuildah example workflow completed successfully!"); + // println!("\nBuildah example workflow completed successfully!"); Ok(()) } diff --git a/src/virt/buildah/containers_test.rs b/src/virt/buildah/containers_test.rs new file mode 100644 index 0000000..6b89fc2 --- /dev/null +++ b/src/virt/buildah/containers_test.rs @@ -0,0 +1,197 @@ +#[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_copy(container: &str, source: &str, dest: &str) -> Result { + test_execute_buildah_command(&["copy", container, source, dest]) + } + + fn test_add(container: &str, source: &str, dest: &str) -> Result { + test_execute_buildah_command(&["add", container, source, dest]) + } + + fn test_commit(container: &str, image_name: &str) -> Result { + test_execute_buildah_command(&["commit", container, image_name]) + } + + fn test_remove(container: &str) -> Result { + test_execute_buildah_command(&["rm", container]) + } + + fn test_list() -> Result { + test_execute_buildah_command(&["containers"]) + } + + // 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"; + 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_copy_function() { + reset_test_state(); + + let container = "my-container"; + let source = "/local/path"; + let dest = "/container/path"; + let result = test_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_add_function() { + reset_test_state(); + + let container = "my-container"; + let source = "/local/path"; + let dest = "/container/path"; + let result = test_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_commit_function() { + reset_test_state(); + + let container = "my-container"; + let image_name = "my-image:latest"; + let result = test_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_remove_function() { + reset_test_state(); + + let container = "my-container"; + let result = test_remove(container); + + assert!(result.is_ok()); + let cmd = get_last_command(); + assert_eq!(cmd, vec!["rm", "my-container"]); + } + + #[test] + fn test_list_function() { + reset_test_state(); + + let result = test_list(); + + assert!(result.is_ok()); + let cmd = get_last_command(); + assert_eq!(cmd, vec!["containers"]); + } + + #[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"), + } + } +} \ No newline at end of file diff --git a/src/virt/buildah/mod.rs b/src/virt/buildah/mod.rs index fb59361..11df9ae 100644 --- a/src/virt/buildah/mod.rs +++ b/src/virt/buildah/mod.rs @@ -1,6 +1,8 @@ mod containers; mod images; mod cmd; +#[cfg(test)] +mod containers_test; use std::fmt; use std::error::Error;