Skip to content

Commit 5105bbe

Browse files
authored
chore: backport Ginkgo E2E test changes from argocd-operator (#940)
Signed-off-by: Jonathan West <jonwest@redhat.com>
1 parent cfdfdb2 commit 5105bbe

23 files changed

+503
-56
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ require (
99
github.com/argoproj/gitops-engine v0.7.1-0.20250617174952-093aef0dad58
1010
github.com/go-logr/logr v1.4.3
1111
github.com/google/go-cmp v0.7.0
12+
github.com/google/uuid v1.6.1-0.20241114170450-2d3c2a9cc518
1213
github.com/hashicorp/go-version v1.7.0
1314
github.com/onsi/ginkgo/v2 v2.22.2
1415
github.com/onsi/gomega v1.36.2
@@ -87,7 +88,6 @@ require (
8788
github.com/google/go-querystring v1.1.0 // indirect
8889
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect
8990
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
90-
github.com/google/uuid v1.6.1-0.20241114170450-2d3c2a9cc518 // indirect
9191
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
9292
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
9393
github.com/inconshreveable/mousetrap v1.1.0 // indirect

test/openshift/e2e/ginkgo/fixture/argocd/fixture.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,45 @@ func HaveApplicationControllerOperationProcessors(operationProcessors int) match
155155
})
156156
}
157157

158+
func HaveCondition(condition metav1.Condition) matcher.GomegaMatcher {
159+
return fetchArgoCD(func(argocd *argov1beta1api.ArgoCD) bool {
160+
161+
if len(argocd.Status.Conditions) != 1 {
162+
GinkgoWriter.Println("HaveCondition: length is zero")
163+
return false
164+
}
165+
166+
instanceCondition := argocd.Status.Conditions[0]
167+
168+
GinkgoWriter.Println("HaveCondition - Message:", instanceCondition.Message, condition.Message)
169+
if instanceCondition.Message != condition.Message {
170+
GinkgoWriter.Println("HaveCondition: message does not match")
171+
return false
172+
}
173+
174+
GinkgoWriter.Println("HaveCondition - Reason:", instanceCondition.Reason, condition.Reason)
175+
if instanceCondition.Reason != condition.Reason {
176+
GinkgoWriter.Println("HaveCondition: reason does not match")
177+
return false
178+
}
179+
180+
GinkgoWriter.Println("HaveCondition - Status:", instanceCondition.Status, condition.Status)
181+
if instanceCondition.Status != condition.Status {
182+
GinkgoWriter.Println("HaveCondition: status does not match")
183+
return false
184+
}
185+
186+
GinkgoWriter.Println("HaveCondition - Type:", instanceCondition.Type, condition.Type)
187+
if instanceCondition.Type != condition.Type {
188+
GinkgoWriter.Println("HaveCondition: type does not match")
189+
return false
190+
}
191+
192+
return true
193+
194+
})
195+
}
196+
158197
// This is intentionally NOT exported, for now. Create another function in this file/package that calls this function, and export that.
159198
func fetchArgoCD(f func(*argov1beta1api.ArgoCD) bool) matcher.GomegaMatcher {
160199

test/openshift/e2e/ginkgo/fixture/configmap/fixture.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,16 @@ func HaveStringDataKeyValue(key string, value string) matcher.GomegaMatcher {
6767
GinkgoWriter.Println("HaveStringDataKeyValue: ConfigMag key", key, "Have:", a, "Expected:", value)
6868
}
6969

70-
return string(a) == value
70+
return a == value
71+
})
72+
73+
}
74+
75+
// NotHaveStringDataKey returns true if ConfigMap's .data 'key' does not exist, false otherwise
76+
func NotHaveStringDataKey(key string) matcher.GomegaMatcher {
77+
return fetchConfigMap(func(cm *corev1.ConfigMap) bool {
78+
_, exists := cm.Data[key]
79+
return !exists
7180
})
7281

7382
}
@@ -108,7 +117,7 @@ func HaveStringDataKeyValueContainsSubstring(key string, substring string) match
108117
GinkgoWriter.Println("HaveStringDataKeyValue: ConfigMag key", key, "Value:", a, "Expected:", substring)
109118
}
110119

111-
return strings.Contains(string(a), substring)
120+
return strings.Contains(a, substring)
112121
})
113122

114123
}

test/openshift/e2e/ginkgo/fixture/deployment/fixture.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,22 @@ func GetTemplateSpecContainerByName(name string, depl appsv1.Deployment) *corev1
151151
return nil
152152
}
153153

154+
func HaveTemplateSpec(podTemplateSpec corev1.PodTemplateSpec) matcher.GomegaMatcher {
155+
return fetchDeployment(func(depl *appsv1.Deployment) bool {
156+
157+
templateSpec := depl.Spec.Template.Spec
158+
159+
if templateSpec.NodeSelector == nil {
160+
GinkgoWriter.Println("HaveTemplateSpec - .spec.template.spec is nil")
161+
return false
162+
}
163+
164+
GinkgoWriter.Println("HaveTemplateSpec - expected:", podTemplateSpec, "actual:", templateSpec)
165+
return reflect.DeepEqual(podTemplateSpec, templateSpec)
166+
})
167+
168+
}
169+
154170
func HaveTemplateSpecNodeSelector(nodeSelector map[string]string) matcher.GomegaMatcher {
155171
return fetchDeployment(func(depl *appsv1.Deployment) bool {
156172

@@ -337,6 +353,23 @@ func HaveContainerWithEnvVar(envKey string, envValue string, containerIndex int)
337353
})
338354
}
339355

356+
func HaveSpecTemplateSpecVolume(volumeParam corev1.Volume) matcher.GomegaMatcher {
357+
return fetchDeployment(func(depl *appsv1.Deployment) bool {
358+
359+
GinkgoWriter.Println("HaveSpecTemplateSpecVolume - Volumes:")
360+
for _, volume := range depl.Spec.Template.Spec.Volumes {
361+
GinkgoWriter.Println("-", volume)
362+
363+
if reflect.DeepEqual(volumeParam, volume) {
364+
return true
365+
}
366+
}
367+
368+
return false
369+
})
370+
371+
}
372+
340373
func HaveConditionTypeStatus(expectedConditionType appsv1.DeploymentConditionType, expectedConditionStatus corev1.ConditionStatus) matcher.GomegaMatcher {
341374
return fetchDeployment(func(depl *appsv1.Deployment) bool {
342375

test/openshift/e2e/ginkgo/fixture/fixture.go

Lines changed: 64 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import (
3737
appsv1 "k8s.io/api/apps/v1"
3838
corev1 "k8s.io/api/core/v1"
3939
rbacv1 "k8s.io/api/rbac/v1"
40+
crdv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
4041
apierr "k8s.io/apimachinery/pkg/api/errors"
4142
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
4243
)
@@ -254,7 +255,7 @@ func CreateRandomE2ETestNamespace() *corev1.Namespace {
254255

255256
testNamespaceName := "gitops-e2e-test-" + randomVal
256257

257-
ns := CreateNamespace(string(testNamespaceName))
258+
ns := CreateNamespace(testNamespaceName)
258259
return ns
259260
}
260261

@@ -329,23 +330,26 @@ func CreateManagedNamespaceWithCleanupFunc(name string, managedByNamespace strin
329330
func nsDeletionFunc(ns *corev1.Namespace) func() {
330331

331332
return func() {
333+
DeleteNamespace(ns)
334+
}
332335

333-
// If you are debugging an E2E test and want to prevent its namespace from being deleted when the test ends (so that you can examine the state of resources in the namespace) you can set E2E_DEBUG_SKIP_CLEANUP env var.
334-
if os.Getenv("E2E_DEBUG_SKIP_CLEANUP") != "" {
335-
GinkgoWriter.Println("Skipping namespace cleanup as E2E_DEBUG_SKIP_CLEANUP is set")
336-
return
337-
}
338-
339-
k8sClient, _, err := utils.GetE2ETestKubeClientWithError()
340-
Expect(err).ToNot(HaveOccurred())
341-
err = k8sClient.Delete(context.Background(), ns, &client.DeleteOptions{PropagationPolicy: ptr.To(metav1.DeletePropagationForeground)})
336+
}
342337

343-
// Error shouldn't occur, UNLESS it's because the NS no longer exists
344-
if err != nil && !apierr.IsNotFound(err) {
345-
Expect(err).ToNot(HaveOccurred())
346-
}
338+
func DeleteNamespace(ns *corev1.Namespace) {
339+
// If you are debugging an E2E test and want to prevent its namespace from being deleted when the test ends (so that you can examine the state of resources in the namespace) you can set E2E_DEBUG_SKIP_CLEANUP env var.
340+
if os.Getenv("E2E_DEBUG_SKIP_CLEANUP") != "" {
341+
GinkgoWriter.Println("Skipping namespace cleanup as E2E_DEBUG_SKIP_CLEANUP is set")
342+
return
347343
}
348344

345+
k8sClient, _, err := utils.GetE2ETestKubeClientWithError()
346+
Expect(err).ToNot(HaveOccurred())
347+
err = k8sClient.Delete(context.Background(), ns, &client.DeleteOptions{PropagationPolicy: ptr.To(metav1.DeletePropagationForeground)})
348+
349+
// Error shouldn't occur, UNLESS it's because the NS no longer exists
350+
if err != nil && !apierr.IsNotFound(err) {
351+
Expect(err).ToNot(HaveOccurred())
352+
}
349353
}
350354

351355
// EnvNonOLM checks if NON_OLM var is set; this variable is set when testing on GitOps operator that is not installed via OLM
@@ -804,7 +808,8 @@ var testReportMap = map[string]testReportEntry{} // acquire testReportLock befor
804808
// - Namespace parameter may be a string, *Namespace, or Namespace
805809
func OutputDebugOnFail(namespaceParams ...any) {
806810

807-
// Convert parameter to string of namespace name
811+
// Convert parameter to string of namespace name:
812+
// - You can specify Namespace, *Namespae, or string, and we will convert it to string namespace
808813
namespaces := []string{}
809814
for _, param := range namespaceParams {
810815

@@ -852,7 +857,7 @@ func OutputDebugOnFail(namespaceParams ...any) {
852857

853858
kubectlOutput, err := osFixture.ExecCommandWithOutputParam(false, "kubectl", "get", "all", "-n", namespace)
854859
if err != nil {
855-
GinkgoWriter.Println("unable to extract operator logs for namespace", namespace, err, kubectlOutput)
860+
GinkgoWriter.Println("unable to list", namespace, err, kubectlOutput)
856861
continue
857862
}
858863

@@ -862,6 +867,18 @@ func OutputDebugOnFail(namespaceParams ...any) {
862867
GinkgoWriter.Println(kubectlOutput)
863868
GinkgoWriter.Println("----------------------------------------------------------------")
864869

870+
kubectlOutput, err = osFixture.ExecCommandWithOutputParam(false, "kubectl", "get", "deployments", "-n", namespace, "-o", "yaml")
871+
if err != nil {
872+
GinkgoWriter.Println("unable to list", namespace, err, kubectlOutput)
873+
continue
874+
}
875+
876+
GinkgoWriter.Println("")
877+
GinkgoWriter.Println("----------------------------------------------------------------")
878+
GinkgoWriter.Println("'kubectl get deployments -n " + namespace + " -o yaml")
879+
GinkgoWriter.Println(kubectlOutput)
880+
GinkgoWriter.Println("----------------------------------------------------------------")
881+
865882
}
866883

867884
kubectlOutput, err := osFixture.ExecCommandWithOutputParam(false, "kubectl", "get", "argocds", "-A", "-o", "yaml")
@@ -877,6 +894,37 @@ func OutputDebugOnFail(namespaceParams ...any) {
877894

878895
}
879896

897+
// EnsureRunningOnOpenShift should be called if a test requires OpenShift (for example, it uses Route CR).
898+
func EnsureRunningOnOpenShift() {
899+
900+
runningOnOpenShift := RunningOnOpenShift()
901+
902+
if !runningOnOpenShift {
903+
Skip("This test requires the cluster to be OpenShift")
904+
return
905+
}
906+
907+
Expect(runningOnOpenShift).To(BeTrueBecause("this test is marked as requiring an OpenShift cluster, and we have detected the cluster is OpenShift"))
908+
909+
}
910+
911+
// RunningOnOpenShift returns true if the cluster is an OpenShift cluster, false otherwise.
912+
func RunningOnOpenShift() bool {
913+
k8sClient, _ := utils.GetE2ETestKubeClient()
914+
915+
crdList := crdv1.CustomResourceDefinitionList{}
916+
Expect(k8sClient.List(context.Background(), &crdList)).To(Succeed())
917+
918+
openshiftAPIsFound := 0
919+
for _, crd := range crdList.Items {
920+
if strings.Contains(crd.Spec.Group, "openshift.io") {
921+
openshiftAPIsFound++
922+
}
923+
}
924+
return openshiftAPIsFound > 5 // I picked 5 as an arbitrary number, could also just be 1
925+
}
926+
927+
//nolint:unused
880928
func outputPodLog(podSubstring string) {
881929
k8sClient, _, err := utils.GetE2ETestKubeClientWithError()
882930
if err != nil {

test/openshift/e2e/ginkgo/fixture/rolebinding/fixture.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@ import (
1616

1717
func HaveSubject(subjectParam rbacv1.Subject) matcher.GomegaMatcher {
1818
return fetchRoleBinding(func(r *rbacv1.RoleBinding) bool {
19-
for _, subject := range r.Subjects {
2019

21-
GinkgoWriter.Println("HaveSubject - ", subject, subjectParam)
20+
GinkgoWriter.Println("HaveSubject - Want:", subjectParam)
21+
for idx, subject := range r.Subjects {
22+
23+
GinkgoWriter.Printf("%d) HaveSubject - Have: %s\n", idx+1, subject)
2224
if reflect.DeepEqual(subjectParam, subject) {
2325
return true
2426
}

test/openshift/e2e/ginkgo/fixture/secret/fixture.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,22 @@ func UpdateWithError(obj *corev1.Secret, modify func(*corev1.Secret)) error {
5454
return err
5555
}
5656

57+
// HaveNonEmptyKeyValue returns true if Secret has the given key, and the value of the key is non-empty
58+
func HaveNonEmptyKeyValue(key string) matcher.GomegaMatcher {
59+
return fetchSecret(func(sec *corev1.Secret) bool {
60+
a, exists := sec.Data[key]
61+
if !exists {
62+
GinkgoWriter.Println("HaveNonEmptyKeyValue - Key:", key, "does not exist")
63+
return false
64+
}
65+
66+
GinkgoWriter.Println("HaveNonEmptyKeyValue - Key:", key, " Have:", string(a))
67+
68+
return len(a) > 0
69+
})
70+
71+
}
72+
5773
// HaveStringDataKeyValue returns true if Secret has 'key' field under .data map, and the value of that field is equal to 'value'
5874
func HaveStringDataKeyValue(key string, value string) matcher.GomegaMatcher {
5975
return fetchSecret(func(sec *corev1.Secret) bool {

test/openshift/e2e/ginkgo/fixture/utils/fixtureUtils.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
admissionv1 "k8s.io/api/admissionregistration/v1"
2525
apps "k8s.io/api/apps/v1"
2626
autoscalingv2 "k8s.io/api/autoscaling/v2"
27+
batchv1 "k8s.io/api/batch/v1"
2728
corev1 "k8s.io/api/core/v1"
2829
networkingv1 "k8s.io/api/networking/v1"
2930
rbacv1 "k8s.io/api/rbac/v1"
@@ -132,6 +133,10 @@ func getKubeClient(config *rest.Config) (client.Client, *runtime.Scheme, error)
132133
return nil, nil, err
133134
}
134135

136+
if err := batchv1.AddToScheme(scheme); err != nil {
137+
return nil, nil, err
138+
}
139+
135140
k8sClient, err := client.New(config, client.Options{Scheme: scheme})
136141
if err != nil {
137142
return nil, nil, err

test/openshift/e2e/ginkgo/parallel/1-004_beta_to_alpha_conversion_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import (
2727
deploymentFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment"
2828
k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s"
2929
fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils"
30-
corev1 "k8s.io/api/apps/v1"
30+
appsv1 "k8s.io/api/apps/v1"
3131
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3232

3333
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -106,7 +106,7 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() {
106106
Expect(argoCDAlpha1.Spec.SSO.Dex.OpenShiftOAuth).To(BeTrue())
107107
Expect(argoCDAlpha1.Spec.Server.Route.Enabled).To(BeTrue())
108108

109-
dexDeployment := &corev1.Deployment{
109+
dexDeployment := &appsv1.Deployment{
110110
ObjectMeta: metav1.ObjectMeta{
111111
Name: "argocd-dex-server",
112112
Namespace: ns.Name,

test/openshift/e2e/ginkgo/parallel/1-005_validate_route_tls_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() {
5050
ctx = context.Background()
5151
})
5252

53-
It("ensures that certificates can be confirmed on server and webhook Routes", func() {
53+
It("ensures that certificates can be confirmed on server and webhook Routes", func() {
54+
55+
fixture.EnsureRunningOnOpenShift()
5456

5557
ns, nsCleanup := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc()
5658
defer nsCleanup()

0 commit comments

Comments
 (0)