From 66a6a244e2399bab978071f9ebba35368e1810a7 Mon Sep 17 00:00:00 2001 From: Jonathan West Date: Thu, 11 Sep 2025 23:27:46 -0400 Subject: [PATCH] chore: backport Ginkgo E2E test changes from argocd-operator Signed-off-by: Jonathan West --- go.mod | 2 +- .../e2e/ginkgo/fixture/argocd/fixture.go | 39 ++++ .../e2e/ginkgo/fixture/configmap/fixture.go | 13 +- .../e2e/ginkgo/fixture/deployment/fixture.go | 33 +++ test/openshift/e2e/ginkgo/fixture/fixture.go | 80 ++++++-- .../e2e/ginkgo/fixture/rolebinding/fixture.go | 6 +- .../e2e/ginkgo/fixture/secret/fixture.go | 16 ++ .../e2e/ginkgo/fixture/utils/fixtureUtils.go | 5 + .../1-004_beta_to_alpha_conversion_test.go | 4 +- .../parallel/1-005_validate_route_tls_test.go | 4 +- .../1-019_validate_volume_mounts_test.go | 192 ++++++++++++++++++ .../1-042_restricted_pss_compliant_test.go | 24 ++- ...validate_custom_labels_annotations_test.go | 56 +++-- ...5_validate_notification_controller_test.go | 2 +- ..._validate_config_management_plugin_test.go | 24 ++- ...1-084_validate_status_host_ingress_test.go | 8 +- ...lidate_applicationset_add_env_vars_test.go | 2 + ..._validate_extra_repo_commands_args_test.go | 2 + ...app_validate-applicationset-status_test.go | 2 + .../1-099_validate_server_autoscale_test.go | 4 +- .../parallel/1-118_validate_redis_ssc_test.go | 2 + .../parallel/1-119_argocd_respectRBAC_test.go | 37 +++- ...te_applicationset_in_any_namespace_test.go | 2 + 23 files changed, 503 insertions(+), 56 deletions(-) diff --git a/go.mod b/go.mod index c17462dab6f..069fd39406c 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/argoproj/gitops-engine v0.7.1-0.20250617174952-093aef0dad58 github.com/go-logr/logr v1.4.3 github.com/google/go-cmp v0.7.0 + github.com/google/uuid v1.6.1-0.20241114170450-2d3c2a9cc518 github.com/hashicorp/go-version v1.7.0 github.com/onsi/ginkgo/v2 v2.22.2 github.com/onsi/gomega v1.36.2 @@ -87,7 +88,6 @@ require ( github.com/google/go-querystring v1.1.0 // indirect github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect - github.com/google/uuid v1.6.1-0.20241114170450-2d3c2a9cc518 // indirect github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect diff --git a/test/openshift/e2e/ginkgo/fixture/argocd/fixture.go b/test/openshift/e2e/ginkgo/fixture/argocd/fixture.go index 1159a190d10..a5be68e9c3b 100644 --- a/test/openshift/e2e/ginkgo/fixture/argocd/fixture.go +++ b/test/openshift/e2e/ginkgo/fixture/argocd/fixture.go @@ -155,6 +155,45 @@ func HaveApplicationControllerOperationProcessors(operationProcessors int) match }) } +func HaveCondition(condition metav1.Condition) matcher.GomegaMatcher { + return fetchArgoCD(func(argocd *argov1beta1api.ArgoCD) bool { + + if len(argocd.Status.Conditions) != 1 { + GinkgoWriter.Println("HaveCondition: length is zero") + return false + } + + instanceCondition := argocd.Status.Conditions[0] + + GinkgoWriter.Println("HaveCondition - Message:", instanceCondition.Message, condition.Message) + if instanceCondition.Message != condition.Message { + GinkgoWriter.Println("HaveCondition: message does not match") + return false + } + + GinkgoWriter.Println("HaveCondition - Reason:", instanceCondition.Reason, condition.Reason) + if instanceCondition.Reason != condition.Reason { + GinkgoWriter.Println("HaveCondition: reason does not match") + return false + } + + GinkgoWriter.Println("HaveCondition - Status:", instanceCondition.Status, condition.Status) + if instanceCondition.Status != condition.Status { + GinkgoWriter.Println("HaveCondition: status does not match") + return false + } + + GinkgoWriter.Println("HaveCondition - Type:", instanceCondition.Type, condition.Type) + if instanceCondition.Type != condition.Type { + GinkgoWriter.Println("HaveCondition: type does not match") + return false + } + + return true + + }) +} + // This is intentionally NOT exported, for now. Create another function in this file/package that calls this function, and export that. func fetchArgoCD(f func(*argov1beta1api.ArgoCD) bool) matcher.GomegaMatcher { diff --git a/test/openshift/e2e/ginkgo/fixture/configmap/fixture.go b/test/openshift/e2e/ginkgo/fixture/configmap/fixture.go index 65e456909d4..a2ff6e617aa 100644 --- a/test/openshift/e2e/ginkgo/fixture/configmap/fixture.go +++ b/test/openshift/e2e/ginkgo/fixture/configmap/fixture.go @@ -67,7 +67,16 @@ func HaveStringDataKeyValue(key string, value string) matcher.GomegaMatcher { GinkgoWriter.Println("HaveStringDataKeyValue: ConfigMag key", key, "Have:", a, "Expected:", value) } - return string(a) == value + return a == value + }) + +} + +// NotHaveStringDataKey returns true if ConfigMap's .data 'key' does not exist, false otherwise +func NotHaveStringDataKey(key string) matcher.GomegaMatcher { + return fetchConfigMap(func(cm *corev1.ConfigMap) bool { + _, exists := cm.Data[key] + return !exists }) } @@ -108,7 +117,7 @@ func HaveStringDataKeyValueContainsSubstring(key string, substring string) match GinkgoWriter.Println("HaveStringDataKeyValue: ConfigMag key", key, "Value:", a, "Expected:", substring) } - return strings.Contains(string(a), substring) + return strings.Contains(a, substring) }) } diff --git a/test/openshift/e2e/ginkgo/fixture/deployment/fixture.go b/test/openshift/e2e/ginkgo/fixture/deployment/fixture.go index fa51bcfc67c..45ffc7ef429 100644 --- a/test/openshift/e2e/ginkgo/fixture/deployment/fixture.go +++ b/test/openshift/e2e/ginkgo/fixture/deployment/fixture.go @@ -151,6 +151,22 @@ func GetTemplateSpecContainerByName(name string, depl appsv1.Deployment) *corev1 return nil } +func HaveTemplateSpec(podTemplateSpec corev1.PodTemplateSpec) matcher.GomegaMatcher { + return fetchDeployment(func(depl *appsv1.Deployment) bool { + + templateSpec := depl.Spec.Template.Spec + + if templateSpec.NodeSelector == nil { + GinkgoWriter.Println("HaveTemplateSpec - .spec.template.spec is nil") + return false + } + + GinkgoWriter.Println("HaveTemplateSpec - expected:", podTemplateSpec, "actual:", templateSpec) + return reflect.DeepEqual(podTemplateSpec, templateSpec) + }) + +} + func HaveTemplateSpecNodeSelector(nodeSelector map[string]string) matcher.GomegaMatcher { return fetchDeployment(func(depl *appsv1.Deployment) bool { @@ -337,6 +353,23 @@ func HaveContainerWithEnvVar(envKey string, envValue string, containerIndex int) }) } +func HaveSpecTemplateSpecVolume(volumeParam corev1.Volume) matcher.GomegaMatcher { + return fetchDeployment(func(depl *appsv1.Deployment) bool { + + GinkgoWriter.Println("HaveSpecTemplateSpecVolume - Volumes:") + for _, volume := range depl.Spec.Template.Spec.Volumes { + GinkgoWriter.Println("-", volume) + + if reflect.DeepEqual(volumeParam, volume) { + return true + } + } + + return false + }) + +} + func HaveConditionTypeStatus(expectedConditionType appsv1.DeploymentConditionType, expectedConditionStatus corev1.ConditionStatus) matcher.GomegaMatcher { return fetchDeployment(func(depl *appsv1.Deployment) bool { diff --git a/test/openshift/e2e/ginkgo/fixture/fixture.go b/test/openshift/e2e/ginkgo/fixture/fixture.go index c9822d78cc6..246309f8542 100644 --- a/test/openshift/e2e/ginkgo/fixture/fixture.go +++ b/test/openshift/e2e/ginkgo/fixture/fixture.go @@ -37,6 +37,7 @@ import ( appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" + crdv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apierr "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -254,7 +255,7 @@ func CreateRandomE2ETestNamespace() *corev1.Namespace { testNamespaceName := "gitops-e2e-test-" + randomVal - ns := CreateNamespace(string(testNamespaceName)) + ns := CreateNamespace(testNamespaceName) return ns } @@ -329,23 +330,26 @@ func CreateManagedNamespaceWithCleanupFunc(name string, managedByNamespace strin func nsDeletionFunc(ns *corev1.Namespace) func() { return func() { + DeleteNamespace(ns) + } - // 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. - if os.Getenv("E2E_DEBUG_SKIP_CLEANUP") != "" { - GinkgoWriter.Println("Skipping namespace cleanup as E2E_DEBUG_SKIP_CLEANUP is set") - return - } - - k8sClient, _, err := utils.GetE2ETestKubeClientWithError() - Expect(err).ToNot(HaveOccurred()) - err = k8sClient.Delete(context.Background(), ns, &client.DeleteOptions{PropagationPolicy: ptr.To(metav1.DeletePropagationForeground)}) +} - // Error shouldn't occur, UNLESS it's because the NS no longer exists - if err != nil && !apierr.IsNotFound(err) { - Expect(err).ToNot(HaveOccurred()) - } +func DeleteNamespace(ns *corev1.Namespace) { + // 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. + if os.Getenv("E2E_DEBUG_SKIP_CLEANUP") != "" { + GinkgoWriter.Println("Skipping namespace cleanup as E2E_DEBUG_SKIP_CLEANUP is set") + return } + k8sClient, _, err := utils.GetE2ETestKubeClientWithError() + Expect(err).ToNot(HaveOccurred()) + err = k8sClient.Delete(context.Background(), ns, &client.DeleteOptions{PropagationPolicy: ptr.To(metav1.DeletePropagationForeground)}) + + // Error shouldn't occur, UNLESS it's because the NS no longer exists + if err != nil && !apierr.IsNotFound(err) { + Expect(err).ToNot(HaveOccurred()) + } } // 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 // - Namespace parameter may be a string, *Namespace, or Namespace func OutputDebugOnFail(namespaceParams ...any) { - // Convert parameter to string of namespace name + // Convert parameter to string of namespace name: + // - You can specify Namespace, *Namespae, or string, and we will convert it to string namespace namespaces := []string{} for _, param := range namespaceParams { @@ -852,7 +857,7 @@ func OutputDebugOnFail(namespaceParams ...any) { kubectlOutput, err := osFixture.ExecCommandWithOutputParam(false, "kubectl", "get", "all", "-n", namespace) if err != nil { - GinkgoWriter.Println("unable to extract operator logs for namespace", namespace, err, kubectlOutput) + GinkgoWriter.Println("unable to list", namespace, err, kubectlOutput) continue } @@ -862,6 +867,18 @@ func OutputDebugOnFail(namespaceParams ...any) { GinkgoWriter.Println(kubectlOutput) GinkgoWriter.Println("----------------------------------------------------------------") + kubectlOutput, err = osFixture.ExecCommandWithOutputParam(false, "kubectl", "get", "deployments", "-n", namespace, "-o", "yaml") + if err != nil { + GinkgoWriter.Println("unable to list", namespace, err, kubectlOutput) + continue + } + + GinkgoWriter.Println("") + GinkgoWriter.Println("----------------------------------------------------------------") + GinkgoWriter.Println("'kubectl get deployments -n " + namespace + " -o yaml") + GinkgoWriter.Println(kubectlOutput) + GinkgoWriter.Println("----------------------------------------------------------------") + } kubectlOutput, err := osFixture.ExecCommandWithOutputParam(false, "kubectl", "get", "argocds", "-A", "-o", "yaml") @@ -877,6 +894,37 @@ func OutputDebugOnFail(namespaceParams ...any) { } +// EnsureRunningOnOpenShift should be called if a test requires OpenShift (for example, it uses Route CR). +func EnsureRunningOnOpenShift() { + + runningOnOpenShift := RunningOnOpenShift() + + if !runningOnOpenShift { + Skip("This test requires the cluster to be OpenShift") + return + } + + Expect(runningOnOpenShift).To(BeTrueBecause("this test is marked as requiring an OpenShift cluster, and we have detected the cluster is OpenShift")) + +} + +// RunningOnOpenShift returns true if the cluster is an OpenShift cluster, false otherwise. +func RunningOnOpenShift() bool { + k8sClient, _ := utils.GetE2ETestKubeClient() + + crdList := crdv1.CustomResourceDefinitionList{} + Expect(k8sClient.List(context.Background(), &crdList)).To(Succeed()) + + openshiftAPIsFound := 0 + for _, crd := range crdList.Items { + if strings.Contains(crd.Spec.Group, "openshift.io") { + openshiftAPIsFound++ + } + } + return openshiftAPIsFound > 5 // I picked 5 as an arbitrary number, could also just be 1 +} + +//nolint:unused func outputPodLog(podSubstring string) { k8sClient, _, err := utils.GetE2ETestKubeClientWithError() if err != nil { diff --git a/test/openshift/e2e/ginkgo/fixture/rolebinding/fixture.go b/test/openshift/e2e/ginkgo/fixture/rolebinding/fixture.go index 11f57997fa4..310f105a179 100644 --- a/test/openshift/e2e/ginkgo/fixture/rolebinding/fixture.go +++ b/test/openshift/e2e/ginkgo/fixture/rolebinding/fixture.go @@ -16,9 +16,11 @@ import ( func HaveSubject(subjectParam rbacv1.Subject) matcher.GomegaMatcher { return fetchRoleBinding(func(r *rbacv1.RoleBinding) bool { - for _, subject := range r.Subjects { - GinkgoWriter.Println("HaveSubject - ", subject, subjectParam) + GinkgoWriter.Println("HaveSubject - Want:", subjectParam) + for idx, subject := range r.Subjects { + + GinkgoWriter.Printf("%d) HaveSubject - Have: %s\n", idx+1, subject) if reflect.DeepEqual(subjectParam, subject) { return true } diff --git a/test/openshift/e2e/ginkgo/fixture/secret/fixture.go b/test/openshift/e2e/ginkgo/fixture/secret/fixture.go index abb9e62669e..625ed56f23d 100644 --- a/test/openshift/e2e/ginkgo/fixture/secret/fixture.go +++ b/test/openshift/e2e/ginkgo/fixture/secret/fixture.go @@ -54,6 +54,22 @@ func UpdateWithError(obj *corev1.Secret, modify func(*corev1.Secret)) error { return err } +// HaveNonEmptyKeyValue returns true if Secret has the given key, and the value of the key is non-empty +func HaveNonEmptyKeyValue(key string) matcher.GomegaMatcher { + return fetchSecret(func(sec *corev1.Secret) bool { + a, exists := sec.Data[key] + if !exists { + GinkgoWriter.Println("HaveNonEmptyKeyValue - Key:", key, "does not exist") + return false + } + + GinkgoWriter.Println("HaveNonEmptyKeyValue - Key:", key, " Have:", string(a)) + + return len(a) > 0 + }) + +} + // HaveStringDataKeyValue returns true if Secret has 'key' field under .data map, and the value of that field is equal to 'value' func HaveStringDataKeyValue(key string, value string) matcher.GomegaMatcher { return fetchSecret(func(sec *corev1.Secret) bool { diff --git a/test/openshift/e2e/ginkgo/fixture/utils/fixtureUtils.go b/test/openshift/e2e/ginkgo/fixture/utils/fixtureUtils.go index 6fad540537f..a4b31924bb6 100644 --- a/test/openshift/e2e/ginkgo/fixture/utils/fixtureUtils.go +++ b/test/openshift/e2e/ginkgo/fixture/utils/fixtureUtils.go @@ -24,6 +24,7 @@ import ( admissionv1 "k8s.io/api/admissionregistration/v1" apps "k8s.io/api/apps/v1" autoscalingv2 "k8s.io/api/autoscaling/v2" + batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" networkingv1 "k8s.io/api/networking/v1" rbacv1 "k8s.io/api/rbac/v1" @@ -132,6 +133,10 @@ func getKubeClient(config *rest.Config) (client.Client, *runtime.Scheme, error) return nil, nil, err } + if err := batchv1.AddToScheme(scheme); err != nil { + return nil, nil, err + } + k8sClient, err := client.New(config, client.Options{Scheme: scheme}) if err != nil { return nil, nil, err diff --git a/test/openshift/e2e/ginkgo/parallel/1-004_beta_to_alpha_conversion_test.go b/test/openshift/e2e/ginkgo/parallel/1-004_beta_to_alpha_conversion_test.go index 930338e1c5f..0773b47f0c2 100644 --- a/test/openshift/e2e/ginkgo/parallel/1-004_beta_to_alpha_conversion_test.go +++ b/test/openshift/e2e/ginkgo/parallel/1-004_beta_to_alpha_conversion_test.go @@ -27,7 +27,7 @@ import ( deploymentFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" - corev1 "k8s.io/api/apps/v1" + appsv1 "k8s.io/api/apps/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" @@ -106,7 +106,7 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { Expect(argoCDAlpha1.Spec.SSO.Dex.OpenShiftOAuth).To(BeTrue()) Expect(argoCDAlpha1.Spec.Server.Route.Enabled).To(BeTrue()) - dexDeployment := &corev1.Deployment{ + dexDeployment := &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Name: "argocd-dex-server", Namespace: ns.Name, diff --git a/test/openshift/e2e/ginkgo/parallel/1-005_validate_route_tls_test.go b/test/openshift/e2e/ginkgo/parallel/1-005_validate_route_tls_test.go index 7a4a5432c8e..872e819fb80 100644 --- a/test/openshift/e2e/ginkgo/parallel/1-005_validate_route_tls_test.go +++ b/test/openshift/e2e/ginkgo/parallel/1-005_validate_route_tls_test.go @@ -50,7 +50,9 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { ctx = context.Background() }) - It("ensures that certificates can be confirmed on server and webhook Routes", func() { + It("ensures that certificates can be confirmed on server and webhook Routes", func() { + + fixture.EnsureRunningOnOpenShift() ns, nsCleanup := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() defer nsCleanup() diff --git a/test/openshift/e2e/ginkgo/parallel/1-019_validate_volume_mounts_test.go b/test/openshift/e2e/ginkgo/parallel/1-019_validate_volume_mounts_test.go index 6cd479a7b83..06c03df01b4 100644 --- a/test/openshift/e2e/ginkgo/parallel/1-019_validate_volume_mounts_test.go +++ b/test/openshift/e2e/ginkgo/parallel/1-019_validate_volume_mounts_test.go @@ -24,6 +24,8 @@ import ( . "github.com/onsi/gomega" "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + deploymentFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -264,6 +266,196 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { }, })) + By("adding volume to applicationset controller, and verifying volumemounts and volumes are set on Deployment") + + argocdFixture.Update(argoCDRandomNS, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.ApplicationSet = &argov1beta1api.ArgoCDApplicationSet{ + Volumes: []corev1.Volume{ + { + Name: "empty-dir-volume", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + }, + VolumeMounts: []corev1.VolumeMount{ + { + Name: "empty-dir-volume", + MountPath: "/etc/test", + }, + }, + } + }) + + Eventually(argoCDRandomNS, "2m", "5s").Should(argocdFixture.BeAvailable()) + Eventually(argoCDRandomNS, "2m", "5s").Should(argocdFixture.HaveApplicationSetControllerStatus("Running")) + + appSetDepl := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "argocd-applicationset-controller", + Namespace: argoCDRandomNS.Namespace, + }, + Spec: appsv1.DeploymentSpec{}, + } + Eventually(appSetDepl).Should(k8sFixture.ExistByName()) + + Expect(appSetDepl.Spec.Template.Spec.Containers[0].VolumeMounts).Should(Equal([]corev1.VolumeMount{ + { + Name: "ssh-known-hosts", + MountPath: "/app/config/ssh", + }, + { + Name: "tls-certs", + MountPath: "/app/config/tls", + }, + { + Name: "gpg-keys", + MountPath: "/app/config/gpg/source", + }, + { + Name: "gpg-keyring", + MountPath: "/app/config/gpg/keys", + }, + { + Name: "tmp", + MountPath: "/tmp", + }, + { + Name: "empty-dir-volume", + MountPath: "/etc/test", + }, + })) + + Expect(appSetDepl.Spec.Template.Spec.Volumes).Should(Equal([]corev1.Volume{ + { + Name: "ssh-known-hosts", + VolumeSource: corev1.VolumeSource{ConfigMap: &corev1.ConfigMapVolumeSource{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "argocd-ssh-known-hosts-cm", + }, + DefaultMode: ptr.To(int32(420)), + }}, + }, + { + Name: "tls-certs", + VolumeSource: corev1.VolumeSource{ConfigMap: &corev1.ConfigMapVolumeSource{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "argocd-tls-certs-cm", + }, + DefaultMode: ptr.To(int32(420)), + }}, + }, + { + Name: "gpg-keys", + VolumeSource: corev1.VolumeSource{ConfigMap: &corev1.ConfigMapVolumeSource{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "argocd-gpg-keys-cm", + }, + DefaultMode: ptr.To(int32(420)), + }}, + }, + { + Name: "gpg-keyring", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + { + Name: "tmp", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + { + Name: "empty-dir-volume", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + })) + + By("adding emptydir volume to .spec.sso and verifying it is set on dex server Deployment") + + argocdFixture.Update(argoCDRandomNS, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.SSO = &argov1beta1api.ArgoCDSSOSpec{ + Provider: argov1beta1api.SSOProviderTypeDex, + Dex: &argov1beta1api.ArgoCDDexSpec{ + Config: "test-config", + Volumes: []corev1.Volume{ + {Name: "empty-dir-volume", VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}}}, + }, + VolumeMounts: []corev1.VolumeMount{ + {Name: "empty-dir-volume", MountPath: "/etc/test"}, + }, + }, + } + }) + + Eventually(argoCDRandomNS, "2m", "5s").Should(argocdFixture.BeAvailable()) + Eventually(argoCDRandomNS, "2m", "5s").Should(argocdFixture.HaveApplicationSetControllerStatus("Running")) + + dexDeployment := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "argocd-dex-server", + Namespace: argoCDRandomNS.Namespace, + }, + } + Eventually(dexDeployment).Should(k8sFixture.ExistByName()) + + Expect(dexDeployment.Spec.Template.Spec.InitContainers[0].VolumeMounts).To(Equal([]corev1.VolumeMount{ + { + Name: "static-files", + MountPath: "/shared", + }, + { + Name: "dexconfig", + MountPath: "/tmp", + }, + { + Name: "empty-dir-volume", + MountPath: "/etc/test", + }, + })) + + Expect(dexDeployment.Spec.Template.Spec.Containers[0].VolumeMounts).To(Equal([]corev1.VolumeMount{ + { + Name: "static-files", + MountPath: "/shared", + }, + { + Name: "dexconfig", + MountPath: "/tmp", + }, + { + Name: "empty-dir-volume", + MountPath: "/etc/test", + }, + })) + + Expect(dexDeployment.Spec.Template.Spec.Volumes).To(Equal([]corev1.Volume{ + { + Name: "static-files", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + { + Name: "dexconfig", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + + { + Name: "empty-dir-volume", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + })) + + Eventually(dexDeployment, "4m", "5s").Should(deploymentFixture.HaveReadyReplicas(1)) + }) }) diff --git a/test/openshift/e2e/ginkgo/parallel/1-042_restricted_pss_compliant_test.go b/test/openshift/e2e/ginkgo/parallel/1-042_restricted_pss_compliant_test.go index 273f0186265..92782bbc0f2 100644 --- a/test/openshift/e2e/ginkgo/parallel/1-042_restricted_pss_compliant_test.go +++ b/test/openshift/e2e/ginkgo/parallel/1-042_restricted_pss_compliant_test.go @@ -21,6 +21,7 @@ import ( "strings" argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + "github.com/google/uuid" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" @@ -53,12 +54,10 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { }) AfterEach(func() { - - fixture.OutputDebugOnFail("test-1-042-restricted-pss-compliant") - Expect(ns).ToNot(BeNil()) - Expect(k8sClient.Delete(ctx, ns)).To(Succeed()) + fixture.OutputDebugOnFail(ns.Name) + fixture.DeleteNamespace(ns) }) It("verifies that all Argo CD components can run with pod-security enforce, warn, and audit of 'restricted'", func() { @@ -68,7 +67,7 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { By("creating a namespace with pod-security enforce set to restricted") ns = &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ - Name: "test-1-042-restricted-pss-compliant", + Name: "gitops-e2e-test-" + uuid.NewString()[0:13], Labels: map[string]string{ "pod-security.kubernetes.io/enforce": "restricted", "pod-security.kubernetes.io/enforce-version": "latest", @@ -100,6 +99,13 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { }, }, } + + if !fixture.RunningOnOpenShift() { + argoCD.Spec.Server = argov1beta1api.ArgoCDServerSpec{ + Ingress: argov1beta1api.ArgoCDIngressSpec{Enabled: true}, + } + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) By("verifying all Argo CD components start as expected under restricted pod security") @@ -150,6 +156,14 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { } }) + if !fixture.RunningOnOpenShift() { + By("removing SSO") + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + argoCD.Spec.SSO = nil + }) + + } + By("ensuring that various Argo CD components become available under restricted security") Eventually(argoCD).Should(argocdFixture.HaveApplicationControllerStatus("Running")) Eventually(argoCD).Should(argocdFixture.HaveServerStatus("Running")) diff --git a/test/openshift/e2e/ginkgo/parallel/1-043_validate_custom_labels_annotations_test.go b/test/openshift/e2e/ginkgo/parallel/1-043_validate_custom_labels_annotations_test.go index f9705e234d1..37ccdeff1c4 100644 --- a/test/openshift/e2e/ginkgo/parallel/1-043_validate_custom_labels_annotations_test.go +++ b/test/openshift/e2e/ginkgo/parallel/1-043_validate_custom_labels_annotations_test.go @@ -18,6 +18,7 @@ package parallel import ( "context" + "strings" argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" . "github.com/onsi/ginkgo/v2" @@ -29,7 +30,6 @@ import ( statefulsetFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/statefulset" fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" @@ -160,25 +160,51 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { By("verifying labels and annotations have been removed from template specs of Argo CD components") - expectLabelsAndAnnotationsRemoved := func(podTemplateSpec corev1.PodTemplateSpec) { + Eventually(controllerSS).Should(k8sFixture.ExistByName()) + Eventually(appsetDepl).Should(k8sFixture.ExistByName()) + Eventually(repoDepl).Should(k8sFixture.ExistByName()) + + expectLabelsAndAnnotationsRemovedFromDepl := func(depl *appsv1.Deployment) { + + By("checking labels and annotations are removed from " + depl.Name) + + Eventually(func() bool { + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(depl), depl); err != nil { + GinkgoWriter.Println(err) + return false + } + + for k := range depl.Spec.Template.Annotations { + if strings.Contains(k, "custom") { + return false + } + } + + for k := range depl.Spec.Template.Labels { + if strings.Contains(k, "custom") { + return false + } + } - for k := range podTemplateSpec.Annotations { - Expect(k).ToNot(ContainSubstring("custom")) - } + return true + }).Should(BeTrue()) - for k := range podTemplateSpec.Labels { - Expect(k).ToNot(ContainSubstring("custom")) - } } - Eventually(serverDepl).Should(k8sFixture.ExistByName()) + + expectLabelsAndAnnotationsRemovedFromDepl(appsetDepl) + expectLabelsAndAnnotationsRemovedFromDepl(serverDepl) + expectLabelsAndAnnotationsRemovedFromDepl(repoDepl) + + // Evaluate the controller statefulset on its own, since it's a StatefulSet not a Deployment Eventually(controllerSS).Should(k8sFixture.ExistByName()) - Eventually(appsetDepl).Should(k8sFixture.ExistByName()) - Eventually(repoDepl).Should(k8sFixture.ExistByName()) - expectLabelsAndAnnotationsRemoved(serverDepl.Spec.Template) - expectLabelsAndAnnotationsRemoved(appsetDepl.Spec.Template) - expectLabelsAndAnnotationsRemoved(repoDepl.Spec.Template) - expectLabelsAndAnnotationsRemoved(controllerSS.Spec.Template) + for k := range controllerSS.Spec.Template.Annotations { + Expect(k).ToNot(ContainSubstring("custom")) + } + + for k := range controllerSS.Spec.Template.Labels { + Expect(k).ToNot(ContainSubstring("custom")) + } }) diff --git a/test/openshift/e2e/ginkgo/parallel/1-055_validate_notification_controller_test.go b/test/openshift/e2e/ginkgo/parallel/1-055_validate_notification_controller_test.go index 5df9acb0cad..dcbe9ff016d 100644 --- a/test/openshift/e2e/ginkgo/parallel/1-055_validate_notification_controller_test.go +++ b/test/openshift/e2e/ginkgo/parallel/1-055_validate_notification_controller_test.go @@ -37,6 +37,7 @@ import ( var _ = Describe("GitOps Operator Parallel E2E Tests", func() { Context("1-055_validate_notification_controller", func() { + // This test supersedes 1-021_validate_notification_controller var ( k8sClient client.Client @@ -45,7 +46,6 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { BeforeEach(func() { fixture.EnsureParallelCleanSlate() - k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() ctx = context.Background() }) diff --git a/test/openshift/e2e/ginkgo/parallel/1-070_validate_config_management_plugin_test.go b/test/openshift/e2e/ginkgo/parallel/1-070_validate_config_management_plugin_test.go index dceeb7c904b..9ee566c7ad2 100644 --- a/test/openshift/e2e/ginkgo/parallel/1-070_validate_config_management_plugin_test.go +++ b/test/openshift/e2e/ginkgo/parallel/1-070_validate_config_management_plugin_test.go @@ -38,10 +38,13 @@ import ( var _ = Describe("GitOps Operator Parallel E2E Tests", func() { Context("1-070_validate_config_management_plugin_test", func() { + // This test supersedes 1-017_validate_cmp var ( - k8sClient client.Client - ctx context.Context + k8sClient client.Client + ctx context.Context + ns *corev1.Namespace + cleanupFunc func() ) BeforeEach(func() { @@ -50,10 +53,16 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { ctx = context.Background() }) + AfterEach(func() { + defer cleanupFunc() + if ns != nil { + fixture.OutputDebugOnFail(ns.Name) + } + }) + It("validates that an Argo CD Application with a ConfigManagementPlugin mounted via sidecar will deploy as expected", func() { - ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() - defer cleanupFunc() + ns, cleanupFunc = fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() By("creating simple namespace-scoped Argo CD instance with a CMP sidecar, where the sidecar is a simple bash script") argoCD := &argov1beta1api.ArgoCD{ @@ -84,6 +93,11 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { }, }, } + + if !fixture.RunningOnOpenShift() { + argoCD.Spec.Repo.SidecarContainers[0].SecurityContext.RunAsUser = ptr.To(int64(999)) + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) By("creating ConfigMap with CMP plugin that will echo a ConfigMap that does not exist in source repository") @@ -139,7 +153,7 @@ spec: Eventually(app, "4m", "5s").Should(applicationFixture.HaveHealthStatusCode(health.HealthStatusHealthy)) Eventually(app, "4m", "5s").Should(applicationFixture.HaveSyncStatusCode(appv1alpha1.SyncStatusCodeSynced)) - By("verifying that the ConfigMap generated by the CMP plugin was successfully deployed to teh target namespace") + By("verifying that the ConfigMap generated by the CMP plugin was successfully deployed to the target namespace") guestbookCM := &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "guestbook", Namespace: ns.Name}} Eventually(guestbookCM).Should(k8sFixture.ExistByName()) }) diff --git a/test/openshift/e2e/ginkgo/parallel/1-084_validate_status_host_ingress_test.go b/test/openshift/e2e/ginkgo/parallel/1-084_validate_status_host_ingress_test.go index 594c1ff4f13..e296d379942 100644 --- a/test/openshift/e2e/ginkgo/parallel/1-084_validate_status_host_ingress_test.go +++ b/test/openshift/e2e/ginkgo/parallel/1-084_validate_status_host_ingress_test.go @@ -49,6 +49,8 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { It("ensures that when Argo CD Server is exposed via an Ingress, that the ingress is created and ArgoCD CR has the correct status information", func() { + // This test supersedes '1-002_verify_hostname_with_ingress' + By("creating simple Argo CD instance with API Server exposed via ingress") ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() defer cleanupFunc() @@ -84,8 +86,10 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { } Eventually(serverIngress).Should(k8sFixture.ExistByName()) - By("verifying ArgoCD CR .status references the host from the ArgoCD CR .spec") - Eventually(argoCD).Should(argocdFixture.HaveHost("test-crane.apps.rh-4.12-111111.dev.openshift.org")) + if fixture.RunningOnOpenShift() { + By("verifying ArgoCD CR .status references the host from the ArgoCD CR .spec") + Eventually(argoCD).Should(argocdFixture.HaveHost("test-crane.apps.rh-4.12-111111.dev.openshift.org")) + } }) diff --git a/test/openshift/e2e/ginkgo/parallel/1-088_validate_applicationset_add_env_vars_test.go b/test/openshift/e2e/ginkgo/parallel/1-088_validate_applicationset_add_env_vars_test.go index 455ca611999..2cd6cbd0e6b 100644 --- a/test/openshift/e2e/ginkgo/parallel/1-088_validate_applicationset_add_env_vars_test.go +++ b/test/openshift/e2e/ginkgo/parallel/1-088_validate_applicationset_add_env_vars_test.go @@ -37,6 +37,8 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { Context("1-088_validate_applicationset_add_env_vars", func() { + // This test supersecdes '1-030_validate_applciationset_add_env_vars' + var ( k8sClient client.Client ctx context.Context diff --git a/test/openshift/e2e/ginkgo/parallel/1-089_validate_extra_repo_commands_args_test.go b/test/openshift/e2e/ginkgo/parallel/1-089_validate_extra_repo_commands_args_test.go index 3635d6465a4..74becd1a7b3 100644 --- a/test/openshift/e2e/ginkgo/parallel/1-089_validate_extra_repo_commands_args_test.go +++ b/test/openshift/e2e/ginkgo/parallel/1-089_validate_extra_repo_commands_args_test.go @@ -35,6 +35,8 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { Context("1-089_validate_extra_repo_commands_args", func() { + // This test supersedes 1-028_validate_extra_repo_commands_args + var ( k8sClient client.Client ctx context.Context diff --git a/test/openshift/e2e/ginkgo/parallel/1-091_argocd_app_validate-applicationset-status_test.go b/test/openshift/e2e/ginkgo/parallel/1-091_argocd_app_validate-applicationset-status_test.go index 2f3fea8d158..901cc8b2155 100644 --- a/test/openshift/e2e/ginkgo/parallel/1-091_argocd_app_validate-applicationset-status_test.go +++ b/test/openshift/e2e/ginkgo/parallel/1-091_argocd_app_validate-applicationset-status_test.go @@ -34,6 +34,8 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { Context("1-091_argocd_app_validate-applicationset-status", func() { + // This test supersedes '1-027_validate_applicationset_status' + var ( k8sClient client.Client ctx context.Context diff --git a/test/openshift/e2e/ginkgo/parallel/1-099_validate_server_autoscale_test.go b/test/openshift/e2e/ginkgo/parallel/1-099_validate_server_autoscale_test.go index 58bcfb6b6b7..8b66e9cb41a 100644 --- a/test/openshift/e2e/ginkgo/parallel/1-099_validate_server_autoscale_test.go +++ b/test/openshift/e2e/ginkgo/parallel/1-099_validate_server_autoscale_test.go @@ -40,6 +40,8 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { Context("1-099_validate_server_autoscale", func() { + // This test supersedes '1-032_validate_server_hpa' + var ( k8sClient client.Client ctx context.Context @@ -52,7 +54,7 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { ctx = context.Background() }) - It("varies that setting ArgoCD CR Server replicas and autoscaling affect the corresponding Deployment and HPA values", func() { + It("verifies that setting ArgoCD CR Server replicas and autoscaling affect the corresponding Deployment and HPA values", func() { By("creating simple Argo CD instance with 2 server replicas") ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() diff --git a/test/openshift/e2e/ginkgo/parallel/1-118_validate_redis_ssc_test.go b/test/openshift/e2e/ginkgo/parallel/1-118_validate_redis_ssc_test.go index 3ee9aaa65b8..93773be9bd2 100644 --- a/test/openshift/e2e/ginkgo/parallel/1-118_validate_redis_ssc_test.go +++ b/test/openshift/e2e/ginkgo/parallel/1-118_validate_redis_ssc_test.go @@ -51,6 +51,8 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { It("verifies that HA pods have expected SSC", func() { + fixture.EnsureRunningOnOpenShift() // SSC requires OpenShift + // This test enables HA redis and thus requires at least 3 nodes node.ExpectHasAtLeastXNodes(3) diff --git a/test/openshift/e2e/ginkgo/parallel/1-119_argocd_respectRBAC_test.go b/test/openshift/e2e/ginkgo/parallel/1-119_argocd_respectRBAC_test.go index 5adc9ad6a14..20854cd3462 100644 --- a/test/openshift/e2e/ginkgo/parallel/1-119_argocd_respectRBAC_test.go +++ b/test/openshift/e2e/ginkgo/parallel/1-119_argocd_respectRBAC_test.go @@ -36,6 +36,8 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { Context("1-119_argocd_respectRBAC", func() { + // This test supersedes 1-045_validate_controller_respect_rbac + var ( k8sClient client.Client ctx context.Context @@ -49,17 +51,18 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { }) - It("ensures that setting .spec.controller.respectRBAC will cause that value to be set in Argo CD's argocd-cm ConfigMap", func() { + It("ensures that setting .spec.controller.respectRBAC will cause that value to be set in Argo CD's argocd-cm ConfigMap, and that invalid values are ignored", func() { - By("creating basic Argo CD instance with respect RBAC set to strict") ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() defer cleanupFunc() + By("creating basic Argo CD instance with respect RBAC set to normal") + argoCD := &argov1beta1api.ArgoCD{ ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: ns.Name}, Spec: argov1beta1api.ArgoCDSpec{ Controller: argov1beta1api.ArgoCDApplicationControllerSpec{ - RespectRBAC: "strict", + RespectRBAC: "normal", }, }, } @@ -75,8 +78,36 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() { } Eventually(argocdCMConfigMap).Should(k8sFixture.ExistByName()) + Eventually(argocdCMConfigMap).Should(configmapFixture.HaveStringDataKeyValue("resource.respectRBAC", "normal")) + + By("updating Argo CD instance to respect RBAC set to strict") + + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.Controller.RespectRBAC = "strict" + }) + + By("verifying strict respectRBAC is set in argocd-cm ConfigMap") + Eventually(argocdCMConfigMap).Should(k8sFixture.ExistByName()) Eventually(argocdCMConfigMap).Should(configmapFixture.HaveStringDataKeyValue("resource.respectRBAC", "strict")) + By("updating Argo CD instance to respect RBAC set to invalid valid") + + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.Controller.RespectRBAC = "somethibg" + }) + + Eventually(argocdCMConfigMap).ShouldNot(configmapFixture.HaveStringDataKeyValue("resource.respectRBAC", "strict")) + Consistently(argocdCMConfigMap).ShouldNot(configmapFixture.HaveStringDataKeyValue("resource.respectRBAC", "strict")) + + By("updating Argo CD instance to respect RBAC set to empty value") + + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.Controller.RespectRBAC = "" + }) + + Eventually(argocdCMConfigMap).ShouldNot(configmapFixture.HaveStringDataKeyValue("resource.respectRBAC", "strict")) + Consistently(argocdCMConfigMap).ShouldNot(configmapFixture.HaveStringDataKeyValue("resource.respectRBAC", "strict")) + }) }) diff --git a/test/openshift/e2e/ginkgo/sequential/1-037_validate_applicationset_in_any_namespace_test.go b/test/openshift/e2e/ginkgo/sequential/1-037_validate_applicationset_in_any_namespace_test.go index 6d85c99ae91..ef2e84d3a81 100644 --- a/test/openshift/e2e/ginkgo/sequential/1-037_validate_applicationset_in_any_namespace_test.go +++ b/test/openshift/e2e/ginkgo/sequential/1-037_validate_applicationset_in_any_namespace_test.go @@ -90,6 +90,8 @@ var _ = Describe("GitOps Operator Sequential E2E Tests", func() { By(fmt.Sprintf("verifying that expected Role/Rolebindings %v exist in %s", names, namespaceName)) for _, roleAndRoleBindingName := range names { + By("verifying '" + roleAndRoleBindingName + "'") + role := &rbacv1.Role{ ObjectMeta: metav1.ObjectMeta{ Name: roleAndRoleBindingName,