This document covers the testing infrastructure for the Team Operator.
The Team Operator uses a two-tier local integration testing strategy:
What it is: Envtest uses a lightweight, embedded Kubernetes API server (etcd + kube-apiserver) to test CRD schema and API storage without a full cluster or running controller.
When to use: For testing CRD schema validation and API storage. No controller reconciler runs in the test environment.
Execution time: Seconds
What it tests:
- CRD schema validation
- API object creation and storage
- Resource serialization/deserialization
- Basic CRUD operations through the API
What it is: Kind (Kubernetes IN Docker) creates a real Kubernetes cluster with Docker containers.
When to use: For end-to-end testing, Helm chart deployment, and integration with other Kubernetes components.
Execution time: Minutes
What it tests:
- Helm chart deployment
- Full operator lifecycle
- Inter-pod communication
- Actual resource creation in Kubernetes
Envtest binaries are automatically downloaded by the Makefile:
make envtestInstall these tools:
# Install kind
# macOS
brew install kind
# Linux
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.23.0/kind-linux-amd64
chmod +x ./kind
sudo mv ./kind /usr/local/bin/kind
# Install kubectl (if not already installed)
# macOS
brew install kubectl
# Install Helm
# macOS
brew install helm
# Linux
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
# Verify Docker is running
docker infoRun all Go tests including envtest-based controller tests:
make go-testOr run the full test suite with code generation:
make testTo run only the Ginkgo-based envtest suite:
KUBEBUILDER_ASSETS="$(pwd)/$(bin/setup-envtest use 1.29.x --bin-dir bin -p path)" \
go test -v ./internal/controller/core/... -run "TestControllers"Create a kind cluster and run integration tests:
# Create kind cluster
make kind-create
# Run integration tests
make test-kind
# Clean up
make kind-deleteFor a full clean run:
make test-kind-fullRun both unit tests and integration tests:
make test-integrationThe envtest suite sets up a test environment with:
- Embedded etcd and kube-apiserver
- All operator CRDs loaded
- A
posit-teamnamespace for test resources
Example test file: internal/controller/core/site_envtest_test.go
var _ = Describe("Site Controller (envtest)", func() {
Context("When creating a Site CR", func() {
It("Should be able to create and retrieve a Site CR", func() {
// Test code using k8sClient from suite_test.go
})
})
})The kind test script:
- Verifies prerequisites (kind, kubectl, helm)
- Installs CRDs
- Deploys the operator via Helm
- Creates test resources
- Validates reconciliation
- Cleans up
For iterative development, keep the kind cluster running between test runs. Don't recreate it each time.
Initial setup (run once):
make kind-setupThis creates the cluster, builds the operator image, loads it into kind, and deploys it via Helm.
After making code changes, rebuild and redeploy:
make kind-setup # rebuilds image, reloads into kind, helm upgradeRun tests against the live cluster:
make kind-testTear down when done:
make kind-teardown # removes Helm release and namespaces
# (also deletes the kind cluster)This workflow is much faster than make test-kind for iterative development. It skips cluster creation and deletion on every run.
Integration tests run automatically via GitHub Actions:
| Event | Envtest | Kind |
|---|---|---|
| Pull Request | Yes | No |
| Push to main | Yes | Yes |
| Nightly schedule | Yes | Yes |
| Manual trigger | Yes | Configurable |
See .github/workflows/integration-tests.yml for details.
The envtest binaries need to be downloaded:
make envtestOr ensure KUBEBUILDER_ASSETS is set to an absolute path:
export KUBEBUILDER_ASSETS="$(pwd)/bin/k8s/1.29.5-$(go env GOOS)-$(go env GOARCH)"Check Docker is running:
docker infoCheck for existing clusters:
kind get clustersDelete and recreate:
make kind-delete kind-createFor envtest, ensure no other test environment is running.
For kind, check cluster health:
kubectl cluster-info --context kind-team-operator-test
kubectl get pods -A- Use the existing
suite_test.gosetup - Create a new
*_test.gofile with GinkgoDescribeblocks - Use
k8sClientfor API operations - Use
ctxfor context - Clean up resources after each test
- Add test functions to
hack/test-kind.sh - Follow the naming convention:
test_<feature> - Use the helper functions (
log_info,wait_for, etc.) - Ensure proper cleanup in the
cleanupfunction
- Use envtest for unit-level controller tests - Fast and no Docker needed
- Use kind for integration tests - When you need a real cluster
- Always clean up test resources - Prevents test pollution
- Use Eventually() for async operations - Controllers are eventually consistent
- Keep test data minimal - Specify only the fields the test needs