Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
170 changes: 170 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
name: CI Tests

on:
push:
branches: [ main, master, develop ]
pull_request:
branches: [ main, master, develop ]
workflow_dispatch:

jobs:
syntax-and-lint:
name: Syntax and Lint Checks
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Install ShellCheck
run: sudo apt-get update && sudo apt-get install -y shellcheck

- name: Check bash syntax
run: |
echo "Checking srv-ctl.sh..."
bash -n srv-ctl.sh
echo "Checking lib/os-utils.sh..."
bash -n lib/os-utils.sh
echo "Checking lib/storage.sh..."
bash -n lib/storage.sh

- name: Prepare test config
run: |
# Use test config for validation
cp tests/fixtures/config.local.test config.local

- name: Run ShellCheck
run: |
echo "ShellCheck srv-ctl.sh..."
shellcheck -x srv-ctl.sh
echo "ShellCheck lib/os-utils.sh..."
shellcheck -x lib/os-utils.sh
echo "ShellCheck lib/storage.sh..."
shellcheck -x lib/storage.sh

unit-tests:
name: Unit Tests
runs-on: ubuntu-latest
needs: syntax-and-lint

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Install bats
run: npm install -g bats

- name: Run unit tests
run: |
echo "Running unit tests..."
bats tests/unit/test-os-utils.bats
bats tests/unit/test-storage.bats

integration-tests:
name: Integration Tests (${{ matrix.os }})
runs-on: ubuntu-latest
needs: unit-tests

strategy:
fail-fast: false
matrix:
os:
- debian:10
- debian:11
- debian:12
- debian:13
- ubuntu:18.04
- ubuntu:20.04
- ubuntu:22.04
- ubuntu:24.04

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Run integration tests in Docker
run: |
docker run --rm \
--privileged \
-v ${{ github.workspace }}:/workspace \
-w /workspace \
${{ matrix.os }} \
bash -c '
set -euo pipefail

# Update package lists
if command -v apt-get &>/dev/null; then
apt-get update -qq
fi

# Install dependencies
echo "Installing dependencies..."
if command -v apt-get &>/dev/null; then
apt-get install -y -qq \
bash \
cryptsetup \
lvm2 \
dosfstools \
ntfs-3g \
util-linux \
sudo
fi

# Setup test environment
echo "Setting up test environment..."
bash tests/fixtures/setup-test-env.sh

# Run integration tests
echo "Running LUKS tests..."
bash tests/integration/test-luks.sh

echo "Running LVM tests..."
bash tests/integration/test-lvm.sh

echo "Running mount tests..."
bash tests/integration/test-mount.sh

# Cleanup
echo "Cleaning up..."
bash tests/fixtures/cleanup-test-env.sh

echo "All integration tests passed on ${{ matrix.os }}!"
'

- name: Upload test logs on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: test-logs-${{ replace(matrix.os, ':', '-') }}
path: |
/tmp/test_env.conf
/var/log/syslog
if-no-files-found: ignore

test-summary:
name: Test Summary
runs-on: ubuntu-latest
needs: [syntax-and-lint, unit-tests, integration-tests]
if: always()

steps:
- name: Check test results
run: |
echo "Test Results:"
echo " Syntax and Lint: ${{ needs.syntax-and-lint.result }}"
echo " Unit Tests: ${{ needs.unit-tests.result }}"
echo " Integration Tests: ${{ needs.integration-tests.result }}"

if [[ "${{ needs.syntax-and-lint.result }}" != "success" ]] || \
[[ "${{ needs.unit-tests.result }}" != "success" ]] || \
[[ "${{ needs.integration-tests.result }}" != "success" ]]; then
echo "Some tests failed!"
exit 1
else
echo "All tests passed!"
fi
97 changes: 97 additions & 0 deletions .github/workflows/vm-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
name: VM Integration Tests

on:
push:
branches: [ main, develop, v2-refactor ]
pull_request:
branches: [ main, develop ]
workflow_dispatch: # Manual trigger
schedule:
- cron: '0 2 * * 0' # Weekly on Sunday at 2 AM

jobs:
# Fast Docker tests run first (gate for VM tests)
docker-tests:
name: Docker Tests (Quick Gate)
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4

- name: Run Docker Tests
run: ./tests/docker/run-docker-tests.sh

# Full VM tests with multiple OS versions (run in parallel)
vm-tests:
name: VM Tests - ${{ matrix.os }}
needs: docker-tests # Only run if Docker tests pass
runs-on: ubuntu-latest
strategy:
fail-fast: false # Continue testing other OSes even if one fails
matrix:
os:
- ubuntu-22.04
- ubuntu-24.04
- debian-11
- debian-12

steps:
- uses: actions/checkout@v4

- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Install VM dependencies
run: |
sudo apt-get update
sudo apt-get install -y qemu-system-x86 qemu-utils cloud-image-utils

- name: Cache VM images
uses: actions/cache@v3
with:
path: ~/.cache/vm-images
key: vm-images-${{ matrix.os }}-${{ hashFiles('tests/vm/Vagrantfile') }}

- name: Download cloud image
run: |
mkdir -p ~/.cache/vm-images
./tests/vm/download-image.sh ${{ matrix.os }}

- name: Run VM tests
timeout-minutes: 15
run: |
./tests/vm/run-vm-tests.sh ${{ matrix.os }}

- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: vm-test-results-${{ matrix.os }}
path: tests/vm/results/

- name: Cleanup
if: always()
run: ./tests/vm/cleanup.sh

# Summary job
test-summary:
name: Test Summary
needs: [docker-tests, vm-tests]
if: always()
runs-on: ubuntu-latest
steps:
- name: Check test results
run: |
echo "Docker Tests: ${{ needs.docker-tests.result }}"
echo "VM Tests: ${{ needs.vm-tests.result }}"

if [ "${{ needs.docker-tests.result }}" != "success" ]; then
echo "❌ Docker tests failed"
exit 1
fi

if [ "${{ needs.vm-tests.result }}" != "success" ]; then
echo "⚠️ Some VM tests failed (check matrix)"
exit 1
fi

echo "✅ All tests passed!"
42 changes: 40 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ Small utility to manage home server services dependent on encrypted storage.

- **cryptsetup**: Version 2.4.0+ (supports both LUKS and BitLocker encryption)
- **lvm2**: Required only if using LVM volumes
- **Root privileges**: Script must be run as root
- **GNU coreutils**: Required for version comparison (`sort -V`)
- **systemd**: Required for service management
- **Root privileges**: Script must be run as root for start/stop/unlock operations

## Configuration

Expand Down Expand Up @@ -65,10 +67,12 @@ sudo ./srv-ctl.sh start # Start all services and mount devices
sudo ./srv-ctl.sh stop # Stop all services and unmount devices
sudo ./srv-ctl.sh unlock-only # Only unlock and mount devices
sudo ./srv-ctl.sh stop-services-only # Only stop services
./srv-ctl.sh validate-config # Validate configuration without making changes
./srv-ctl.sh validate-config # Validate configuration (no root required)
./srv-ctl.sh help # Show help message
```

**Note**: The `validate-config` command does not require root privileges unless key files have restricted permissions.

## Migration from Old Format

If you have an existing `config.local` from an earlier version, you'll need to update it to the new format. The main changes:
Expand All @@ -87,3 +91,37 @@ If you have an existing `config.local` from an earlier version, you'll need to u
- Enhanced validation and error handling

Use `./srv-ctl.sh validate-config` to check your configuration after updating.

## Development & Testing

The project includes comprehensive tests with Docker and VM-based testing:

```bash
# Run local tests (no root required)
./tests/run-tests.sh

# Run tests in Docker (isolated, safe)
./tests/docker/run-docker-tests.sh

# Run full VM tests (CI only, multi-OS)
./tests/vm/run-vm-tests.sh ubuntu-22.04
```

See [`tests/README.md`](tests/README.md) for detailed testing documentation.

## Project Structure

```
srv-ctl/
├── srv-ctl.sh # Main script
├── lib/
│ ├── os-utils.sh # OS-level utilities
│ └── storage.sh # Storage operations
├── config.local.template # Configuration template
└── tests/ # Test suite
```

## License

See repository for license information.

Loading
Loading