- Complete bash framework with strict error handling - Modular library system (docker, alpine, components, initramfs, kernel, testing) - Rust component integration (zinit, rfs, mycelium) with musl targeting - Rootless Docker/Podman support for GitHub Actions - Centralized configuration in config/build.conf - 2-stage module loading system - Strip + UPX optimization for minimal size - Complete zinit integration replacing OpenRC - GitHub Actions CI/CD pipeline - Comprehensive documentation and usage guides Components: - Latest stable kernel 6.12.44 - Alpine Linux 3.22 base - ThreeFold components: zinit, mycelium, rfs, corex - Target: ~8-12MB final initramfs.cpio.xz
367 lines
10 KiB
Bash
367 lines
10 KiB
Bash
#!/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 |