#!/usr/bin/env python3 """ Test case definitions for deb-bootc-image-builder. This module defines test cases and test data for various scenarios, including: - Basic functionality tests - Edge case tests - Error condition tests - Debian-specific test cases """ import pytest import os import tempfile import shutil import json import yaml from typing import Dict, List, Any, Optional import logging # Configure logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) class TestCaseDefinitions: """Test case definitions for deb-bootc-image-builder.""" @staticmethod def get_basic_functionality_tests() -> List[Dict[str, Any]]: """Get basic functionality test cases.""" return [ { "name": "basic_debian_image_build", "description": "Test basic Debian image building functionality", "container": "debian:trixie", "release": "trixie", "arch": "amd64", "image_type": "qcow2", "packages": ["linux-image-amd64", "systemd", "ostree"], "expected_result": "success" }, { "name": "debian_with_custom_packages", "description": "Test Debian image building with custom packages", "container": "debian:bookworm", "release": "bookworm", "arch": "amd64", "image_type": "qcow2", "packages": [ "linux-image-amd64", "systemd", "ostree", "grub-efi-amd64", "initramfs-tools", "sudo", "network-manager" ], "expected_result": "success" }, { "name": "debian_arm64_build", "description": "Test Debian ARM64 image building", "container": "debian:trixie", "release": "trixie", "arch": "arm64", "image_type": "qcow2", "packages": ["linux-image-arm64", "systemd", "ostree"], "expected_result": "success" } ] @staticmethod def get_edge_case_tests() -> List[Dict[str, Any]]: """Get edge case test cases.""" return [ { "name": "empty_package_list", "description": "Test building with empty package list", "container": "debian:trixie", "release": "trixie", "arch": "amd64", "image_type": "qcow2", "packages": [], "expected_result": "error", "expected_error": "No packages specified" }, { "name": "invalid_release", "description": "Test building with invalid Debian release", "container": "debian:trixie", "release": "invalid-release", "arch": "amd64", "image_type": "qcow2", "packages": ["linux-image-amd64"], "expected_result": "error", "expected_error": "Invalid Debian release" }, { "name": "invalid_architecture", "description": "Test building with invalid architecture", "container": "debian:trixie", "release": "trixie", "arch": "invalid-arch", "image_type": "qcow2", "packages": ["linux-image-amd64"], "expected_result": "error", "expected_error": "Invalid architecture" }, { "name": "very_long_package_list", "description": "Test building with very long package list", "container": "debian:trixie", "release": "trixie", "arch": "amd64", "image_type": "qcow2", "packages": [f"package-{i}" for i in range(1000)], "expected_result": "success" } ] @staticmethod def get_error_condition_tests() -> List[Dict[str, Any]]: """Get error condition test cases.""" return [ { "name": "invalid_container_image", "description": "Test building with invalid container image", "container": "invalid:image", "release": "trixie", "arch": "amd64", "image_type": "qcow2", "packages": ["linux-image-amd64"], "expected_result": "error", "expected_error": "Invalid container image" }, { "name": "network_failure", "description": "Test building with network failure simulation", "container": "debian:trixie", "release": "trixie", "arch": "amd64", "image_type": "qcow2", "packages": ["linux-image-amd64"], "expected_result": "error", "expected_error": "Network error", "simulate_network_failure": True }, { "name": "disk_space_exhaustion", "description": "Test building with disk space exhaustion", "container": "debian:trixie", "release": "trixie", "arch": "amd64", "image_type": "qcow2", "packages": ["linux-image-amd64"], "expected_result": "error", "expected_error": "Disk space exhausted", "simulate_disk_full": True } ] @staticmethod def get_debian_specific_tests() -> List[Dict[str, Any]]: """Get Debian-specific test cases.""" return [ { "name": "debian_trixie_minimal", "description": "Test Debian Trixie minimal image", "container": "debian:trixie", "release": "trixie", "arch": "amd64", "image_type": "qcow2", "packages": [ "linux-image-amd64", "systemd", "ostree", "grub-efi-amd64", "initramfs-tools" ], "debian_specific": { "initramfs_tools": True, "grub_efi": True, "ostree_integration": True }, "expected_result": "success" }, { "name": "debian_bookworm_desktop", "description": "Test Debian Bookworm desktop image", "container": "debian:bookworm", "release": "bookworm", "arch": "amd64", "image_type": "qcow2", "packages": [ "linux-image-amd64", "systemd", "ostree", "grub-efi-amd64", "initramfs-tools", "task-desktop", "xorg", "lightdm" ], "debian_specific": { "initramfs_tools": True, "grub_efi": True, "ostree_integration": True, "desktop_environment": True }, "expected_result": "success" }, { "name": "debian_bullseye_server", "description": "Test Debian Bullseye server image", "container": "debian:bullseye", "release": "bullseye", "arch": "amd64", "image_type": "qcow2", "packages": [ "linux-image-amd64", "systemd", "ostree", "grub-efi-amd64", "initramfs-tools", "openssh-server", "nginx", "postgresql" ], "debian_specific": { "initramfs_tools": True, "grub_efi": True, "ostree_integration": True, "server_services": True }, "expected_result": "success" } ] @staticmethod def get_performance_tests() -> List[Dict[str, Any]]: """Get performance test cases.""" return [ { "name": "small_image_build_time", "description": "Test build time for small image", "container": "debian:trixie", "release": "trixie", "arch": "amd64", "image_type": "qcow2", "packages": ["linux-image-amd64", "systemd"], "performance_requirements": { "max_build_time": 300, # 5 minutes "max_image_size": 1024 # 1GB }, "expected_result": "success" }, { "name": "large_image_build_time", "description": "Test build time for large image", "container": "debian:trixie", "release": "trixie", "arch": "amd64", "image_type": "qcow2", "packages": [f"package-{i}" for i in range(500)], "performance_requirements": { "max_build_time": 1800, # 30 minutes "max_image_size": 10240 # 10GB }, "expected_result": "success" } ] @staticmethod def get_integration_tests() -> List[Dict[str, Any]]: """Get integration test cases.""" return [ { "name": "full_pipeline_test", "description": "Test complete image building pipeline", "container": "debian:trixie", "release": "trixie", "arch": "amd64", "image_type": "qcow2", "packages": [ "linux-image-amd64", "systemd", "ostree", "grub-efi-amd64", "initramfs-tools" ], "pipeline_stages": [ "filesystem_setup", "package_installation", "ostree_integration", "bootloader_configuration", "image_generation" ], "expected_result": "success" }, { "name": "cross_architecture_test", "description": "Test cross-architecture building", "container": "debian:trixie", "release": "trixie", "architectures": ["amd64", "arm64"], "image_type": "qcow2", "packages": ["linux-image-amd64", "systemd", "ostree"], "expected_result": "success" } ] class TestDataGenerator: """Generate test data for various test scenarios.""" @staticmethod def generate_manifest(test_case: Dict[str, Any]) -> Dict[str, Any]: """Generate a manifest from a test case.""" manifest = { "pipeline": { "build": { "name": "org.osbuild.debian-filesystem", "options": { "rootfs_type": "ext4", "ostree_integration": True, "home_symlink": True } }, "stages": [ { "name": "org.osbuild.apt", "options": { "packages": test_case.get("packages", []), "release": test_case.get("release", "trixie"), "arch": test_case.get("arch", "amd64") } } ] } } # Add Debian-specific stages if specified if test_case.get("debian_specific", {}).get("grub_efi"): manifest["pipeline"]["stages"].append({ "name": "org.osbuild.debian-grub", "options": { "uefi": True, "secure_boot": False, "timeout": 5 } }) if test_case.get("debian_specific", {}).get("initramfs_tools"): manifest["pipeline"]["stages"].append({ "name": "org.osbuild.debian-kernel", "options": { "kernel_package": f"linux-image-{test_case.get('arch', 'amd64')}", "initramfs_tools": True, "ostree_integration": True } }) return manifest @staticmethod def generate_test_environment(test_case: Dict[str, Any]) -> Dict[str, Any]: """Generate test environment configuration.""" return { "work_dir": "/tmp/test-env", "output_dir": "/tmp/test-output", "cache_dir": "/tmp/test-cache", "temp_dir": "/tmp/test-temp", "network_enabled": not test_case.get("simulate_network_failure", False), "disk_space_available": not test_case.get("simulate_disk_full", False) } @staticmethod def generate_expected_output(test_case: Dict[str, Any]) -> Dict[str, Any]: """Generate expected output for a test case.""" expected_output = { "status": test_case.get("expected_result", "success"), "image_type": test_case.get("image_type", "qcow2"), "architecture": test_case.get("arch", "amd64"), "release": test_case.get("release", "trixie") } if test_case.get("expected_result") == "success": expected_output["image_path"] = f"/tmp/test-output/debian-{test_case.get('release')}-{test_case.get('arch')}.{test_case.get('image_type')}" expected_output["build_log"] = "Build completed successfully" else: expected_output["error"] = test_case.get("expected_error", "Unknown error") expected_output["build_log"] = f"Build failed: {test_case.get('expected_error', 'Unknown error')}" return expected_output def load_test_cases_from_file(file_path: str) -> List[Dict[str, Any]]: """Load test cases from a file.""" try: with open(file_path, 'r') as f: if file_path.endswith('.json'): return json.load(f) elif file_path.endswith('.yaml') or file_path.endswith('.yml'): return yaml.safe_load(f) else: raise ValueError(f"Unsupported file format: {file_path}") except Exception as e: logger.error(f"Failed to load test cases from {file_path}: {e}") return [] def save_test_cases_to_file(test_cases: List[Dict[str, Any]], file_path: str) -> bool: """Save test cases to a file.""" try: with open(file_path, 'w') as f: if file_path.endswith('.json'): json.dump(test_cases, f, indent=2) elif file_path.endswith('.yaml') or file_path.endswith('.yml'): yaml.dump(test_cases, f, default_flow_style=False) else: raise ValueError(f"Unsupported file format: {file_path}") return True except Exception as e: logger.error(f"Failed to save test cases to {file_path}: {e}") return False def validate_test_case(test_case: Dict[str, Any]) -> Dict[str, Any]: """Validate a test case definition.""" validation_result = { "valid": True, "errors": [], "warnings": [] } # Check required fields required_fields = ["name", "description", "container", "release", "arch", "image_type", "packages"] for field in required_fields: if field not in test_case: validation_result["valid"] = False validation_result["errors"].append(f"Missing required field: {field}") # Check field types if "packages" in test_case and not isinstance(test_case["packages"], list): validation_result["valid"] = False validation_result["errors"].append("Packages field must be a list") if "arch" in test_case and test_case["arch"] not in ["amd64", "arm64", "i386"]: validation_result["warnings"].append(f"Unsupported architecture: {test_case['arch']}") if "release" in test_case and test_case["release"] not in ["trixie", "bookworm", "bullseye"]: validation_result["warnings"].append(f"Unsupported Debian release: {test_case['release']}") return validation_result if __name__ == "__main__": # Test the test case definitions test_cases = TestCaseDefinitions.get_basic_functionality_tests() print(f"Generated {len(test_cases)} basic functionality test cases") for test_case in test_cases: manifest = TestDataGenerator.generate_manifest(test_case) print(f"Generated manifest for {test_case['name']}: {len(manifest['pipeline']['stages'])} stages") validation = validate_test_case(test_case) print(f"Validation for {test_case['name']}: {'Valid' if validation['valid'] else 'Invalid'}") if validation['errors']: print(f" Errors: {validation['errors']}") if validation['warnings']: print(f" Warnings: {validation['warnings']}")