From e9a860517004b1f5c4713ce4ed93058fd0266fe9 Mon Sep 17 00:00:00 2001 From: Bastian Krol Date: Thu, 22 Aug 2024 15:14:44 +0200 Subject: [PATCH] test(e2e): introduce workloadType as struct --- test-resources/node.js/express/cronjob.yaml | 53 +-- .../node.js/express/cronjob.yaml.template | 33 -- test/e2e/application_under_test.go | 342 +++++++++++------- test/e2e/e2e_test.go | 227 +++++------- test/e2e/verify_instrumentation.go | 8 +- 5 files changed, 331 insertions(+), 332 deletions(-) delete mode 100644 test-resources/node.js/express/cronjob.yaml.template diff --git a/test-resources/node.js/express/cronjob.yaml b/test-resources/node.js/express/cronjob.yaml index 0ce6ea5d..51dc4dfd 100644 --- a/test-resources/node.js/express/cronjob.yaml +++ b/test-resources/node.js/express/cronjob.yaml @@ -1,30 +1,33 @@ +# SPDX-FileCopyrightText: Copyright 2024 Dash0 Inc. +# SPDX-License-Identifier: Apache-2.0 + apiVersion: batch/v1 kind: CronJob metadata: - name: dash0-operator-nodejs-20-express-test-cronjob + name: dash0-operator-nodejs-20-express-test-cronjob spec: - jobTemplate: + schedule: "* * * * *" + jobTemplate: + spec: + template: spec: - template: - spec: - containers: - - env: - - name: PORT - value: "1205" - - name: DASH0_DEBUG - value: "true" - - name: TRIGGER_SELF_AND_EXIT - value: "true" - image: dash0-operator-nodejs-20-express-test-app:latest - imagePullPolicy: Never - name: dash0-operator-nodejs-20-express-test-cronjob-app - ports: - - containerPort: 1205 - readinessProbe: - httpGet: - path: /ready - port: 1205 - initialDelaySeconds: 1 - periodSeconds: 1 - restartPolicy: Never - schedule: '* * * * *' + restartPolicy: Never + containers: + - name: dash0-operator-nodejs-20-express-test-cronjob-app + image: "dash0-operator-nodejs-20-express-test-app:latest" + env: + - name: PORT + value: "1205" + - name: DASH0_DEBUG + value: "true" + - name: TRIGGER_SELF_AND_EXIT + value: "true" + ports: + - containerPort: 1205 + imagePullPolicy: Never + readinessProbe: + httpGet: + path: /ready + port: 1205 + initialDelaySeconds: 1 + periodSeconds: 1 \ No newline at end of file diff --git a/test-resources/node.js/express/cronjob.yaml.template b/test-resources/node.js/express/cronjob.yaml.template deleted file mode 100644 index 51dc4dfd..00000000 --- a/test-resources/node.js/express/cronjob.yaml.template +++ /dev/null @@ -1,33 +0,0 @@ -# SPDX-FileCopyrightText: Copyright 2024 Dash0 Inc. -# SPDX-License-Identifier: Apache-2.0 - -apiVersion: batch/v1 -kind: CronJob -metadata: - name: dash0-operator-nodejs-20-express-test-cronjob -spec: - schedule: "* * * * *" - jobTemplate: - spec: - template: - spec: - restartPolicy: Never - containers: - - name: dash0-operator-nodejs-20-express-test-cronjob-app - image: "dash0-operator-nodejs-20-express-test-app:latest" - env: - - name: PORT - value: "1205" - - name: DASH0_DEBUG - value: "true" - - name: TRIGGER_SELF_AND_EXIT - value: "true" - ports: - - containerPort: 1205 - imagePullPolicy: Never - readinessProbe: - httpGet: - path: /ready - port: 1205 - initialDelaySeconds: 1 - periodSeconds: 1 \ No newline at end of file diff --git a/test/e2e/application_under_test.go b/test/e2e/application_under_test.go index bcb04f00..9e850556 100644 --- a/test/e2e/application_under_test.go +++ b/test/e2e/application_under_test.go @@ -15,11 +15,129 @@ import ( . "github.com/onsi/gomega" ) +type workloadType struct { + workloadTypeString string + port int + isBatch bool + waitCommand func(string) *exec.Cmd +} + const ( applicationUnderTestNamespace = "e2e-application-under-test-namespace" applicationPath = "test-resources/node.js/express" ) +var ( + temporaryManifestFiles []string + + workloadTypeCronjob = workloadType{ + workloadTypeString: "cronjob", + port: 1205, + isBatch: true, + waitCommand: nil, + } + workloadTypeDaemonSet = workloadType{ + workloadTypeString: "daemonset", + port: 1206, + isBatch: false, + waitCommand: func(namespace string) *exec.Cmd { + return exec.Command( + "kubectl", + "rollout", + "status", + "daemonset", + "dash0-operator-nodejs-20-express-test-daemonset", + "--namespace", + namespace, + "--timeout", + "60s", + ) + }, + } + workloadTypeDeployment = workloadType{ + workloadTypeString: "deployment", + isBatch: false, + port: 1207, + waitCommand: func(namespace string) *exec.Cmd { + return exec.Command( + "kubectl", + "wait", + "deployment.apps/dash0-operator-nodejs-20-express-test-deployment", + "--for", + "condition=Available", + "--namespace", + namespace, + "--timeout", + "60s", + ) + }, + } + workloadTypeJob = workloadType{ + workloadTypeString: "job", + port: 1208, + isBatch: true, + waitCommand: nil, + } + workloadTypePod = workloadType{ + workloadTypeString: "pod", + port: 1211, + isBatch: false, + waitCommand: func(namespace string) *exec.Cmd { + return exec.Command( + "kubectl", + "wait", + "pod", + "--namespace", + namespace, + "--selector", + "app=dash0-operator-nodejs-20-express-test-pod-app", + "--for", + "condition=ContainersReady", + "--timeout", + "60s", + ) + }, + } + workloadTypeReplicaSet = workloadType{ + workloadTypeString: "replicaset", + port: 1209, + isBatch: false, + waitCommand: func(namespace string) *exec.Cmd { + return exec.Command( + "kubectl", + "wait", + "pod", + "--namespace", + namespace, + "--selector", + "app=dash0-operator-nodejs-20-express-test-replicaset-app", + "--for", + "condition=ContainersReady", + "--timeout", + "60s", + ) + }, + } + workloadTypeStatefulSet = workloadType{ + workloadTypeString: "statefulset", + port: 1210, + isBatch: false, + waitCommand: func(namespace string) *exec.Cmd { + return exec.Command( + "kubectl", + "rollout", + "status", + "statefulset", + "dash0-operator-nodejs-20-express-test-statefulset", + "--namespace", + namespace, + "--timeout", + "60s", + ) + }, + } +) + func rebuildNodeJsApplicationContainerImage() { By("building the dash0-operator-nodejs-20-express-test-app image") Expect( @@ -33,53 +151,16 @@ func rebuildNodeJsApplicationContainerImage() { ))).To(Succeed()) } -func installNodeJsCronJob(namespace string, testId string) error { - addTestIdToCronjobManifest(testId) - return installNodeJsApplication( - namespace, - "cronjob", - nil, - ) -} - func uninstallNodeJsCronJob(namespace string) error { return uninstallNodeJsApplication(namespace, "cronjob") } -func installNodeJsDaemonSet(namespace string, testId string) error { +func installNodeJsDaemonSetWithOptOutLabel(namespace string) error { return installNodeJsApplication( namespace, + manifest("daemonset.opt-out"), "daemonset", - exec.Command( - "kubectl", - "rollout", - "status", - "daemonset", - "dash0-operator-nodejs-20-express-test-daemonset", - "--namespace", - namespace, - "--timeout", - "60s", - ), - ) -} - -//nolint:unparam -func installNodeJsDaemonSetWithOptOutLabel(namespace string, testId string) error { - return installNodeJsApplication( - namespace, - "daemonset.opt-out", - exec.Command( - "kubectl", - "rollout", - "status", - "daemonset", - "dash0-operator-nodejs-20-express-test-daemonset", - "--namespace", - namespace, - "--timeout", - "60s", - ), + workloadTypeDaemonSet.waitCommand(namespace), ) } @@ -87,21 +168,12 @@ func uninstallNodeJsDaemonSet(namespace string) error { return uninstallNodeJsApplication(namespace, "daemonset") } -func installNodeJsDeployment(namespace string, testId string) error { - return installNodeJsApplication( +//nolint:unparam +func installNodeJsDeployment(namespace string) error { + return installNodeJsWorkload( + workloadTypeDeployment, namespace, - "deployment", - exec.Command( - "kubectl", - "wait", - "deployment.apps/dash0-operator-nodejs-20-express-test-deployment", - "--for", - "condition=Available", - "--namespace", - namespace, - "--timeout", - "60s", - ), + "", ) } @@ -110,11 +182,10 @@ func uninstallNodeJsDeployment(namespace string) error { } func installNodeJsJob(namespace string, testId string) error { - addTestIdToJobManifest(testId) - return installNodeJsApplication( + return installNodeJsWorkload( + workloadTypeJob, namespace, - "job", - nil, + testId, ) } @@ -122,24 +193,11 @@ func uninstallNodeJsJob(namespace string) error { return uninstallNodeJsApplication(namespace, "job") } -//nolint:unparam -func installNodeJsPod(namespace string, testId string) error { - return installNodeJsApplication( +func installNodeJsPod(namespace string) error { + return installNodeJsWorkload( + workloadTypePod, namespace, - "pod", - exec.Command( - "kubectl", - "wait", - "pod", - "--namespace", - namespace, - "--selector", - "app=dash0-operator-nodejs-20-express-test-pod-app", - "--for", - "condition=ContainersReady", - "--timeout", - "60s", - ), + "", ) } @@ -147,47 +205,15 @@ func uninstallNodeJsPod(namespace string) error { return uninstallNodeJsApplication(namespace, "pod") } -//nolint:unparam -func installNodeJsReplicaSet(namespace string, testId string) error { - return installNodeJsApplication( - namespace, - "replicaset", - exec.Command( - "kubectl", - "wait", - "pod", - "--namespace", - namespace, - "--selector", - "app=dash0-operator-nodejs-20-express-test-replicaset-app", - "--for", - "condition=ContainersReady", - "--timeout", - "60s", - ), - ) -} - func uninstallNodeJsReplicaSet(namespace string) error { return uninstallNodeJsApplication(namespace, "replicaset") } -//nolint:unparam -func installNodeJsStatefulSet(namespace string, testId string) error { - return installNodeJsApplication( +func installNodeJsStatefulSet(namespace string) error { + return installNodeJsWorkload( + workloadTypeStatefulSet, namespace, - "statefulset", - exec.Command( - "kubectl", - "rollout", - "status", - "statefulset", - "dash0-operator-nodejs-20-express-test-statefulset", - "--namespace", - namespace, - "--timeout", - "60s", - ), + "", ) } @@ -195,20 +221,35 @@ func uninstallNodeJsStatefulSet(namespace string) error { return uninstallNodeJsApplication(namespace, "statefulset") } -func removeAllTestApplications(namespace string) { - By("uninstalling the test applications") - Expect(uninstallNodeJsCronJob(namespace)).To(Succeed()) - Expect(uninstallNodeJsDaemonSet(namespace)).To(Succeed()) - Expect(uninstallNodeJsDeployment(namespace)).To(Succeed()) - Expect(uninstallNodeJsJob(namespace)).To(Succeed()) - Expect(uninstallNodeJsPod(namespace)).To(Succeed()) - Expect(uninstallNodeJsReplicaSet(namespace)).To(Succeed()) - Expect(uninstallNodeJsStatefulSet(namespace)).To(Succeed()) +func installNodeJsWorkload(workloadType workloadType, namespace string, testId string) error { + manifestFile := manifest(workloadType.workloadTypeString) + if workloadType.isBatch { + switch workloadType.workloadTypeString { + case "cronjob": + manifestFile = addTestIdToCronjobManifest(testId) + case "job": + manifestFile = addTestIdToJobManifest(testId) + default: + return fmt.Errorf("unsupported batch workload type %s", workloadType.workloadTypeString) + } + } + + var waitCommand *exec.Cmd + if workloadType.waitCommand != nil { + waitCommand = workloadType.waitCommand(namespace) + } + return installNodeJsApplication( + namespace, + manifestFile, + workloadType.workloadTypeString, + waitCommand, + ) } func installNodeJsApplication( namespace string, - workloadType string, + manifestFile string, + workloadTypeString string, waitCommand *exec.Cmd, ) error { err := runAndIgnoreOutput(exec.Command( @@ -217,7 +258,7 @@ func installNodeJsApplication( "--namespace", namespace, "-f", - manifest(workloadType), + manifestFile, )) if err != nil { return err @@ -225,7 +266,7 @@ func installNodeJsApplication( if waitCommand == nil { return nil } - return waitForApplicationToBecomeReady(workloadType, waitCommand) + return waitForApplicationToBecomeReady(workloadTypeString, waitCommand) } func uninstallNodeJsApplication(namespace string, workloadType string) error { @@ -241,6 +282,17 @@ func uninstallNodeJsApplication(namespace string, workloadType string) error { )) } +func removeAllTestApplications(namespace string) { + By("uninstalling the test applications") + Expect(uninstallNodeJsCronJob(namespace)).To(Succeed()) + Expect(uninstallNodeJsDaemonSet(namespace)).To(Succeed()) + Expect(uninstallNodeJsDeployment(namespace)).To(Succeed()) + Expect(uninstallNodeJsJob(namespace)).To(Succeed()) + Expect(uninstallNodeJsPod(namespace)).To(Succeed()) + Expect(uninstallNodeJsReplicaSet(namespace)).To(Succeed()) + Expect(uninstallNodeJsStatefulSet(namespace)).To(Succeed()) +} + func addOptOutLabel(namespace string, workloadType string, workloadName string) error { return runAndIgnoreOutput( exec.Command( @@ -268,9 +320,9 @@ func removeOptOutLabel(namespace string, workloadType string, workloadName strin )) } -func addTestIdToCronjobManifest(testId string) { - filename := manifest("cronjob") - applicationManifestContentRaw, err := os.ReadFile(filename) +func addTestIdToCronjobManifest(testId string) string { + source := manifest("cronjob") + applicationManifestContentRaw, err := os.ReadFile(source) Expect(err).ToNot(HaveOccurred()) applicationManifestParsed := make(map[string]interface{}) Expect(yaml.Unmarshal(applicationManifestContentRaw, &applicationManifestParsed)).To(Succeed()) @@ -281,19 +333,34 @@ func addTestIdToCronjobManifest(testId string) { applicationManifestParsed["spec"] = cronjobSpec updatedApplicationManifestContentRaw, err := yaml.Marshal(&applicationManifestParsed) Expect(err).ToNot(HaveOccurred()) - Expect(os.WriteFile(filename, updatedApplicationManifestContentRaw, 0644)).To(Succeed()) + return writeManifest("cronjob", testId, updatedApplicationManifestContentRaw) } -func addTestIdToJobManifest(testId string) { - filename := manifest("job") - applicationManifestContentRaw, err := os.ReadFile(filename) +func addTestIdToJobManifest(testId string) string { + source := manifest("job") + applicationManifestContentRaw, err := os.ReadFile(source) Expect(err).ToNot(HaveOccurred()) applicationManifestParsed := make(map[string]interface{}) Expect(yaml.Unmarshal(applicationManifestContentRaw, &applicationManifestParsed)).To(Succeed()) applicationManifestParsed["spec"] = addEnvVarToContainer(testId, applicationManifestParsed) updatedApplicationManifestContentRaw, err := yaml.Marshal(&applicationManifestParsed) Expect(err).ToNot(HaveOccurred()) - Expect(os.WriteFile(filename, updatedApplicationManifestContentRaw, 0644)).To(Succeed()) + return writeManifest("job", testId, updatedApplicationManifestContentRaw) +} + +func writeManifest(workloadTypeString string, testId string, updatedApplicationManifestContentRaw []byte) string { + target, err := os.CreateTemp(os.TempDir(), fmt.Sprintf("%s_%s.yaml", workloadTypeString, testId)) + Expect(err).ToNot(HaveOccurred()) + targetName := target.Name() + temporaryManifestFiles = append(temporaryManifestFiles, targetName) + Expect(os.WriteFile(targetName, updatedApplicationManifestContentRaw, 0644)).To(Succeed()) + return targetName +} + +func removeAllTemporaryManifests() { + for _, tmpfile := range temporaryManifestFiles { + _ = os.Remove(tmpfile) + } } func addEnvVarToContainer(testId string, jobTemplateOrManifest map[string]interface{}) map[string]interface{} { @@ -303,10 +370,23 @@ func addEnvVarToContainer(testId string, jobTemplateOrManifest map[string]interf containers := (podSpec["containers"]).([]interface{}) container := (containers[0]).(map[string]interface{}) env := (container["env"]).([]interface{}) + + for _, v := range env { + envVar := (v).(map[string]interface{}) + if envVar["name"] == "TEST_ID" { + // TEST_ID already present, we just need to update the value + envVar["value"] = testId + return jobSpec + } + } + + // no TEST_ID present, we need to add a new env var newEnvVar := make(map[string]string) newEnvVar["name"] = "TEST_ID" newEnvVar["value"] = testId env = append(env, newEnvVar) + + // since append does not modify the original slice, we need to update all the objects all the way up the hierarchy container["env"] = env containers[0] = container podSpec["containers"] = containers diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index bb7a524e..c8edad7a 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -66,6 +66,7 @@ var _ = Describe("Dash0 Kubernetes Operator", Ordered, func() { }) AfterAll(func() { + removeAllTemporaryManifests() if applicationUnderTestNamespace != "default" { By("removing namespace for application under test") _ = runAndIgnoreOutput(exec.Command("kubectl", "delete", "ns", applicationUnderTestNamespace)) @@ -95,40 +96,29 @@ var _ = Describe("Dash0 Kubernetes Operator", Ordered, func() { undeployOperator(operatorNamespace) }) - workloadConfigs := []controllerTestWorkloadConfig{ - { - workloadType: "cronjob", - port: 1205, - installWorkload: installNodeJsCronJob, - isBatch: true, - }, { - workloadType: "daemonset", - port: 1206, - installWorkload: installNodeJsDaemonSet, - }, { - workloadType: "deployment", - port: 1207, - installWorkload: installNodeJsDeployment, - }, { - workloadType: "replicaset", - port: 1209, - installWorkload: installNodeJsReplicaSet, - }, { - workloadType: "statefulset", - port: 1210, - installWorkload: installNodeJsStatefulSet, - }, + controllerTestWorkloadTypes := []workloadType{ + workloadTypeCronjob, + workloadTypeDaemonSet, + workloadTypeDeployment, + workloadTypeReplicaSet, + workloadTypeStatefulSet, } Describe("when instrumenting existing workloads", func() { It("should instrument and uninstrument all workload types", func() { testIds := make(map[string]string) + for _, workloadType := range controllerTestWorkloadTypes { + testIds[workloadType.workloadTypeString] = generateTestId(workloadType.workloadTypeString) + } + By("deploying all workloads") - runInParallelForAllWorkloadTypes(workloadConfigs, func(config controllerTestWorkloadConfig) { - testId := generateTestId(config.workloadType) - testIds[config.workloadType] = testId - By(fmt.Sprintf("deploying the Node.js %s", config.workloadType)) - Expect(config.installWorkload(applicationUnderTestNamespace, testId)).To(Succeed()) + runInParallelForAllWorkloadTypes(controllerTestWorkloadTypes, func(workloadType workloadType) { + By(fmt.Sprintf("deploying the Node.js %s", workloadType.workloadTypeString)) + Expect(installNodeJsWorkload( + workloadType, + applicationUnderTestNamespace, + testIds[workloadType.workloadTypeString], + )).To(Succeed()) }) By("all workloads have been deployed") @@ -140,14 +130,15 @@ var _ = Describe("Dash0 Kubernetes Operator", Ordered, func() { operatorHelmChart, ) - runInParallelForAllWorkloadTypes(workloadConfigs, func(config controllerTestWorkloadConfig) { - By(fmt.Sprintf("verifying that the Node.js %s has been instrumented by the controller", config.workloadType)) + runInParallelForAllWorkloadTypes(controllerTestWorkloadTypes, func(workloadType workloadType) { + By(fmt.Sprintf("verifying that the Node.js %s has been instrumented by the controller", + workloadType.workloadTypeString)) verifyThatWorkloadHasBeenInstrumented( applicationUnderTestNamespace, - config.workloadType, - config.port, - config.isBatch, - testIds[config.workloadType], + workloadType.workloadTypeString, + workloadType.port, + workloadType.isBatch, + testIds[workloadType.workloadTypeString], images, "controller", ) @@ -156,13 +147,13 @@ var _ = Describe("Dash0 Kubernetes Operator", Ordered, func() { undeployDash0MonitoringResource(applicationUnderTestNamespace) - runInParallelForAllWorkloadTypes(workloadConfigs, func(config controllerTestWorkloadConfig) { + runInParallelForAllWorkloadTypes(controllerTestWorkloadTypes, func(workloadType workloadType) { verifyThatInstrumentationHasBeenReverted( applicationUnderTestNamespace, - config.workloadType, - config.port, - config.isBatch, - testIds[config.workloadType], + workloadType.workloadTypeString, + workloadType.port, + workloadType.isBatch, + testIds[workloadType.workloadTypeString], "controller", ) }) @@ -204,9 +195,8 @@ var _ = Describe("Dash0 Kubernetes Operator", Ordered, func() { }) It("should ignore existing pods", func() { - testId := generateTestId("pod") By("installing the Node.js pod") - Expect(installNodeJsPod(applicationUnderTestNamespace, testId)).To(Succeed()) + Expect(installNodeJsPod(applicationUnderTestNamespace)).To(Succeed()) deployOperator(operatorNamespace, operatorHelmChart, operatorHelmChartUrl, images, true) deployDash0MonitoringResource( applicationUnderTestNamespace, @@ -225,7 +215,7 @@ var _ = Describe("Dash0 Kubernetes Operator", Ordered, func() { It("should update instrumentation modifications at startup", func() { testId := generateTestId("deployment") By("installing the Node.js deployment") - Expect(installNodeJsDeployment(applicationUnderTestNamespace, testId)).To(Succeed()) + Expect(installNodeJsDeployment(applicationUnderTestNamespace)).To(Succeed()) initialImages := Images{ operator: ImageSpec{ @@ -323,31 +313,25 @@ var _ = Describe("Dash0 Kubernetes Operator", Ordered, func() { undeployDash0MonitoringResource(applicationUnderTestNamespace) }) - type webhookTest struct { - workloadType string - port int - installWorkload func(string, string) error - isBatch bool - } - DescribeTable( "when instrumenting new workloads", - func(config webhookTest) { - testId := generateTestId(config.workloadType) - By(fmt.Sprintf("installing the Node.js %s", config.workloadType)) - Expect(config.installWorkload(applicationUnderTestNamespace, testId)).To(Succeed()) - By(fmt.Sprintf("verifying that the Node.js %s has been instrumented by the webhook", config.workloadType)) + func(workloadType workloadType) { + testId := generateTestId(workloadType.workloadTypeString) + By(fmt.Sprintf("installing the Node.js %s", workloadType.workloadTypeString)) + Expect(installNodeJsWorkload(workloadType, applicationUnderTestNamespace, testId)).To(Succeed()) + By(fmt.Sprintf("verifying that the Node.js %s has been instrumented by the webhook", + workloadType.workloadTypeString)) verifyThatWorkloadHasBeenInstrumented( applicationUnderTestNamespace, - config.workloadType, - config.port, - config.isBatch, + workloadType.workloadTypeString, + workloadType.port, + workloadType.isBatch, testId, images, "webhook", ) - if config.workloadType == "job" { + if workloadType.workloadTypeString == "job" { // For all other workload types, reverting the instrumentation is tested by the controller test // suite. But the controller cannot instrument jobs, so we cannot test the (failing) // uninstrumentation procedure there. Thus, for jobs, we test the failing uninstrumentation and @@ -359,7 +343,7 @@ var _ = Describe("Dash0 Kubernetes Operator", Ordered, func() { // Verify that the instrumentation labels are still in place -- since we cannot undo the // instrumentation, the labels must also not be removed. By("verifying that the job still has labels") - verifyLabels(g, applicationUnderTestNamespace, config.workloadType, true, images, "webhook") + verifyLabels(g, applicationUnderTestNamespace, workloadType.workloadTypeString, true, images, "webhook") By("verifying failed uninstrumentation event") verifyFailedUninstrumentationEvent( @@ -375,49 +359,19 @@ var _ = Describe("Dash0 Kubernetes Operator", Ordered, func() { }, labelChangeTimeout, pollingInterval).Should(Succeed()) } }, - Entry("should instrument new cron jobs", webhookTest{ - workloadType: "cronjob", - port: 1205, - installWorkload: installNodeJsCronJob, - isBatch: true, - }), - Entry("should instrument new daemon sets", webhookTest{ - workloadType: "daemonset", - port: 1206, - installWorkload: installNodeJsDaemonSet, - }), - Entry("should instrument new deployments", webhookTest{ - workloadType: "deployment", - port: 1207, - installWorkload: installNodeJsDeployment, - }), - Entry("should instrument new jobs", webhookTest{ - workloadType: "job", - port: 1208, - installWorkload: installNodeJsJob, - isBatch: true, - }), - Entry("should instrument new pods", webhookTest{ - workloadType: "pod", - port: 1211, - installWorkload: installNodeJsPod, - }), - Entry("should instrument new replica sets", webhookTest{ - workloadType: "replicaset", - port: 1209, - installWorkload: installNodeJsReplicaSet, - }), - Entry("should instrument new stateful sets", webhookTest{ - workloadType: "statefulset", - port: 1210, - installWorkload: installNodeJsStatefulSet, - }), + Entry("should instrument new cron jobs", workloadTypeCronjob), + Entry("should instrument new daemon sets", workloadTypeDaemonSet), + Entry("should instrument new deployments", workloadTypeDeployment), + Entry("should instrument new jobs", workloadTypeJob), + Entry("should instrument new pods", workloadTypePod), + Entry("should instrument new replica sets", workloadTypeReplicaSet), + Entry("should instrument new stateful sets", workloadTypeStatefulSet), ) It("should revert an instrumented workload when the opt-out label is added after the fact", func() { testId := generateTestId("deployment") By("installing the Node.js deployment") - Expect(installNodeJsDeployment(applicationUnderTestNamespace, testId)).To(Succeed()) + Expect(installNodeJsDeployment(applicationUnderTestNamespace)).To(Succeed()) By("verifying that the Node.js deployment has been instrumented by the webhook") verifyThatWorkloadHasBeenInstrumented( applicationUnderTestNamespace, @@ -449,7 +403,7 @@ var _ = Describe("Dash0 Kubernetes Operator", Ordered, func() { It("should instrument a workload when the opt-out label is removed from it", func() { testId := generateTestId("daemonset") By("installing the Node.js daemonset with dash0.com/enable=false") - Expect(installNodeJsDaemonSetWithOptOutLabel(applicationUnderTestNamespace, testId)).To(Succeed()) + Expect(installNodeJsDaemonSetWithOptOutLabel(applicationUnderTestNamespace)).To(Succeed()) By("verifying that the Node.js daemonset has not been instrumented by the webhook") Consistently(func(g Gomega) { verifyNoDash0LabelsOrOnlyOptOut(g, applicationUnderTestNamespace, "daemonset", true) @@ -503,7 +457,7 @@ var _ = Describe("Dash0 Kubernetes Operator", Ordered, func() { ) By("installing the Node.js stateful set") - Expect(installNodeJsStatefulSet(applicationUnderTestNamespace, testId)).To(Succeed()) + Expect(installNodeJsStatefulSet(applicationUnderTestNamespace)).To(Succeed()) By("verifying that the Node.js stateful set has not been instrumented by the webhook (due to " + "namespace-level opt-out via the Dash0Monitoring resource)") Consistently(func(g Gomega) { @@ -537,7 +491,7 @@ var _ = Describe("Dash0 Kubernetes Operator", Ordered, func() { ) By("installing the Node.js deployment") - Expect(installNodeJsDeployment(applicationUnderTestNamespace, testId)).To(Succeed()) + Expect(installNodeJsDeployment(applicationUnderTestNamespace)).To(Succeed()) By("verifying that the Node.js deployment has been instrumented by the webhook") verifyThatWorkloadHasBeenInstrumented( applicationUnderTestNamespace, @@ -622,7 +576,7 @@ var _ = Describe("Dash0 Kubernetes Operator", Ordered, func() { operatorHelmChart, ) - Expect(installNodeJsDeployment(applicationUnderTestNamespace, testId)).To(Succeed()) + Expect(installNodeJsDeployment(applicationUnderTestNamespace)).To(Succeed()) By("verifying that the Node.js deployment has been instrumented by the controller") Eventually(func(g Gomega) { @@ -687,16 +641,12 @@ var _ = Describe("Dash0 Kubernetes Operator", Ordered, func() { configs := []removalTestNamespaceConfig{ { - namespace: "e2e-application-under-test-namespace-removal-1", - workloadType: "daemonset", - port: 1206, - installWorkload: installNodeJsDaemonSet, + namespace: "e2e-application-under-test-namespace-removal-1", + workloadType: workloadTypeDaemonSet, }, { - namespace: "e2e-application-under-test-namespace-removal-2", - workloadType: "deployment", - port: 1207, - installWorkload: installNodeJsDeployment, + namespace: "e2e-application-under-test-namespace-removal-2", + workloadType: workloadTypeDeployment, }, } @@ -704,11 +654,18 @@ var _ = Describe("Dash0 Kubernetes Operator", Ordered, func() { It("should remove all Dash0 monitoring resources and uninstrument all workloads", func() { By("deploying workloads") testIds := make(map[string]string) + for _, config := range configs { + testIds[config.workloadType.workloadTypeString] = generateTestId(config.workloadType.workloadTypeString) + } + runInParallelForAllWorkloadTypes(configs, func(config removalTestNamespaceConfig) { - testId := generateTestId(config.workloadType) - testIds[config.workloadType] = testId - By(fmt.Sprintf("deploying the Node.js %s to namespace %s", config.workloadType, config.namespace)) - Expect(config.installWorkload(config.namespace, testId)).To(Succeed()) + By(fmt.Sprintf("deploying the Node.js %s to namespace %s", + config.workloadType.workloadTypeString, config.namespace)) + Expect(installNodeJsWorkload( + config.workloadType, + config.namespace, + testIds[config.workloadType.workloadTypeString], + )).To(Succeed()) }) deployOperator(operatorNamespace, operatorHelmChart, operatorHelmChartUrl, images, true) @@ -722,13 +679,14 @@ var _ = Describe("Dash0 Kubernetes Operator", Ordered, func() { }) runInParallelForAllWorkloadTypes(configs, func(config removalTestNamespaceConfig) { - By(fmt.Sprintf("verifying that the Node.js %s has been instrumented by the controller", config.workloadType)) + By(fmt.Sprintf("verifying that the Node.js %s has been instrumented by the controller", + config.workloadType.workloadTypeString)) verifyThatWorkloadHasBeenInstrumented( config.namespace, - config.workloadType, - config.port, + config.workloadType.workloadTypeString, + config.workloadType.port, false, - testIds[config.workloadType], + testIds[config.workloadType.workloadTypeString], images, "controller", ) @@ -739,10 +697,10 @@ var _ = Describe("Dash0 Kubernetes Operator", Ordered, func() { runInParallelForAllWorkloadTypes(configs, func(config removalTestNamespaceConfig) { verifyThatInstrumentationHasBeenReverted( config.namespace, - config.workloadType, - config.port, + config.workloadType.workloadTypeString, + config.workloadType.port, false, - testIds[config.workloadType], + testIds[config.workloadType.workloadTypeString], "controller", ) }) @@ -763,26 +721,17 @@ type workloadConfig interface { GetWorkloadType() string } -type controllerTestWorkloadConfig struct { - workloadType string - port int - installWorkload func(string, string) error - isBatch bool -} - -func (c controllerTestWorkloadConfig) GetWorkloadType() string { - return c.workloadType +func (wt workloadType) GetWorkloadType() string { + return wt.workloadTypeString } type removalTestNamespaceConfig struct { - namespace string - workloadType string - port int - installWorkload func(string, string) error + namespace string + workloadType workloadType } func (c removalTestNamespaceConfig) GetWorkloadType() string { - return c.workloadType + return c.workloadType.workloadTypeString } func runInParallelForAllWorkloadTypes[C workloadConfig]( @@ -792,16 +741,16 @@ func runInParallelForAllWorkloadTypes[C workloadConfig]( passed := make(map[string]bool) var wg sync.WaitGroup for _, config := range workloadConfigs { - workloadType := config.GetWorkloadType() - passed[workloadType] = false + workloadTypeString := config.GetWorkloadType() + passed[workloadTypeString] = false wg.Add(1) go func(cfg C) { defer GinkgoRecover() defer wg.Done() - fmt.Fprintf(GinkgoWriter, "(before test step: %s)\n", workloadType) + fmt.Fprintf(GinkgoWriter, "(before test step: %s)\n", workloadTypeString) testStep(cfg) - fmt.Fprintf(GinkgoWriter, "(after test step: %s)\n", workloadType) - passed[workloadType] = true + fmt.Fprintf(GinkgoWriter, "(after test step: %s)\n", workloadTypeString) + passed[workloadTypeString] = true }(config) } wg.Wait() diff --git a/test/e2e/verify_instrumentation.go b/test/e2e/verify_instrumentation.go index 68835eaa..4436b6be 100644 --- a/test/e2e/verify_instrumentation.go +++ b/test/e2e/verify_instrumentation.go @@ -145,13 +145,13 @@ func verifyThatInstrumentationIsRevertedEventually( By(fmt.Sprintf("%s: matching spans are no longer captured", workloadType)) } -func waitForApplicationToBecomeReady(templateName string, waitCommand *exec.Cmd) error { - By(fmt.Sprintf("waiting for %s to become ready", templateName)) +func waitForApplicationToBecomeReady(workloadType string, waitCommand *exec.Cmd) error { + By(fmt.Sprintf("waiting for %s to become ready", workloadType)) err := runAndIgnoreOutput(waitCommand) if err != nil { - By(fmt.Sprintf("%s never became ready", templateName)) + By(fmt.Sprintf("%s never became ready", workloadType)) } else { - By(fmt.Sprintf("%s is ready now", templateName)) + By(fmt.Sprintf("%s is ready now", workloadType)) } return err }