Browse Source

Refactor ClusterExternalSecretController tests (#2499)

Signed-off-by: shuheiktgw <s-kitagawa@mercari.com>
Shuhei Kitagawa 2 years ago
parent
commit
e5f953bd5f

+ 352 - 315
pkg/controllers/clusterexternalsecret/clusterexternalsecret_controller_test.go

@@ -16,381 +16,418 @@ package clusterexternalsecret
 
 import (
 	"context"
+	"fmt"
 	"math/rand"
 	"time"
 
 	. "github.com/onsi/ginkgo/v2"
 	. "github.com/onsi/gomega"
 	v1 "k8s.io/api/core/v1"
-	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/types"
-	"sigs.k8s.io/controller-runtime/pkg/client"
+	crclient "sigs.k8s.io/controller-runtime/pkg/client"
 
 	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
 	"github.com/external-secrets/external-secrets/pkg/controllers/clusterexternalsecret/cesmetrics"
-	ctest "github.com/external-secrets/external-secrets/pkg/controllers/commontest"
 	ctrlmetrics "github.com/external-secrets/external-secrets/pkg/controllers/metrics"
 )
 
+func init() {
+	ctrlmetrics.SetUpLabelNames(false)
+	cesmetrics.SetUpMetrics()
+}
+
 var (
-	timeout  = time.Second * 10
+	timeout  = time.Second * 3
 	interval = time.Millisecond * 250
 )
 
-var letterRunes = []rune("abcdefghijklmnopqrstuvwxyz")
-
-func RandString(n int) string {
-	b := make([]rune, n)
-	for i := range b {
-		b[i] = letterRunes[rand.Intn(len(letterRunes))]
-	}
-	return string(b)
+type testCase struct {
+	namespaces                    []v1.Namespace
+	clusterExternalSecret         func(namespaces []v1.Namespace) esv1beta1.ClusterExternalSecret
+	beforeCheck                   func(ctx context.Context, namespaces []v1.Namespace, created esv1beta1.ClusterExternalSecret)
+	expectedClusterExternalSecret func(namespaces []v1.Namespace, created esv1beta1.ClusterExternalSecret) esv1beta1.ClusterExternalSecret
+	expectedExternalSecrets       func(namespaces []v1.Namespace, created esv1beta1.ClusterExternalSecret) []esv1beta1.ExternalSecret
 }
 
-type testNamespace struct {
-	namespace  v1.Namespace
-	containsES bool
-	deletedES  bool
-}
+var _ = Describe("ClusterExternalSecret controller", func() {
+	defaultClusterExternalSecret := func() *esv1beta1.ClusterExternalSecret {
+		return &esv1beta1.ClusterExternalSecret{
+			ObjectMeta: metav1.ObjectMeta{
+				Name: fmt.Sprintf("test-ces-%s", randString(10)),
+			},
+			Spec: esv1beta1.ClusterExternalSecretSpec{
+				ExternalSecretSpec: esv1beta1.ExternalSecretSpec{
+					SecretStoreRef: esv1beta1.SecretStoreRef{
+						Name: "test-store",
+					},
+					Target: esv1beta1.ExternalSecretTarget{
+						Name: "test-secret",
+					},
+					Data: []esv1beta1.ExternalSecretData{
+						{
+							SecretKey: "test-secret-key",
+							RemoteRef: esv1beta1.ExternalSecretDataRemoteRef{
+								Key: "test-remote-key",
+							},
+						},
+					},
+				},
+			},
+		}
+	}
 
-type testCase struct {
-	clusterExternalSecret *esv1beta1.ClusterExternalSecret
+	DescribeTable("When reconciling a ClusterExternal Secret",
+		func(tc testCase) {
+			ctx := context.Background()
+			By("creating namespaces")
+			var namespaces []v1.Namespace
+			for _, ns := range tc.namespaces {
+				err := k8sClient.Create(ctx, &ns)
+				Expect(err).ShouldNot(HaveOccurred())
+				namespaces = append(namespaces, ns)
+			}
 
-	// These are the namespaces that are being tested
-	externalSecretNamespaces []testNamespace
+			By("creating a cluster external secret")
+			ces := tc.clusterExternalSecret(tc.namespaces)
+			err := k8sClient.Create(ctx, &ces)
+			Expect(err).ShouldNot(HaveOccurred())
 
-	// The labels to be used for the namespaces
-	namespaceLabels map[string]string
+			By("running before check")
+			if tc.beforeCheck != nil {
+				tc.beforeCheck(ctx, namespaces, ces)
+			}
 
-	// This is a setup function called for each test much like BeforeEach but with knowledge of the test case
-	// This is used by default to create namespaces and random labels
-	setup func(*testCase)
+			// the before check above may have updated the namespaces, so refresh them
+			for i, ns := range namespaces {
+				err := k8sClient.Get(ctx, types.NamespacedName{Name: ns.Name}, &ns)
+				Expect(err).ShouldNot(HaveOccurred())
+				namespaces[i] = ns
+			}
 
-	// Is a method that's ran after everything has been created, but before the check methods are called
-	beforeCheck func(*testCase)
+			By("checking the cluster external secret")
+			expectedCES := tc.expectedClusterExternalSecret(namespaces, ces)
 
-	// A function to do any work needed before a test is ran
-	preTest func()
+			Eventually(func(g Gomega) {
+				key := types.NamespacedName{Name: expectedCES.Name}
+				var gotCes esv1beta1.ClusterExternalSecret
+				err = k8sClient.Get(ctx, key, &gotCes)
+				g.Expect(err).ShouldNot(HaveOccurred())
 
-	// checkCondition should return true if the externalSecret
-	// has the expected condition
-	checkCondition func(*esv1beta1.ClusterExternalSecret) bool
+				g.Expect(gotCes.Labels).To(Equal(expectedCES.Labels))
+				g.Expect(gotCes.Annotations).To(Equal(expectedCES.Annotations))
+				g.Expect(gotCes.Spec).To(Equal(expectedCES.Spec))
+				g.Expect(gotCes.Status).To(Equal(expectedCES.Status))
+			}).WithTimeout(timeout).WithPolling(interval).Should(Succeed())
 
-	// checkExternalSecret is called after the condition has been verified
-	// use this to verify the externalSecret
-	checkClusterExternalSecret func(*esv1beta1.ClusterExternalSecret)
+			By("checking the external secrets")
+			expectedESs := tc.expectedExternalSecrets(namespaces, ces)
 
-	// checkExternalSecret is called after the condition has been verified
-	// use this to verify the externalSecret
-	checkExternalSecret func(*esv1beta1.ClusterExternalSecret, *esv1beta1.ExternalSecret)
-}
+			Eventually(func(g Gomega) {
+				var gotESs []esv1beta1.ExternalSecret
+				for _, ns := range namespaces {
+					var externalSecrets esv1beta1.ExternalSecretList
+					err := k8sClient.List(ctx, &externalSecrets, crclient.InNamespace(ns.Name))
+					g.Expect(err).ShouldNot(HaveOccurred())
 
-type testTweaks func(*testCase)
+					gotESs = append(gotESs, externalSecrets.Items...)
+				}
 
-var _ = Describe("ClusterExternalSecret controller", func() {
-	const (
-		ClusterExternalSecretName      = "test-ces"
-		ExternalSecretName             = "test-es"
-		ExternalSecretStore            = "test-store"
-		ExternalSecretTargetSecretName = "test-secret"
-	)
+				g.Expect(len(gotESs)).Should(Equal(len(expectedESs)))
+				for _, gotES := range gotESs {
+					found := false
+					for _, expectedES := range expectedESs {
+						if gotES.Namespace == expectedES.Namespace && gotES.Name == expectedES.Name {
+							found = true
+							g.Expect(gotES.Labels).To(Equal(expectedES.Labels))
+							g.Expect(gotES.Annotations).To(Equal(expectedES.Annotations))
+							g.Expect(gotES.Spec).To(Equal(expectedES.Spec))
+						}
+					}
+					g.Expect(found).To(Equal(true))
+				}
+			}).WithTimeout(timeout).WithPolling(interval).Should(Succeed())
+		},
 
-	var ExternalSecretNamespaceTargets = []testNamespace{
-		{
-			namespace: v1.Namespace{
-				ObjectMeta: metav1.ObjectMeta{
-					Name: "test-ns-1",
-				},
+		Entry("Should use cluster external secret name if external secret name isn't defined", testCase{
+			namespaces: []v1.Namespace{
+				{ObjectMeta: metav1.ObjectMeta{Name: randomNamespaceName()}},
 			},
-			containsES: true,
-		},
-		{
-			namespace: v1.Namespace{
-				ObjectMeta: metav1.ObjectMeta{
-					Name: "test-ns-2",
-				},
+			clusterExternalSecret: func(namespaces []v1.Namespace) esv1beta1.ClusterExternalSecret {
+				ces := defaultClusterExternalSecret()
+				ces.Spec.NamespaceSelector.MatchLabels = map[string]string{"kubernetes.io/metadata.name": namespaces[0].Name}
+				return *ces
 			},
-			containsES: true,
-		},
-		{
-			namespace: v1.Namespace{
-				ObjectMeta: metav1.ObjectMeta{
-					Name: "test-ns-5",
-				},
+			expectedClusterExternalSecret: func(namespaces []v1.Namespace, created esv1beta1.ClusterExternalSecret) esv1beta1.ClusterExternalSecret {
+				return esv1beta1.ClusterExternalSecret{
+					ObjectMeta: metav1.ObjectMeta{
+						Name: created.Name,
+					},
+					Spec: created.Spec,
+					Status: esv1beta1.ClusterExternalSecretStatus{
+						ProvisionedNamespaces: []string{namespaces[0].Name},
+						Conditions: []esv1beta1.ClusterExternalSecretStatusCondition{
+							{
+								Type:   esv1beta1.ClusterExternalSecretReady,
+								Status: v1.ConditionTrue,
+							},
+						},
+					},
+				}
 			},
-			containsES: false,
-		},
-	}
-
-	const targetProp = "targetProperty"
-	const remoteKey = "barz"
-	const remoteProperty = "bang"
-
-	makeDefaultTestCase := func() *testCase {
-		return &testCase{
-			checkCondition: func(ces *esv1beta1.ClusterExternalSecret) bool {
-				cond := GetClusterExternalSecretCondition(ces.Status, esv1beta1.ClusterExternalSecretReady)
-				if cond == nil || cond.Status != v1.ConditionTrue {
-					return false
+			expectedExternalSecrets: func(namespaces []v1.Namespace, created esv1beta1.ClusterExternalSecret) []esv1beta1.ExternalSecret {
+				return []esv1beta1.ExternalSecret{
+					{
+						ObjectMeta: metav1.ObjectMeta{
+							Namespace: namespaces[0].Name,
+							Name:      created.Name,
+						},
+						Spec: created.Spec.ExternalSecretSpec,
+					},
 				}
-				return true
 			},
-			checkClusterExternalSecret: func(es *esv1beta1.ClusterExternalSecret) {
-				// To be implemented by the tests
+		}),
+		Entry("Should set external secret name and metadata if the fields are set", testCase{
+			namespaces: []v1.Namespace{
+				{ObjectMeta: metav1.ObjectMeta{Name: randomNamespaceName()}},
 			},
-			checkExternalSecret: func(*esv1beta1.ClusterExternalSecret, *esv1beta1.ExternalSecret) {
-				// To be implemented by the tests
+			clusterExternalSecret: func(namespaces []v1.Namespace) esv1beta1.ClusterExternalSecret {
+				ces := defaultClusterExternalSecret()
+				ces.Spec.NamespaceSelector.MatchLabels = map[string]string{"kubernetes.io/metadata.name": namespaces[0].Name}
+				ces.Spec.ExternalSecretName = "test-es"
+				ces.Spec.ExternalSecretMetadata = esv1beta1.ExternalSecretMetadata{
+					Labels:      map[string]string{"test-label-key1": "test-label-value1", "test-label-key2": "test-label-value2"},
+					Annotations: map[string]string{"test-annotation-key1": "test-annotation-value1", "test-annotation-key2": "test-annotation-value2"},
+				}
+				return *ces
 			},
-			clusterExternalSecret: &esv1beta1.ClusterExternalSecret{
-				ObjectMeta: metav1.ObjectMeta{
-					GenerateName: ClusterExternalSecretName,
-				},
-				Spec: esv1beta1.ClusterExternalSecretSpec{
-					NamespaceSelector:  metav1.LabelSelector{},
-					ExternalSecretName: ExternalSecretName,
-					ExternalSecretSpec: esv1beta1.ExternalSecretSpec{
-						SecretStoreRef: esv1beta1.SecretStoreRef{
-							Name: ExternalSecretStore,
+			expectedClusterExternalSecret: func(namespaces []v1.Namespace, created esv1beta1.ClusterExternalSecret) esv1beta1.ClusterExternalSecret {
+				return esv1beta1.ClusterExternalSecret{
+					ObjectMeta: metav1.ObjectMeta{
+						Name: created.Name,
+					},
+					Spec: created.Spec,
+					Status: esv1beta1.ClusterExternalSecretStatus{
+						ProvisionedNamespaces: []string{namespaces[0].Name},
+						Conditions: []esv1beta1.ClusterExternalSecretStatusCondition{
+							{
+								Type:   esv1beta1.ClusterExternalSecretReady,
+								Status: v1.ConditionTrue,
+							},
 						},
-						Target: esv1beta1.ExternalSecretTarget{
-							Name: ExternalSecretTargetSecretName,
+					},
+				}
+			},
+			expectedExternalSecrets: func(namespaces []v1.Namespace, created esv1beta1.ClusterExternalSecret) []esv1beta1.ExternalSecret {
+				return []esv1beta1.ExternalSecret{
+					{
+						ObjectMeta: metav1.ObjectMeta{
+							Namespace:   namespaces[0].Name,
+							Name:        "test-es",
+							Labels:      map[string]string{"test-label-key1": "test-label-value1", "test-label-key2": "test-label-value2"},
+							Annotations: map[string]string{"test-annotation-key1": "test-annotation-value1", "test-annotation-key2": "test-annotation-value2"},
 						},
-						Data: []esv1beta1.ExternalSecretData{
+						Spec: created.Spec.ExternalSecretSpec,
+					},
+				}
+			},
+		}),
+		Entry("Should not overwrite existing external secrets and error out if one is present", testCase{
+			namespaces: []v1.Namespace{
+				{ObjectMeta: metav1.ObjectMeta{Name: randomNamespaceName()}},
+			},
+			clusterExternalSecret: func(namespaces []v1.Namespace) esv1beta1.ClusterExternalSecret {
+				ces := defaultClusterExternalSecret()
+				ces.Spec.NamespaceSelector.MatchLabels = map[string]string{"kubernetes.io/metadata.name": namespaces[0].Name}
+				return *ces
+			},
+			beforeCheck: func(ctx context.Context, namespaces []v1.Namespace, created esv1beta1.ClusterExternalSecret) {
+				es := &esv1beta1.ExternalSecret{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      created.Name,
+						Namespace: namespaces[0].Name,
+					},
+				}
+				Expect(k8sClient.Create(ctx, es)).ShouldNot(HaveOccurred())
+			},
+			expectedClusterExternalSecret: func(namespaces []v1.Namespace, created esv1beta1.ClusterExternalSecret) esv1beta1.ClusterExternalSecret {
+				return esv1beta1.ClusterExternalSecret{
+					ObjectMeta: metav1.ObjectMeta{
+						Name: created.Name,
+					},
+					Spec: created.Spec,
+					Status: esv1beta1.ClusterExternalSecretStatus{
+						FailedNamespaces: []esv1beta1.ClusterExternalSecretNamespaceFailure{
 							{
-								SecretKey: targetProp,
-								RemoteRef: esv1beta1.ExternalSecretDataRemoteRef{
-									Key:      remoteKey,
-									Property: remoteProperty,
-								},
+								Namespace: namespaces[0].Name,
+								Reason:    "external secret already exists in namespace",
+							},
+						},
+						Conditions: []esv1beta1.ClusterExternalSecretStatusCondition{
+							{
+								Type:    esv1beta1.ClusterExternalSecretNotReady,
+								Status:  v1.ConditionTrue,
+								Message: "one or more namespaces failed",
 							},
 						},
 					},
-				},
-			},
-			setup: func(tc *testCase) {
-				// Generate a random label since we don't want to match previous ones.
-				tc.namespaceLabels = map[string]string{
-					RandString(5): RandString(5),
 				}
-
-				namespaces := []testNamespace{}
-				for _, ns := range ExternalSecretNamespaceTargets {
-					name, err := ctest.CreateNamespaceWithLabels(ns.namespace.Name, k8sClient, tc.namespaceLabels)
-					Expect(err).ToNot(HaveOccurred())
-
-					newNs := ns
-					newNs.namespace.ObjectMeta.Name = name
-					namespaces = append(namespaces, newNs)
+			},
+			expectedExternalSecrets: func(namespaces []v1.Namespace, created esv1beta1.ClusterExternalSecret) []esv1beta1.ExternalSecret {
+				return []esv1beta1.ExternalSecret{
+					{
+						ObjectMeta: metav1.ObjectMeta{
+							Namespace: namespaces[0].Name,
+							Name:      created.Name,
+						},
+						Spec: esv1beta1.ExternalSecretSpec{
+							Target: esv1beta1.ExternalSecretTarget{
+								CreationPolicy: "Owner",
+								DeletionPolicy: "Retain",
+							},
+							RefreshInterval: &metav1.Duration{Duration: time.Hour},
+						},
+					},
 				}
-
-				tc.externalSecretNamespaces = namespaces
-
-				tc.clusterExternalSecret.Spec.NamespaceSelector.MatchLabels = tc.namespaceLabels
 			},
-		}
-	}
-
-	// If the ES does noes not have a name specified then it should use the CES name
-	syncWithoutESName := func(tc *testCase) {
-		tc.clusterExternalSecret.Spec.ExternalSecretName = ""
-		tc.checkExternalSecret = func(ces *esv1beta1.ClusterExternalSecret, es *esv1beta1.ExternalSecret) {
-			Expect(es.ObjectMeta.Name).To(Equal(ces.ObjectMeta.Name))
-		}
-	}
-
-	syncWithESMetadata := func(tc *testCase) {
-		tc.clusterExternalSecret.Spec.ExternalSecretMetadata = esv1beta1.ExternalSecretMetadata{
-			Labels:      map[string]string{"test-label-key1": "test-label-value1", "test-label-key2": "test-label-value2"},
-			Annotations: map[string]string{"test-annotation-key1": "test-annotation-value1", "test-annotation-key2": "test-annotation-value2"},
-		}
-		tc.checkExternalSecret = func(ces *esv1beta1.ClusterExternalSecret, es *esv1beta1.ExternalSecret) {
-			Expect(es.ObjectMeta.Labels).To(Equal(map[string]string{"test-label-key1": "test-label-value1", "test-label-key2": "test-label-value2"}))
-			Expect(es.ObjectMeta.Annotations).To(Equal(map[string]string{"test-annotation-key1": "test-annotation-value1", "test-annotation-key2": "test-annotation-value2"}))
-		}
-	}
-
-	doNotOverwriteExistingES := func(tc *testCase) {
-		tc.preTest = func() {
-			es := &esv1beta1.ExternalSecret{
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      ExternalSecretName,
-					Namespace: tc.externalSecretNamespaces[0].namespace.Name,
+		}),
+		Entry("Should delete external secrets when namespaces no longer match", testCase{
+			namespaces: []v1.Namespace{
+				{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:   randomNamespaceName(),
+						Labels: map[string]string{"no-longer-match-label-key": "no-longer-match-label-value"},
+					},
 				},
-			}
-
-			err := k8sClient.Create(context.Background(), es, &client.CreateOptions{})
-			Expect(err).ShouldNot(HaveOccurred())
-		}
-		tc.checkCondition = func(ces *esv1beta1.ClusterExternalSecret) bool {
-			cond := GetClusterExternalSecretCondition(ces.Status, esv1beta1.ClusterExternalSecretPartiallyReady)
-			return cond != nil
-		}
-		tc.checkClusterExternalSecret = func(ces *esv1beta1.ClusterExternalSecret) {
-			Expect(len(ces.Status.FailedNamespaces)).Should(Equal(1))
-
-			failure := ces.Status.FailedNamespaces[0]
-
-			Expect(failure.Namespace).Should(Equal(tc.externalSecretNamespaces[0].namespace.Name))
-			Expect(failure.Reason).Should(Equal(errSecretAlreadyExists))
-		}
-	}
-
-	populatedProvisionedNamespaces := func(tc *testCase) {
-		tc.checkClusterExternalSecret = func(ces *esv1beta1.ClusterExternalSecret) {
-			for _, namespace := range tc.externalSecretNamespaces {
-				if !namespace.containsES {
-					continue
-				}
-
-				Expect(sliceContainsString(namespace.namespace.Name, ces.Status.ProvisionedNamespaces)).To(BeTrue())
-			}
-		}
-	}
-
-	deleteESInNonMatchingNS := func(tc *testCase) {
-		tc.beforeCheck = func(tc *testCase) {
-			ns := tc.externalSecretNamespaces[0]
-
-			// Remove the labels, but leave the should contain ES so we can still check it
-			ns.namespace.ObjectMeta.Labels = map[string]string{}
-			tc.externalSecretNamespaces[0].deletedES = true
-
-			err := k8sClient.Update(context.Background(), &ns.namespace, &client.UpdateOptions{})
-			Expect(err).ToNot(HaveOccurred())
-			time.Sleep(time.Second) // Sleep to make sure the controller gets it.
-		}
-	}
+				{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:   randomNamespaceName(),
+						Labels: map[string]string{"no-longer-match-label-key": "no-longer-match-label-value"},
+					},
+				},
+			},
+			clusterExternalSecret: func(namespaces []v1.Namespace) esv1beta1.ClusterExternalSecret {
+				ces := defaultClusterExternalSecret()
+				ces.Spec.RefreshInterval = &metav1.Duration{Duration: 100 * time.Millisecond}
+				ces.Spec.NamespaceSelector.MatchLabels = map[string]string{"no-longer-match-label-key": "no-longer-match-label-value"}
+				return *ces
+			},
+			beforeCheck: func(ctx context.Context, namespaces []v1.Namespace, created esv1beta1.ClusterExternalSecret) {
+				// Wait until the target ESs have been created
+				Eventually(func(g Gomega) {
+					for _, ns := range namespaces {
+						key := types.NamespacedName{Namespace: ns.Name, Name: created.Name}
+						g.Expect(k8sClient.Get(ctx, key, &esv1beta1.ExternalSecret{})).ShouldNot(HaveOccurred())
+					}
+				}).WithTimeout(timeout).WithPolling(interval).Should(Succeed())
 
-	syncWithMatchExpressions := func(tc *testCase) {
-		tc.setup = func(tc *testCase) {
-			prefixes := []string{"foo", "bar", "baz"}
-			for _, prefix := range prefixes {
-				labels := map[string]string{
-					"e2e":    "with-label-selector",
-					"prefix": prefix,
+				for _, ns := range namespaces {
+					ns.Labels = map[string]string{}
+					Expect(k8sClient.Update(ctx, &ns)).ShouldNot(HaveOccurred())
 				}
-				ns, err := ctest.CreateNamespaceWithLabels(prefix, k8sClient, labels)
-				Expect(err).ToNot(HaveOccurred())
-				tc.externalSecretNamespaces = append(tc.externalSecretNamespaces, testNamespace{
-					namespace: v1.Namespace{
-						ObjectMeta: metav1.ObjectMeta{
-							Name: ns,
+			},
+			expectedClusterExternalSecret: func(namespaces []v1.Namespace, created esv1beta1.ClusterExternalSecret) esv1beta1.ClusterExternalSecret {
+				return esv1beta1.ClusterExternalSecret{
+					ObjectMeta: metav1.ObjectMeta{
+						Name: created.Name,
+					},
+					Spec: created.Spec,
+					Status: esv1beta1.ClusterExternalSecretStatus{
+						ProvisionedNamespaces: []string{namespaces[0].Name, namespaces[1].Name},
+						Conditions: []esv1beta1.ClusterExternalSecretStatusCondition{
+							{
+								Type:   esv1beta1.ClusterExternalSecretReady,
+								Status: v1.ConditionTrue,
+							},
 						},
 					},
-					containsES: true,
-				})
-			}
-			tc.clusterExternalSecret.Spec.NamespaceSelector.MatchExpressions = []metav1.LabelSelectorRequirement{
+				}
+			},
+			expectedExternalSecrets: func(namespaces []v1.Namespace, created esv1beta1.ClusterExternalSecret) []esv1beta1.ExternalSecret {
+				return []esv1beta1.ExternalSecret{}
+			},
+		}),
+		Entry("Should sync with match expression", testCase{
+			namespaces: []v1.Namespace{
 				{
-					Key:      "prefix",
-					Operator: metav1.LabelSelectorOpIn,
-					Values:   prefixes,
+					ObjectMeta: metav1.ObjectMeta{
+						Name:   randomNamespaceName(),
+						Labels: map[string]string{"prefix": "foo"},
+					},
 				},
-			}
-		}
-		tc.checkClusterExternalSecret = func(ces *esv1beta1.ClusterExternalSecret) {
-			for _, namespace := range tc.externalSecretNamespaces {
-				var es esv1beta1.ExternalSecret
-				err := k8sClient.Get(context.Background(), types.NamespacedName{
-					Namespace: namespace.namespace.Name,
-					Name:      ExternalSecretName,
-				}, &es)
-				Expect(err).ToNot(HaveOccurred())
-				Expect(sliceContainsString(namespace.namespace.Name, ces.Status.ProvisionedNamespaces)).To(BeTrue())
-			}
-		}
-	}
-
-	DescribeTable("When reconciling a ClusterExternal Secret",
-		func(tweaks ...testTweaks) {
-			tc := makeDefaultTestCase()
-			for _, tweak := range tweaks {
-				tweak(tc)
-			}
-
-			// Run test setup
-			tc.setup(tc)
-
-			if tc.preTest != nil {
-				By("running pre-test")
-				tc.preTest()
-			}
-			ctx := context.Background()
-			By("creating namespaces and cluster external secret")
-			err := k8sClient.Create(ctx, tc.clusterExternalSecret)
-			Expect(err).ShouldNot(HaveOccurred())
-			cesKey := types.NamespacedName{Name: tc.clusterExternalSecret.Name}
-			createdCES := &esv1beta1.ClusterExternalSecret{}
-
-			By("checking the ces condition")
-			Eventually(func() bool {
-				err := k8sClient.Get(ctx, cesKey, createdCES)
-				if err != nil {
-					return false
+				{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:   randomNamespaceName(),
+						Labels: map[string]string{"prefix": "bar"},
+					},
+				},
+				{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:   randomNamespaceName(),
+						Labels: map[string]string{"prefix": "baz"},
+					},
+				},
+			},
+			clusterExternalSecret: func(namespaces []v1.Namespace) esv1beta1.ClusterExternalSecret {
+				ces := defaultClusterExternalSecret()
+				ces.Spec.RefreshInterval = &metav1.Duration{Duration: 100 * time.Millisecond}
+				ces.Spec.NamespaceSelector.MatchExpressions = []metav1.LabelSelectorRequirement{
+					{
+						Key:      "prefix",
+						Operator: metav1.LabelSelectorOpIn,
+						Values:   []string{"foo", "bar"}, // "baz" is excluded
+					},
 				}
-				return tc.checkCondition(createdCES)
-			}, timeout, interval).Should(BeTrue())
-
-			// Run before check
-			if tc.beforeCheck != nil {
-				tc.beforeCheck(tc)
-			}
-
-			tc.checkClusterExternalSecret(createdCES)
-
-			if tc.checkExternalSecret != nil {
-				for _, ns := range tc.externalSecretNamespaces {
-
-					if !ns.containsES {
-						continue
-					}
-
-					es := &esv1beta1.ExternalSecret{}
-
-					esName := createdCES.Spec.ExternalSecretName
-					if esName == "" {
-						esName = createdCES.ObjectMeta.Name
-					}
-
-					esLookupKey := types.NamespacedName{
-						Name:      esName,
-						Namespace: ns.namespace.Name,
-					}
-
-					Eventually(func() bool {
-						err := k8sClient.Get(ctx, esLookupKey, es)
-
-						if ns.deletedES && apierrors.IsNotFound(err) {
-							return true
-						}
-
-						return err == nil
-					}, timeout, interval).Should(BeTrue())
-					tc.checkExternalSecret(createdCES, es)
+				return *ces
+			},
+			expectedClusterExternalSecret: func(namespaces []v1.Namespace, created esv1beta1.ClusterExternalSecret) esv1beta1.ClusterExternalSecret {
+				return esv1beta1.ClusterExternalSecret{
+					ObjectMeta: metav1.ObjectMeta{
+						Name: created.Name,
+					},
+					Spec: created.Spec,
+					Status: esv1beta1.ClusterExternalSecretStatus{
+						ProvisionedNamespaces: []string{namespaces[0].Name, namespaces[1].Name},
+						Conditions: []esv1beta1.ClusterExternalSecretStatusCondition{
+							{
+								Type:   esv1beta1.ClusterExternalSecretReady,
+								Status: v1.ConditionTrue,
+							},
+						},
+					},
 				}
-			}
-		},
-
-		Entry("Should use cluster external secret name if external secret name isn't defined", syncWithoutESName),
-		Entry("Should set external secret metadata if the field is set", syncWithESMetadata),
-		Entry("Should not overwrite existing external secrets and error out if one is present", doNotOverwriteExistingES),
-		Entry("Should have list of all provisioned namespaces", populatedProvisionedNamespaces),
-		Entry("Should delete external secrets when namespaces no longer match", deleteESInNonMatchingNS),
-		Entry("Should sync with label selector", syncWithMatchExpressions))
+			},
+			expectedExternalSecrets: func(namespaces []v1.Namespace, created esv1beta1.ClusterExternalSecret) []esv1beta1.ExternalSecret {
+				return []esv1beta1.ExternalSecret{
+					{
+						ObjectMeta: metav1.ObjectMeta{
+							Namespace: namespaces[0].Name,
+							Name:      created.Name,
+						},
+						Spec: created.Spec.ExternalSecretSpec,
+					},
+					{
+						ObjectMeta: metav1.ObjectMeta{
+							Namespace: namespaces[1].Name,
+							Name:      created.Name,
+						},
+						Spec: created.Spec.ExternalSecretSpec,
+					},
+				}
+			},
+		}))
 })
 
-func sliceContainsString(toFind string, collection []string) bool {
-	for _, val := range collection {
-		if val == toFind {
-			return true
-		}
-	}
+var letterRunes = []rune("abcdefghijklmnopqrstuvwxyz")
 
-	return false
+func randString(n int) string {
+	b := make([]rune, n)
+	for i := range b {
+		b[i] = letterRunes[rand.Intn(len(letterRunes))]
+	}
+	return string(b)
 }
 
-func init() {
-	ctrlmetrics.SetUpLabelNames(false)
-	cesmetrics.SetUpMetrics()
+func randomNamespaceName() string {
+	return fmt.Sprintf("testns-%s", randString(10))
 }

+ 1 - 3
pkg/controllers/clusterexternalsecret/suite_test.go

@@ -24,7 +24,6 @@ import (
 	. "github.com/onsi/gomega"
 	"go.uber.org/zap/zapcore"
 	"k8s.io/client-go/kubernetes/scheme"
-	"k8s.io/client-go/rest"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/controller"
@@ -38,7 +37,6 @@ import (
 // These tests use Ginkgo (BDD-style Go testing framework). Refer to
 // http://onsi.github.io/ginkgo/ to learn more about Ginkgo.
 
-var cfg *rest.Config
 var k8sClient client.Client
 var testEnv *envtest.Environment
 var cancel context.CancelFunc
@@ -62,7 +60,7 @@ var _ = BeforeSuite(func() {
 	ctx, cancel = context.WithCancel(context.Background())
 
 	var err error
-	cfg, err = testEnv.Start()
+	cfg, err := testEnv.Start()
 	Expect(err).ToNot(HaveOccurred())
 	Expect(cfg).ToNot(BeNil())
 

+ 0 - 11
pkg/controllers/clusterexternalsecret/util.go

@@ -35,17 +35,6 @@ func NewClusterExternalSecretCondition(failedNamespaces map[string]string, names
 	return condition
 }
 
-// GetClusterExternalSecretCondition returns the condition with the provided type.
-func GetClusterExternalSecretCondition(status esv1beta1.ClusterExternalSecretStatus, condType esv1beta1.ClusterExternalSecretConditionType) *esv1beta1.ClusterExternalSecretStatusCondition {
-	for i := range status.Conditions {
-		c := status.Conditions[i]
-		if c.Type == condType {
-			return &c
-		}
-	}
-	return nil
-}
-
 func SetClusterExternalSecretCondition(ces *esv1beta1.ClusterExternalSecret, condition esv1beta1.ClusterExternalSecretStatusCondition) {
 	ces.Status.Conditions = append(filterOutCondition(ces.Status.Conditions, condition.Type), condition)
 	cesmetrics.UpdateClusterExternalSecretCondition(ces, &condition)