#!/bin/bash # Testing with QEMU and cloud-hypervisor # Source common functions LIB_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "${LIB_SCRIPT_DIR}/common.sh" # Testing configuration QEMU_MEMORY="${QEMU_MEMORY:-512M}" QEMU_TIMEOUT="${QEMU_TIMEOUT:-60}" CLOUD_HYPERVISOR_MEMORY="${CLOUD_HYPERVISOR_MEMORY:-512M}" # Test kernel boot with QEMU function testing_qemu_boot() { local kernel_file="$1" local test_type="${2:-basic}" local timeout="${3:-$QEMU_TIMEOUT}" section_header "Testing with QEMU" if [[ ! -f "$kernel_file" ]]; then log_error "Kernel file not found: ${kernel_file}" return 1 fi # Check if QEMU is available if ! command_exists "qemu-system-x86_64"; then log_error "QEMU not found. Install with: apt-get install qemu-system-x86" return 1 fi log_info "Kernel file: ${kernel_file}" log_info "Memory: ${QEMU_MEMORY}" log_info "Test type: ${test_type}" log_info "Timeout: ${timeout}s" case "$test_type" in "basic") testing_qemu_basic_boot "$kernel_file" "$timeout" ;; "serial") testing_qemu_serial_boot "$kernel_file" "$timeout" ;; "interactive") testing_qemu_interactive_boot "$kernel_file" ;; *) log_error "Unknown QEMU test type: ${test_type}" return 1 ;; esac } # Basic QEMU boot test (automated) function testing_qemu_basic_boot() { local kernel_file="$1" local timeout="$2" log_info "Running basic QEMU boot test (${timeout}s timeout)" # QEMU command for automated testing local qemu_cmd="qemu-system-x86_64 \ -kernel $kernel_file \ -m $QEMU_MEMORY \ -nographic \ -serial mon:stdio \ -append 'console=ttyS0,115200 console=tty1 loglevel=7 panic=10' \ -no-reboot" log_info "QEMU command: ${qemu_cmd}" # Run with timeout if timeout "$timeout" $qemu_cmd 2>&1 | tee /tmp/qemu-boot.log; then log_info "QEMU boot test completed" else local exit_code=$? if [[ $exit_code -eq 124 ]]; then log_info "QEMU boot test timed out (${timeout}s) - this may be normal" else log_error "QEMU boot test failed with exit code: ${exit_code}" return 1 fi fi # Check boot log for success indicators testing_analyze_boot_log "/tmp/qemu-boot.log" } # QEMU serial console test function testing_qemu_serial_boot() { local kernel_file="$1" local timeout="$2" log_info "Running QEMU serial console test" # QEMU command optimized for serial console local qemu_cmd="qemu-system-x86_64 \ -kernel $kernel_file \ -m $QEMU_MEMORY \ -nographic \ -serial stdio \ -append 'console=ttyS0,115200n8 console=tty1 consoleblank=0 earlyprintk=serial,ttyS0,115200n8 loglevel=7'" log_info "QEMU serial command: ${qemu_cmd}" # Run with timeout and capture output timeout "$timeout" $qemu_cmd 2>&1 | tee /tmp/qemu-serial.log # Analyze serial output testing_analyze_boot_log "/tmp/qemu-serial.log" } # Interactive QEMU boot (no timeout) function testing_qemu_interactive_boot() { local kernel_file="$1" log_info "Starting interactive QEMU session" log_info "Use Ctrl+A, X to exit QEMU" # Interactive QEMU command local qemu_cmd="qemu-system-x86_64 \ -kernel $kernel_file \ -m $QEMU_MEMORY \ -nographic \ -serial mon:stdio \ -append 'console=ttyS0,115200 console=tty1 loglevel=7'" log_info "QEMU command: ${qemu_cmd}" # Run interactively safe_execute $qemu_cmd } # Test kernel boot with cloud-hypervisor function testing_cloud_hypervisor_boot() { local kernel_file="$1" local test_type="${2:-basic}" local timeout="${3:-$QEMU_TIMEOUT}" section_header "Testing with cloud-hypervisor" if [[ ! -f "$kernel_file" ]]; then log_error "Kernel file not found: ${kernel_file}" return 1 fi # Check if cloud-hypervisor is available if ! command_exists "cloud-hypervisor"; then log_error "cloud-hypervisor not found. Install from: https://github.com/cloud-hypervisor/cloud-hypervisor" return 1 fi log_info "Kernel file: ${kernel_file}" log_info "Memory: ${CLOUD_HYPERVISOR_MEMORY}" log_info "Test type: ${test_type}" case "$test_type" in "basic") testing_cloud_hypervisor_basic "$kernel_file" "$timeout" ;; "serial") testing_cloud_hypervisor_serial "$kernel_file" "$timeout" ;; *) log_error "Unknown cloud-hypervisor test type: ${test_type}" return 1 ;; esac } # Basic cloud-hypervisor test function testing_cloud_hypervisor_basic() { local kernel_file="$1" local timeout="$2" log_info "Running basic cloud-hypervisor test" # cloud-hypervisor command local ch_cmd="cloud-hypervisor \ --kernel $kernel_file \ --memory size=${CLOUD_HYPERVISOR_MEMORY} \ --serial tty \ --console off \ --cmdline 'console=ttyS0,115200 loglevel=7 panic=10'" log_info "cloud-hypervisor command: ${ch_cmd}" # Run with timeout if timeout "$timeout" $ch_cmd 2>&1 | tee /tmp/cloud-hypervisor-boot.log; then log_info "cloud-hypervisor test completed" else local exit_code=$? if [[ $exit_code -eq 124 ]]; then log_info "cloud-hypervisor test timed out (${timeout}s)" else log_error "cloud-hypervisor test failed with exit code: ${exit_code}" return 1 fi fi # Analyze boot log testing_analyze_boot_log "/tmp/cloud-hypervisor-boot.log" } # cloud-hypervisor serial test function testing_cloud_hypervisor_serial() { local kernel_file="$1" local timeout="$2" log_info "Running cloud-hypervisor serial test" # cloud-hypervisor command with serial focus local ch_cmd="cloud-hypervisor \ --kernel $kernel_file \ --memory size=${CLOUD_HYPERVISOR_MEMORY} \ --serial tty \ --console off \ --cmdline 'console=ttyS0,115200n8 earlyprintk=serial loglevel=7'" log_info "cloud-hypervisor serial command: ${ch_cmd}" timeout "$timeout" $ch_cmd 2>&1 | tee /tmp/cloud-hypervisor-serial.log testing_analyze_boot_log "/tmp/cloud-hypervisor-serial.log" } # Analyze boot log for success/failure indicators function testing_analyze_boot_log() { local log_file="$1" section_header "Analyzing Boot Log" if [[ ! -f "$log_file" ]]; then log_warn "Boot log file not found: ${log_file}" return 1 fi local log_size=$(get_file_size "$log_file") log_info "Boot log size: ${log_size}" # Success indicators local success_patterns=( "zinit.*starting" "zinit.*initialized" "login:" "zero-os.*login:" "Alpine Linux" "Welcome to Alpine" ) # Error indicators local error_patterns=( "Kernel panic" "kernel BUG" "Unable to mount root" "VFS: Cannot open root device" "not syncing" "Attempted to kill init" ) local success_count=0 local error_count=0 # Check for success patterns for pattern in "${success_patterns[@]}"; do if grep -i "$pattern" "$log_file" >/dev/null 2>&1; then log_info "✓ Found success indicator: ${pattern}" ((success_count++)) fi done # Check for error patterns for pattern in "${error_patterns[@]}"; do if grep -i "$pattern" "$log_file" >/dev/null 2>&1; then log_error "✗ Found error indicator: ${pattern}" ((error_count++)) fi done # Summary log_info "Boot log analysis:" log_info " Success indicators: ${success_count}" log_info " Error indicators: ${error_count}" if [[ $error_count -gt 0 ]]; then log_error "Boot test failed - errors detected in log" log_info "Check full log at: ${log_file}" return 1 elif [[ $success_count -gt 0 ]]; then log_info "Boot test successful - system appears to be working" return 0 else log_warn "Boot test inconclusive - no clear success/error indicators" return 2 fi } # Run comprehensive test suite function testing_run_all() { local kernel_file="$1" local test_timeout="${2:-60}" section_header "Running Comprehensive Test Suite" local test_results=() # Test with QEMU log_info "Running QEMU tests..." if testing_qemu_boot "$kernel_file" "basic" "$test_timeout"; then test_results+=("QEMU-basic: PASS") else test_results+=("QEMU-basic: FAIL") fi if testing_qemu_boot "$kernel_file" "serial" "$test_timeout"; then test_results+=("QEMU-serial: PASS") else test_results+=("QEMU-serial: FAIL") fi # Test with cloud-hypervisor (if available) if command_exists "cloud-hypervisor"; then log_info "Running cloud-hypervisor tests..." if testing_cloud_hypervisor_boot "$kernel_file" "basic" "$test_timeout"; then test_results+=("cloud-hypervisor-basic: PASS") else test_results+=("cloud-hypervisor-basic: FAIL") fi else log_warn "cloud-hypervisor not available, skipping tests" test_results+=("cloud-hypervisor: SKIPPED") fi # Report results section_header "Test Results Summary" local passed=0 local failed=0 local skipped=0 for result in "${test_results[@]}"; do if [[ "$result" =~ PASS ]]; then log_info "✓ $result" ((passed++)) elif [[ "$result" =~ FAIL ]]; then log_error "✗ $result" ((failed++)) else log_warn "⚠ $result" ((skipped++)) fi done log_info "Test summary: ${passed} passed, ${failed} failed, ${skipped} skipped" if [[ $failed -eq 0 ]]; then log_info "All tests passed successfully" return 0 else log_error "Some tests failed" return 1 fi } # Export functions export -f testing_qemu_boot testing_qemu_basic_boot testing_qemu_serial_boot testing_qemu_interactive_boot export -f testing_cloud_hypervisor_boot testing_cloud_hypervisor_basic testing_cloud_hypervisor_serial export -f testing_analyze_boot_log testing_run_all