Testing

The Perses Operator uses unit, integration, end-to-end (e2e), and alerting rule tests.

Some test commands use tools installed locally under bin/. Run make build-tools to install all tools, or let the Makefile targets (e.g. make test-unit, make test-integration) install them automatically.

Unit Tests#

Unit tests validate individual functions and utilities using standard Go testing with testify or Ginkgo.

# Run all unit tests
make test-unit

# Run a single test by name (testify)
go test ./internal/metrics/... -run TestNewMetrics -v

# Run a single test by name (Ginkgo)
# --focus matches against Describe/It block descriptions
bin/ginkgo --focus "GetVolumes" -v ./internal/perses/common/...

Integration Tests#

Integration tests use Ginkgo with envtest to spin up a lightweight API server with CRDs installed. These tests validate controller reconcile logic, CRD validation, and resource management.

# Run all integration tests
make test-integration

# Run a single integration test by name
# --focus matches against Ginkgo Describe/It block descriptions
KUBEBUILDER_ASSETS="$(bin/setup-envtest use -p path)" \
  bin/ginkgo --focus "should successfully reconcile" -v ./controllers/...

E2E Tests (kuttl)#

E2E tests use kuttl to validate the operator end-to-end in a real kind cluster, including deployment, resource synchronization, and cleanup.

Prerequisites#

Quick Start#

make e2e-setup    # Create cluster + deploy operator
make test-e2e     # Run tests
make e2e-cleanup  # Tear down

When iterating:

  1. Run make e2e-setup once to create the cluster and deploy the operator.
  2. Run make test-e2e to run the tests.
  3. After code changes, run make e2e-deploy to rebuild and redeploy the operator, then make test-e2e again.

Configuration#

The following Makefile variables can be overridden to customize the e2e environment:

VariableDefaultDescription
KIND_CLUSTER_NAMEkuttl-e2eName of the kind cluster
E2E_TAGGit short SHAImage tag for the operator
E2E_IMGdocker.io/persesdev/perses-operator:<E2E_TAG>Full operator image reference

Test Structure#

Tests are under test/e2e/ following the kuttl convention. Kuttl creates a random namespace per test case for isolation. Steps run sequentially.

test/e2e/
├── kuttl-test.yaml
├── global-datasource/      # Global datasource sync
├── multi-instance-sync/    # Dashboard/datasource sync across instances
├── namespace-isolation/    # Namespace-scoped resource isolation
├── perses-deployment/      # database.sql → Deployment
├── perses-emptydir/        # emptyDir storage
├── perses-statefulset/     # database.file → StatefulSet with PVC
├── perses-volumes/         # Custom volumes and volume mounts
└── resource-update/        # Update existing resources and assert reconciliation
  • To add a new test case, create a directory under test/e2e/.
  • To add steps to an existing test case, add numbered files (e.g. 05-install.yaml, 05-assert.yaml).

Debugging#

# Operator logs
kubectl logs -n perses-operator-system deployment/perses-operator-controller-manager -f

# Run a single test case
bin/kubectl-kuttl test --config test/e2e/kuttl-test.yaml --test perses-statefulset

Alerting Rule Tests#

Alerting rules are validated using promtool. When adding or modifying rules, add corresponding test cases to test/promtool/alerts_test.yaml and run:

make test-alerts

See Developer Guide for the full workflow.

Integration vs E2E Tests#

AspectIntegration TestsE2E Tests
EnvironmentLightweight API server via envtest (no real cluster)Real Kubernetes cluster via kind
ScopeController reconcile logic, CRD validation, status updatesFull operator lifecycle including pod scheduling and networking
SpeedFast (seconds)Slower (minutes, includes cluster setup)
FrameworkGinkgo + envtestkuttl