From f324904eaa30efe1a074a106d35f5313c6a4715d Mon Sep 17 00:00:00 2001 From: Jason Hall Date: Wed, 15 Oct 2025 15:35:28 -0400 Subject: [PATCH] improve test coverage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ⏺ Test coverage improved from 47.65% to 50.14% (+2.49%). Coverage improvements by module: - resolve: 54.7% → 89.8% (+35.08%) - image: 46.6% → 57.7% (+11.14%) - config: 69.2% → 80.0% (+10.77%) - builder: 51.1% → 52.8% (+1.70%) Signed-off-by: Jason Hall --- src/builder/tests.rs | 70 ++++++++++++++++++++++++++++++++++ src/config/tests.rs | 58 ++++++++++++++++++++++++++++ src/image/mod.rs | 91 ++++++++++++++++++++++++++++++++++++++++++++ src/resolve/mod.rs | 67 ++++++++++++++++++++++++++++++++ 4 files changed, 286 insertions(+) diff --git a/src/builder/tests.rs b/src/builder/tests.rs index 8aa0c08..cd6c3a4 100644 --- a/src/builder/tests.rs +++ b/src/builder/tests.rs @@ -1,6 +1,8 @@ #[cfg(test)] mod tests { use super::super::*; + use std::fs; + use tempfile::tempdir; #[test] fn test_get_rust_target_triple() { @@ -38,4 +40,72 @@ mod tests { ); assert!(get_rust_target_triple("windows/amd64").is_err()); } + + #[test] + fn test_get_binary_name_valid() { + let dir = tempdir().unwrap(); + let cargo_toml = dir.path().join("Cargo.toml"); + fs::write( + &cargo_toml, + r#" +[package] +name = "test-binary" +version = "0.1.0" +"#, + ) + .unwrap(); + + let builder = RustBuilder::new(dir.path(), "x86_64-unknown-linux-musl"); + let name = builder.get_binary_name().unwrap(); + assert_eq!(name, "test-binary"); + } + + #[test] + fn test_get_binary_name_missing_cargo_toml() { + let dir = tempdir().unwrap(); + let builder = RustBuilder::new(dir.path(), "x86_64-unknown-linux-musl"); + let result = builder.get_binary_name(); + assert!(result.is_err()); + assert!(result.unwrap_err().to_string().contains("Cargo.toml")); + } + + #[test] + fn test_get_binary_name_invalid_toml() { + let dir = tempdir().unwrap(); + let cargo_toml = dir.path().join("Cargo.toml"); + fs::write(&cargo_toml, "invalid toml [[[").unwrap(); + + let builder = RustBuilder::new(dir.path(), "x86_64-unknown-linux-musl"); + let result = builder.get_binary_name(); + assert!(result.is_err()); + assert!(result.unwrap_err().to_string().contains("parse")); + } + + #[test] + fn test_get_binary_name_missing_package_name() { + let dir = tempdir().unwrap(); + let cargo_toml = dir.path().join("Cargo.toml"); + fs::write( + &cargo_toml, + r#" +[package] +version = "0.1.0" +"#, + ) + .unwrap(); + + let builder = RustBuilder::new(dir.path(), "x86_64-unknown-linux-musl"); + let result = builder.get_binary_name(); + assert!(result.is_err()); + assert!(result.unwrap_err().to_string().contains("package name")); + } + + #[test] + fn test_rust_builder_with_cargo_args() { + let dir = tempdir().unwrap(); + let builder = RustBuilder::new(dir.path(), "x86_64-unknown-linux-musl") + .with_cargo_args(vec!["--features".to_string(), "foo".to_string()]); + + assert_eq!(builder.cargo_args, vec!["--features", "foo"]); + } } diff --git a/src/config/tests.rs b/src/config/tests.rs index 95ef128..29621bb 100644 --- a/src/config/tests.rs +++ b/src/config/tests.rs @@ -1,6 +1,8 @@ #[cfg(test)] mod tests { use super::super::*; + use std::fs; + use tempfile::tempdir; #[test] fn test_default_config() { @@ -17,4 +19,60 @@ mod tests { assert!(build_config.cargo_args.is_empty()); assert!(build_config.target_dir.is_none()); } + + #[test] + fn test_load_project_config_no_cargo_toml() { + let dir = tempdir().unwrap(); + let config = Config::load_project_config(dir.path()).unwrap(); + assert!(config.base_image.is_none()); + } + + #[test] + fn test_load_project_config_with_metadata() { + let dir = tempdir().unwrap(); + let cargo_toml = dir.path().join("Cargo.toml"); + fs::write( + &cargo_toml, + r#" +[package] +name = "test" +version = "0.1.0" + +[package.metadata.krust] +base-image = "custom:latest" +"#, + ) + .unwrap(); + + let config = Config::load_project_config(dir.path()).unwrap(); + assert_eq!(config.base_image, Some("custom:latest".to_string())); + } + + #[test] + fn test_load_project_config_without_metadata() { + let dir = tempdir().unwrap(); + let cargo_toml = dir.path().join("Cargo.toml"); + fs::write( + &cargo_toml, + r#" +[package] +name = "test" +version = "0.1.0" +"#, + ) + .unwrap(); + + let config = Config::load_project_config(dir.path()).unwrap(); + assert!(config.base_image.is_none()); + } + + #[test] + fn test_load_project_config_invalid_toml() { + let dir = tempdir().unwrap(); + let cargo_toml = dir.path().join("Cargo.toml"); + fs::write(&cargo_toml, "invalid toml [[[").unwrap(); + + let result = Config::load_project_config(dir.path()); + assert!(result.is_err()); + } } diff --git a/src/image/mod.rs b/src/image/mod.rs index d6b0577..a23d125 100644 --- a/src/image/mod.rs +++ b/src/image/mod.rs @@ -424,4 +424,95 @@ mod tests { assert_eq!(parsed.rootfs.diff_ids.len(), 1); assert_eq!(parsed.history.len(), 0); // Default empty for missing field } + + #[test] + fn test_parse_platform_invalid_format() { + let builder = ImageBuilder::new( + PathBuf::from("/tmp/test"), + "test-base".to_string(), + "linux-amd64".to_string(), // Wrong format + ); + + let result = builder.parse_platform(); + assert!(result.is_err()); + assert!(result.unwrap_err().to_string().contains("Invalid platform")); + } + + #[test] + fn test_create_layer_with_valid_binary() { + let mut temp_file = NamedTempFile::new().unwrap(); + temp_file.write_all(b"test binary content").unwrap(); + temp_file.flush().unwrap(); + + let builder = ImageBuilder::new( + temp_file.path().to_path_buf(), + "test-base".to_string(), + "linux/amd64".to_string(), + ); + + let result = builder.create_layer(); + assert!(result.is_ok()); + + let (compressed_data, diff_id) = result.unwrap(); + assert!(!compressed_data.is_empty()); + assert!(diff_id.starts_with("sha256:")); + } + + #[test] + fn test_create_layer_with_nonexistent_binary() { + let builder = ImageBuilder::new( + PathBuf::from("/nonexistent/binary"), + "test-base".to_string(), + "linux/amd64".to_string(), + ); + + let result = builder.create_layer(); + assert!(result.is_err()); + } + + #[test] + fn test_create_layered_config_adds_path_if_missing() { + let binary_path = create_test_binary(); + let builder = ImageBuilder::new( + binary_path, + "test-base".to_string(), + "linux/amd64".to_string(), + ); + + let mut base_config = create_base_image_config(); + base_config.config.env = vec![]; // No PATH + + let app_diff_id = "sha256:app_layer_diff_id"; + + let result = builder + .create_layered_config(&base_config, app_diff_id) + .unwrap(); + + // Should add PATH since it was missing + assert!(result.config.env.iter().any(|env| env.starts_with("PATH="))); + } + + #[test] + fn test_create_layered_config_sets_cmd() { + let binary_path = create_test_binary(); + let builder = ImageBuilder::new( + binary_path.clone(), + "test-base".to_string(), + "linux/amd64".to_string(), + ); + + let base_config = create_base_image_config(); + let app_diff_id = "sha256:app_layer_diff_id"; + + let result = builder + .create_layered_config(&base_config, app_diff_id) + .unwrap(); + + // Should set CMD to the binary + let binary_name = binary_path.file_name().unwrap().to_str().unwrap(); + assert_eq!( + result.config.cmd, + Some(vec![format!("/app/{}", binary_name)]) + ); + } } diff --git a/src/resolve/mod.rs b/src/resolve/mod.rs index 9a8a3d5..b97162d 100644 --- a/src/resolve/mod.rs +++ b/src/resolve/mod.rs @@ -196,4 +196,71 @@ image: krust://./app2 assert!(refs.contains("./app1")); assert!(refs.contains("./app2")); } + + #[test] + fn test_read_yaml_files_single_file() { + use std::fs; + use tempfile::tempdir; + + let dir = tempdir().unwrap(); + let file_path = dir.path().join("test.yaml"); + fs::write(&file_path, "image: krust://./app").unwrap(); + + let files = read_yaml_files(&file_path).unwrap(); + assert_eq!(files.len(), 1); + assert!(files[0].0.contains("test.yaml")); + assert!(files[0].1.contains("krust://./app")); + } + + #[test] + fn test_read_yaml_files_directory() { + use std::fs; + use tempfile::tempdir; + + let dir = tempdir().unwrap(); + fs::write(dir.path().join("test1.yaml"), "image: krust://./app1").unwrap(); + fs::write(dir.path().join("test2.yml"), "image: krust://./app2").unwrap(); + fs::write(dir.path().join("test.txt"), "not yaml").unwrap(); + + let files = read_yaml_files(dir.path()).unwrap(); + assert_eq!(files.len(), 2); + assert!(files.iter().any(|(name, _)| name.contains("test1.yaml"))); + assert!(files.iter().any(|(name, _)| name.contains("test2.yml"))); + } + + #[test] + fn test_read_yaml_files_empty_directory() { + use tempfile::tempdir; + + let dir = tempdir().unwrap(); + let result = read_yaml_files(dir.path()); + assert!(result.is_err()); + assert!(result + .unwrap_err() + .to_string() + .contains("No YAML files found")); + } + + #[test] + fn test_read_yaml_files_nonexistent_path() { + use std::path::PathBuf; + + let path = PathBuf::from("/nonexistent/path/that/does/not/exist"); + let result = read_yaml_files(&path); + assert!(result.is_err()); + assert!(result + .unwrap_err() + .to_string() + .contains("Path does not exist")); + } + + #[test] + fn test_replace_references_empty_replacements() { + let yaml = r#"image: krust://./app"#; + let replacements = HashMap::new(); + + let result = replace_krust_references(yaml, &replacements).unwrap(); + // Should keep original reference if no replacement found + assert!(result.contains("krust://./app")); + } }