From dee2dd789b5104eed421ac8cd5d0e2b817c2641a Mon Sep 17 00:00:00 2001 From: Danil Grigorev Date: Thu, 22 Feb 2024 15:00:14 +0100 Subject: [PATCH 1/2] Update tests to use same envtest helper, add eventual checks for cache consistency Signed-off-by: Danil Grigorev --- Makefile | 1 + .../controllers/import_controller_test.go | 222 ++++++++++-------- .../controllers/patch_kcfg_controller_test.go | 57 ++--- internal/controllers/suite_test.go | 91 +++---- internal/sync/secret_mapper_sync_test.go | 206 ++++++++-------- internal/sync/suite_test.go | 4 +- internal/test/envtest.go | 66 ------ internal/test/helpers/envtest.go | 51 +++- util/predicates/suite_test.go | 51 +++- 9 files changed, 400 insertions(+), 349 deletions(-) delete mode 100644 internal/test/envtest.go diff --git a/Makefile b/Makefile index bd41b7ac..8827018e 100644 --- a/Makefile +++ b/Makefile @@ -283,6 +283,7 @@ KUBEBUILDER_ASSETS ?= $(shell $(SETUP_ENVTEST) use --use-env -p path $(KUBEBUILD .PHONY: test test: $(SETUP_ENVTEST) manifests ## Run tests. + go clean -testcache KUBEBUILDER_ASSETS="$(KUBEBUILDER_ASSETS)" go test ./... $(TEST_ARGS) ##@ Build diff --git a/internal/controllers/import_controller_test.go b/internal/controllers/import_controller_test.go index 98d6a27c..b388c346 100644 --- a/internal/controllers/import_controller_test.go +++ b/internal/controllers/import_controller_test.go @@ -25,6 +25,7 @@ import ( "net/http" "net/http/httptest" "strings" + "time" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -49,6 +50,7 @@ import ( var _ = Describe("reconcile CAPI Cluster", func() { var ( r *CAPIImportReconciler + ns *corev1.Namespace capiCluster *clusterv1.Cluster rancherCluster *provisioningv1.Cluster clusterRegistrationToken *managementv3.ClusterRegistrationToken @@ -57,38 +59,47 @@ var _ = Describe("reconcile CAPI Cluster", func() { ) BeforeEach(func() { + var err error + + ns, err = testEnv.CreateNamespace(ctx, "commonns") + Expect(err).ToNot(HaveOccurred()) + ns.Labels = map[string]string{ + importLabelName: "true", + } + Expect(cl.Update(ctx, ns)).To(Succeed()) + r = &CAPIImportReconciler{ - Client: cl, - RancherClient: cl, // rancher and rancher-turtles deployed in the same cluster + Client: testEnv, + RancherClient: testEnv, // rancher and rancher-turtles deployed in the same cluster remoteClientGetter: remote.NewClusterClient, - Scheme: testEnv.Scheme, + Scheme: testEnv.GetScheme(), } capiCluster = &clusterv1.Cluster{ ObjectMeta: metav1.ObjectMeta{ Name: "test-cluster", - Namespace: testNamespace, + Namespace: ns.Name, }, } rancherCluster = &provisioningv1.Cluster{ ObjectMeta: metav1.ObjectMeta{ Name: turtlesnaming.Name(capiCluster.Name).ToRancherName(), - Namespace: testNamespace, + Namespace: ns.Name, }, } clusterRegistrationToken = &managementv3.ClusterRegistrationToken{ ObjectMeta: metav1.ObjectMeta{ Name: clusterName, - Namespace: testNamespace, + Namespace: ns.Name, }, } capiKubeconfigSecret = &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ Name: fmt.Sprintf("%s-kubeconfig", capiCluster.Name), - Namespace: testNamespace, + Namespace: ns.Name, }, Data: map[string][]byte{ secret.KubeconfigDataName: kubeConfigBytes, @@ -111,6 +122,7 @@ var _ = Describe("reconcile CAPI Cluster", func() { } Expect(err).ToNot(HaveOccurred()) Expect(test.CleanupAndWait(ctx, cl, clientObjs...)).To(Succeed()) + Expect(testEnv.Cleanup(ctx, ns)).To(Succeed()) }) It("should reconcile a CAPI cluster when control plane not ready", func() { @@ -134,17 +146,18 @@ var _ = Describe("reconcile CAPI Cluster", func() { capiCluster.Status.ControlPlaneReady = true Expect(cl.Status().Update(ctx, capiCluster)).To(Succeed()) - res, err := r.Reconcile(ctx, reconcile.Request{ - NamespacedName: types.NamespacedName{ - Namespace: capiCluster.Namespace, - Name: capiCluster.Name, - }, - }) - Expect(err).ToNot(HaveOccurred()) - Expect(res.Requeue).To(BeTrue()) - - cluster := &provisioningv1.Cluster{} - Expect(cl.Get(ctx, client.ObjectKeyFromObject(rancherCluster), cluster)).ToNot(HaveOccurred()) + Eventually(ctx, func(g Gomega) { + res, err := r.Reconcile(ctx, reconcile.Request{ + NamespacedName: types.NamespacedName{ + Namespace: capiCluster.Namespace, + Name: capiCluster.Name, + }, + }) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(res.Requeue).To(BeTrue()) + }).Should(Succeed()) + + Eventually(testEnv.GetAs(rancherCluster, &provisioningv1.Cluster{})).ShouldNot(BeNil()) }) It("should reconcile a CAPI cluster when rancher cluster doesn't exist and annotation is set on the namespace", func() { @@ -152,17 +165,18 @@ var _ = Describe("reconcile CAPI Cluster", func() { capiCluster.Status.ControlPlaneReady = true Expect(cl.Status().Update(ctx, capiCluster)).To(Succeed()) - res, err := r.Reconcile(ctx, reconcile.Request{ - NamespacedName: types.NamespacedName{ - Namespace: capiCluster.Namespace, - Name: capiCluster.Name, - }, - }) - Expect(err).ToNot(HaveOccurred()) - Expect(res.Requeue).To(BeTrue()) - - cluster := &provisioningv1.Cluster{} - Expect(cl.Get(ctx, client.ObjectKeyFromObject(rancherCluster), cluster)).ToNot(HaveOccurred()) + Eventually(ctx, func(g Gomega) { + res, err := r.Reconcile(ctx, reconcile.Request{ + NamespacedName: types.NamespacedName{ + Namespace: capiCluster.Namespace, + Name: capiCluster.Name, + }, + }) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(res.Requeue).To(BeTrue()) + }).Should(Succeed()) + + Eventually(testEnv.GetAs(rancherCluster, &provisioningv1.Cluster{})).ShouldNot(BeNil()) }) It("should reconcile a CAPI cluster when rancher cluster exists", func() { @@ -179,41 +193,41 @@ var _ = Describe("reconcile CAPI Cluster", func() { Expect(cl.Create(ctx, capiKubeconfigSecret)).To(Succeed()) Expect(cl.Create(ctx, rancherCluster)).To(Succeed()) - cluster := &provisioningv1.Cluster{} - Expect(cl.Get(ctx, client.ObjectKeyFromObject(rancherCluster), cluster)).To(Succeed()) + cluster := rancherCluster.DeepCopy() cluster.Status.ClusterName = clusterName Expect(cl.Status().Update(ctx, cluster)).To(Succeed()) Expect(cl.Create(ctx, clusterRegistrationToken)).To(Succeed()) - token := &managementv3.ClusterRegistrationToken{} - Expect(cl.Get(ctx, client.ObjectKeyFromObject(clusterRegistrationToken), token)).To(Succeed()) + token := clusterRegistrationToken.DeepCopy() token.Status.ManifestURL = server.URL Expect(cl.Status().Update(ctx, token)).To(Succeed()) - _, err := r.Reconcile(ctx, reconcile.Request{ - NamespacedName: types.NamespacedName{ - Namespace: capiCluster.Namespace, - Name: capiCluster.Name, - }, - }) - Expect(err).ToNot(HaveOccurred()) - - objs, err := manifestToObjects(strings.NewReader(testdata.ImportManifest)) - Expect(err).ToNot(HaveOccurred()) - - for _, obj := range objs { - u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj) - Expect(err).ToNot(HaveOccurred()) - - unstructuredObj := &unstructured.Unstructured{} - unstructuredObj.SetUnstructuredContent(u) - unstructuredObj.SetGroupVersionKind(obj.GetObjectKind().GroupVersionKind()) - - Expect(cl.Get(ctx, client.ObjectKey{ - Namespace: unstructuredObj.GetNamespace(), - Name: unstructuredObj.GetName(), - }, unstructuredObj)).To(Succeed()) - } + Eventually(ctx, func(g Gomega) { + _, err := r.Reconcile(ctx, reconcile.Request{ + NamespacedName: types.NamespacedName{ + Namespace: capiCluster.Namespace, + Name: capiCluster.Name, + }, + }) + g.Expect(err).ToNot(HaveOccurred()) + + objs, err := manifestToObjects(strings.NewReader(testdata.ImportManifest)) + g.Expect(err).ToNot(HaveOccurred()) + + for _, obj := range objs { + u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj) + g.Expect(err).ToNot(HaveOccurred()) + + unstructuredObj := &unstructured.Unstructured{} + unstructuredObj.SetUnstructuredContent(u) + unstructuredObj.SetGroupVersionKind(obj.GetObjectKind().GroupVersionKind()) + + g.Expect(cl.Get(ctx, client.ObjectKey{ + Namespace: unstructuredObj.GetNamespace(), + Name: unstructuredObj.GetName(), + }, unstructuredObj)).To(Succeed()) + } + }, 30*time.Second).Should(Succeed()) }) It("should reconcile a CAPI cluster when rancher cluster exists but cluster name not set", func() { @@ -222,14 +236,16 @@ var _ = Describe("reconcile CAPI Cluster", func() { Expect(cl.Status().Update(ctx, capiCluster)).To(Succeed()) Expect(cl.Create(ctx, rancherCluster)).To(Succeed()) - res, err := r.Reconcile(ctx, reconcile.Request{ - NamespacedName: types.NamespacedName{ - Namespace: capiCluster.Namespace, - Name: capiCluster.Name, - }, - }) - Expect(err).ToNot(HaveOccurred()) - Expect(res.Requeue).To(BeTrue()) + Eventually(ctx, func(g Gomega) { + res, err := r.Reconcile(ctx, reconcile.Request{ + NamespacedName: types.NamespacedName{ + Namespace: capiCluster.Namespace, + Name: capiCluster.Name, + }, + }) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(res.Requeue).To(BeTrue()) + }).Should(Succeed()) }) It("should reconcile a CAPI cluster when rancher cluster exists and agent is deployed", func() { @@ -238,8 +254,7 @@ var _ = Describe("reconcile CAPI Cluster", func() { Expect(cl.Status().Update(ctx, capiCluster)).To(Succeed()) Expect(cl.Create(ctx, rancherCluster)).To(Succeed()) - cluster := &provisioningv1.Cluster{} - Expect(cl.Get(ctx, client.ObjectKeyFromObject(rancherCluster), cluster)).ToNot(HaveOccurred()) + cluster := rancherCluster.DeepCopy() cluster.Status.AgentDeployed = true Expect(cl.Status().Update(ctx, cluster)).To(Succeed()) @@ -266,25 +281,25 @@ var _ = Describe("reconcile CAPI Cluster", func() { Expect(cl.Create(ctx, capiKubeconfigSecret)).To(Succeed()) Expect(cl.Create(ctx, rancherCluster)).To(Succeed()) - cluster := &provisioningv1.Cluster{} - Expect(cl.Get(ctx, client.ObjectKeyFromObject(rancherCluster), cluster)).ToNot(HaveOccurred()) + cluster := rancherCluster.DeepCopy() cluster.Status.ClusterName = clusterName Expect(cl.Status().Update(ctx, cluster)).To(Succeed()) Expect(cl.Create(ctx, clusterRegistrationToken)).To(Succeed()) - token := &managementv3.ClusterRegistrationToken{} - Expect(cl.Get(ctx, client.ObjectKeyFromObject(clusterRegistrationToken), token)).To(Succeed()) + token := clusterRegistrationToken.DeepCopy() token.Status.ManifestURL = server.URL Expect(cl.Status().Update(ctx, token)).To(Succeed()) - res, err := r.Reconcile(ctx, reconcile.Request{ - NamespacedName: types.NamespacedName{ - Namespace: capiCluster.Namespace, - Name: capiCluster.Name, - }, - }) - Expect(err).ToNot(HaveOccurred()) - Expect(res.Requeue).To(BeTrue()) + Eventually(ctx, func(g Gomega) { + res, err := r.Reconcile(ctx, reconcile.Request{ + NamespacedName: types.NamespacedName{ + Namespace: capiCluster.Namespace, + Name: capiCluster.Name, + }, + }) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(res.Requeue).To(BeTrue()) + }).Should(Succeed()) }) It("should reconcile a CAPI cluster when rancher cluster exists and a cluster registration token does not exist", func() { @@ -301,21 +316,21 @@ var _ = Describe("reconcile CAPI Cluster", func() { Expect(cl.Create(ctx, capiKubeconfigSecret)).To(Succeed()) Expect(cl.Create(ctx, rancherCluster)).To(Succeed()) - cluster := &provisioningv1.Cluster{} - Expect(cl.Get(ctx, client.ObjectKeyFromObject(rancherCluster), cluster)).ToNot(HaveOccurred()) + cluster := rancherCluster.DeepCopy() cluster.Status.ClusterName = clusterName Expect(cl.Status().Update(ctx, cluster)).To(Succeed()) - res, err := r.Reconcile(ctx, reconcile.Request{ - NamespacedName: types.NamespacedName{ - Namespace: capiCluster.Namespace, - Name: capiCluster.Name, - }, - }) - Expect(err).ToNot(HaveOccurred()) - Expect(res.Requeue).To(BeTrue()) - - Expect(cl.Get(ctx, client.ObjectKeyFromObject(clusterRegistrationToken), clusterRegistrationToken)).ToNot(HaveOccurred()) + Eventually(ctx, func(g Gomega) { + res, err := r.Reconcile(ctx, reconcile.Request{ + NamespacedName: types.NamespacedName{ + Namespace: capiCluster.Namespace, + Name: capiCluster.Name, + }, + }) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(res.Requeue).To(BeTrue()) + g.Expect(cl.Get(ctx, client.ObjectKeyFromObject(clusterRegistrationToken), clusterRegistrationToken)).ToNot(HaveOccurred()) + }).Should(Succeed()) }) It("should reconcile a CAPI cluster when rancher cluster exists and registration manifests url is empty", func() { @@ -326,21 +341,22 @@ var _ = Describe("reconcile CAPI Cluster", func() { Expect(cl.Create(ctx, capiKubeconfigSecret)).To(Succeed()) Expect(cl.Create(ctx, rancherCluster)).To(Succeed()) - cluster := &provisioningv1.Cluster{} - Expect(cl.Get(ctx, client.ObjectKeyFromObject(rancherCluster), cluster)).ToNot(HaveOccurred()) + cluster := rancherCluster.DeepCopy() cluster.Status.ClusterName = clusterName Expect(cl.Status().Update(ctx, cluster)).To(Succeed()) - Expect(cl.Create(ctx, clusterRegistrationToken)).To(Succeed()) - - res, err := r.Reconcile(ctx, reconcile.Request{ - NamespacedName: types.NamespacedName{ - Namespace: capiCluster.Namespace, - Name: capiCluster.Name, - }, - }) - Expect(err).ToNot(HaveOccurred()) - Expect(res.Requeue).To(BeTrue()) + Expect(testEnv.Create(ctx, clusterRegistrationToken)).To(Succeed()) + + Eventually(ctx, func(g Gomega) { + res, err := r.Reconcile(ctx, reconcile.Request{ + NamespacedName: types.NamespacedName{ + Namespace: capiCluster.Namespace, + Name: capiCluster.Name, + }, + }) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(res.Requeue).To(BeTrue()) + }).Should(Succeed()) }) }) diff --git a/internal/controllers/patch_kcfg_controller_test.go b/internal/controllers/patch_kcfg_controller_test.go index 0fe197bd..d964648f 100644 --- a/internal/controllers/patch_kcfg_controller_test.go +++ b/internal/controllers/patch_kcfg_controller_test.go @@ -39,9 +39,15 @@ var _ = Describe("Patch Rancher v2Prov Kubeconfig secrets", func() { rancherCluster *provisioningv1.Cluster kubeconfigSecret *corev1.Secret clusterName string + ns *corev1.Namespace ) BeforeEach(func() { + var err error + + ns, err = testEnv.CreateNamespace(ctx, "v2prov") + Expect(err).ToNot(HaveOccurred()) + r = &RancherKubeconfigSecretReconciler{ Client: cl, } @@ -50,7 +56,7 @@ var _ = Describe("Patch Rancher v2Prov Kubeconfig secrets", func() { rancherCluster = &provisioningv1.Cluster{ ObjectMeta: metav1.ObjectMeta{ Name: clusterName, - Namespace: testNamespace, + Namespace: ns.Name, }, TypeMeta: metav1.TypeMeta{ Kind: "Cluster", @@ -65,7 +71,7 @@ var _ = Describe("Patch Rancher v2Prov Kubeconfig secrets", func() { kubeconfigSecret = &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ Name: fmt.Sprintf("%s-kubeconfig", clusterName), - Namespace: testNamespace, + Namespace: ns.Name, OwnerReferences: []metav1.OwnerReference{ { APIVersion: "provisioning.cattle.io/v1", @@ -87,6 +93,7 @@ var _ = Describe("Patch Rancher v2Prov Kubeconfig secrets", func() { kubeconfigSecret, } Expect(test.CleanupAndWait(ctx, cl, clientObjs...)).To(Succeed()) + Expect(testEnv.Cleanup(ctx, ns)).To(Succeed()) }) It("should add label to a v2prov secret", func() { @@ -101,10 +108,11 @@ var _ = Describe("Patch Rancher v2Prov Kubeconfig secrets", func() { Expect(err).NotTo(HaveOccurred()) updatedSecret := &corev1.Secret{} - err = cl.Get(ctx, client.ObjectKeyFromObject(kubeconfigSecret), updatedSecret) + Eventually(ctx, func(g Gomega) { + g.Expect(cl.Get(ctx, client.ObjectKeyFromObject(kubeconfigSecret), updatedSecret)).ToNot(HaveOccurred()) + g.Expect(updatedSecret.GetLabels()).To(HaveLen(1)) + }).Should(Succeed()) - Expect(err).ShouldNot(HaveOccurred()) - Expect(updatedSecret.Labels).To(HaveLen(1)) labvelVal, labelFound := updatedSecret.Labels["cluster.x-k8s.io/cluster-name"] Expect(labelFound).To(BeTrue(), "Failed to find expected CAPI label") Expect(labvelVal).To(Equal(clusterName)) @@ -125,15 +133,14 @@ var _ = Describe("Patch Rancher v2Prov Kubeconfig secrets", func() { Expect(err).NotTo(HaveOccurred()) updatedSecret := &corev1.Secret{} - err = cl.Get(ctx, client.ObjectKeyFromObject(kubeconfigSecret), updatedSecret) - - Expect(err).ShouldNot(HaveOccurred()) - Expect(updatedSecret.Labels).To(HaveLen(1)) - labvelVal, labelFound := updatedSecret.Labels["cluster.x-k8s.io/cluster-name"] - Expect(labelFound).To(BeTrue(), "Failed to find expected CAPI label") - Expect(labvelVal).To(Equal(clusterName)) - - Expect(kubeconfigSecret.ResourceVersion).To(Equal(updatedSecret.ResourceVersion), "Secret shouldn't have been updated") + Eventually(ctx, func(g Gomega) { + g.Expect(cl.Get(ctx, client.ObjectKeyFromObject(kubeconfigSecret), updatedSecret)).ToNot(HaveOccurred()) + g.Expect(updatedSecret.Labels).To(HaveLen(1)) + labvelVal, labelFound := updatedSecret.Labels["cluster.x-k8s.io/cluster-name"] + g.Expect(labelFound).To(BeTrue(), "Failed to find expected CAPI label") + g.Expect(labvelVal).To(Equal(clusterName)) + g.Expect(kubeconfigSecret.ResourceVersion).To(Equal(updatedSecret.ResourceVersion), "Secret shouldn't have been updated") + }) }) It("should not change already existing labels but add label to v2prov secret", func() { @@ -152,10 +159,10 @@ var _ = Describe("Patch Rancher v2Prov Kubeconfig secrets", func() { Expect(err).NotTo(HaveOccurred()) updatedSecret := &corev1.Secret{} - err = cl.Get(ctx, client.ObjectKeyFromObject(kubeconfigSecret), updatedSecret) - - Expect(err).ShouldNot(HaveOccurred()) - Expect(updatedSecret.Labels).To(HaveLen(2)) + Eventually(ctx, func(g Gomega) { + g.Expect(cl.Get(ctx, client.ObjectKeyFromObject(kubeconfigSecret), updatedSecret)).ToNot(HaveOccurred()) + g.Expect(updatedSecret.GetLabels()).To(HaveLen(2)) + }).Should(Succeed()) labvelVal, labelFound := updatedSecret.Labels["cluster.x-k8s.io/cluster-name"] Expect(labelFound).To(BeTrue(), "Failed to find expected CAPI label") @@ -179,11 +186,7 @@ var _ = Describe("Patch Rancher v2Prov Kubeconfig secrets", func() { }) Expect(err).NotTo(HaveOccurred()) - updatedSecret := &corev1.Secret{} - err = cl.Get(ctx, client.ObjectKeyFromObject(kubeconfigSecret), updatedSecret) - - Expect(err).ShouldNot(HaveOccurred()) - Expect(updatedSecret.Labels).To(HaveLen(0)) + Eventually(testEnv.GetAs(kubeconfigSecret, &corev1.Secret{})).Should(HaveField("Labels", HaveLen(0))) }) It("should not add a label to a non-v2prov Rancher cluster secret", func() { @@ -203,9 +206,9 @@ var _ = Describe("Patch Rancher v2Prov Kubeconfig secrets", func() { Expect(err).NotTo(HaveOccurred()) updatedSecret := &corev1.Secret{} - err = cl.Get(ctx, client.ObjectKeyFromObject(kubeconfigSecret), updatedSecret) - - Expect(err).ShouldNot(HaveOccurred()) - Expect(updatedSecret.Labels).To(HaveLen(0)) + Eventually(ctx, func(g Gomega) { + g.Expect(cl.Get(ctx, client.ObjectKeyFromObject(kubeconfigSecret), updatedSecret)).ToNot(HaveOccurred()) + g.Expect(updatedSecret.Labels).To(HaveLen(0)) + }) }) }) diff --git a/internal/controllers/suite_test.go b/internal/controllers/suite_test.go index 7b9c0dd7..1707b0e9 100644 --- a/internal/controllers/suite_test.go +++ b/internal/controllers/suite_test.go @@ -17,66 +17,85 @@ limitations under the License. package controllers import ( - "context" - "path/filepath" + "fmt" + "path" "testing" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - "github.com/rancher-sandbox/rancher-turtles/internal/test" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "github.com/rancher-sandbox/rancher-turtles/internal/test/helpers" + "k8s.io/client-go/kubernetes/scheme" + ctrl "sigs.k8s.io/controller-runtime" + turtlesv1 "github.com/rancher-sandbox/rancher-turtles/api/v1alpha1" managementv3 "github.com/rancher-sandbox/rancher-turtles/internal/rancher/management/v3" provisioningv1 "github.com/rancher-sandbox/rancher-turtles/internal/rancher/provisioning/v1" + operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" - "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd/api" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/envtest" logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" ) var ( - testEnv *envtest.Environment cfg *rest.Config cl client.Client - ctx = context.Background() - testNamespace = "test-namespace" + testEnv *helpers.TestEnvironment kubeConfigBytes []byte + ctx = ctrl.SetupSignalHandler() ) +func setup() { + utilruntime.Must(clusterv1.AddToScheme(scheme.Scheme)) + utilruntime.Must(operatorv1.AddToScheme(scheme.Scheme)) + utilruntime.Must(turtlesv1.AddToScheme(scheme.Scheme)) + utilruntime.Must(provisioningv1.AddToScheme(scheme.Scheme)) + utilruntime.Must(managementv3.AddToScheme(scheme.Scheme)) + + testEnvConfig := helpers.NewTestEnvironmentConfiguration( + path.Join("hack", "crd", "bases"), + path.Join("config", "crd", "bases"), + ) + + var err error + + testEnv, err = testEnvConfig.Build() + if err != nil { + panic(err) + } + + cfg = testEnv.Config + cl = testEnv.Client + + go func() { + fmt.Println("Starting the manager") + if err := testEnv.StartManager(ctx); err != nil { + panic(fmt.Sprintf("Failed to start the envtest manager: %v", err)) + } + }() +} + +func teardown() { + if err := testEnv.Stop(); err != nil { + panic(fmt.Sprintf("Failed to stop envtest: %v", err)) + } +} + func TestController(t *testing.T) { RegisterFailHandler(Fail) + setup() + defer teardown() RunSpecs(t, "Rancher Turtles Controller Suite") } var _ = BeforeSuite(func() { - logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) - - By("bootstrapping test environment") var err error - testEnv = &envtest.Environment{ - CRDDirectoryPaths: []string{ - filepath.Join("..", "..", "hack", "crd", "bases"), - }, - ErrorIfCRDPathMissing: true, - Scheme: runtime.NewScheme(), - } - - utilruntime.Must(clusterv1.AddToScheme(testEnv.Scheme)) - utilruntime.Must(provisioningv1.AddToScheme(testEnv.Scheme)) - utilruntime.Must(managementv3.AddToScheme(testEnv.Scheme)) - - cfg, cl, err = test.StartEnvTest(testEnv) - Expect(err).NotTo(HaveOccurred()) - Expect(cfg).NotTo(BeNil()) - Expect(cl).NotTo(BeNil()) + logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) kubeConfig := &api.Config{ Kind: "Config", @@ -104,18 +123,4 @@ var _ = BeforeSuite(func() { kubeConfigBytes, err = clientcmd.Write(*kubeConfig) Expect(err).NotTo(HaveOccurred()) - - Expect(cl.Create(ctx, &corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: testNamespace, - Labels: map[string]string{ - importLabelName: "true", - }, - }, - })).To(Succeed()) -}) - -var _ = AfterSuite(func() { - By("tearing down the test environment") - Expect(test.StopEnvTest(testEnv)).To(Succeed()) }) diff --git a/internal/sync/secret_mapper_sync_test.go b/internal/sync/secret_mapper_sync_test.go index acaf296c..2751f85d 100644 --- a/internal/sync/secret_mapper_sync_test.go +++ b/internal/sync/secret_mapper_sync_test.go @@ -108,10 +108,11 @@ var _ = Describe("SecretMapperSync get", func() { RancherSecret: sync.SecretMapperSync{}.GetSecret(capiProvider), } - err := syncer.Get(context.Background()) - Expect(err).NotTo(HaveOccurred()) - Expect(syncer.RancherSecret.Annotations).To(Equal(rancherSecret.Annotations)) - Expect(syncer.RancherSecret.Name).To(Equal(rancherSecret.Name)) + Eventually(func(g Gomega) { + g.Expect(syncer.Get(context.Background())).ToNot(HaveOccurred()) + g.Expect(syncer.RancherSecret.Annotations).To(Equal(rancherSecret.Annotations)) + g.Expect(syncer.RancherSecret.Name).To(Equal(rancherSecret.Name)) + }) }) It("should ignore similarly named secret for a different driver", func() { @@ -129,12 +130,13 @@ var _ = Describe("SecretMapperSync get", func() { RancherSecret: sync.SecretMapperSync{}.GetSecret(capiProvider), } - err := syncer.Get(context.Background()) - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("unable to locate rancher secret with name")) - Expect(conditions.Get(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).ToNot(BeNil()) - Expect(conditions.IsFalse(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).To(BeTrue()) - Expect(conditions.GetMessage(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).To(Equal("Rancher Credentials secret named test-rancher-secret was not located")) + Eventually(func(g Gomega) { + g.Expect(syncer.Get(context.Background())).To(HaveOccurred()) + g.Expect(err.Error()).To(ContainSubstring("unable to locate rancher secret with name")) + g.Expect(conditions.Get(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).ToNot(BeNil()) + g.Expect(conditions.IsFalse(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).To(BeTrue()) + g.Expect(conditions.GetMessage(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).To(Equal("Rancher Credentials secret named test-rancher-secret was not located")) + }) }) It("should handle when the source Rancher secret is not found", func() { @@ -149,13 +151,13 @@ var _ = Describe("SecretMapperSync get", func() { RancherSecret: sync.SecretMapperSync{}.GetSecret(capiProvider), } - err := syncer.Get(context.Background()) - - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("unable to locate rancher secret with name")) - Expect(conditions.Get(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).ToNot(BeNil()) - Expect(conditions.IsFalse(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).To(BeTrue()) - Expect(conditions.GetMessage(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).To(Equal("Rancher Credentials secret named test-rancher-secret was not located")) + Eventually(func(g Gomega) { + g.Expect(syncer.Get(context.Background())).To(HaveOccurred()) + g.Expect(err.Error()).To(ContainSubstring("unable to locate rancher secret with name")) + g.Expect(conditions.Get(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).ToNot(BeNil()) + g.Expect(conditions.IsFalse(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).To(BeTrue()) + g.Expect(conditions.GetMessage(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).To(Equal("Rancher Credentials secret named test-rancher-secret was not located")) + }) }) It("should not error when the destination secret is not created yet", func() { @@ -166,10 +168,11 @@ var _ = Describe("SecretMapperSync get", func() { RancherSecret: sync.SecretMapperSync{}.GetSecret(capiProvider), } - err := syncer.Get(context.Background()) - Expect(err).NotTo(HaveOccurred()) - Expect(syncer.RancherSecret.Annotations).To(Equal(rancherSecret.Annotations)) - Expect(syncer.RancherSecret.Name).To(Equal(rancherSecret.Name)) + Eventually(func(g Gomega) { + g.Expect(syncer.Get(context.Background())).ToNot(HaveOccurred()) + g.Expect(syncer.RancherSecret.Annotations).To(Equal(rancherSecret.Annotations)) + g.Expect(syncer.RancherSecret.Name).To(Equal(rancherSecret.Name)) + }) }) It("should point to the right initial secret", func() { @@ -185,9 +188,11 @@ var _ = Describe("SecretMapperSync get", func() { SecretSync: sync.NewSecretSync(testEnv, capiProvider).(*sync.SecretSync), RancherSecret: sync.SecretMapperSync{}.GetSecret(capiProvider), } - err := syncer.Sync(context.Background()) - Expect(err).To(BeNil()) - Expect(syncer.SecretSync.Secret.StringData).To(HaveLen(0)) + + Eventually(func(g Gomega) { + g.Expect(syncer.Sync(context.Background())).To(BeNil()) + g.Expect(syncer.SecretSync.Secret.StringData).To(HaveLen(0)) + }) }) It("provider requirements azure", func() { @@ -196,23 +201,24 @@ var _ = Describe("SecretMapperSync get", func() { Expect(testEnv.Client.Create(ctx, rancherSecret)).ToNot(HaveOccurred()) syncer := sync.NewSecretMapperSync(ctx, testEnv, capiProvider).(*sync.SecretMapperSync) - err := syncer.Sync(context.Background()) - Expect(err).ToNot(HaveOccurred()) - Expect(conditions.Get(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).ToNot(BeNil()) - Expect(conditions.IsFalse(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).To(BeTrue()) - Expect(conditions.GetMessage(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).To( - ContainSubstring("key not found: azurecredentialConfig-subscriptionId, key not found: azurecredentialConfig-clientId, key not found: azurecredentialConfig-clientSecret, key not found: azurecredentialConfig-tenantId")) - - Expect(syncer.Secret.StringData).To(Equal(map[string]string{ - "AZURE_CLIENT_ID_B64": "", - "AZURE_CLIENT_SECRET_B64": "", - "AZURE_TENANT_ID_B64": "", - "AZURE_SUBSCRIPTION_ID": "", - "AZURE_CLIENT_ID": "", - "AZURE_CLIENT_SECRET": "", - "AZURE_TENANT_ID": "", - "AZURE_SUBSCRIPTION_ID_B64": "", - })) + Eventually(func(g Gomega) { + g.Expect(syncer.Sync(context.Background())).ToNot(HaveOccurred()) + g.Expect(conditions.Get(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).ToNot(BeNil()) + g.Expect(conditions.IsFalse(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).To(BeTrue()) + g.Expect(conditions.GetMessage(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).To( + ContainSubstring("key not found: azurecredentialConfig-subscriptionId, key not found: azurecredentialConfig-clientId, key not found: azurecredentialConfig-clientSecret, key not found: azurecredentialConfig-tenantId")) + + g.Expect(syncer.Secret.StringData).To(Equal(map[string]string{ + "AZURE_CLIENT_ID_B64": "", + "AZURE_CLIENT_SECRET_B64": "", + "AZURE_TENANT_ID_B64": "", + "AZURE_SUBSCRIPTION_ID": "", + "AZURE_CLIENT_ID": "", + "AZURE_CLIENT_SECRET": "", + "AZURE_TENANT_ID": "", + "AZURE_SUBSCRIPTION_ID_B64": "", + })) + }) }) It("provider requirements aws", func() { @@ -221,19 +227,20 @@ var _ = Describe("SecretMapperSync get", func() { syncer := sync.NewSecretMapperSync(ctx, testEnv, capiProvider).(*sync.SecretMapperSync) syncer.RancherSecret = rancherSecret - err := syncer.Sync(context.Background()) - Expect(err).ToNot(HaveOccurred()) - Expect(conditions.Get(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).ToNot(BeNil()) - Expect(conditions.IsFalse(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).To(BeTrue()) - Expect(conditions.GetMessage(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).To( - ContainSubstring("key not found: amazonec2credentialConfig-accessKey, key not found: amazonec2credentialConfig-secretKey, key not found: amazonec2credentialConfig-defaultRegion")) - - Expect(syncer.Secret.StringData).To(Equal(map[string]string{ - "AWS_REGION": "", - "AWS_B64ENCODED_CREDENTIALS": "", - "AWS_ACCESS_KEY_ID": "", - "AWS_SECRET_ACCESS_KEY": "", - })) + Eventually(ctx, func(g Gomega) { + g.Expect(syncer.Sync(context.Background())).ToNot(HaveOccurred()) + g.Expect(conditions.Get(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).ToNot(BeNil()) + g.Expect(conditions.IsFalse(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).To(BeTrue()) + g.Expect(conditions.GetMessage(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).To( + ContainSubstring("key not found: amazonec2credentialConfig-accessKey, key not found: amazonec2credentialConfig-secretKey, key not found: amazonec2credentialConfig-defaultRegion")) + + g.Expect(syncer.Secret.StringData).To(Equal(map[string]string{ + "AWS_REGION": "", + "AWS_B64ENCODED_CREDENTIALS": "", + "AWS_ACCESS_KEY_ID": "", + "AWS_SECRET_ACCESS_KEY": "", + })) + }) }) It("provider requirements gcp", func() { @@ -242,16 +249,17 @@ var _ = Describe("SecretMapperSync get", func() { Expect(testEnv.Client.Create(ctx, rancherSecret)).ToNot(HaveOccurred()) syncer := sync.NewSecretMapperSync(ctx, testEnv, capiProvider).(*sync.SecretMapperSync) - err := syncer.Sync(context.Background()) - Expect(err).ToNot(HaveOccurred()) - Expect(conditions.Get(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).ToNot(BeNil()) - Expect(conditions.IsFalse(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).To(BeTrue()) - Expect(conditions.GetMessage(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).To( - ContainSubstring("googlecredentialConfig-authEncodedJson")) - - Expect(syncer.Secret.StringData).To(Equal(map[string]string{ - "GCP_B64ENCODED_CREDENTIALS": "", - })) + Eventually(ctx, func(g Gomega) { + g.Expect(syncer.Sync(context.Background())).ToNot(HaveOccurred()) + g.Expect(conditions.Get(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).ToNot(BeNil()) + g.Expect(conditions.IsFalse(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).To(BeTrue()) + g.Expect(conditions.GetMessage(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).To( + ContainSubstring("googlecredentialConfig-authEncodedJson")) + + g.Expect(syncer.Secret.StringData).To(Equal(map[string]string{ + "GCP_B64ENCODED_CREDENTIALS": "", + })) + }) }) It("provider requirements digitalocean", func() { capiProvider.Spec.Name = "digitalocean" @@ -259,17 +267,18 @@ var _ = Describe("SecretMapperSync get", func() { Expect(testEnv.Client.Create(ctx, rancherSecret)).ToNot(HaveOccurred()) syncer := sync.NewSecretMapperSync(ctx, testEnv, capiProvider).(*sync.SecretMapperSync) - err := syncer.Sync(context.Background()) - Expect(err).ToNot(HaveOccurred()) - Expect(conditions.Get(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).ToNot(BeNil()) - Expect(conditions.IsFalse(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).To(BeTrue()) - Expect(conditions.GetMessage(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).To( - ContainSubstring("key not found: digitaloceancredentialConfig-accessToken")) - - Expect(syncer.Secret.StringData).To(Equal(map[string]string{ - "DO_B64ENCODED_CREDENTIALS": "", - "DIGITALOCEAN_ACCESS_TOKEN": "", - })) + Eventually(ctx, func(g Gomega) { + g.Expect(syncer.Sync(context.Background())).ToNot(HaveOccurred()) + g.Expect(conditions.Get(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).ToNot(BeNil()) + g.Expect(conditions.IsFalse(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).To(BeTrue()) + g.Expect(conditions.GetMessage(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).To( + ContainSubstring("key not found: digitaloceancredentialConfig-accessToken")) + + g.Expect(syncer.Secret.StringData).To(Equal(map[string]string{ + "DO_B64ENCODED_CREDENTIALS": "", + "DIGITALOCEAN_ACCESS_TOKEN": "", + })) + }) }) It("provider requirements vsphere", func() { capiProvider.Spec.Name = "vsphere" @@ -277,16 +286,17 @@ var _ = Describe("SecretMapperSync get", func() { Expect(testEnv.Client.Create(ctx, rancherSecret)).ToNot(HaveOccurred()) syncer := sync.NewSecretMapperSync(ctx, testEnv, capiProvider).(*sync.SecretMapperSync) - err := syncer.Sync(context.Background()) - Expect(err).ToNot(HaveOccurred()) - Expect(conditions.Get(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).ToNot(BeNil()) - Expect(conditions.IsFalse(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).To(BeTrue()) - Expect(conditions.GetMessage(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).To( - ContainSubstring("key not found: vmwarevsphere-password, key not found: vmwarevsphere-username")) - Expect(syncer.Secret.StringData).To(Equal(map[string]string{ - "VSPHERE_PASSWORD": "", - "VSPHERE_USERNAME": "", - })) + Eventually(ctx, func(g Gomega) { + g.Expect(syncer.Sync(context.Background())).ToNot(HaveOccurred()) + g.Expect(conditions.Get(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).ToNot(BeNil()) + g.Expect(conditions.IsFalse(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).To(BeTrue()) + g.Expect(conditions.GetMessage(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).To( + ContainSubstring("key not found: vmwarevsphere-password, key not found: vmwarevsphere-username")) + g.Expect(syncer.Secret.StringData).To(Equal(map[string]string{ + "VSPHERE_PASSWORD": "", + "VSPHERE_USERNAME": "", + })) + }) }) It("prepare aws secret", func() { @@ -301,17 +311,19 @@ var _ = Describe("SecretMapperSync get", func() { syncer := sync.NewSecretMapperSync(ctx, testEnv, capiProvider).(*sync.SecretMapperSync) - Expect(syncer.Get(context.Background())).ToNot(HaveOccurred()) - Expect(syncer.RancherSecret.Data["amazonec2credentialConfig-defaultRegion"]).ToNot(BeEmpty()) - Expect(syncer.Sync(context.Background())).ToNot(HaveOccurred()) - Expect(syncer.Secret.StringData).To(Equal(map[string]string{ - "AWS_REGION": "us-west-1", - "AWS_B64ENCODED_CREDENTIALS": "W2RlZmF1bHRdCmF3c19hY2Nlc3Nfa2V5X2lkID0gdGVzdAphd3Nfc2VjcmV0X2FjY2Vzc19rZXkgPSB0ZXN0CnJlZ2lvbiA9IHVzLXdlc3QtMQ==", - "AWS_ACCESS_KEY_ID": "test", - "AWS_SECRET_ACCESS_KEY": "test", - })) - - Expect(conditions.Get(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).ToNot(BeNil()) - Expect(conditions.IsTrue(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).To(BeTrue()) + Eventually(ctx, func(g Gomega) { + g.Expect(syncer.Get(context.Background())).ToNot(HaveOccurred()) + g.Expect(syncer.RancherSecret.Data["amazonec2credentialConfig-defaultRegion"]).ToNot(BeEmpty()) + g.Expect(syncer.Sync(context.Background())).ToNot(HaveOccurred()) + g.Expect(syncer.Secret.StringData).To(Equal(map[string]string{ + "AWS_REGION": "us-west-1", + "AWS_B64ENCODED_CREDENTIALS": "W2RlZmF1bHRdCmF3c19hY2Nlc3Nfa2V5X2lkID0gdGVzdAphd3Nfc2VjcmV0X2FjY2Vzc19rZXkgPSB0ZXN0CnJlZ2lvbiA9IHVzLXdlc3QtMQ==", + "AWS_ACCESS_KEY_ID": "test", + "AWS_SECRET_ACCESS_KEY": "test", + })) + + g.Expect(conditions.Get(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).ToNot(BeNil()) + g.Expect(conditions.IsTrue(syncer.Source, turtlesv1.RancherCredentialsSecretCondition)).To(BeTrue()) + }) }) }) diff --git a/internal/sync/suite_test.go b/internal/sync/suite_test.go index 13f3616a..6f7aba65 100644 --- a/internal/sync/suite_test.go +++ b/internal/sync/suite_test.go @@ -54,9 +54,9 @@ func setup() { utilruntime.Must(operatorv1.AddToScheme(scheme.Scheme)) utilruntime.Must(turtlesv1.AddToScheme(scheme.Scheme)) - testEnvConfig := helpers.NewTestEnvironmentConfiguration([]string{ + testEnvConfig := helpers.NewTestEnvironmentConfiguration( path.Join("config", "crd", "bases"), - }) + ) var err error testEnv, err = testEnvConfig.Build() if err != nil { diff --git a/internal/test/envtest.go b/internal/test/envtest.go deleted file mode 100644 index 7b967b0c..00000000 --- a/internal/test/envtest.go +++ /dev/null @@ -1,66 +0,0 @@ -/* -Copyright © 2023 - 2024 SUSE LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package test - -import ( - "errors" - - "k8s.io/apimachinery/pkg/runtime" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - clientgoscheme "k8s.io/client-go/kubernetes/scheme" - "k8s.io/client-go/rest" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/envtest" - - clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" - - managementv3 "github.com/rancher-sandbox/rancher-turtles/internal/rancher/management/v3" - provisioningv1 "github.com/rancher-sandbox/rancher-turtles/internal/rancher/provisioning/v1" -) - -var scheme = runtime.NewScheme() - -func init() { - utilruntime.Must(clientgoscheme.AddToScheme(scheme)) - utilruntime.Must(clusterv1.AddToScheme(scheme)) - utilruntime.Must(provisioningv1.AddToScheme(scheme)) - utilruntime.Must(managementv3.AddToScheme(scheme)) -} - -// StartEnvTest starts a new test environment. -func StartEnvTest(testEnv *envtest.Environment) (*rest.Config, client.Client, error) { - cfg, err := testEnv.Start() - if err != nil { - return nil, nil, err - } - - if cfg == nil { - return nil, nil, errors.New("envtest.Environment.Start() returned nil config") - } - - cl, err := client.New(cfg, client.Options{Scheme: scheme}) - if err != nil { - return nil, nil, err - } - - return cfg, cl, nil -} - -// StopEnvTest stops the test environment. -func StopEnvTest(testEnv *envtest.Environment) error { - return testEnv.Stop() -} diff --git a/internal/test/helpers/envtest.go b/internal/test/helpers/envtest.go index 35ed9594..743e54b6 100644 --- a/internal/test/helpers/envtest.go +++ b/internal/test/helpers/envtest.go @@ -41,6 +41,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/envtest" + "sigs.k8s.io/controller-runtime/pkg/envtest/komega" "sigs.k8s.io/controller-runtime/pkg/manager" "sigs.k8s.io/controller-runtime/pkg/metrics/server" @@ -116,18 +117,22 @@ func (t *TestEnvironment) CreateNamespace(ctx context.Context, generateName stri } // NewTestEnvironmentConfiguration creates a new test environment configuration for running tests. -func NewTestEnvironmentConfiguration(crdDirectoryPaths []string) *TestEnvironmentConfiguration { +func NewTestEnvironmentConfiguration(crdDirectoryPaths ...string) *TestEnvironmentConfiguration { resolvedCrdDirectoryPaths := []string{} - for _, p := range crdDirectoryPaths { + for _, group := range crdDirectoryPaths { resolvedCrdDirectoryPaths = append( resolvedCrdDirectoryPaths, - path.Join(root, p), - getFilePathToAPI(root, "sigs.k8s.io", "cluster-api", "config/crd/bases"), - getFilePathToAPI(root, "sigs.k8s.io", "cluster-api-operator", "config/crd/bases"), + path.Join([]string{root, group}...), ) } + resolvedCrdDirectoryPaths = append( + resolvedCrdDirectoryPaths, + getFilePathToAPI(root, "sigs.k8s.io", "cluster-api", "config/crd/bases"), + getFilePathToAPI(root, "sigs.k8s.io", "cluster-api-operator", "config/crd/bases"), + ) + return &TestEnvironmentConfiguration{ env: &envtest.Environment{ ErrorIfCRDPathMissing: true, @@ -156,6 +161,8 @@ func (t *TestEnvironmentConfiguration) Build() (*TestEnvironment, error) { klog.Fatalf("Failed to start testenv manager: %v", err) } + komega.SetClient(mgr.GetClient()) + return &TestEnvironment{ Manager: mgr, Client: mgr.GetClient(), @@ -179,6 +186,40 @@ func (t *TestEnvironment) Stop() error { return t.env.Stop() } +// KeyAs is an opposite of client.ObjectKeyFromObject, to construct a new client.Object from provider namespace/name. +// Example: +// +// emptyCluster := testEnv.KeyAs(client.ObjectKeyFromObject(rancherCluster), &provisioningv1.Cluster{}) +// Expect(cl.Get(ctx, emptyCluster)).To(Succeed()) +func (t *TestEnvironment) KeyAs(key client.ObjectKey, to client.Object) client.Object { + to.SetName(key.Name) + to.SetNamespace(key.Namespace) + + return to +} + +// GetAs is a wrapper on komega.Object helper, allowing to construct a new object from an existing object metadata +// and match for object state in kubernetes cluster. +// Example: +// +// // Expecting cluster to be present in the kubernetes API server and be stored in &provisioningv1.Cluster{}. +// // rancherCluster will not be modified during this operation +// g.Eventually(testEnv.GetKeyAs(rancherCluster, &provisioningv1.Cluster{})).ShouldNot(BeNil()) +func (t *TestEnvironment) GetAs(obj, as client.Object) func() (client.Object, error) { + return komega.Object(t.KeyAs(client.ObjectKeyFromObject(obj), as)) +} + +// GetKeyAs is a wrapper on komega.Object helper, allowing to construct a new object from a key +// and match for object state in kubernetes cluster. +// Example: +// +// // Expecting cluster to be present in the kubernetes API server and be stored in &provisioningv1.Cluster{} +// rancherClusterKey := types.NamespaceName{Name: "cluster", Namespace: "default"} +// g.Eventually(testEnv.GetKeyAs(rancherClusterKey, &provisioningv1.Cluster{})).ShouldNot(BeNil()) +func (t *TestEnvironment) GetKeyAs(key client.ObjectKey, as client.Object) func() (client.Object, error) { + return komega.Object(t.KeyAs(key, as)) +} + func getFilePathToAPI(root, org, pkg, apis string) string { modBits, err := os.ReadFile(filepath.Join(root, "go.mod")) //nolint:gosec if err != nil { diff --git a/util/predicates/suite_test.go b/util/predicates/suite_test.go index 02c86cdd..ee4265ef 100644 --- a/util/predicates/suite_test.go +++ b/util/predicates/suite_test.go @@ -18,20 +18,30 @@ package predicates import ( "context" + "fmt" + "path" "testing" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - "github.com/rancher-sandbox/rancher-turtles/internal/test" + "github.com/rancher-sandbox/rancher-turtles/internal/test/helpers" + "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" + + turtlesv1 "github.com/rancher-sandbox/rancher-turtles/api/v1alpha1" + managementv3 "github.com/rancher-sandbox/rancher-turtles/internal/rancher/management/v3" + provisioningv1 "github.com/rancher-sandbox/rancher-turtles/internal/rancher/provisioning/v1" + operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2" + clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" + + utilruntime "k8s.io/apimachinery/pkg/util/runtime" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/envtest" logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" ) var ( - testEnv *envtest.Environment + testEnv *helpers.TestEnvironment cfg *rest.Config cl client.Client ctx = context.Background() @@ -48,8 +58,31 @@ var _ = BeforeSuite(func() { By("bootstrapping test environment") var err error - testEnv = &envtest.Environment{} - cfg, cl, err = test.StartEnvTest(testEnv) + + utilruntime.Must(clusterv1.AddToScheme(scheme.Scheme)) + utilruntime.Must(operatorv1.AddToScheme(scheme.Scheme)) + utilruntime.Must(turtlesv1.AddToScheme(scheme.Scheme)) + utilruntime.Must(provisioningv1.AddToScheme(scheme.Scheme)) + utilruntime.Must(managementv3.AddToScheme(scheme.Scheme)) + + testEnvConfig := helpers.NewTestEnvironmentConfiguration( + path.Join("hack", "crd", "bases"), + ) + + testEnv, err = testEnvConfig.Build() + if err != nil { + panic(err) + } + + cfg = testEnv.Config + cl = testEnv + + go func() { + fmt.Println("Starting the manager") + if err := testEnv.StartManager(ctx); err != nil { + panic(fmt.Sprintf("Failed to start the envtest manager: %v", err)) + } + }() Expect(err).NotTo(HaveOccurred()) Expect(cfg).NotTo(BeNil()) Expect(cl).NotTo(BeNil()) @@ -57,5 +90,11 @@ var _ = BeforeSuite(func() { var _ = AfterSuite(func() { By("tearing down the test environment") - Expect(test.StopEnvTest(testEnv)).To(Succeed()) + teardown() }) + +func teardown() { + if err := testEnv.Stop(); err != nil { + panic(fmt.Sprintf("Failed to stop envtest: %v", err)) + } +} From ae22d09fefc9814792aa2137cebe197aecec971e Mon Sep 17 00:00:00 2001 From: Danil Grigorev Date: Fri, 23 Feb 2024 11:46:23 +0100 Subject: [PATCH 2/2] Fix: namespace lookup error resulting in automatic cluster import Signed-off-by: Danil Grigorev --- util/predicates/cluster_predicates.go | 2 +- util/predicates/cluster_predicates_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/util/predicates/cluster_predicates.go b/util/predicates/cluster_predicates.go index fba0eb38..4cbbf2ff 100644 --- a/util/predicates/cluster_predicates.go +++ b/util/predicates/cluster_predicates.go @@ -149,7 +149,7 @@ func processIfClusterOrNamespaceWithImportLabel(ctx context.Context, logger logr shouldImport, err := util.ShouldAutoImport(ctx, log, cl, cluster, label) if err != nil { log.Error(err, "namespace or cluster has already import annotation set, ignoring it") - return true + return false } return shouldImport diff --git a/util/predicates/cluster_predicates_test.go b/util/predicates/cluster_predicates_test.go index aaf75dcd..b65c1fd6 100644 --- a/util/predicates/cluster_predicates_test.go +++ b/util/predicates/cluster_predicates_test.go @@ -144,11 +144,11 @@ var _ = Describe("ClusterOrNamespaceWithImportLabel", func() { Expect(result).To(BeTrue()) }) - It("should return true if client fails to get namespace", func() { + It("should return false if client fails to get namespace", func() { namespace.Name = "non-existent-ns" capiCluster.Namespace = namespace.Name result := ClusterOrNamespaceWithImportLabel(ctx, logger, cl, importLabel).UpdateFunc(event.UpdateEvent{ObjectNew: capiCluster}) - Expect(result).To(BeTrue()) + Expect(result).To(BeFalse()) }) It("should return false when cluster and namespace have no import label", func() {