#!/usr/bin/env python3 """ Test command line options for deb-bootc-image-builder. This module tests command line argument parsing and validation, including: - Required arguments - Optional arguments - Argument validation - Debian-specific options """ import pytest import os import tempfile import shutil import json from unittest.mock import Mock, patch import logging # Configure logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) class TestCommandLineOptions: """Test cases for command line options.""" def test_required_arguments(self, work_dir): """Test required command line arguments.""" # Test minimum required arguments required_args = { "container": "debian:trixie", "output": work_dir } # Validate required arguments for arg_name, arg_value in required_args.items(): assert arg_value is not None, f"Required argument {arg_name} is None" if arg_name == "output": assert os.path.exists(arg_value), f"Output directory {arg_value} does not exist" def test_optional_arguments(self, work_dir): """Test optional command line arguments.""" # Test optional arguments with default values optional_args = { "release": "trixie", "arch": "amd64", "image_type": "qcow2", "verbose": False, "clean": False } # Validate optional arguments for arg_name, arg_value in optional_args.items(): assert arg_name in optional_args, f"Optional argument {arg_name} not found" assert arg_value is not None, f"Optional argument {arg_name} has no default value" def test_debian_specific_options(self, work_dir): """Test Debian-specific command line options.""" # Test Debian-specific options debian_options = { "release": "trixie", "arch": "amd64", "package_manager": "apt", "initramfs_tools": True, "grub_efi": True } # Validate Debian-specific options assert debian_options["release"] in ["trixie", "bookworm", "bullseye"], \ f"Invalid Debian release: {debian_options['release']}" assert debian_options["arch"] in ["amd64", "arm64", "i386"], \ f"Invalid architecture: {debian_options['arch']}" assert debian_options["package_manager"] == "apt", \ f"Invalid package manager: {debian_options['package_manager']}" assert debian_options["initramfs_tools"] is True, \ "initramfs-tools should be enabled for Debian" assert debian_options["grub_efi"] is True, \ "GRUB EFI should be enabled for Debian" def test_argument_validation(self, work_dir): """Test argument validation logic.""" # Test valid arguments valid_args = { "container": "debian:trixie", "output": work_dir, "release": "trixie", "arch": "amd64" } validation_result = self._validate_arguments(valid_args) assert validation_result["valid"] is True, \ f"Valid arguments failed validation: {validation_result.get('error', 'Unknown error')}" # Test invalid arguments invalid_args = { "container": "invalid:image", "output": "/nonexistent/path", "release": "invalid-release", "arch": "invalid-arch" } validation_result = self._validate_arguments(invalid_args) assert validation_result["valid"] is False, \ "Invalid arguments should fail validation" def test_output_directory_handling(self, work_dir): """Test output directory handling.""" # Test existing directory existing_dir = work_dir result = self._handle_output_directory(existing_dir) assert result["success"] is True, \ f"Existing directory handling failed: {result.get('error', 'Unknown error')}" # Test non-existent directory creation new_dir = os.path.join(work_dir, "new_output") result = self._handle_output_directory(new_dir) assert result["success"] is True, \ f"New directory creation failed: {result.get('error', 'Unknown error')}" assert os.path.exists(new_dir), "New directory was not created" # Test invalid directory path invalid_dir = "/invalid/path/with/permissions/issue" result = self._handle_output_directory(invalid_dir) assert result["success"] is False, "Invalid directory should fail" def test_container_image_validation(self, work_dir): """Test container image validation.""" # Test valid Debian image valid_image = "debian:trixie" result = self._validate_container_image(valid_image) assert result["valid"] is True, \ f"Valid Debian image failed validation: {result.get('error', 'Unknown error')}" # Test invalid image invalid_image = "invalid:image" result = self._validate_container_image(invalid_image) assert result["valid"] is False, "Invalid image should fail validation" # Test image with specific architecture arch_image = "debian:trixie-amd64" result = self._validate_container_image(arch_image) assert result["valid"] is True, \ f"Architecture-specific image failed validation: {result.get('error', 'Unknown error')}" def test_package_list_validation(self, work_dir): """Test package list validation.""" # Test valid Debian packages valid_packages = [ "linux-image-amd64", "systemd", "ostree", "grub-efi-amd64", "initramfs-tools" ] result = self._validate_package_list(valid_packages) assert result["valid"] is True, \ f"Valid packages failed validation: {result.get('error', 'Unknown error')}" # Test invalid packages invalid_packages = [ "invalid-package", "nonexistent-package" ] result = self._validate_package_list(invalid_packages) assert result["valid"] is False, "Invalid packages should fail validation" def test_manifest_generation(self, work_dir): """Test manifest generation from command line options.""" # Test manifest generation options = { "container": "debian:trixie", "release": "trixie", "arch": "amd64", "image_type": "qcow2", "packages": ["linux-image-amd64", "systemd", "ostree"] } manifest = self._generate_manifest(options) # Validate generated manifest assert "pipeline" in manifest assert "build" in manifest["pipeline"] assert "stages" in manifest["pipeline"] # Validate Debian-specific content build_stage = manifest["pipeline"]["build"] assert build_stage["name"] == "org.osbuild.debian-filesystem" # Validate APT stage apt_stage = next((s for s in manifest["pipeline"]["stages"] if s["name"] == "org.osbuild.apt"), None) assert apt_stage is not None assert apt_stage["options"]["release"] == "trixie" assert apt_stage["options"]["arch"] == "amd64" def _validate_arguments(self, args): """Mock argument validation.""" # Check required arguments if "container" not in args or not args["container"]: return {"valid": False, "error": "Container image is required"} if "output" not in args or not args["output"]: return {"valid": False, "error": "Output directory is required"} # Check Debian-specific validation if "release" in args: valid_releases = ["trixie", "bookworm", "bullseye"] if args["release"] not in valid_releases: return {"valid": False, "error": f"Invalid Debian release: {args['release']}"} if "arch" in args: valid_archs = ["amd64", "arm64", "i386"] if args["arch"] not in valid_archs: return {"valid": False, "error": f"Invalid architecture: {args['arch']}"} return {"valid": True} def _handle_output_directory(self, output_dir): """Mock output directory handling.""" try: if not os.path.exists(output_dir): os.makedirs(output_dir, exist_ok=True) # Test if directory is writable test_file = os.path.join(output_dir, "test_write") with open(test_file, 'w') as f: f.write("test") os.remove(test_file) return {"success": True} except Exception as e: return {"success": False, "error": str(e)} def _validate_container_image(self, image): """Mock container image validation.""" # Check if it's a valid Debian image if image.startswith("debian:"): return {"valid": True, "type": "debian"} else: return {"valid": False, "error": "Not a valid Debian image"} def _validate_package_list(self, packages): """Mock package list validation.""" # Check if packages look like valid Debian packages valid_packages = [ "linux-image-amd64", "systemd", "ostree", "grub-efi-amd64", "initramfs-tools", "util-linux", "parted", "e2fsprogs" ] for pkg in packages: if pkg not in valid_packages: return {"valid": False, "error": f"Invalid package: {pkg}"} return {"valid": True} def _generate_manifest(self, options): """Mock manifest generation.""" return { "pipeline": { "build": { "name": "org.osbuild.debian-filesystem", "options": { "rootfs_type": "ext4", "ostree_integration": True } }, "stages": [ { "name": "org.osbuild.apt", "options": { "packages": options.get("packages", []), "release": options.get("release", "trixie"), "arch": options.get("arch", "amd64") } } ] } } if __name__ == "__main__": pytest.main([__file__])