This guide covers testing patterns, fixtures, and best practices for incus-compose.
- gotestsum - required to run tests via just; install with
go install gotest.tools/gotestsum@latest - just - must be a recent version; the one shipped with Debian Trixie is too old and will not work
Use just --list to see all available commands. Below is the complete reference:
Run with:
just testTests use a dedicated cache project (incus-compose-tests-cache) separate from the CLI's image cache (the default project unless --image-cache is set). This keeps test images isolated and avoids polluting the user's cache.
The test cache is configured via ClientProvideConnection in test setup, pointing to a test-specific project.
The nested Incus environment is configured via .env file:
INCUS_REMOTE- The remote to use.TEST_PROCS(default 2) - number of tests to run in parallel.INCUS_COMPOSE_WORKERS(default 4) - number of resources to create in parallel per test.
There's also just test-slow which includes slow (long-running) tests.
| Command | Description |
|---|---|
just test |
Run all tests against nested Incus (preferred also runs in CI) |
just test ./client/... |
Run tests for specific package |
just test -v -run TestName |
Run specific test with verbose output |
just test-local |
Run unit tests only (no Incus connection required) |
just test-slow |
Run tests that take long to run |
just update-snapshots |
Update all snapshot test files |
just update-snapshots ./cmd/incus-compose/... |
Update snapshots for specific package |
just update-slow-snapshots |
Update snapshot for slow test files |
| Command | Description |
|---|---|
just build |
Build the binary |
just run <args> |
Run incus-compose via go run (uses .env) |
just run-local <args> |
Run against local Incus (ignores .env) |
just incus <args> |
Run commands in the nested Incus container |
| Command | Description |
|---|---|
just lint |
Lint all files with golangci-lint |
just fix |
Fix lint issues with golangci-lint |
just pre-commit |
Run before committing (tidy, lint, test) |
| Command | Description |
|---|---|
just dev-install |
Create nested Incus dev environment |
Tests live alongside the code they test:
client/
├── client.go
├── client_test.go # Tests for client.go
├── resources.go
└── resources_test.go # Tests for resources.go
project/
├── project.go
└── project_test.go # Tests for project.go
Unit tests use mock resources that implement client.ResourceOperation interface. They require no Incus connection and run fast.
Examples: client/operation_test.go, client/resources_test.go
Run with:
just test-localMocks implement the same interfaces as real resources:
type MockInstance struct {
name string
kind string
priority int
exists bool
done bool
error error
}
func (m *MockInstance) Name() string { return m.name }
func (m *MockInstance) Kind() string { return m.kind }
func (m *MockInstance) Priority() int { return m.priority }
func (m *MockInstance) Exists() bool { return m.exists }
func (m *MockInstance) Done() bool { return m.done }
func (m *MockInstance) Error() error { return m.error }
func (m *MockInstance) Handle() error { return m.error }Located in test/fixtures/. Each fixture is a minimal compose scenario.
simple-nginx/- Simplest casewordpress/- Multi-service with volumeswith_profiles/- Profile testingwith_env/- Environment variable testingwith-secrets/- Secrets management testingwith-restart/- Restart policies testing
Snapshot portability: Normalize absolute paths before snapshotting:
output = strings.ReplaceAll(output, fixturePath, "$FIXTURE_PATH")Self-contained fixtures: Define env vars like $USER or $HOME in .env to avoid OS dependencies:
USER=testuser
HOME=/home/testuserPure YAML: Compose files should be pure YAML without comments:
services:
web:
image: images:alpine/edge
ports:
- "8080:80"Snapshots live in test/snapshots/ and are named by test function and case.
Update snapshots:
just update-snapshotsSnapshot naming: TestFunctionName_TestCase.yaml
# Run a single test verbosely
just test -v -run TestInstanceSecretSuite
# Run tests for a specific package
just test ./client/...
# Quick validation before commit
just pre-commit
# Test a compose file
just run -f test/fixtures/simple-nginx/compose.yaml config- Test isolation - Each test gets fresh resources via
SetupTest() - Error aggregation - Use
errors.Join()for batch operation errors - Priority testing - Verify creation/deletion order respects priorities
- Mock consistency - Mocks should behave like real resources
- Fixture reuse - Share fixtures across tests but keep them minimal
- Snapshot hygiene - Review snapshot diffs carefully during updates
- Contributing - coding, style, and workflow rules
- Architecture - the design these tests exercise
- Client Package - Stack and resource internals