Migrating from envtest
github.com/yyewolf/petri/controllerruntime/envtest is a drop-in replacement
for controller-runtime's envtest package. In a kubebuilder project, change
the import in suite_test.go and nothing else:
- "sigs.k8s.io/controller-runtime/pkg/envtest"
+ "github.com/yyewolf/petri/controllerruntime/envtest"
package envtest_test
import (
"path/filepath"
"testing"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/client"
// The one line that changes from kubebuilder's scaffold, which imports
// "sigs.k8s.io/controller-runtime/pkg/envtest".
"github.com/yyewolf/petri/controllerruntime/envtest"
)
var (
cfg *rest.Config
k8sClient client.Client
testEnv *envtest.Environment
)
func TestControllers(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Controller Suite")
}
var _ = BeforeSuite(func() {
testEnv = &envtest.Environment{
CRDDirectoryPaths: []string{filepath.Join("..", "crds", "testdata")},
ErrorIfCRDPathMissing: true,
}
var err error
cfg, err = testEnv.Start()
Expect(err).NotTo(HaveOccurred())
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
Expect(err).NotTo(HaveOccurred())
})
var _ = AfterSuite(func() {
Expect(testEnv.Stop()).To(Succeed())
})
You can then remove the setup-envtest step from your Makefile and CI,
KUBEBUILDER_ASSETS, and any cache of downloaded binaries.
What Start does
Environment.Start starts a dedicated control plane and installs the CRDs and
webhook configurations. Like envtest, it fills in LocalServingHost,
LocalServingPort and LocalServingCertDir for your webhook server. Stop
removes the webhook configurations and the certificate directory, then stops
the plane.
Supported fields: CRDDirectoryPaths, CRDs, ErrorIfCRDPathMissing,
CRDInstallOptions.Paths, CRDInstallOptions.CRDs,
WebhookInstallOptions.Paths, WebhookInstallOptions.MutatingWebhooks,
WebhookInstallOptions.ValidatingWebhooks,
WebhookInstallOptions.LocalServingHost, WebhookInstallOptions.LocalServingPort,
WebhookInstallOptions.LocalServingCertDir, Scheme,
AttachControlPlaneOutput and DisableDefaultControllers.
Some fields would change what your tests check, so Start fails when they are
set instead of ignoring them:
UseExistingCluster: petri never talks to a real cluster;BinaryAssetsDirectory: petri runs no binaries;CRDInstallOptions.CleanUpAfterUse: petri never deletes CRDs.
A CRD path that is missing or has no manifests always fails, whatever
ErrorIfCRDPathMissing says.
What changes
The drop-in runs petri's default controllers, the namespace controller and the garbage collector, so your suite sees what a cluster would do:
package envtest_test
import (
"time"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
)
var _ = Describe("Namespaces", func() {
It("go away when deleted, unlike with envtest", func(ctx SpecContext) {
ns := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{GenerateName: "scratch-"}}
Expect(k8sClient.Create(ctx, ns)).To(Succeed())
Expect(k8sClient.Delete(ctx, ns)).To(Succeed())
// envtest runs no namespace controller, so there the namespace would
// stay Terminating forever. petri runs it by default.
Eventually(func(ctx SpecContext) error {
return k8sClient.Get(ctx, client.ObjectKeyFromObject(ns), &corev1.Namespace{})
}).WithContext(ctx).WithTimeout(30 * time.Second).Should(Satisfy(apierrors.IsNotFound))
})
})
| envtest | petri | |
|---|---|---|
| Deleted namespace | stays Terminating | removed |
| Deleting an owner | dependents stay | dependents deleted |
| Binaries | kube-apiserver and etcd, downloaded | none, compiled in |
| Kubernetes version | any, per binary | your k8s.io/client-go minor |
| Workload controllers | none | opt-in with testEnv.EnableControllers(t, ...) |
A test that relied on envtest's behaviour may notice. The usual case is a
custom resource with a finalizer that nothing removes: its namespace now stays
Terminating until the finalizer goes, as on a cluster. Remove the finalizer
in the test's cleanup, or set DisableDefaultControllers: true to get
envtest's behaviour back.
petri cannot test version skew, such as your client against an older API server; see compatibility.