#!/usr/bin/env python3 """ Test cross-architecture building for deb-bootc-image-builder. This module tests cross-architecture image building, including: - Cross-arch manifest validation - Multi-architecture package handling - Cross-arch image generation """ 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 TestCrossArchitectureBuilding: """Test cases for cross-architecture building functionality.""" def test_cross_arch_manifest_validation(self, work_dir): """Test cross-architecture manifest validation.""" # Create a test cross-arch manifest manifest = { "pipeline": { "build": { "name": "org.osbuild.debian-filesystem", "options": { "rootfs_type": "ext4", "ostree_integration": True } }, "stages": [ { "name": "org.osbuild.apt", "options": { "packages": ["linux-image-amd64", "systemd"], "release": "trixie", "arch": "amd64" } } ] }, "target_architectures": ["amd64", "arm64"] } # Validate manifest structure assert "pipeline" in manifest assert "target_architectures" in manifest # Validate target architectures target_archs = manifest["target_architectures"] assert "amd64" in target_archs assert "arm64" in target_archs assert len(target_archs) == 2 def test_multi_arch_package_handling(self, work_dir): """Test multi-architecture package handling.""" # Test package lists for different architectures amd64_packages = ["linux-image-amd64", "grub-efi-amd64"] arm64_packages = ["linux-image-arm64", "grub-efi-arm64"] # Validate package architecture specificity for pkg in amd64_packages: assert "amd64" in pkg, f"Package {pkg} should be amd64 specific" for pkg in arm64_packages: assert "arm64" in pkg, f"Package {pkg} should be arm64 specific" # Test package installation for different architectures amd64_result = self._install_arch_packages(amd64_packages, "amd64", work_dir) arm64_result = self._install_arch_packages(arm64_packages, "arm64", work_dir) assert amd64_result is True assert arm64_result is True def test_cross_arch_filesystem_creation(self, work_dir): """Test cross-architecture filesystem creation.""" # Test filesystem structure for different architectures for arch in ["amd64", "arm64"]: fs_structure = self._create_arch_filesystem(work_dir, arch) expected_dirs = ["/etc", "/var", "/home", "/boot", "/usr"] for expected_dir in expected_dirs: full_path = os.path.join(work_dir, arch, expected_dir.lstrip("/")) assert os.path.exists(full_path), f"Directory {expected_dir} not created for {arch}" # Test architecture-specific paths arch_specific_path = os.path.join(work_dir, arch, "usr", "lib", arch) assert os.path.exists(arch_specific_path), f"Architecture-specific path not created for {arch}" def test_cross_arch_bootloader_configuration(self, work_dir): """Test cross-architecture bootloader configuration.""" # Test GRUB configuration for different architectures for arch in ["amd64", "arm64"]: grub_config = self._configure_arch_grub(work_dir, arch) assert "GRUB_DEFAULT" in grub_config assert "GRUB_TIMEOUT" in grub_config assert "GRUB_CMDLINE_LINUX" in grub_config # Test architecture-specific boot options if arch == "amd64": assert "efi" in grub_config["GRUB_CMDLINE_LINUX"] elif arch == "arm64": assert "arm64" in grub_config["GRUB_CMDLINE_LINUX"] def test_cross_arch_image_generation(self, work_dir): """Test cross-architecture image generation.""" # Test image generation for different architectures for arch in ["amd64", "arm64"]: image_result = self._generate_arch_image(work_dir, arch) assert image_result["status"] == "success" assert image_result["architecture"] == arch assert "image_path" in image_result assert os.path.exists(image_result["image_path"]) # Test image properties image_props = self._get_image_properties(image_result["image_path"]) assert image_props["architecture"] == arch assert image_props["size"] > 0 def test_cross_arch_dependency_resolution(self, work_dir): """Test cross-architecture dependency resolution.""" # Test dependency resolution for different architectures for arch in ["amd64", "arm64"]: deps = self._resolve_arch_dependencies(arch, work_dir) assert "packages" in deps assert "repositories" in deps # Validate architecture-specific dependencies packages = deps["packages"] for pkg in packages: if arch in pkg: assert pkg.endswith(arch), f"Package {pkg} should end with {arch}" def _install_arch_packages(self, packages, arch, work_dir): """Mock architecture-specific package installation.""" logger.info(f"Installing {arch} packages: {packages}") return True def _create_arch_filesystem(self, work_dir, arch): """Create architecture-specific filesystem structure.""" arch_dir = os.path.join(work_dir, arch) dirs = [ "etc", "var", "home", "boot", "usr", "usr/bin", "usr/lib", "usr/sbin", f"usr/lib/{arch}" ] for dir_path in dirs: full_path = os.path.join(arch_dir, dir_path) os.makedirs(full_path, exist_ok=True) # Create /home -> /var/home symlink var_home = os.path.join(arch_dir, "var", "home") os.makedirs(var_home, exist_ok=True) home_link = os.path.join(arch_dir, "home") if os.path.exists(home_link): os.remove(home_link) os.symlink(var_home, home_link) return {"status": "created", "architecture": arch, "directories": dirs} def _configure_arch_grub(self, work_dir, arch): """Configure GRUB for specific architecture.""" arch_dir = os.path.join(work_dir, arch) if arch == "amd64": grub_config = { "GRUB_DEFAULT": "0", "GRUB_TIMEOUT": "5", "GRUB_CMDLINE_LINUX": "console=ttyS0,115200n8 console=tty0 efi" } elif arch == "arm64": grub_config = { "GRUB_DEFAULT": "0", "GRUB_TIMEOUT": "5", "GRUB_CMDLINE_LINUX": "console=ttyAMA0,115200 console=tty0 arm64" } else: grub_config = { "GRUB_DEFAULT": "0", "GRUB_TIMEOUT": "5", "GRUB_CMDLINE_LINUX": "console=tty0" } # Write GRUB configuration grub_dir = os.path.join(arch_dir, "etc", "default") os.makedirs(grub_dir, exist_ok=True) grub_file = os.path.join(grub_dir, "grub") with open(grub_file, 'w') as f: for key, value in grub_config.items(): f.write(f'{key}="{value}"\n') return grub_config def _generate_arch_image(self, work_dir, arch): """Mock architecture-specific image generation.""" arch_dir = os.path.join(work_dir, arch) image_path = os.path.join(arch_dir, f"debian-trixie-{arch}.img") # Create a dummy image file with open(image_path, 'wb') as f: f.write(f"Debian {arch} image content".encode()) return { "status": "success", "architecture": arch, "image_path": image_path, "size": os.path.getsize(image_path) } def _get_image_properties(self, image_path): """Get image properties.""" return { "architecture": image_path.split("-")[-1].replace(".img", ""), "size": os.path.getsize(image_path), "path": image_path } def _resolve_arch_dependencies(self, arch, work_dir): """Mock architecture-specific dependency resolution.""" if arch == "amd64": packages = ["linux-image-amd64", "grub-efi-amd64", "initramfs-tools"] repositories = ["debian", "debian-security"] elif arch == "arm64": packages = ["linux-image-arm64", "grub-efi-arm64", "initramfs-tools"] repositories = ["debian", "debian-security"] else: packages = ["linux-image-generic", "grub-efi", "initramfs-tools"] repositories = ["debian", "debian-security"] return { "packages": packages, "repositories": repositories, "architecture": arch } if __name__ == "__main__": pytest.main([__file__])