Testing
Tazuna’s tests are split into 3 layers: unit / integration / e2e. Each layer corresponds 1:1 with a make target; unit always runs on PRs (CI), while e2e is a manual layer that assumes KinD.
Layers and How to Run
| Layer | Command | Targets | Prerequisites |
|---|---|---|---|
| unit | make test | go test ./... | None. Runs on every push / PR via the CI workflow in GitHub Actions. |
| integration | make test-integration | go test -tags=integration ./... | None. Additional tests tagged with the integration build tag are targets. |
| e2e | make test-e2e | go test -tags=e2e -count=1 ./test/e2e/... | KinD cluster. Internally runs make build && make devenv-create. |
| All | make test-all | unit → integration → e2e | Same as e2e |
| Coverage | make cover | Runs unit tests with -race -covermode=atomic -coverprofile=coverage.out, then outputs a summary | None |
In CI (.github/workflows/ci.yaml), go test -race -covermode=atomic -coverprofile=coverage.out ./... is run, so the contents largely match make cover.
Unit Tests
Written as *_test.go in every package. Standard Go tests. They have no dependency on KinD or external CLIs, and go test ./... is self-contained.
PR review requires this layer to be green as a prerequisite.
Integration Tests
Additional tests tagged with the integration build tag. Run with make test-integration. The place to isolate scenarios that have no external dependencies but are too heavy for unit tests.
Running go test -tags=integration ./... directly is equivalent.
E2E Tests
Real-cluster tests placed in test/e2e/. Isolated by the e2e build tag, with only ./test/e2e/... targeted.
Running make test-e2e internally runs the following in order.
make build(build./tazuna)make devenv-create(stand up the KinD clustertazuna, or switch context if one already exists)go test -tags=e2e -count=1 ./test/e2e/...
-count=1 is set so that e2e tests are not cached and actually run every time. The KinD cluster is cleaned up by make devenv-destroy (kind delete cluster --name tazuna).
KinD Cluster Specifications
| Item | Value |
|---|---|
| Cluster name | tazuna |
| kubeconfig context | kind-tazuna |
| Config file | .github/kind-config.yaml |
Because CI and developer local environments share the same KinD config, e2e that passes locally generally also passes in CI.
Test Data
E2E fixtures are placed per-case under test/e2e/testdata/. Each case directory holds a tazuna.yaml alongside the actual content (kustomize/ / helmfile/ etc.) corresponding to its type.
test/e2e/testdata/
├── kustomize-minimal/ # minimal case for type: kustomize
├── helmfile-minimal/ # minimal case for type: helmfile
├── parallel-minimal/ # type: parallel
├── testplugin-minimal/ # basic Test plugin (WaitUntil/ExistNonExist)
├── testplugin-cel/ # case with complex CEL expressions in WaitUntil
├── tags-filter-minimal/ # --tags filter
├── state-minimal/ # state list/diff/sync
├── state-modified/ # "modified" judgment in state diff
├── destroy-minimal/ # tazuna destroy
└── check-invalid/ # tazuna check error cases
When adding a new feature, the common flow is to add a corresponding fixture directory with a single minimal tazuna.yaml, and add a *_test.go under test/e2e/.
Lint
make lint
Simply calls golangci-lint run. The golangci-lint version is managed via mise.toml, so running mise install is sufficient — no additional steps required.
CI also runs the same golangci-lint. Running it locally before opening a PR reduces back-and-forth.