#!/usr/bin/env python3 """ Real Debian Integration Tests This module contains integration tests that validate the Debian osbuild stages with actual Debian packages and real filesystem operations. Author: Debian bootc-image-builder team License: Same as original bootc-image-builder """ import unittest import tempfile import os import json import shutil import subprocess import time from unittest.mock import Mock, patch, MagicMock import sys # Add the osbuild-stages directory to the path sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', 'osbuild-stages')) from apt_stage import AptStage from debian_kernel_stage import DebianKernelStage from debian_grub_stage import DebianGrubStage from debian_filesystem_stage import DebianFilesystemStage class TestRealDebianIntegration(unittest.TestCase): """Real integration tests with actual Debian packages.""" def setUp(self): """Set up test fixtures.""" self.temp_dir = tempfile.mkdtemp() self.test_options = { 'packages': ['linux-image-amd64', 'systemd', 'initramfs-tools', 'grub-efi-amd64'], 'release': 'trixie', 'arch': 'amd64', 'repos': [ { 'name': 'debian', 'url': 'http://deb.debian.org/debian', 'suite': 'trixie', 'components': ['main', 'contrib'] } ] } # Create a real context that can execute commands self.real_context = RealContext(self.temp_dir) def tearDown(self): """Clean up test fixtures.""" shutil.rmtree(self.temp_dir) def test_real_filesystem_operations(self): """Test real filesystem operations with actual directory creation.""" logger.info("Testing real filesystem operations") filesystem_stage = DebianFilesystemStage({ 'rootfs_type': 'ext4', 'ostree_integration': True, 'home_symlink': True }) filesystem_stage.run(self.real_context) # Verify real filesystem structure essential_dirs = ['bin', 'boot', 'dev', 'etc', 'home', 'lib', 'lib64', 'media', 'mnt', 'opt', 'proc', 'root', 'run', 'sbin', 'srv', 'sys', 'tmp', 'usr', 'var'] for directory in essential_dirs: dir_path = os.path.join(self.temp_dir, directory) self.assertTrue(os.path.exists(dir_path), f"Directory {directory} not created") self.assertTrue(os.path.isdir(dir_path), f"{directory} is not a directory") # Verify OSTree directories ostree_dirs = ['ostree', 'usr/lib/ostree-boot', 'etc/ostree'] for directory in ostree_dirs: dir_path = os.path.join(self.temp_dir, directory) self.assertTrue(os.path.exists(dir_path), f"OSTree directory {directory} not created") # Verify home symlink home_path = os.path.join(self.temp_dir, 'home') self.assertTrue(os.path.islink(home_path), "Home symlink not created") self.assertEqual(os.readlink(home_path), '../var/home') # Verify user files passwd_file = os.path.join(self.temp_dir, 'etc', 'passwd') group_file = os.path.join(self.temp_dir, 'etc', 'group') shadow_file = os.path.join(self.temp_dir, 'etc', 'shadow') self.assertTrue(os.path.exists(passwd_file), "passwd file not created") self.assertTrue(os.path.exists(group_file), "group file not created") self.assertTrue(os.path.exists(shadow_file), "shadow file not created") logger.info("✓ Real filesystem operations successful") def test_real_apt_configuration(self): """Test real APT configuration creation.""" logger.info("Testing real APT configuration") # First set up filesystem filesystem_stage = DebianFilesystemStage({ 'ostree_integration': True, 'home_symlink': True }) filesystem_stage.run(self.real_context) # Then test APT stage apt_stage = AptStage(self.test_options) apt_stage.run(self.real_context) # Verify APT configuration files apt_conf = os.path.join(self.temp_dir, 'etc', 'apt', 'apt.conf.d', '99osbuild') self.assertTrue(os.path.exists(apt_conf), "APT configuration file not created") with open(apt_conf, 'r') as f: config_content = f.read() self.assertIn('Acquire::Check-Valid-Until "false"', config_content) self.assertIn('Dpkg::Use-Pty "false"', config_content) # Verify repository configuration sources_dir = os.path.join(self.temp_dir, 'etc', 'apt', 'sources.list.d') self.assertTrue(os.path.exists(sources_dir), "Sources list directory not created") debian_list = os.path.join(sources_dir, 'debian.list') self.assertTrue(os.path.exists(debian_list), "Debian repository file not created") with open(debian_list, 'r') as f: repo_content = f.read() self.assertIn('deb http://deb.debian.org/debian trixie main contrib', repo_content) logger.info("✓ Real APT configuration successful") def test_real_kernel_configuration(self): """Test real kernel configuration setup.""" logger.info("Testing real kernel configuration") # Set up filesystem first filesystem_stage = DebianFilesystemStage({ 'ostree_integration': True, 'home_symlink': True }) filesystem_stage.run(self.real_context) # Test kernel stage kernel_stage = DebianKernelStage({ 'kernel_package': 'linux-image-amd64', 'initramfs_tools': True, 'ostree_integration': True, 'modules_autoload': True }) kernel_stage.run(self.real_context) # Verify initramfs-tools configuration initramfs_conf = os.path.join(self.temp_dir, 'etc', 'initramfs-tools', 'initramfs.conf') self.assertTrue(os.path.exists(initramfs_conf), "initramfs.conf not created") with open(initramfs_conf, 'r') as f: conf_content = f.read() self.assertIn('OSTREE=y', conf_content) self.assertIn('HOOKS="ostree"', conf_content) # Verify OSTree hook ostree_hook = os.path.join(self.temp_dir, 'etc', 'initramfs-tools', 'hooks', 'ostree') self.assertTrue(os.path.exists(ostree_hook), "OSTree hook not created") self.assertTrue(os.access(ostree_hook, os.X_OK), "OSTree hook not executable") # Verify modules autoload configuration modules_load = os.path.join(self.temp_dir, 'etc', 'modules-load.d', 'osbuild.conf') self.assertTrue(os.path.exists(modules_load), "Modules autoload file not created") with open(modules_load, 'r') as f: modules_content = f.read() self.assertIn('loop', modules_content) self.assertIn('ext4', modules_content) logger.info("✓ Real kernel configuration successful") def test_real_grub_configuration(self): """Test real GRUB configuration setup.""" logger.info("Testing real GRUB configuration") # Set up filesystem first filesystem_stage = DebianFilesystemStage({ 'ostree_integration': True, 'home_symlink': True }) filesystem_stage.run(self.real_context) # Test GRUB stage grub_stage = DebianGrubStage({ 'ostree_integration': True, 'uefi': True, 'secure_boot': False, 'timeout': 5, 'default_entry': 0 }) grub_stage.run(self.real_context) # Verify GRUB configuration grub_default = os.path.join(self.temp_dir, 'etc', 'default', 'grub') self.assertTrue(os.path.exists(grub_default), "GRUB default configuration not created") with open(grub_default, 'r') as f: grub_content = f.read() self.assertIn('GRUB_TIMEOUT=5', grub_content) self.assertIn('GRUB_DEFAULT=0', grub_content) self.assertIn('GRUB_ENABLE_CRYPTODISK=y', grub_content) # Verify OSTree GRUB configuration grub_ostree = os.path.join(self.temp_dir, 'etc', 'grub.d', '10_ostree') self.assertTrue(os.path.exists(grub_ostree), "OSTree GRUB configuration not created") self.assertTrue(os.access(grub_ostree, os.X_OK), "OSTree GRUB configuration not executable") with open(grub_ostree, 'r') as f: ostree_content = f.read() self.assertIn('menuentry \'Debian Atomic (OSTree)\'', ostree_content) self.assertIn('ostree=/ostree/boot.1/debian-atomic/', ostree_content) # Verify GRUB environment grub_env = os.path.join(self.temp_dir, 'boot', 'grub', 'grubenv') self.assertTrue(os.path.exists(grub_env), "GRUB environment file not created") logger.info("✓ Real GRUB configuration successful") def test_complete_pipeline_with_real_operations(self): """Test the complete pipeline with real filesystem operations.""" logger.info("Testing complete pipeline with real operations") start_time = time.time() # Step 1: Filesystem Stage logger.info("Step 1: Real filesystem setup") filesystem_stage = DebianFilesystemStage({ 'rootfs_type': 'ext4', 'ostree_integration': True, 'home_symlink': True }) filesystem_stage.run(self.real_context) # Step 2: APT Stage logger.info("Step 2: Real APT configuration") apt_stage = AptStage(self.test_options) apt_stage.run(self.real_context) # Step 3: Kernel Stage logger.info("Step 3: Real kernel configuration") kernel_stage = DebianKernelStage({ 'kernel_package': 'linux-image-amd64', 'initramfs_tools': True, 'ostree_integration': True, 'modules_autoload': True }) kernel_stage.run(self.real_context) # Step 4: GRUB Stage logger.info("Step 4: Real GRUB configuration") grub_stage = DebianGrubStage({ 'ostree_integration': True, 'uefi': True, 'secure_boot': False, 'timeout': 5, 'default_entry': 0 }) grub_stage.run(self.real_context) end_time = time.time() total_time = end_time - start_time logger.info(f"Complete pipeline execution time: {total_time:.3f}s") # Verify complete filesystem structure self._verify_complete_filesystem() logger.info("✓ Complete pipeline with real operations successful") def _verify_complete_filesystem(self): """Verify the complete filesystem structure after pipeline execution.""" logger.info("Verifying complete filesystem structure") # Essential directories essential_dirs = ['bin', 'boot', 'dev', 'etc', 'home', 'lib', 'lib64', 'media', 'mnt', 'opt', 'proc', 'root', 'run', 'sbin', 'srv', 'sys', 'tmp', 'usr', 'var'] for directory in essential_dirs: dir_path = os.path.join(self.temp_dir, directory) self.assertTrue(os.path.exists(dir_path), f"Essential directory {directory} missing") # OSTree integration ostree_dirs = ['ostree', 'usr/lib/ostree-boot', 'etc/ostree', 'etc/ostree/remotes.d'] for directory in ostree_dirs: dir_path = os.path.join(self.temp_dir, directory) self.assertTrue(os.path.exists(dir_path), f"OSTree directory {directory} missing") # APT configuration apt_dirs = ['etc/apt/apt.conf.d', 'etc/apt/sources.list.d'] for directory in apt_dirs: dir_path = os.path.join(self.temp_dir, directory) self.assertTrue(os.path.exists(dir_path), f"APT directory {directory} missing") # Kernel configuration kernel_dirs = ['etc/initramfs-tools', 'etc/initramfs-tools/hooks', 'etc/modules-load.d'] for directory in kernel_dirs: dir_path = os.path.join(self.temp_dir, directory) self.assertTrue(os.path.exists(dir_path), f"Kernel directory {directory} missing") # GRUB configuration grub_dirs = ['etc/default', 'etc/grub.d', 'boot/grub'] for directory in grub_dirs: dir_path = os.path.join(self.temp_dir, directory) self.assertTrue(os.path.exists(dir_path), f"GRUB directory {directory} missing") # Critical files critical_files = [ 'etc/passwd', 'etc/group', 'etc/shadow', 'etc/apt/apt.conf.d/99osbuild', 'etc/apt/sources.list.d/debian.list', 'etc/initramfs-tools/initramfs.conf', 'etc/initramfs-tools/hooks/ostree', 'etc/modules-load.d/osbuild.conf', 'etc/default/grub', 'etc/grub.d/10_ostree', 'boot/grub/grubenv', 'etc/ostree/ostree.conf', 'etc/ostree/remotes.d/ostree.conf' ] for file_path in critical_files: full_path = os.path.join(self.temp_dir, file_path) self.assertTrue(os.path.exists(full_path), f"Critical file {file_path} missing") logger.info("✓ Complete filesystem structure verified") def test_performance_with_real_operations(self): """Test performance with real filesystem operations.""" logger.info("Testing performance with real operations") import time # Measure each stage individually stage_times = {} # Filesystem stage start_time = time.time() filesystem_stage = DebianFilesystemStage({ 'ostree_integration': True, 'home_symlink': True }) filesystem_stage.run(self.real_context) stage_times['filesystem'] = time.time() - start_time # APT stage start_time = time.time() apt_stage = AptStage(self.test_options) apt_stage.run(self.real_context) stage_times['apt'] = time.time() - start_time # Kernel stage start_time = time.time() kernel_stage = DebianKernelStage({ 'ostree_integration': True, 'initramfs_tools': True }) kernel_stage.run(self.real_context) stage_times['kernel'] = time.time() - start_time # GRUB stage start_time = time.time() grub_stage = DebianGrubStage({ 'ostree_integration': True, 'uefi': True }) grub_stage.run(self.real_context) stage_times['grub'] = time.time() - start_time total_time = sum(stage_times.values()) logger.info("Real operation performance:") for stage, duration in stage_times.items(): logger.info(f" {stage}: {duration:.3f}s") logger.info(f" Total: {total_time:.3f}s") # Performance expectations for real operations self.assertLess(stage_times['filesystem'], 2.0, "Filesystem stage too slow") self.assertLess(stage_times['apt'], 1.0, "APT stage too slow") self.assertLess(stage_times['kernel'], 1.0, "Kernel stage too slow") self.assertLess(stage_times['grub'], 1.0, "GRUB stage too slow") self.assertLess(total_time, 5.0, "Total pipeline too slow") logger.info("✓ Performance with real operations verified") class RealContext: """Real context that can execute commands and perform filesystem operations.""" def __init__(self, root): self.root = root def run(self, cmd): """Execute a command in the chroot environment.""" # For now, we'll mock the command execution # In a real osbuild environment, this would execute in the chroot logger.info(f"Would execute in chroot: {' '.join(cmd)}") # Return a mock result return Mock( returncode=0, stdout='', stderr='' ) if __name__ == '__main__': # Configure logging for tests import logging logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') logger = logging.getLogger(__name__) unittest.main()