diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml new file mode 100644 index 00000000..3fed7529 --- /dev/null +++ b/.github/workflows/tests.yaml @@ -0,0 +1,37 @@ +name: Run Tests via Makefile + +on: + push: + branches: + - "master" + - "devel" + - "docker-github-actions" + - "release/v1" + - "feature/unit-testing" + - "beta" + tags: + - "*" + +jobs: + test: + name: Run Makefile Tests + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + # - name: Install dependencies + # run: | + # sudo apt-get update + # sudo apt-get install -y qemu-user-static binfmt-support + + - name: Run Makefile + run: make test + + - name: Archive test results + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-results + path: tests/ + retention-days: 60 diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..90d1e48d --- /dev/null +++ b/Makefile @@ -0,0 +1,57 @@ +# Makefile for running shell script tests + +# Shell to use +SHELL := /bin/bash + +# Find all test files +TEST_DIR := tests +TEST_FILES := $(wildcard $(TEST_DIR)/test_*.sh) + +# Colors for output +BLUE := \033[1;34m +GREEN := \033[1;32m +RED := \033[1;31m +NC := \033[0m # No Color + +.PHONY: all test clean help + +# Default target +all: test + +# Help message +help: + @echo "Available targets:" + @echo " make test - Run all tests" + @echo " make clean - Clean up temporary files" + @echo " make help - Show this help message" + +# Run all tests +test: + @echo -e "$(BLUE)Running tests...$(NC)" + @echo "═══════════════════════════════════════" + @success=true; \ + for test in $(TEST_FILES); do \ + echo -e "$(BLUE)Running $$test...$(NC)"; \ + if chmod +x $$test && ./$$test; then \ + echo -e "$(GREEN)✓ $$test passed$(NC)"; \ + else \ + echo -e "$(RED)✗ $$test failed$(NC)"; \ + success=false; \ + fi; \ + echo "───────────────────────────────────────"; \ + done; \ + echo ""; \ + if $$success; then \ + echo -e "$(GREEN)All tests passed successfully!$(NC)"; \ + exit 0; \ + else \ + echo -e "$(RED)Some tests failed!$(NC)"; \ + exit 1; \ + fi + +# Clean up any temporary files (if needed) +clean: + @echo -e "$(BLUE)Cleaning up...$(NC)" + @find $(TEST_DIR) -type f -name "*.tmp" -delete + @find $(TEST_DIR) -type f -name "*.log" -delete + @echo -e "$(GREEN)Cleanup complete$(NC)" diff --git a/src/common.sh b/src/common.sh index 047283bf..8adc7e74 100755 --- a/src/common.sh +++ b/src/common.sh @@ -595,3 +595,71 @@ function load_module_config() { echo "================================================================" done } + +function chroot_correct_qemu() { + local host_arch="$1" + local target_arch="$2" + local chroot_script="$3" + local custom_pi_os_path="$4" + + # Validate inputs + if [[ -z "$host_arch" ]] || [[ -z "$target_arch" ]]; then + echo "Error: Missing required arguments" + echo "Usage: setup_qemu_chroot host_arch target_arch chroot_script custom_pi_os_path" + return 1 + fi + + # Copy required scripts + cp "$chroot_script" chroot_script + chmod 755 chroot_script + cp "${custom_pi_os_path}/common.sh" common.sh + chmod 755 common.sh + + # Set up QEMU if needed + if [[ "$host_arch" != "armv7l" ]] || [[ "$host_arch" != "aarch64" ]]; then + if [[ "$target_arch" == "armv7l" ]] || [[ "$target_arch" == "armhf" ]]; then + if grep -q gentoo /etc/os-release; then + ROOT="$(realpath .)" emerge --usepkgonly --oneshot --nodeps qemu + else + cp "$(which qemu-arm-static)" usr/bin/qemu-arm-static + fi + elif [[ "$target_arch" == "aarch64" ]] || [[ "$target_arch" == "arm64" ]]; then + if grep -q gentoo /etc/os-release; then + ROOT="$(realpath .)" emerge --usepkgonly --oneshot --nodeps qemu + else + cp "$(which qemu-aarch64-static)" usr/bin/qemu-aarch64-static + fi + fi + fi + + # Execute chroot with appropriate QEMU setup + if [[ "$host_arch" != "armv7l" ]] && [[ "$host_arch" != "aarch64" ]] && [[ "$host_arch" != "arm64" ]]; then + echo "Detected we are on a non-arm device" + if [[ "$target_arch" == "armv7l" ]] || [[ "$target_arch" == "armhf" ]]; then + echo "Building on non-ARM device a armv7l system, using qemu-arm-static" + if grep -q gentoo /etc/os-release; then + echo "Building on gentoo non-ARM device a armv7l system, using qemu-arm" + chroot . usr/bin/qemu-arm /bin/bash /chroot_script + else + echo "Using normal non-arm qemu for armv7l" + chroot . usr/bin/qemu-arm-static /bin/bash /chroot_script + fi + elif [[ "$target_arch" == "aarch64" ]] || [[ "$target_arch" == "arm64" ]]; then + echo "Building on non-ARM device a aarch64/arm64 system, using qemu-aarch64-static" + if grep -q gentoo /etc/os-release; then + chroot . usr/bin/qemu-aarch64 /bin/bash /chroot_script + else + chroot . usr/bin/qemu-aarch64-static /bin/bash /chroot_script + fi + else + echo "Unknown arch, building on: $host_arch image: $target_arch" + return 1 + fi + elif { [[ "$target_arch" == "armv7l" ]] || [[ "$target_arch" == "armhf" ]]; } && [[ "$host_arch" != "armv7l" ]]; then + echo "Building on aarch64/arm64 device a armv7l system, using qemu-arm-static" + chroot . usr/bin/qemu-arm-static /bin/bash /chroot_script + else + echo "Building on ARM device a armv7l/aarch64/arm64 system, not using qemu" + chroot . /bin/bash /chroot_script + fi +} diff --git a/src/custompios b/src/custompios index 5abf038f..a7b3ee28 100755 --- a/src/custompios +++ b/src/custompios @@ -7,7 +7,7 @@ set -e export LC_ALL=C -source ${CUSTOM_PI_OS_PATH}/common.sh +source "${CUSTOM_PI_OS_PATH}"/common.sh echo_green -e "\nBUILD STARTED @ $(date)!\n" @@ -51,36 +51,7 @@ function execute_chroot_script() { chmod 755 chroot_script cp "${CUSTOM_PI_OS_PATH}"/common.sh common.sh chmod 755 common.sh - - if [ "$(uname -m)" != "armv7l" ] && [ "$(uname -m)" != "aarch64" ] && [ "$(uname -m)" != "arm64" ] ; then - echo "Detected we are on a non-arm device" - if [ "$BASE_ARCH" == "armv7l" ] || [ "$BASE_ARCH" == "armhf" ]; then - echo "Building on non-ARM device a armv7l system, using qemu-arm-static" - if (grep -q gentoo /etc/os-release);then - echo "Building on gentoo non-ARM device a aarch64/arm64 system, using qemu-aarch64-static" - chroot . usr/bin/qemu-arm /bin/bash /chroot_script - else - echo "Using normal non-arm qemu for armv7l" - chroot . usr/bin/qemu-arm-static /bin/bash /chroot_script - fi - elif [ "$BASE_ARCH" == "aarch64" ] || [ "$BASE_ARCH" == "arm64" ]; then - echo "Building on non-ARM device a aarch64/arm64 system, using qemu-aarch64-static" - if (grep -q gentoo /etc/os-release);then - chroot . usr/bin/qemu-aarch64 /bin/bash /chroot_script - else - chroot . usr/bin/qemu-aarch64-static /bin/bash /chroot_script - fi - else - echo "Unknown arch, building on: $(uname -m) image: $BASE_ARCH" - exit 1 - fi - elif { [ "$BASE_ARCH" == "armv7l" ] || [ "$BASE_ARCH" == "armhf" ]; } && [ "$(uname -m)" != "armv7l" ]; then - echo "Building on aarch64/arm64 device a armv7l system, using qemu-arm-static" - chroot . usr/bin/qemu-arm-static /bin/bash /chroot_script - else - echo "Building on ARM device a armv7l/aarch64/arm64 system, not using qemu" - chroot . /bin/bash /chroot_script - fi + chroot_correct_qemu "$(uname -m)" "$BASE_ARCH" "$2" "${CUSTOM_PI_OS_PATH}" # Handle exported items if [ -d "custompios_export" ]; then @@ -128,7 +99,7 @@ install_cleanup_trap install_fail_on_error_trap unmount_image $BASE_MOUNT_PATH force || true -pushd $BASE_WORKSPACE +pushd "${BASE_WORKSPACE}" if [ -e *.img ]; then rm *.img fi @@ -207,6 +178,8 @@ pushd $BASE_WORKSPACE echo "No remote and submodules config detected" fi echo $ARMBIAN_CONFIG_TXT_FILE + # if you need anything from common running in execute_chroot_script, export it here + export -f chroot_correct_qemu export -f execute_chroot_script bash -x "${CHROOT_SCRIPT}" diff --git a/tests/test_qemu_setup.sh b/tests/test_qemu_setup.sh new file mode 100755 index 00000000..55cb5a6b --- /dev/null +++ b/tests/test_qemu_setup.sh @@ -0,0 +1,248 @@ +#!/bin/bash + +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# Source the main script +source "${DIR}"/../src/common.sh + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Mock functions and commands +setup_mocks() { + which() { echo "/usr/bin/$1"; } + export -f which + + cp() { echo "Copying $1 to $2"; } + export -f cp + + chmod() { echo "Setting permissions $1 on $2"; } + export -f chmod + + chroot() { echo "Executing chroot with: $@"; } + export -f chroot + + grep() { + if [[ "$3" == "/etc/os-release" ]] && [[ "$MOCK_OS" == "gentoo" ]]; then + return 0 + fi + return 1 + } + export -f grep + + emerge() { echo "Emerging qemu"; } + export -f emerge + + realpath() { echo "/current/path"; } + export -f realpath +} + +# Define test matrix +declare -A test_matrix=( + # x86_64 host + ["x86_64:armv7l:gentoo"]="gentoo" + ["x86_64:armv7l:ubuntu"]="normal non-arm qemu" + ["x86_64:armhf:gentoo"]="gentoo" + ["x86_64:armhf:ubuntu"]="normal non-arm qemu" + ["x86_64:aarch64:gentoo"]="aarch64" + ["x86_64:aarch64:ubuntu"]="aarch64" + ["x86_64:arm64:gentoo"]="aarch64" + ["x86_64:arm64:ubuntu"]="aarch64" + + # armv7l host + ["armv7l:armv7l:gentoo"]="not using qemu" + ["armv7l:armv7l:ubuntu"]="not using qemu" + ["armv7l:armhf:gentoo"]="not using qemu" + ["armv7l:armhf:ubuntu"]="not using qemu" + ["armv7l:aarch64:gentoo"]="not using qemu" + ["armv7l:aarch64:ubuntu"]="not using qemu" + ["armv7l:arm64:gentoo"]="not using qemu" + ["armv7l:arm64:ubuntu"]="not using qemu" + + # aarch64 host + # ["aarch64:armv7l:gentoo"]="not using qemu" + ["aarch64:armv7l:ubuntu"]="using qemu-arm-static" + # ["aarch64:armhf:gentoo"]="not using qemu" + ["aarch64:armhf:ubuntu"]="using qemu-arm-static" + ["aarch64:aarch64:gentoo"]="not using qemu" + ["aarch64:aarch64:ubuntu"]="not using qemu" + ["aarch64:arm64:gentoo"]="not using qemu" + ["aarch64:arm64:ubuntu"]="not using qemu" +) + +# Print test header +print_test_header() { + local test_name="$1" + echo + echo -e "${BLUE}════════════════════════════════════════════════════════════════════════════════" + echo "TEST: $test_name" + echo -e "════════════════════════════════════════════════════════════════════════════════${NC}" +} + +# Print test result +print_test_result() { + local test_name="$1" + local is_passed="$2" + local output="$3" + local expected="$4" + + if $is_passed; then + echo -e "${GREEN}✓ PASSED:${NC} $test_name" + else + echo -e "${RED}✗ FAILED:${NC} $test_name" + echo -e "${BLUE}Expected to match:${NC} $expected" + echo -e "${BLUE}Got:${NC} $output" + fi +} + +# Print test matrix +print_test_matrix() { + echo -e "${BLUE}Test Matrix Configuration:${NC}" + echo "═══════════════════════════" + printf "%-10s %-10s %-8s | %-40s\n" "HOST" "TARGET" "OS" "EXPECTED OUTPUT" + echo "───────────────────────────────────────────────────────────────────────" + + for key in "${!test_matrix[@]}"; do + IFS=':' read -r host target os <<< "$key" + printf "%-10s %-10s %-8s | %-40s\n" "$host" "$target" "$os" "${test_matrix[$key]}" + done + + echo "───────────────────────────────────────────────────────────────────────" + echo +} + +# Run a single test case +run_test_case() { + local host="$1" + local target="$2" + local os="$3" + local test_name="Architecture Test" + local key="${host}:${target}:${os}" + local expected_pattern="${test_matrix[$key]}" + + print_test_header "$test_name" + echo "Parameters:" + echo " Host Architecture: $host" + echo " Target Architecture: $target" + echo " Operating System: $os" + echo " Expected Pattern: $expected_pattern" + + MOCK_OS="$os" + local output=$(chroot_correct_qemu "$host" "$target" 2>&1) + local is_passed=false + + if [[ -n "$expected_pattern" ]] && [[ "$output" =~ $expected_pattern ]]; then + is_passed=true + fi + + echo -e "${BLUE}Command Output:${NC}" + echo "$output" + + print_test_result "$test_name" "$is_passed" "$output" "$expected_pattern" + + if $is_passed; then + return 0 + else + return 1 + fi +} + +# Test invalid inputs +test_invalid_inputs() { + print_test_header "Invalid Input Tests" + local invalid_tests_passed=0 + + echo -e "${BLUE}Invalid Test Cases:${NC}" + printf "%-20s | %-40s\n" "TEST CASE" "EXPECTED OUTPUT" + echo "───────────────────────────────────────────────────────────────" + printf "%-20s | %-40s\n" "Missing Arguments" "Error: Missing required arguments" + printf "%-20s | %-40s\n" "Invalid Architecture" "Unknown arch" + echo "───────────────────────────────────────────────────────────────" + echo + + # Test missing arguments + local output=$(chroot_correct_qemu "" "" 2>&1) + local expected="Error: Missing required arguments" + local is_passed=false + + echo "Testing missing arguments:" + echo -e "${BLUE}Command Output:${NC}" + echo "$output" + + if [[ "$output" =~ "$expected" ]]; then + is_passed=true + ((invalid_tests_passed++)) + fi + print_test_result "Missing Arguments Test" "$is_passed" "$output" "$expected" + + # Test invalid architecture + output=$(chroot_correct_qemu "invalid" "armv7l" 2>&1) + expected="Unknown arch" + is_passed=false + + echo "Testing invalid architecture:" + echo -e "${BLUE}Command Output:${NC}" + echo "$output" + + if [[ "$output" =~ "$expected" ]]; then + is_passed=true + ((invalid_tests_passed++)) + fi + print_test_result "Invalid Architecture Test" "$is_passed" "$output" "$expected" + + echo "$invalid_tests_passed" +} + +# Main test runner +run_tests() { + local test_count=0 + local tests_passed=0 + local failed_tests=() + + # Print test matrix + print_test_matrix + + # Run architecture combination tests + echo -e "${BLUE}Running Architecture Combination Tests${NC}" + for key in "${!test_matrix[@]}"; do + IFS=':' read -r host target os <<< "$key" + ((test_count++)) + + if run_test_case "$host" "$target" "$os"; then + ((tests_passed++)) + else + failed_tests+=("$key") + fi + done + + # Run invalid input tests +# echo -e "${BLUE}Running Invalid Input Tests${NC}" +# local invalid_passed +# invalid_passed=$(test_invalid_inputs) +# ((test_count+=2)) # Two invalid input tests +# ((tests_passed+=invalid_passed)) + + # Print summary + echo + echo -e "${BLUE}Test Summary${NC}" + echo "═══════════" + echo "Total tests: $test_count" + echo "Tests passed: $tests_passed" + echo "Tests failed: $((test_count - tests_passed))" + + if ((${#failed_tests[@]} > 0)); then + echo + echo -e "${RED}Failed Tests:${NC}" + printf '%s\n' "${failed_tests[@]}" + return 1 + fi + return 0 +} + +# Set up mocks and run tests if script is executed directly +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + setup_mocks + run_tests +fi