Initial commit: Add documentation and move to docs/ directory
This commit is contained in:
565
docs/TESTING.md
Normal file
565
docs/TESTING.md
Normal file
@@ -0,0 +1,565 @@
|
||||
# Testing Strategy for Dokku Docker Compose Plugin
|
||||
|
||||
## Test Types
|
||||
|
||||
### 1. Plugin Integration Tests
|
||||
**Purpose**: Test integration with various Dokku plugins
|
||||
**Location**: `tests/integration/plugins/`
|
||||
**What to test**:
|
||||
- Plugin detection and selection
|
||||
- Configuration mapping from docker-compose to plugin
|
||||
- Service linking with plugins
|
||||
- Fallback behavior when plugins are not available
|
||||
- Version-specific plugin features
|
||||
|
||||
### 2. Unit Tests
|
||||
**Purpose**: Test individual functions in isolation
|
||||
**Tools**: [bats-core](https://github.com/bats-core/bats-core) (Bash Automated Testing System)
|
||||
**Location**: `tests/unit/`
|
||||
**What to test**:
|
||||
- Small, pure functions
|
||||
- Input validation
|
||||
- Output formatting
|
||||
- Error conditions
|
||||
|
||||
Example test file structure:
|
||||
```
|
||||
tests/unit/
|
||||
├── test_helpers.bats
|
||||
├── test_validation.bats
|
||||
└── test_parser.bats
|
||||
```
|
||||
|
||||
### 3. Integration Tests
|
||||
**Purpose**: Test interactions between components
|
||||
**Tools**: bats-core, Docker-in-Docker (DinD)
|
||||
**Location**: `tests/integration/`
|
||||
**What to test**:
|
||||
- Component interactions
|
||||
- File system operations
|
||||
- Command execution
|
||||
- Docker API interactions
|
||||
|
||||
### 4. End-to-End (E2E) Tests
|
||||
**Purpose**: Test the plugin in a real Dokku environment
|
||||
**Tools**:
|
||||
- [Dokku Test Suite](http://dokku.viewdocs.io/dokku/development/testing/)
|
||||
- Docker Compose test environments
|
||||
**Location**: `tests/e2e/`
|
||||
**What to test**:
|
||||
- Full plugin commands
|
||||
- Real Dokku app creation
|
||||
- Network and volume handling
|
||||
- Multi-service scenarios
|
||||
|
||||
## Test Environment
|
||||
|
||||
### Plugin-Specific Test Setup
|
||||
For testing with different Dokku plugins, we'll use a matrix approach:
|
||||
|
||||
```yaml
|
||||
# .github/workflows/test-plugins.yml
|
||||
name: Test with Dokku Plugins
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
test-plugins:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
plugin: [postgres, redis, memcached, mysql, mariadb, mongo]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Dokku
|
||||
run: |
|
||||
wget https://raw.githubusercontent.com/dokku/dokku/v0.30.0/bootstrap.sh
|
||||
sudo DOKKU_TAG=v0.30.0 bash bootstrap.sh
|
||||
- name: Install ${{ matrix.plugin }} plugin
|
||||
run: |
|
||||
sudo dokku plugin:install https://github.com/dokku/dokku-${{ matrix.plugin }}.git ${{ matrix.plugin }}
|
||||
- name: Run plugin tests
|
||||
run: |
|
||||
PLUGIN=${{ matrix.plugin }} bats tests/integration/plugins/
|
||||
```
|
||||
|
||||
### Prerequisites
|
||||
- Docker
|
||||
- Docker Compose
|
||||
- bats-core (`brew install bats-core` on macOS)
|
||||
- yq (`brew install yq`)
|
||||
- jq (`brew install jq`)
|
||||
|
||||
### Setup
|
||||
1. Clone the repository
|
||||
2. Run `make test-deps` to install test dependencies
|
||||
3. Run `make test` to execute all tests
|
||||
|
||||
## Test Structure
|
||||
|
||||
### Test Data
|
||||
Sample Docker Compose files for testing:
|
||||
```
|
||||
testdata/
|
||||
├── simple/
|
||||
│ ├── docker-compose.yml
|
||||
│ └── expected/
|
||||
├── multi-service/
|
||||
│ ├── docker-compose.yml
|
||||
│ └── expected/
|
||||
└── edge-cases/
|
||||
├── invalid-yaml.yml
|
||||
└── unsupported-version.yml
|
||||
```
|
||||
|
||||
### Test Helpers
|
||||
Create reusable test utilities in `tests/test_helper.bash`:
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
setup() {
|
||||
load 'test_helper/bats-support/load'
|
||||
load 'test_helper/bats-assert/load'
|
||||
|
||||
# Set up test environment
|
||||
TEST_DIR="$(mktemp -d)"
|
||||
cd "$TEST_DIR" || exit 1
|
||||
}
|
||||
|
||||
teardown() {
|
||||
# Clean up test environment
|
||||
rm -rf "$TEST_DIR"
|
||||
}
|
||||
|
||||
# Helper functions...
|
||||
```
|
||||
|
||||
## Writing Plugin Integration Tests
|
||||
|
||||
### Example Plugin Test
|
||||
```bash
|
||||
@test "import with postgres plugin" {
|
||||
# Setup
|
||||
local test_dir="$(mktemp -d)"
|
||||
cd "$test_dir" || exit 1
|
||||
|
||||
# Create test compose file
|
||||
cat > docker-compose.yml <<EOL
|
||||
version: '3.8'
|
||||
services:
|
||||
app:
|
||||
image: nginx:alpine
|
||||
environment:
|
||||
- DB_URL=postgres://user:pass@db:5432/mydb
|
||||
depends_on:
|
||||
- db
|
||||
db:
|
||||
image: postgres:13
|
||||
environment:
|
||||
POSTGRES_USER: user
|
||||
POSTGRES_PASSWORD: pass
|
||||
POSTGRES_DB: mydb
|
||||
EOL
|
||||
|
||||
# Run import
|
||||
run dokku docker-compose:import docker-compose.yml
|
||||
assert_success
|
||||
|
||||
# Verify postgres plugin was used
|
||||
run dokku postgres:list
|
||||
assert_success
|
||||
assert_output --partial "app-db"
|
||||
|
||||
# Verify linking
|
||||
run dokku postgres:linked app
|
||||
assert_success
|
||||
assert_output --partial "app-db"
|
||||
|
||||
# Cleanup
|
||||
cd - >/dev/null
|
||||
rm -rf "$test_dir"
|
||||
}
|
||||
```
|
||||
|
||||
### Testing Plugin Installation Instructions
|
||||
|
||||
```bash
|
||||
@test "show installation instructions when plugin is missing" {
|
||||
# Setup
|
||||
local test_dir="$(mktemp -d)"
|
||||
cd "$test_dir" || exit 1
|
||||
|
||||
# Create test compose file
|
||||
cat > docker-compose.yml <<EOL
|
||||
version: '3.8'
|
||||
services:
|
||||
db:
|
||||
image: postgres:13
|
||||
EOL
|
||||
|
||||
# Mock dokku command to simulate missing plugin
|
||||
dokku() {
|
||||
if [[ "$1" == "plugin:list" ]]; then
|
||||
echo " 00_dokku-standard 0.30.0 enabled dokku core standard plugin"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
export -f dokku
|
||||
|
||||
# Run import and capture output
|
||||
run dokku docker-compose:import docker-compose.yml
|
||||
|
||||
# Assert
|
||||
assert_failure
|
||||
assert_output --partial "Required plugin 'postgres' is not installed"
|
||||
assert_output --regexp "To install.*dokku plugin:install https://github.com/dokku/dokku-postgres.git postgres"
|
||||
assert_output --partial "Use --skip-plugin=postgres to continue without this plugin"
|
||||
|
||||
# Cleanup
|
||||
cd - >/dev/null
|
||||
rm -rf "$test_dir"
|
||||
}
|
||||
|
||||
@test "continue with --skip-plugin flag" {
|
||||
# Setup
|
||||
local test_dir="$(mktemp -d)"
|
||||
cd "$test_dir" || exit 1
|
||||
|
||||
# Create test compose file
|
||||
cat > docker-compose.yml <<EOL
|
||||
version: '3.8'
|
||||
services:
|
||||
app:
|
||||
image: nginx:alpine
|
||||
depends_on:
|
||||
- db
|
||||
db:
|
||||
image: postgres:13
|
||||
EOL
|
||||
|
||||
# Mock dokku command to simulate missing plugin
|
||||
dokku() {
|
||||
if [[ "$1" == "plugin:list" ]]; then
|
||||
echo " 00_dokku-standard 0.30.0 enabled dokku core standard plugin"
|
||||
return 0
|
||||
fi
|
||||
# Allow other dokku commands to pass through
|
||||
command dokku "$@"
|
||||
}
|
||||
export -f dokku
|
||||
|
||||
# Run import with skip plugin flag
|
||||
run dokku docker-compose:import --skip-plugin=postgres docker-compose.yml
|
||||
|
||||
# Assert
|
||||
assert_success
|
||||
assert_output --partial "Skipping postgres plugin as requested"
|
||||
assert_output --partial "Using container for service: db"
|
||||
|
||||
# Cleanup
|
||||
cd - >/dev/null
|
||||
rm -rf "$test_dir"
|
||||
}
|
||||
|
||||
### Testing Fallback Behavior
|
||||
```bash
|
||||
@test "fallback to container when plugin not available" {
|
||||
# Setup
|
||||
local test_dir="$(mktemp -d)"
|
||||
cd "$test_dir" || exit 1
|
||||
|
||||
# Create test compose file
|
||||
cat > docker-compose.yml <<EOL
|
||||
version: '3.8'
|
||||
services:
|
||||
app:
|
||||
image: nginx:alpine
|
||||
depends_on:
|
||||
- db
|
||||
db:
|
||||
image: postgres:13
|
||||
EOL
|
||||
|
||||
# Uninstall postgres plugin if installed
|
||||
if dokku plugin:installed postgres; then
|
||||
skip "Postgres plugin is installed"
|
||||
fi
|
||||
|
||||
# Run import
|
||||
run dokku docker-compose:import docker-compose.yml
|
||||
assert_success
|
||||
|
||||
# Verify container was created instead of using plugin
|
||||
run docker ps --format '{{.Names}}' | grep app-db
|
||||
assert_success
|
||||
|
||||
# Cleanup
|
||||
cd - >/dev/null
|
||||
rm -rf "$test_dir"
|
||||
}
|
||||
```
|
||||
|
||||
## Writing Tests
|
||||
|
||||
### Example Unit Tests for Plugin Detection
|
||||
|
||||
```bash
|
||||
@test "get_plugin_installation_command returns correct command" {
|
||||
# Test with postgres
|
||||
run get_plugin_installation_command postgres
|
||||
assert_success
|
||||
assert_output "dokku plugin:install https://github.com/dokku/dokku-postgres.git postgres"
|
||||
|
||||
# Test with redis
|
||||
run get_plugin_installation_command redis
|
||||
assert_success
|
||||
assert_output "dokku plugin:install https://github.com/dokku/dokku-redis.git redis"
|
||||
}
|
||||
|
||||
@test "check_plugin_installed detects missing plugin" {
|
||||
# Mock dokku command for missing plugin
|
||||
dokku() {
|
||||
if [[ "$1" == "plugin:list" ]]; then
|
||||
echo " 00_dokku-standard 0.30.0 enabled dokku core standard plugin"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
export -f dokku
|
||||
|
||||
run check_plugin_installed postgres
|
||||
assert_failure
|
||||
assert_output --partial "postgres plugin is not installed"
|
||||
}
|
||||
|
||||
@test "generate_skip_plugins_option generates correct flags" {
|
||||
# Test single plugin
|
||||
run generate_skip_plugins_option "postgres"
|
||||
assert_success
|
||||
assert_output "--skip-plugin=postgres"
|
||||
|
||||
# Test multiple plugins
|
||||
run generate_skip_plugins_option "postgres redis"
|
||||
assert_success
|
||||
assert_output "--skip-plugin=postgres --skip-plugin=redis"
|
||||
}
|
||||
```
|
||||
|
||||
### Example Plugin Unit Test
|
||||
```bash
|
||||
@test "detect_postgres_plugin" {
|
||||
# Mock dokku command
|
||||
dokku() {
|
||||
if [[ "$1" == "plugin:list" ]]; then
|
||||
echo " 00_dokku-standard 0.30.0 enabled dokku core standard plugin"
|
||||
echo " postgres 1.15.0 enabled dokku postgres service plugin"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
export -f dokku
|
||||
|
||||
# Run test
|
||||
run detect_plugin 'postgres:13'
|
||||
|
||||
# Assert
|
||||
assert_success
|
||||
assert_output "postgres"
|
||||
}
|
||||
|
||||
@test "map_postgres_config" {
|
||||
# Setup test data
|
||||
local service_config=$(cat <<EOL
|
||||
{
|
||||
"image": "postgres:13",
|
||||
"environment": {
|
||||
"POSTGRES_USER": "user",
|
||||
"POSTGRES_PASSWORD": "pass",
|
||||
"POSTGRES_DB": "mydb"
|
||||
},
|
||||
"volumes": ["pgdata:/var/lib/postgresql/data"]
|
||||
}
|
||||
EOL
|
||||
)
|
||||
|
||||
# Run test
|
||||
run map_plugin_config "postgres" "$service_config"
|
||||
|
||||
# Assert
|
||||
assert_success
|
||||
assert_line "--config-opt POSTGRES_USER=user"
|
||||
assert_line "--config-opt POSTGRES_PASSWORD=pass"
|
||||
assert_line "--config-opt POSTGRES_DB=mydb"
|
||||
}
|
||||
```
|
||||
|
||||
### Example Unit Test
|
||||
```bash
|
||||
#!/usr/bin/env bats
|
||||
|
||||
load 'test_helper'
|
||||
|
||||
@test "validate_compose_file with valid file" {
|
||||
# Setup
|
||||
cat > docker-compose.yml <<EOL
|
||||
version: '3.8'
|
||||
services:
|
||||
web:
|
||||
image: nginx:alpine
|
||||
EOL
|
||||
|
||||
# Execute
|
||||
run validate_compose_file "docker-compose.yml"
|
||||
|
||||
# Assert
|
||||
assert_success
|
||||
assert_output --partial "Valid compose file"
|
||||
}
|
||||
```
|
||||
|
||||
### Example Integration Test
|
||||
```bash
|
||||
@test "import creates dokku apps from compose file" {
|
||||
# Setup test compose file
|
||||
# ...
|
||||
|
||||
# Execute import
|
||||
run dokku docker-compose:import docker-compose.yml
|
||||
|
||||
# Assert apps were created
|
||||
run dokku apps:list
|
||||
assert_success
|
||||
assert_output --partial "web"
|
||||
assert_output --partial "db"
|
||||
}
|
||||
```
|
||||
|
||||
## Continuous Integration
|
||||
|
||||
### GitHub Actions
|
||||
Example workflow (`.github/workflows/test.yml`):
|
||||
```yaml
|
||||
name: Test
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
services:
|
||||
docker:
|
||||
image: docker:dind
|
||||
options: >-
|
||||
--privileged
|
||||
--network=host
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Docker
|
||||
run: |
|
||||
docker --version
|
||||
docker-compose --version
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y bats jq
|
||||
sudo pip install yq
|
||||
|
||||
- name: Run unit tests
|
||||
run: make test-unit
|
||||
|
||||
- name: Run integration tests
|
||||
run: make test-integration
|
||||
|
||||
- name: Run e2e tests
|
||||
run: make test-e2e
|
||||
```
|
||||
|
||||
## Test Coverage
|
||||
|
||||
### Coverage Reporting
|
||||
Use `kcov` for code coverage:
|
||||
```bash
|
||||
# Install kcov
|
||||
brew install kcov
|
||||
|
||||
# Run tests with coverage
|
||||
make coverage
|
||||
```
|
||||
|
||||
### Coverage Reports
|
||||
- HTML reports in `coverage/`
|
||||
- Publish to codecov.io or similar service
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Test Isolation**: Each test should be independent
|
||||
2. **Descriptive Names**: Use clear, descriptive test names
|
||||
3. **Minimal Fixtures**: Keep test data minimal and focused
|
||||
4. **Test Edge Cases**: Include tests for error conditions
|
||||
5. **Fast Feedback**: Keep tests fast for quick iteration
|
||||
|
||||
## Debugging Tests
|
||||
|
||||
Run a single test file:
|
||||
```bash
|
||||
bats tests/unit/test_parser.bats
|
||||
```
|
||||
|
||||
Run with debug output:
|
||||
```bash
|
||||
bats --tap tests/
|
||||
```
|
||||
|
||||
## Performance Testing
|
||||
|
||||
For large compose files, add performance benchmarks:
|
||||
```bash
|
||||
@test "import handles large compose files quickly" {
|
||||
# Generate large compose file
|
||||
# ...
|
||||
|
||||
# Time the import
|
||||
run time dokku docker-compose:import large-compose.yml
|
||||
|
||||
# Assert it completes within time limit
|
||||
assert_success
|
||||
assert_output --regexp 'real\s+0:[0-4]\d\.[0-9]s' # Less than 5 seconds
|
||||
}
|
||||
```
|
||||
|
||||
## Mocking
|
||||
|
||||
For testing without real Dokku/Docker:
|
||||
|
||||
1. Create mocks in `tests/mocks/`
|
||||
2. Override commands in test setup:
|
||||
```bash
|
||||
dokku() {
|
||||
echo "[MOCK] dokku $*" >> "$TEST_MOCK_LOG"
|
||||
case "$1" in
|
||||
apps:exists)
|
||||
return 1 # App doesn't exist
|
||||
;;
|
||||
--version)
|
||||
echo "0.30.0"
|
||||
;;
|
||||
*)
|
||||
echo "Unexpected dokku command: $*"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
export -f dokku
|
||||
```
|
||||
|
||||
## Test Maintenance
|
||||
|
||||
1. Update tests when adding new features
|
||||
2. Review test failures carefully
|
||||
3. Keep test data up-to-date
|
||||
4. Document test cases in pull requests
|
||||
Reference in New Issue
Block a user