diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a2312a3..b74a631 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,9 +30,9 @@ jobs: - name: Find bash scripts run: | - # Find files that contain a bash shebang and save the list + # Find files that contain a bash shebang and save the list (exclude markdown and Dockerfiles) mkdir -p .github/tmp - find . -type f -not -path './.git/*' -exec grep -Il '^#!.*\bbash\b' {} \; > .github/tmp/bash-files || true + find . -type f -not -path './.git/*' ! -name '*.md' ! -name 'Dockerfile*' -exec grep -Il '^#!.*\bbash\b' {} \; > .github/tmp/bash-files || true echo "Found files:" && cat .github/tmp/bash-files || true - name: Install ShellCheck diff --git a/.github/workflows/test-ubuntu.yml b/.github/workflows/test-ubuntu.yml new file mode 100644 index 0000000..46b9295 --- /dev/null +++ b/.github/workflows/test-ubuntu.yml @@ -0,0 +1,64 @@ +name: Test Ubuntu Bootstrap + +on: + push: + branches: [ main ] + paths: + - 'ubuntu/**' + - 'generic/**' + - 'bootstrap' + - '.github/workflows/test-ubuntu.yml' + pull_request: + branches: [ main ] + paths: + - 'ubuntu/**' + - 'generic/**' + - 'bootstrap' + workflow_dispatch: + +jobs: + shellcheck: + name: ShellCheck Linting + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Run ShellCheck + run: | + sudo apt-get update && sudo apt-get install -y shellcheck + find ubuntu/ generic/ -type f ! -name "*.md" -exec shellcheck -x --severity=error {} \; + shellcheck -x --severity=error bootstrap + + docker-test: + name: Docker Test (Ubuntu ${{ matrix.ubuntu-version }}) + runs-on: ubuntu-latest + strategy: + matrix: + ubuntu-version: ['24.04', '25.10'] + fail-fast: false + + steps: + - uses: actions/checkout@v4 + + - name: Build test image + run: | + docker build \ + --build-arg UBUNTU_VERSION=${{ matrix.ubuntu-version }} \ + -f test/docker/Dockerfile.ubuntu-noninteractive \ + -t ubuntu-bootstrap-test:${{ matrix.ubuntu-version }} \ + . + + - name: Run bootstrap tests + run: | + docker run --rm ubuntu-bootstrap-test:${{ matrix.ubuntu-version }} + + - name: Test individual scripts + run: | + docker run --rm ubuntu-bootstrap-test:${{ matrix.ubuntu-version }} bash -c " + cd /home/testuser/linux-bootstrap && \ + bash -n ubuntu/bootstrap && \ + bash -n ubuntu/install-essential-packages && \ + bash -n ubuntu/install-dev-packages && \ + bash -n ubuntu/install-desktop-packages && \ + echo 'All syntax checks passed' + " diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..665827c --- /dev/null +++ b/Makefile @@ -0,0 +1,65 @@ +.PHONY: help test test-auto test-interactive test-all test-syntax lint clean build-test-images docker-clean shellcheck + +# Default target +.DEFAULT_GOAL := help + +# Ubuntu versions to test +UBUNTU_VERSIONS := 24.04 25.10 + +help: ## Show this help message + @echo "Linux Bootstrap Testing Makefile" + @echo "" + @echo "Usage: make [target]" + @echo "" + @echo "Available targets:" + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-20s\033[0m %s\n", $$1, $$2}' + +test: test-auto ## Run automated tests (default: Ubuntu 24.04) + +test-auto: ## Run automated tests on Ubuntu 24.04 + @./test/run-tests.sh auto + +test-interactive: ## Start interactive Docker container for manual testing + @./test/run-tests.sh interactive + +test-all: ## Run tests on all Ubuntu versions (24.04, 25.10) + @./test/run-tests.sh all + +test-syntax: ## Run syntax checks on all bash scripts + @./test/run-tests.sh syntax + +lint: shellcheck ## Run all linting tools + +shellcheck: ## Run shellcheck on all scripts + @echo "Running shellcheck..." + @if command -v shellcheck >/dev/null 2>&1; then \ + shellcheck -x --severity=error bootstrap; \ + shellcheck -x --severity=error ubuntu/bootstrap; \ + find ubuntu/ -type f -name 'install-*' -exec shellcheck -x --severity=error {} \+; \ + find generic/ -type f -exec shellcheck -x --severity=error {} \+; \ + else \ + echo "shellcheck not installed. Install with: sudo apt-get install shellcheck"; \ + exit 1; \ + fi + +build-test-images: ## Build Docker test images for all Ubuntu versions + @echo "Building test images for Ubuntu versions: $(UBUNTU_VERSIONS)" + @for version in $(UBUNTU_VERSIONS); do \ + echo "Building Ubuntu $$version..."; \ + docker build \ + --build-arg UBUNTU_VERSION=$$version \ + -f test/docker/Dockerfile.ubuntu-noninteractive \ + -t ubuntu-bootstrap-test:$$version \ + .; \ + done + +clean: docker-clean ## Clean up all test artifacts + +docker-clean: ## Remove all test Docker images + @echo "Cleaning up Docker test images..." + @docker images | grep ubuntu-bootstrap-test | awk '{print $$3}' | xargs -r docker rmi || true + @echo "Cleanup complete" + +ci: test-syntax test-all ## Run full CI test suite (syntax + all versions) + +quick: test-syntax test-auto ## Quick check: syntax + single version test diff --git a/arch/bootstrap b/arch/bootstrap old mode 100644 new mode 100755 diff --git a/arch/install-essential-packages b/arch/install-essential-packages old mode 100644 new mode 100755 diff --git a/bootstrap b/bootstrap old mode 100644 new mode 100755 diff --git a/fedora/bootstrap b/fedora/bootstrap old mode 100644 new mode 100755 diff --git a/fedora/install-packages b/fedora/install-packages old mode 100644 new mode 100755 diff --git a/fedora/set-hostname b/fedora/set-hostname old mode 100644 new mode 100755 diff --git a/generic/add-user-to-groups b/generic/add-user-to-groups old mode 100644 new mode 100755 index dd94c99..ea002c2 --- a/generic/add-user-to-groups +++ b/generic/add-user-to-groups @@ -2,7 +2,7 @@ # source <(curl -fsSL https://raw.githubusercontent.com/mapitman/linux-bootstrap/main/generic/add-user-to-groups) # Allow current user to access the serial port -sudo usermod -aG dialout $USER +sudo usermod -aG dialout "$USER" # Add current user to docker group -sudo usermod -aG docker $USER \ No newline at end of file +sudo usermod -aG docker "$USER" \ No newline at end of file diff --git a/generic/auto-cpufreq b/generic/auto-cpufreq deleted file mode 100644 index bccac52..0000000 --- a/generic/auto-cpufreq +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash -# source <(curl -fsSL https://raw.githubusercontent.com/mapitman/linux-bootstrap/main/generic/auto-cpufreq) - -mkdir -p ~/src/github/AdnanHodzic -git clone git@github.com:AdnanHodzic/auto-cpufreq.git ~/src/github/AdnanHodzic/auto-cpufreq -cd ~/src/github/AdnanHodzic/auto-cpufreq && sudo ./auto-cpufreq-installer && cd - -sudo auto-cpufreq --install diff --git a/generic/create-directories b/generic/create-directories old mode 100644 new mode 100755 index 6c7db6b..638455c --- a/generic/create-directories +++ b/generic/create-directories @@ -3,7 +3,7 @@ # Create some directories that I use for development echo "Setting up source code directories..." -mkdir -p $HOME/src/github -mkdir -p $HOME/src/gitlab -mkdir -p $HOME/src/work -mkdir -p $HOME/src/aur +mkdir -p "$HOME"/src/github +mkdir -p "$HOME"/src/gitlab +mkdir -p "$HOME"/src/work +mkdir -p "$HOME"/src/aur diff --git a/generic/create-ssh-key b/generic/create-ssh-key old mode 100644 new mode 100755 diff --git a/generic/github-auth-login b/generic/github-auth-login old mode 100644 new mode 100755 diff --git a/generic/github-auth-logout b/generic/github-auth-logout old mode 100644 new mode 100755 diff --git a/generic/homebrew b/generic/homebrew old mode 100644 new mode 100755 diff --git a/generic/install-jetbrains-tools b/generic/install-jetbrains-tools old mode 100644 new mode 100755 diff --git a/generic/install-zsh-customizations b/generic/install-zsh-customizations old mode 100644 new mode 100755 index a7e033b..e1b0867 --- a/generic/install-zsh-customizations +++ b/generic/install-zsh-customizations @@ -24,7 +24,7 @@ fi # Autosuggestions if [[ ! -d $HOME/.oh-my-zsh/custom/plugins/zsh-autosuggestions ]] then - git clone --depth=1 https://github.com/zsh-users/zsh-autosuggestions $HOME/.oh-my-zsh/custom/plugins/zsh-autosuggestions + git clone --depth=1 https://github.com/zsh-users/zsh-autosuggestions "$HOME"/.oh-my-zsh/custom/plugins/zsh-autosuggestions rm -rf "$HOME"/.oh-my-zsh/custom/plugins/zsh-autosuggestions/.git rm -rf "$HOME"/.oh-my-zsh/custom/plugins/zsh-autosuggestions/.github rm -rf "$HOME"/.oh-my-zsh/custom/plugins/zsh-autosuggestions/.circleci @@ -33,6 +33,6 @@ fi # Syntax Highlighting if [[ ! -d $HOME/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting ]] then - git clone --depth=1 https://github.com/zsh-users/zsh-syntax-highlighting.git $HOME/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting + git clone --depth=1 https://github.com/zsh-users/zsh-syntax-highlighting.git "$HOME"/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting rm -rf "$HOME"/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting/.git fi diff --git a/generic/lazyvim b/generic/lazyvim old mode 100644 new mode 100755 diff --git a/pop_os/bootstrap b/pop_os/bootstrap old mode 100644 new mode 100755 diff --git a/pop_os/install-makemkv b/pop_os/install-makemkv old mode 100644 new mode 100755 diff --git a/pop_os/install-optical-disc-packages b/pop_os/install-optical-disc-packages old mode 100644 new mode 100755 diff --git a/pop_os/install-packages b/pop_os/install-packages old mode 100644 new mode 100755 diff --git a/scripts/check.sh b/scripts/check.sh old mode 100644 new mode 100755 diff --git a/test/README.md b/test/README.md new file mode 100644 index 0000000..3082c4b --- /dev/null +++ b/test/README.md @@ -0,0 +1,195 @@ +# Testing Strategy for Ubuntu Bootstrap Scripts + +This directory contains automated testing infrastructure for the Ubuntu bootstrap scripts using Docker and QEMU. + +## Quick Start + +### Option 1: Docker (Recommended for Quick Testing) + +Docker provides fast, lightweight testing ideal for package installation validation. + +**Interactive Testing:** +```bash +# Build the test image +docker build -f test/docker/Dockerfile.ubuntu -t ubuntu-bootstrap-test . + +# Run interactively to manually test scripts +docker run -it --rm ubuntu-bootstrap-test + +# Inside the container, test individual scripts: +cd linux-bootstrap +bash ubuntu/install-essential-packages +``` + +**Automated Testing:** +```bash +# Build and run non-interactive tests +docker build -f test/docker/Dockerfile.ubuntu-noninteractive -t ubuntu-bootstrap-test-auto . +docker run --rm ubuntu-bootstrap-test-auto +``` + +**Test Different Ubuntu Versions:** +```bash +# Ubuntu 22.04 LTS +docker build --build-arg UBUNTU_VERSION=22.04 -f test/docker/Dockerfile.ubuntu -t ubuntu-bootstrap-test:22.04 . + +# Ubuntu 24.04 LTS +docker build --build-arg UBUNTU_VERSION=24.04 -f test/docker/Dockerfile.ubuntu -t ubuntu-bootstrap-test:24.04 . +``` + +### Option 2: QEMU (For Full System Testing) + +QEMU provides a complete VM environment for testing system-level changes that Docker can't replicate (systemd, kernel modules, etc.). + +```bash +# See test/qemu/README.md for QEMU setup instructions +``` + +## Testing Approaches + +### 1. Unit Testing (Individual Scripts) + +Test each script independently: + +```bash +docker run -it --rm ubuntu-bootstrap-test bash -c " + cd linux-bootstrap && \ + bash ubuntu/install-essential-packages && \ + echo 'Essential packages installed successfully' +" +``` + +### 2. Integration Testing (Full Bootstrap) + +Test the complete bootstrap flow (requires handling interactive prompts): + +```bash +# Create a script with automated responses +cat > test-full-bootstrap.sh << 'EOF' +#!/bin/bash +# Simulate user responses: n for dev, n for desktop, n for media, n for optical +echo -e "n\nn\nn\nn" | bash ubuntu/bootstrap +EOF + +docker run -it --rm -v $(pwd)/test-full-bootstrap.sh:/tmp/test.sh ubuntu-bootstrap-test bash /tmp/test.sh +``` + +### 3. GitHub Actions CI/CD + +Add `.github/workflows/test-ubuntu.yml` to automatically test on every push: + +```yaml +name: Test Ubuntu Bootstrap + +on: [push, pull_request] + +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + ubuntu-version: ['20.04', '22.04', '24.04'] + + steps: + - uses: actions/checkout@v3 + + - name: Build test image + run: | + docker build \ + --build-arg UBUNTU_VERSION=${{ matrix.ubuntu-version }} \ + -f test/docker/Dockerfile.ubuntu-noninteractive \ + -t ubuntu-bootstrap-test . + + - name: Run tests + run: docker run --rm ubuntu-bootstrap-test +``` + +## Docker vs QEMU: When to Use Each + +| Feature | Docker | QEMU | +|---------|--------|------| +| **Speed** | Fast (seconds) | Slow (minutes) | +| **Isolation** | Process-level | Full VM | +| **Systemd** | Limited support | Full support | +| **Kernel Modules** | Host kernel only | Full kernel | +| **Use Case** | Package installation testing | Full system configuration | +| **CI/CD** | ✅ Ideal | ❌ Too slow | + +**Recommendation:** +- Use **Docker** for 95% of testing (package installs, script syntax, basic functionality) +- Use **QEMU** only when testing systemd services, kernel modules, or boot configuration + +## Limitations and Workarounds + +### Docker Limitations + +1. **Interactive Prompts**: Scripts with `read -p` need automation or modification + - **Workaround**: Use `echo` piping or create non-interactive variants + +2. **Systemd**: Some systemd operations won't work in Docker + - **Workaround**: Mock systemd commands or skip in tests + +3. **Privileged Operations**: Some hardware/kernel operations unavailable + - **Workaround**: Use `--privileged` flag or test in QEMU + +### Testing Interactive Scripts + +For scripts with prompts, create test wrappers: + +```bash +# Automatically answer "yes" to all prompts +yes | bash ubuntu/bootstrap + +# Provide specific answers +echo -e "y\nn\ny" | bash ubuntu/bootstrap +``` + +Or modify scripts to support environment variables: + +```bash +# In the script: +if [[ -n "$CI" ]]; then + # Non-interactive mode + REPLY="n" +else + read -p "Install development tools? " -n 1 -r + echo +fi +``` + +## Recommended Testing Workflow + +1. **Local Development**: + ```bash + # Quick syntax check + bash -n ubuntu/bootstrap + shellcheck ubuntu/bootstrap + + # Test in Docker + docker build -f test/docker/Dockerfile.ubuntu -t ubuntu-bootstrap-test . + docker run -it --rm ubuntu-bootstrap-test + ``` + +2. **Before Commit**: + ```bash + # Run automated tests + docker build -f test/docker/Dockerfile.ubuntu-noninteractive -t test . + docker run --rm test + ``` + +3. **CI Pipeline**: + - Automated Docker tests on every push + - Test multiple Ubuntu versions (20.04, 22.04, 24.04) + +4. **Major Changes**: + - Full QEMU VM test with clean Ubuntu ISO + - Manual verification on physical hardware + +## Future Enhancements + +- [ ] Add GitHub Actions CI workflow +- [ ] Create QEMU automated testing with cloud-init +- [ ] Add test coverage for all distros (Fedora, Arch, Pop!_OS) +- [ ] Create non-interactive mode for all bootstrap scripts +- [ ] Add smoke tests to verify installed packages work +- [ ] Create test fixtures for different user scenarios diff --git a/test/docker/.dockerignore b/test/docker/.dockerignore new file mode 100644 index 0000000..c34901c --- /dev/null +++ b/test/docker/.dockerignore @@ -0,0 +1,6 @@ +# Don't copy test artifacts into test containers +test/ +.git/ +.github/ +*.md +LICENSE diff --git a/test/docker/Dockerfile.ubuntu b/test/docker/Dockerfile.ubuntu new file mode 100644 index 0000000..dd1e37a --- /dev/null +++ b/test/docker/Dockerfile.ubuntu @@ -0,0 +1,36 @@ +# Testing Dockerfile for Ubuntu bootstrap scripts +# Usage: +# docker build -f test/docker/Dockerfile.ubuntu -t ubuntu-bootstrap-test . +# docker run -it --rm ubuntu-bootstrap-test + +ARG UBUNTU_VERSION=22.04 +FROM ubuntu:${UBUNTU_VERSION} + +# Prevent interactive prompts during package installation +ENV DEBIAN_FRONTEND=noninteractive +ENV TZ=UTC + +# Install minimal dependencies needed for the bootstrap process +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + curl \ + ca-certificates \ + sudo \ + openssh-client \ + git \ + && rm -rf /var/lib/apt/lists/* + +# Create a test user with sudo privileges (mimics a fresh Ubuntu install) +RUN useradd -m -s /bin/bash testuser && \ + echo "testuser ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers + +# Switch to test user +USER testuser +WORKDIR /home/testuser + +# Copy bootstrap scripts into the container for local testing +# (alternatively, they'll be sourced from GitHub) +COPY --chown=testuser:testuser . /home/testuser/linux-bootstrap + +# Default command: start bash for interactive testing +CMD ["/bin/bash"] diff --git a/test/docker/Dockerfile.ubuntu-noninteractive b/test/docker/Dockerfile.ubuntu-noninteractive new file mode 100644 index 0000000..bd78f1d --- /dev/null +++ b/test/docker/Dockerfile.ubuntu-noninteractive @@ -0,0 +1,49 @@ +# Non-interactive testing Dockerfile for Ubuntu bootstrap scripts +# This version automatically runs the bootstrap with "no" answers to all prompts +# Usage: +# docker build -f test/docker/Dockerfile.ubuntu-noninteractive -t ubuntu-bootstrap-test-auto . +# docker run --rm ubuntu-bootstrap-test-auto + +ARG UBUNTU_VERSION=22.04 +FROM ubuntu:${UBUNTU_VERSION} + +ENV DEBIAN_FRONTEND=noninteractive +ENV TZ=UTC + +# Install minimal dependencies +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + curl \ + ca-certificates \ + sudo \ + openssh-client \ + git \ + && rm -rf /var/lib/apt/lists/* + +# Create a test user with sudo privileges +RUN useradd -m -s /bin/bash testuser && \ + echo "testuser ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers + +USER testuser +WORKDIR /home/testuser + +# Copy bootstrap scripts +COPY --chown=testuser:testuser . /home/testuser/linux-bootstrap + +# Create a non-interactive test runner +RUN cat <<'EOF' > /home/testuser/run-tests.sh && chmod +x /home/testuser/run-tests.sh +#!/bin/bash +set -e +cd /home/testuser/linux-bootstrap + +# Test just the essential packages (no prompts) +echo "Testing essential packages installation..." +bash ubuntu/install-essential-packages + +echo "" +echo "=================================" +echo "Essential packages test completed" +echo "=================================" +EOF + +CMD ["/home/testuser/run-tests.sh"] diff --git a/test/monitor-test.sh b/test/monitor-test.sh new file mode 100755 index 0000000..dd7d0a1 --- /dev/null +++ b/test/monitor-test.sh @@ -0,0 +1,57 @@ +#!/bin/bash +# Monitor and log the test output for debugging +# Usage: ./test/monitor-test.sh [output-file] + +OUTPUT_FILE="${1:-test-output-$(date +%Y%m%d-%H%M%S).log}" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" + +echo "Running interactive test and logging to: $OUTPUT_FILE" +echo "Press Ctrl+C to stop the test" +echo "" + +cd "$PROJECT_ROOT" + +# Build the image +echo "Building test image..." +docker build -f test/docker/Dockerfile.ubuntu -t ubuntu-bootstrap-test . 2>&1 | tee "$OUTPUT_FILE" + +# Run the container and execute the bootstrap automatically +echo "" +echo "Running bootstrap in container..." +echo "(Answering 'n' to all prompts automatically)" +echo "" + +{ + echo "Container started at: $(date)" + echo "========================================" + echo "" + # Run bootstrap with automatic "no" answers + docker run --rm ubuntu-bootstrap-test bash -c " + cd linux-bootstrap + echo 'Testing bootstrap with automatic no responses...' + echo -e '\n\n\n\n' | bash bootstrap 2>&1 + EXIT_CODE=\$? + echo '' + echo '========================================' + echo 'Bootstrap completed with exit code:' \$EXIT_CODE + exit \$EXIT_CODE + " +} 2>&1 | tee -a "$OUTPUT_FILE" + +# Note: PIPESTATUS is bash-specific; the /bin/bash shebang above is required. +EXIT_CODE=${PIPESTATUS[0]} + +echo "" +echo "========================================" +echo "Test completed with exit code: $EXIT_CODE" +echo "Full output saved to: $OUTPUT_FILE" +echo "" + +if [ $EXIT_CODE -ne 0 ]; then + echo "FAILURES DETECTED - Review the log file for details" + exit 1 +else + echo "All tests passed!" + exit 0 +fi diff --git a/test/qemu/README.md b/test/qemu/README.md new file mode 100644 index 0000000..e562a1b --- /dev/null +++ b/test/qemu/README.md @@ -0,0 +1,142 @@ +# QEMU Testing Setup for Ubuntu Bootstrap + +For full system-level testing when Docker's limitations are too restrictive. + +## Prerequisites + +```bash +sudo apt-get install qemu-system-x86 qemu-utils cloud-image-utils +``` + +## Quick Start with Ubuntu Cloud Images + +Ubuntu provides pre-built cloud images perfect for automated testing: + +```bash +#!/bin/bash +# Download Ubuntu cloud image +wget https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img + +# Create a larger disk (cloud images are small) +qemu-img create -f qcow2 -F qcow2 -b jammy-server-cloudimg-amd64.img ubuntu-test.qcow2 20G + +# Create cloud-init config for auto-login +cat > user-data << EOF +#cloud-config +users: + - name: testuser + sudo: ALL=(ALL) NOPASSWD:ALL + shell: /bin/bash + ssh_authorized_keys: + - ssh-rsa YOUR_SSH_KEY_HERE + +packages: + - curl + - git + +runcmd: + - echo "Bootstrap test VM ready" +EOF + +# Create metadata +cat > meta-data << EOF +instance-id: ubuntu-bootstrap-test +local-hostname: ubuntu-test +EOF + +# Generate cloud-init ISO +cloud-localds seed.img user-data meta-data + +# Start VM +qemu-system-x86_64 \ + -machine accel=kvm:tcg \ + -cpu host \ + -m 4096 \ + -nographic \ + -drive file=ubuntu-test.qcow2,format=qcow2 \ + -drive file=seed.img,format=raw \ + -net nic -net user,hostfwd=tcp::2222-:22 + +# Connect via SSH (from another terminal) +ssh -p 2222 testuser@localhost +``` + +## Automated Testing Script + +Create `test/qemu/run-test.sh`: + +```bash +#!/bin/bash +set -e + +VM_NAME="ubuntu-bootstrap-test" +IMAGE="ubuntu-test.qcow2" + +# Clean up previous test +rm -f "$IMAGE" seed.img + +# Download fresh image +wget -O base.img https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img + +# Create test disk +qemu-img create -f qcow2 -F qcow2 -b base.img "$IMAGE" 20G + +# Generate cloud-init config +cat > user-data << 'EOF' +#cloud-config +users: + - name: testuser + sudo: ALL=(ALL) NOPASSWD:ALL + shell: /bin/bash + +packages: + - curl + - git + - ca-certificates + +runcmd: + # Run the bootstrap script + - sudo -u testuser bash -c 'cd /home/testuser && curl -fsSL https://raw.githubusercontent.com/mapitman/linux-bootstrap/main/ubuntu/install-essential-packages | bash' + - echo "Bootstrap completed" > /tmp/bootstrap-done + - poweroff +EOF + +echo "instance-id: $VM_NAME" > meta-data +cloud-localds seed.img user-data meta-data + +# Run VM (headless, auto-shutdown after bootstrap) +timeout 600 qemu-system-x86_64 \ + -machine accel=kvm:tcg \ + -cpu host \ + -m 2048 \ + -nographic \ + -drive file="$IMAGE",format=qcow2 \ + -drive file=seed.img,format=raw \ + -net nic -net user || true + +echo "VM test completed" +``` + +## Pros and Cons + +**Pros:** +- Full Ubuntu environment (systemd, kernel, all services) +- Tests exactly as it would run on bare metal +- Can test reboot behavior, kernel modules, etc. + +**Cons:** +- Slow (several minutes per test) +- Requires more disk space (several GB per test) +- Not practical for CI/CD +- More complex setup + +## When to Use QEMU Testing + +Use QEMU testing when: +- Testing systemd service installation/configuration +- Testing kernel module loading +- Testing boot configuration changes +- Verifying the full end-to-end bootstrap experience +- Before releasing a major version + +For regular development and CI/CD, stick with Docker testing. diff --git a/test/run-tests.sh b/test/run-tests.sh new file mode 100755 index 0000000..1715aee --- /dev/null +++ b/test/run-tests.sh @@ -0,0 +1,153 @@ +#!/bin/bash +# Quick test runner for Ubuntu bootstrap scripts +# Usage: ./test/run-tests.sh [interactive|auto|all|syntax|clean] + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" + +cd "$PROJECT_ROOT" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +print_header() { + echo -e "\n${GREEN}===================================${NC}" + echo -e "${GREEN}$1${NC}" + echo -e "${GREEN}===================================${NC}\n" +} + +print_error() { + echo -e "${RED}ERROR: $1${NC}" +} + +print_warning() { + echo -e "${YELLOW}WARNING: $1${NC}" +} + +# Check if Docker is available +if ! command -v docker &> /dev/null; then + print_error "Docker is not installed or not in PATH" + exit 1 +fi + +MODE="${1:-auto}" + +case "$MODE" in + interactive|i) + print_header "Building Interactive Test Container" + docker build -f test/docker/Dockerfile.ubuntu -t ubuntu-bootstrap-test . + + print_header "Starting Interactive Test Session" + echo "You can now test scripts manually. Try:" + echo " cd linux-bootstrap" + echo " bash ubuntu/install-essential-packages" + echo "" + docker run -it --rm ubuntu-bootstrap-test + ;; + + auto|a) + print_header "Running Automated Tests" + + # Test Ubuntu 24.04 + print_header "Testing Ubuntu 24.04 LTS" + docker build \ + --build-arg UBUNTU_VERSION=24.04 \ + -f test/docker/Dockerfile.ubuntu-noninteractive \ + -t ubuntu-bootstrap-test:24.04 \ + . + docker run --rm ubuntu-bootstrap-test:24.04 + + echo -e "\n${GREEN}✓ Ubuntu 24.04 tests passed${NC}\n" + ;; + + all) + print_header "Running Comprehensive Tests" + + VERSIONS=("24.04" "25.10") + FAILED=() + + for VERSION in "${VERSIONS[@]}"; do + print_header "Testing Ubuntu $VERSION" + + if docker build \ + --build-arg UBUNTU_VERSION="$VERSION" \ + -f test/docker/Dockerfile.ubuntu-noninteractive \ + -t ubuntu-bootstrap-test:"$VERSION" \ + . && \ + docker run --rm ubuntu-bootstrap-test:"$VERSION"; then + echo -e "\n${GREEN}✓ Ubuntu $VERSION tests passed${NC}\n" + else + print_error "Ubuntu $VERSION tests failed" + FAILED+=("$VERSION") + fi + done + + # Summary + print_header "Test Summary" + if [ ${#FAILED[@]} -eq 0 ]; then + echo -e "${GREEN}All tests passed!${NC}" + else + echo -e "${RED}Failed versions: ${FAILED[*]}${NC}" + exit 1 + fi + ;; + + syntax) + print_header "Running Syntax Checks" + + echo "Checking bootstrap scripts..." + bash -n bootstrap + bash -n ubuntu/bootstrap + + echo "Checking ubuntu scripts..." + for script in ubuntu/install-*; do + echo " Checking $script" + bash -n "$script" + done + + echo "Checking generic scripts..." + for script in generic/*; do + echo " Checking $script" + bash -n "$script" + done + + echo -e "\n${GREEN}✓ All syntax checks passed${NC}\n" + + if command -v shellcheck &> /dev/null; then + print_header "Running ShellCheck" + # ShellCheck is treated as advisory linting here; syntax errors still fail via set -e + shellcheck bootstrap ubuntu/bootstrap || print_warning "ShellCheck found issues" + else + print_warning "shellcheck not installed, skipping advanced linting" + echo "Install with: sudo apt-get install shellcheck" + fi + ;; + + clean) + print_header "Cleaning Up Test Images" + docker images | grep ubuntu-bootstrap-test | awk '{print $3}' | xargs -r docker rmi + echo -e "${GREEN}Cleanup complete${NC}" + ;; + + *) + echo "Usage: ./test/run-tests.sh [interactive|auto|all|syntax|clean]" + echo "" + echo "Modes:" + echo " interactive (i) - Start interactive Docker container for manual testing" + echo " auto (a) - Run automated tests on Ubuntu 24.04 (default)" + echo " all - Run tests on Ubuntu 24.04 and 25.10" + echo " syntax - Run syntax checks and linting only" + echo " clean - Remove all test Docker images" + echo "" + echo "Examples:" + echo " ./test/run-tests.sh auto # Quick automated test" + echo " ./test/run-tests.sh interactive # Manual testing" + echo " ./test/run-tests.sh all # Full test suite" + exit 1 + ;; +esac diff --git a/ubuntu/bootstrap b/ubuntu/bootstrap old mode 100644 new mode 100755 diff --git a/ubuntu/install-desktop-packages b/ubuntu/install-desktop-packages old mode 100644 new mode 100755 index 9160626..723d8d1 --- a/ubuntu/install-desktop-packages +++ b/ubuntu/install-desktop-packages @@ -70,6 +70,3 @@ rm chrome-remote-desktop_current_amd64.deb # Install GhosTTY /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/mkasberg/ghostty-ubuntu/HEAD/install.sh)" - -# Install auto-cpufreq -source <(curl -fsSL https://raw.githubusercontent.com/mapitman/linux-bootstrap/main/generic/auto-cpufreq) diff --git a/ubuntu/install-dev-packages b/ubuntu/install-dev-packages old mode 100644 new mode 100755 diff --git a/ubuntu/install-essential-packages b/ubuntu/install-essential-packages old mode 100644 new mode 100755 diff --git a/ubuntu/install-makemkv b/ubuntu/install-makemkv old mode 100644 new mode 100755 index 6292490..7179962 --- a/ubuntu/install-makemkv +++ b/ubuntu/install-makemkv @@ -6,7 +6,7 @@ if ! type makemkv then MAKEMKV_VERSION="1.17.6" mkdir -p /tmp/makemkv-build - pushd /tmp/makemkv-build + pushd /tmp/makemkv-build || exit curl -O "https://www.makemkv.com/download/makemkv-bin-$MAKEMKV_VERSION.tar.gz" curl -O "https://www.makemkv.com/download/makemkv-oss-$MAKEMKV_VERSION.tar.gz" @@ -16,7 +16,7 @@ then tar xzvf "makemkv-oss-$MAKEMKV_VERSION.tar.gz" tar xjvf ffmpeg-snapshot.tar.bz2 - popd + popd || exit sudo apt-get install -y \ build-essential \ @@ -31,19 +31,19 @@ then yasm \ libfdk-aac-dev - pushd /tmp/makemkv-build/ffmpeg + pushd /tmp/makemkv-build/ffmpeg || exit ./configure --prefix=/tmp/ffmpeg --enable-static --disable-shared --enable-pic --enable-libfdk-aac make install - popd + popd || exit - pushd "/tmp/makemkv-build/makemkv-oss-$MAKEMKV_VERSION" + pushd "/tmp/makemkv-build/makemkv-oss-$MAKEMKV_VERSION" || exit PKG_CONFIG_PATH=/tmp/ffmpeg/lib/pkgconfig ./configure make sudo make install - popd + popd || exit - pushd "/tmp/makemkv-build/makemkv-bin-$MAKEMKV_VERSION" + pushd "/tmp/makemkv-build/makemkv-bin-$MAKEMKV_VERSION" || exit make sudo make install - popd + popd || exit fi diff --git a/ubuntu/install-media-cli-tools b/ubuntu/install-media-cli-tools old mode 100644 new mode 100755 diff --git a/ubuntu/install-optical-disc-packages b/ubuntu/install-optical-disc-packages old mode 100644 new mode 100755