Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions .github/workflows/test-ubuntu.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
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 -exec shellcheck -x {} \; || true
shellcheck bootstrap || true
Comment thread
mapitman marked this conversation as resolved.
Outdated

docker-test:
name: Docker Test (Ubuntu ${{ matrix.ubuntu-version }})
runs-on: ubuntu-latest
strategy:
matrix:
ubuntu-version: ['20.04', '22.04', '24.04']
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'
"
Comment thread
mapitman marked this conversation as resolved.

smoke-test:
name: Smoke Test - Essential Packages
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Test essential packages installation
run: |
# Test the script can run without errors
sudo bash ubuntu/install-essential-packages || echo "Expected to fail on non-fresh system"

- name: Verify syntax of all scripts
run: |
bash -n bootstrap
bash -n ubuntu/bootstrap
for script in ubuntu/install-*; do
bash -n "$script"
done
for script in generic/*; do
bash -n "$script"
done
Comment thread
mapitman marked this conversation as resolved.
Outdated
65 changes: 65 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -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 := 20.04 22.04 24.04

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 22.04)

test-auto: ## Run automated tests on Ubuntu 22.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 (20.04, 22.04, 24.04)
@./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 bootstrap || true; \
shellcheck ubuntu/bootstrap || true; \
find ubuntu/ -type f -name 'install-*' -exec shellcheck {} \; || true; \
find generic/ -type f -exec shellcheck {} \; || true; \
Comment thread
mapitman marked this conversation as resolved.
Outdated
else \
echo "shellcheck not installed. Install with: sudo apt-get install shellcheck"; \
exit 1; \
fi

Comment thread
mapitman marked this conversation as resolved.
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
Comment thread
mapitman marked this conversation as resolved.
195 changes: 195 additions & 0 deletions test/README.md
Original file line number Diff line number Diff line change
@@ -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

Copilot AI Dec 20, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GitHub Actions checkout action uses @V3, but a newer version @v4 is already used in other jobs in this same file. For consistency and to use the latest stable version, update this to @v4.

Suggested change
- uses: actions/checkout@v3
- uses: actions/checkout@v4

Copilot uses AI. Check for mistakes.

- 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
6 changes: 6 additions & 0 deletions test/docker/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Don't copy test artifacts into test containers
test/
.git/
.github/
*.md
Comment on lines +1 to +5

Copilot AI Dec 20, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The .dockerignore file excludes all markdown files with *.md, which means test/README.md and test/qemu/README.md won't be copied into containers. While this is likely intentional for reducing image size, it may cause confusion if developers expect documentation to be available inside test containers. Consider being more specific (e.g., excluding only root-level README.md) or add a comment explaining this choice.

Suggested change
# Don't copy test artifacts into test containers
test/
.git/
.github/
*.md
# Don't copy test artifacts or top-level docs into test containers
test/
.git/
.github/
README.md

Copilot uses AI. Check for mistakes.
LICENSE
36 changes: 36 additions & 0 deletions test/docker/Dockerfile.ubuntu
Original file line number Diff line number Diff line change
@@ -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"]
Loading
Loading