From 752916de6efbbd83954b997bc9e18b5ca5d74ff2 Mon Sep 17 00:00:00 2001 From: emmaaroche Date: Mon, 25 May 2026 15:28:51 +0100 Subject: [PATCH 1/3] test: add E2E tests for manual approval and rejection workflows Signed-off-by: emmaaroche --- test/e2e/automatic_approval_test.go | 162 +------------------ test/e2e/manual_workflow_test.go | 240 ++++++++++++++++++++++++++++ test/e2e/test_helpers.go | 168 +++++++++++++++++++ 3 files changed, 415 insertions(+), 155 deletions(-) create mode 100644 test/e2e/manual_workflow_test.go diff --git a/test/e2e/automatic_approval_test.go b/test/e2e/automatic_approval_test.go index 80fa876..df43e72 100644 --- a/test/e2e/automatic_approval_test.go +++ b/test/e2e/automatic_approval_test.go @@ -38,65 +38,7 @@ var _ = Describe("Automatic Approval", Ordered, func() { ) AfterEach(func() { - specReport := CurrentSpecReport() - if specReport.Failed() { - By("Fetching controller manager pod name") - cmd := exec.Command("kubectl", "get", - "pods", "-l", "control-plane=controller-manager", - "-o", "go-template={{ range .items }}"+ - "{{ if not .metadata.deletionTimestamp }}"+ - "{{ .metadata.name }}"+ - "{{ \"\\n\" }}{{ end }}{{ end }}", - "-n", controllerNamespace, - ) - podOutput, err := utils.Run(cmd) - if err != nil { - _, _ = fmt.Fprintf(GinkgoWriter, "Failed to get controller pod name: %s\n", err) - return - } - podNames := utils.GetNonEmptyLines(podOutput) - if len(podNames) == 0 { - _, _ = fmt.Fprintf(GinkgoWriter, "No controller pod found\n") - return - } - controllerPodName := podNames[0] - - By("Fetching controller manager pod logs") - cmd = exec.Command("kubectl", "logs", controllerPodName, "-n", controllerNamespace) - controllerLogs, err := utils.Run(cmd) - if err == nil { - _, _ = fmt.Fprintf(GinkgoWriter, "Controller logs:\n%s\n", controllerLogs) - } else { - _, _ = fmt.Fprintf(GinkgoWriter, "Failed to get Controller logs: %s\n", err) - } - - By("Fetching Kubernetes events in owner namespace") - cmd = exec.Command("kubectl", "get", "events", "-n", ownerNamespace, "--sort-by=.lastTimestamp") - eventsOutput, err := utils.Run(cmd) - if err == nil { - _, _ = fmt.Fprintf(GinkgoWriter, "Events in %s:\n%s\n", ownerNamespace, eventsOutput) - } else { - _, _ = fmt.Fprintf(GinkgoWriter, "Failed to get events in %s: %s\n", ownerNamespace, err) - } - - By("Fetching Kubernetes events in consumer namespace") - cmd = exec.Command("kubectl", "get", "events", "-n", consumerNamespace, "--sort-by=.lastTimestamp") - eventsOutput, err = utils.Run(cmd) - if err == nil { - _, _ = fmt.Fprintf(GinkgoWriter, "Events in %s:\n%s\n", consumerNamespace, eventsOutput) - } else { - _, _ = fmt.Fprintf(GinkgoWriter, "Failed to get events in %s: %s\n", consumerNamespace, err) - } - - By("Fetching controller manager pod description") - cmd = exec.Command("kubectl", "describe", "pod", controllerPodName, "-n", controllerNamespace) - podDescription, err := utils.Run(cmd) - if err == nil { - _, _ = fmt.Fprintf(GinkgoWriter, "Pod description:\n%s\n", podDescription) - } else { - _, _ = fmt.Fprintf(GinkgoWriter, "Failed to describe controller pod: %s\n", err) - } - } + LogDebugInfoOnFailure(ownerNamespace, consumerNamespace, controllerNamespace) }) BeforeAll(func() { @@ -108,104 +50,14 @@ var _ = Describe("Automatic Approval", Ordered, func() { }) AfterAll(func() { - By("cleaning up kuadrant namespace") - cmd := exec.Command("kubectl", "delete", "ns", kuadrantNamespace, "--wait=false") - _, _ = utils.Run(cmd) - - By("cleaning up owner namespace") - cmd = exec.Command("kubectl", "delete", "ns", ownerNamespace, "--wait=false") - _, _ = utils.Run(cmd) - - By("cleaning up consumer namespace") - cmd = exec.Command("kubectl", "delete", "ns", consumerNamespace, "--wait=false") - _, _ = utils.Run(cmd) + CleanupNamespaces(ownerNamespace, consumerNamespace, kuadrantNamespace) }) Context("APIKey with automatic approval mode", func() { It("should create APIKeyRequest, automatic approval, and approve the APIKey", func() { - By("creating an HTTPRoute as a reference target") - httpRouteYAML := fmt.Sprintf(` -apiVersion: gateway.networking.k8s.io/v1 -kind: HTTPRoute -metadata: - name: test-route - namespace: %s -spec: - parentRefs: - - name: test-gateway - rules: - - matches: - - path: - type: PathPrefix - value: /api - backendRefs: - - name: test-service - port: 8080 -`, ownerNamespace) - - cmd := exec.Command("kubectl", "apply", "-f", "-") - cmd.Stdin = utils.StringReader(httpRouteYAML) - _, err := utils.Run(cmd) - Expect(err).NotTo(HaveOccurred(), "Failed to create HTTPRoute") - - By("creating an AuthPolicy with API key authentication") - authPolicyYAML := fmt.Sprintf(` -apiVersion: kuadrant.io/v1 -kind: AuthPolicy -metadata: - name: test-auth-policy - namespace: %s -spec: - targetRef: - group: gateway.networking.k8s.io - kind: HTTPRoute - name: test-route - rules: - authentication: - "api-key": - apiKey: - selector: - matchLabels: - kuadrant.io/apikeys: "true" - credentials: - authorizationHeader: - prefix: "API-KEY" -`, ownerNamespace) - - cmd = exec.Command("kubectl", "apply", "-f", "-") - cmd.Stdin = utils.StringReader(authPolicyYAML) - _, err = utils.Run(cmd) - Expect(err).NotTo(HaveOccurred(), "Failed to create AuthPolicy") - - By("updating AuthPolicy status to Accepted and Enforced") - authPolicyStatusPatch := `{ - "status": { - "conditions": [ - { - "type": "Accepted", - "status": "True", - "reason": "Accepted", - "message": "AuthPolicy has been accepted", - "lastTransitionTime": "2024-01-01T00:00:00Z" - }, - { - "type": "Enforced", - "status": "True", - "reason": "Enforced", - "message": "AuthPolicy has been successfully enforced", - "lastTransitionTime": "2024-01-01T00:00:00Z" - } - ] - } - }` - - cmd = exec.Command("kubectl", "patch", "authpolicy", "test-auth-policy", - "-n", ownerNamespace, - "--type=merge", - "--subresource=status", - "-p", authPolicyStatusPatch) - _, err = utils.Run(cmd) - Expect(err).NotTo(HaveOccurred(), "Failed to update AuthPolicy status") + By("creating HTTPRoute and AuthPolicy") + CreateHTTPRoute(ownerNamespace) + CreateAuthPolicy(ownerNamespace) By("creating an APIProduct with automatic approval mode") apiProductYAML := fmt.Sprintf(` @@ -225,9 +77,9 @@ spec: name: test-route `, apiProductName, ownerNamespace) - cmd = exec.Command("kubectl", "apply", "-f", "-") + cmd := exec.Command("kubectl", "apply", "-f", "-") cmd.Stdin = utils.StringReader(apiProductYAML) - _, err = utils.Run(cmd) + _, err := utils.Run(cmd) Expect(err).NotTo(HaveOccurred(), "Failed to create APIProduct") By("verifying APIProduct was created") diff --git a/test/e2e/manual_workflow_test.go b/test/e2e/manual_workflow_test.go new file mode 100644 index 0000000..ed9e549 --- /dev/null +++ b/test/e2e/manual_workflow_test.go @@ -0,0 +1,240 @@ +/* +Copyright 2026. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package e2e + +import ( + "fmt" + "os/exec" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "github.com/kuadrant/developer-portal-controller/test/utils" +) + +var _ = Describe("Manual Approval Workflows", Ordered, func() { + const ( + ownerNamespace = "api-owner-manual-test" + consumerNamespace = "api-consumer-manual-test" + kuadrantNamespace = "kuadrant-manual-ns" + controllerNamespace = "developer-portal-controller-system" + ) + + AfterEach(func() { + LogDebugInfoOnFailure(ownerNamespace, consumerNamespace, controllerNamespace) + }) + + BeforeAll(func() { + SetDefaultEventuallyTimeout(2 * time.Minute) + SetDefaultEventuallyPollingInterval(2 * time.Second) + + By("setting up namespaces and Kuadrant instance") + SetupNamespacesAndKuadrant(ownerNamespace, consumerNamespace, kuadrantNamespace) + + By("creating HTTPRoute and AuthPolicy") + CreateHTTPRoute(ownerNamespace) + CreateAuthPolicy(ownerNamespace) + }) + + AfterAll(func() { + CleanupNamespaces(ownerNamespace, consumerNamespace, kuadrantNamespace) + }) + + testManualApprovalWorkflow := func(apiProductName, apiKeyName string, approved bool, useCase, userID, email string) { + By("creating an APIProduct with manual approval mode") + apiProductYAML := fmt.Sprintf(` +apiVersion: devportal.kuadrant.io/v1alpha1 +kind: APIProduct +metadata: + name: %s + namespace: %s +spec: + displayName: "Manual Test API" + description: "API Product for testing manual approval/rejection" + approvalMode: manual + publishStatus: Published + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: test-route +`, apiProductName, ownerNamespace) + + cmd := exec.Command("kubectl", "apply", "-f", "-") + cmd.Stdin = utils.StringReader(apiProductYAML) + _, err := utils.Run(cmd) + Expect(err).NotTo(HaveOccurred(), "Failed to create APIProduct") + + By("verifying APIProduct was created") + Eventually(func(g Gomega) { + cmd := exec.Command("kubectl", "get", "apiproduct", apiProductName, + "-n", ownerNamespace, "-o", "jsonpath={.metadata.name}") + output, err := utils.Run(cmd) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(output).To(Equal(apiProductName)) + }).Should(Succeed()) + + By("creating a secret with API key in the consumer namespace") + secretYAML := fmt.Sprintf(` +apiVersion: v1 +kind: Secret +metadata: + name: %s-secret + namespace: %s +type: Opaque +stringData: + api_key: test-api-key-value +`, apiKeyName, consumerNamespace) + + cmd = exec.Command("kubectl", "apply", "-f", "-") + cmd.Stdin = utils.StringReader(secretYAML) + _, err = utils.Run(cmd) + Expect(err).NotTo(HaveOccurred(), "Failed to create secret") + + By("creating an APIKey in the consumer namespace") + apiKeyYAML := fmt.Sprintf(` +apiVersion: devportal.kuadrant.io/v1alpha1 +kind: APIKey +metadata: + name: %s + namespace: %s +spec: + apiProductRef: + name: %s + namespace: %s + secretRef: + name: %s-secret + planTier: premium + useCase: "%s" + requestedBy: + userId: %s + email: %s +`, apiKeyName, consumerNamespace, apiProductName, ownerNamespace, apiKeyName, useCase, userID, email) + + cmd = exec.Command("kubectl", "apply", "-f", "-") + cmd.Stdin = utils.StringReader(apiKeyYAML) + _, err = utils.Run(cmd) + Expect(err).NotTo(HaveOccurred(), "Failed to create APIKey") + + By("verifying APIKey was created") + Eventually(func(g Gomega) { + cmd := exec.Command("kubectl", "get", "apikey", apiKeyName, + "-n", consumerNamespace, "-o", "jsonpath={.metadata.name}") + output, err := utils.Run(cmd) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(output).To(Equal(apiKeyName)) + }).Should(Succeed()) + + By("verifying APIKey has Pending condition") + Eventually(func(g Gomega) { + cmd := exec.Command("kubectl", "get", "apikey", apiKeyName, + "-n", consumerNamespace, "-o", "jsonpath={.status.conditions[?(@.type=='Pending')].status}") + output, err := utils.Run(cmd) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(output).To(Equal("True"), "APIKey should have Pending=True condition") + }).Should(Succeed()) + + By("verifying APIKeyRequest was created in the owner namespace") + var apiKeyRequestName string + Eventually(func(g Gomega) { + cmd := exec.Command("kubectl", "get", "apikeyrequest", + "-n", ownerNamespace, + "-o", "jsonpath={.items[?(@.spec.apiKeyRef.name=='"+apiKeyName+"')].metadata.name}") + output, err := utils.Run(cmd) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(output).NotTo(BeEmpty(), "APIKeyRequest should be created") + apiKeyRequestName = output + }).Should(Succeed()) + + By("verifying APIKeyRequest has Pending condition") + Eventually(func(g Gomega) { + cmd := exec.Command("kubectl", "get", "apikeyrequest", apiKeyRequestName, + "-n", ownerNamespace, "-o", "jsonpath={.status.conditions[?(@.type=='Pending')].status}") + output, err := utils.Run(cmd) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(output).To(Equal("True"), "APIKeyRequest should have Pending=True condition") + }).Should(Succeed()) + + var approvalReason, expectedCondition string + if approved { + approvalReason = "API access approved for testing" + expectedCondition = "Approved" + } else { + approvalReason = "API access denied for testing" + expectedCondition = "Denied" + } + + By(fmt.Sprintf("manually creating APIKeyApproval with approved=%v", approved)) + apiKeyApprovalYAML := fmt.Sprintf(` +apiVersion: devportal.kuadrant.io/v1alpha1 +kind: APIKeyApproval +metadata: + name: %s-manual + namespace: %s +spec: + apiKeyRequestRef: + name: %s + approved: %t + reviewedBy: test-owner + reviewedAt: "2026-05-25T00:00:00Z" + reason: "%s" +`, apiKeyRequestName, ownerNamespace, apiKeyRequestName, approved, approvalReason) + + cmd = exec.Command("kubectl", "apply", "-f", "-") + cmd.Stdin = utils.StringReader(apiKeyApprovalYAML) + _, err = utils.Run(cmd) + Expect(err).NotTo(HaveOccurred(), "Failed to create APIKeyApproval") + + By(fmt.Sprintf("verifying APIKeyRequest gets %s condition", expectedCondition)) + Eventually(func(g Gomega) { + cmd := exec.Command("kubectl", "get", "apikeyrequest", apiKeyRequestName, + "-n", ownerNamespace, + "-o", fmt.Sprintf("jsonpath={.status.conditions[?(@.type=='%s')].status}", expectedCondition)) + output, err := utils.Run(cmd) + g.Expect(err).NotTo(HaveOccurred()) + errMsg := fmt.Sprintf("APIKeyRequest should have %s=True condition", expectedCondition) + g.Expect(output).To(Equal("True"), errMsg) + }).Should(Succeed()) + + By(fmt.Sprintf("verifying APIKey eventually gets %s condition", expectedCondition)) + Eventually(func(g Gomega) { + jsonPath := fmt.Sprintf("jsonpath={.status.conditions[?(@.type=='%s')].status}", expectedCondition) + cmd := exec.Command("kubectl", "get", "apikey", apiKeyName, + "-n", consumerNamespace, "-o", jsonPath) + output, err := utils.Run(cmd) + g.Expect(err).NotTo(HaveOccurred()) + errMsg := fmt.Sprintf("APIKey should have %s=True condition", expectedCondition) + g.Expect(output).To(Equal("True"), errMsg) + }).Should(Succeed()) + } + + It("should approve an APIKey request", func() { + testManualApprovalWorkflow( + "manual-approve-api", "test-manual-apikey", + true, + "Testing manual approval flow", "test-user-123", "test@example.com", + ) + }) + + It("should reject an APIKey request", func() { + testManualApprovalWorkflow( + "rejection-api", "test-rejection-apikey", + false, + "Testing rejection flow", "test-user-456", "test-rejection@example.com", + ) + }) +}) diff --git a/test/e2e/test_helpers.go b/test/e2e/test_helpers.go index aef0fc0..00b2192 100644 --- a/test/e2e/test_helpers.go +++ b/test/e2e/test_helpers.go @@ -20,6 +20,7 @@ import ( "fmt" "os/exec" + "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" "github.com/kuadrant/developer-portal-controller/test/utils" @@ -54,3 +55,170 @@ spec: {} _, err = utils.Run(cmd) gomega.Expect(err).NotTo(gomega.HaveOccurred(), "Failed to create Kuadrant") } + +// CleanupNamespaces deletes the specified namespaces asynchronously +func CleanupNamespaces(ownerNamespace, consumerNamespace, kuadrantNamespace string) { + ginkgo.By("cleaning up kuadrant namespace") + cmd := exec.Command("kubectl", "delete", "ns", kuadrantNamespace, "--wait=false") + _, _ = utils.Run(cmd) + + ginkgo.By("cleaning up owner namespace") + cmd = exec.Command("kubectl", "delete", "ns", ownerNamespace, "--wait=false") + _, _ = utils.Run(cmd) + + ginkgo.By("cleaning up consumer namespace") + cmd = exec.Command("kubectl", "delete", "ns", consumerNamespace, "--wait=false") + _, _ = utils.Run(cmd) +} + +// LogDebugInfoOnFailure logs controller logs and events when a test fails +func LogDebugInfoOnFailure(ownerNamespace, consumerNamespace, controllerNamespace string) { + specReport := ginkgo.CurrentSpecReport() + if !specReport.Failed() { + return + } + + ginkgo.By("Fetching controller manager pod name") + cmd := exec.Command("kubectl", "get", + "pods", "-l", "control-plane=controller-manager", + "-o", "go-template={{ range .items }}"+ + "{{ if not .metadata.deletionTimestamp }}"+ + "{{ .metadata.name }}"+ + "{{ \"\\n\" }}{{ end }}{{ end }}", + "-n", controllerNamespace, + ) + podOutput, err := utils.Run(cmd) + if err != nil { + _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, "Failed to get controller pod name: %s\n", err) + return + } + podNames := utils.GetNonEmptyLines(podOutput) + if len(podNames) == 0 { + _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, "No controller pod found\n") + return + } + controllerPodName := podNames[0] + + ginkgo.By("Fetching controller manager pod logs") + cmd = exec.Command("kubectl", "logs", controllerPodName, "-n", controllerNamespace) + controllerLogs, err := utils.Run(cmd) + if err == nil { + _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, "Controller logs:\n%s\n", controllerLogs) + } else { + _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, "Failed to get Controller logs: %s\n", err) + } + + ginkgo.By("Fetching Kubernetes events in owner namespace") + cmd = exec.Command("kubectl", "get", "events", "-n", ownerNamespace, "--sort-by=.lastTimestamp") + eventsOutput, err := utils.Run(cmd) + if err == nil { + _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, "Events in %s:\n%s\n", ownerNamespace, eventsOutput) + } else { + _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, "Failed to get events in %s: %s\n", ownerNamespace, err) + } + + ginkgo.By("Fetching Kubernetes events in consumer namespace") + cmd = exec.Command("kubectl", "get", "events", "-n", consumerNamespace, "--sort-by=.lastTimestamp") + eventsOutput, err = utils.Run(cmd) + if err == nil { + _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, "Events in %s:\n%s\n", consumerNamespace, eventsOutput) + } else { + _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, "Failed to get events in %s: %s\n", consumerNamespace, err) + } + + ginkgo.By("Fetching controller manager pod description") + cmd = exec.Command("kubectl", "describe", "pod", controllerPodName, "-n", controllerNamespace) + podDescription, err := utils.Run(cmd) + if err == nil { + _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, "Pod description:\n%s\n", podDescription) + } else { + _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, "Failed to describe controller pod: %s\n", err) + } +} + +// CreateHTTPRoute creates an HTTPRoute in the specified namespace +func CreateHTTPRoute(namespace string) { + httpRouteYAML := fmt.Sprintf(` +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: test-route + namespace: %s +spec: + parentRefs: + - name: test-gateway + rules: + - matches: + - path: + type: PathPrefix + value: /api + backendRefs: + - name: test-service + port: 8080 +`, namespace) + + cmd := exec.Command("kubectl", "apply", "-f", "-") + cmd.Stdin = utils.StringReader(httpRouteYAML) + _, err := utils.Run(cmd) + gomega.Expect(err).NotTo(gomega.HaveOccurred(), "Failed to create HTTPRoute") +} + +// CreateAuthPolicy creates an AuthPolicy and patches its status to Accepted/Enforced +func CreateAuthPolicy(namespace string) { + authPolicyYAML := fmt.Sprintf(` +apiVersion: kuadrant.io/v1 +kind: AuthPolicy +metadata: + name: test-auth-policy + namespace: %s +spec: + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: test-route + rules: + authentication: + "api-key": + apiKey: + selector: + matchLabels: + kuadrant.io/apikeys: "true" + credentials: + authorizationHeader: + prefix: "API-KEY" +`, namespace) + + cmd := exec.Command("kubectl", "apply", "-f", "-") + cmd.Stdin = utils.StringReader(authPolicyYAML) + _, err := utils.Run(cmd) + gomega.Expect(err).NotTo(gomega.HaveOccurred(), "Failed to create AuthPolicy") + + authPolicyStatusPatch := `{ + "status": { + "conditions": [ + { + "type": "Accepted", + "status": "True", + "reason": "Accepted", + "message": "AuthPolicy has been accepted", + "lastTransitionTime": "2024-01-01T00:00:00Z" + }, + { + "type": "Enforced", + "status": "True", + "reason": "Enforced", + "message": "AuthPolicy has been successfully enforced", + "lastTransitionTime": "2024-01-01T00:00:00Z" + } + ] + } + }` + + cmd = exec.Command("kubectl", "patch", "authpolicy", "test-auth-policy", + "-n", namespace, + "--type=merge", + "--subresource=status", + "-p", authPolicyStatusPatch) + _, err = utils.Run(cmd) + gomega.Expect(err).NotTo(gomega.HaveOccurred(), "Failed to update AuthPolicy status") +} From da74336765e3d7a93030d281acd40b6b26ee074e Mon Sep 17 00:00:00 2001 From: emmaaroche Date: Mon, 25 May 2026 16:42:04 +0100 Subject: [PATCH 2/3] address coderabbit review Signed-off-by: emmaaroche --- test/e2e/test_helpers.go | 59 ++++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/test/e2e/test_helpers.go b/test/e2e/test_helpers.go index 00b2192..20bc60f 100644 --- a/test/e2e/test_helpers.go +++ b/test/e2e/test_helpers.go @@ -60,15 +60,21 @@ spec: {} func CleanupNamespaces(ownerNamespace, consumerNamespace, kuadrantNamespace string) { ginkgo.By("cleaning up kuadrant namespace") cmd := exec.Command("kubectl", "delete", "ns", kuadrantNamespace, "--wait=false") - _, _ = utils.Run(cmd) + output, err := utils.Run(cmd) + gomega.Expect(err).NotTo(gomega.HaveOccurred(), + "Failed to delete kuadrant namespace %s: %s", kuadrantNamespace, output) ginkgo.By("cleaning up owner namespace") cmd = exec.Command("kubectl", "delete", "ns", ownerNamespace, "--wait=false") - _, _ = utils.Run(cmd) + output, err = utils.Run(cmd) + gomega.Expect(err).NotTo(gomega.HaveOccurred(), + "Failed to delete owner namespace %s: %s", ownerNamespace, output) ginkgo.By("cleaning up consumer namespace") cmd = exec.Command("kubectl", "delete", "ns", consumerNamespace, "--wait=false") - _, _ = utils.Run(cmd) + output, err = utils.Run(cmd) + gomega.Expect(err).NotTo(gomega.HaveOccurred(), + "Failed to delete consumer namespace %s: %s", consumerNamespace, output) } // LogDebugInfoOnFailure logs controller logs and events when a test fails @@ -88,24 +94,27 @@ func LogDebugInfoOnFailure(ownerNamespace, consumerNamespace, controllerNamespac "-n", controllerNamespace, ) podOutput, err := utils.Run(cmd) + controllerPodName := "" if err != nil { _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, "Failed to get controller pod name: %s\n", err) - return - } - podNames := utils.GetNonEmptyLines(podOutput) - if len(podNames) == 0 { - _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, "No controller pod found\n") - return + } else { + podNames := utils.GetNonEmptyLines(podOutput) + if len(podNames) == 0 { + _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, "No controller pod found\n") + } else { + controllerPodName = podNames[0] + } } - controllerPodName := podNames[0] - ginkgo.By("Fetching controller manager pod logs") - cmd = exec.Command("kubectl", "logs", controllerPodName, "-n", controllerNamespace) - controllerLogs, err := utils.Run(cmd) - if err == nil { - _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, "Controller logs:\n%s\n", controllerLogs) - } else { - _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, "Failed to get Controller logs: %s\n", err) + if controllerPodName != "" { + ginkgo.By("Fetching controller manager pod logs") + cmd = exec.Command("kubectl", "logs", controllerPodName, "-n", controllerNamespace) + controllerLogs, err := utils.Run(cmd) + if err == nil { + _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, "Controller logs:\n%s\n", controllerLogs) + } else { + _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, "Failed to get Controller logs: %s\n", err) + } } ginkgo.By("Fetching Kubernetes events in owner namespace") @@ -126,13 +135,15 @@ func LogDebugInfoOnFailure(ownerNamespace, consumerNamespace, controllerNamespac _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, "Failed to get events in %s: %s\n", consumerNamespace, err) } - ginkgo.By("Fetching controller manager pod description") - cmd = exec.Command("kubectl", "describe", "pod", controllerPodName, "-n", controllerNamespace) - podDescription, err := utils.Run(cmd) - if err == nil { - _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, "Pod description:\n%s\n", podDescription) - } else { - _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, "Failed to describe controller pod: %s\n", err) + if controllerPodName != "" { + ginkgo.By("Fetching controller manager pod description") + cmd = exec.Command("kubectl", "describe", "pod", controllerPodName, "-n", controllerNamespace) + podDescription, err := utils.Run(cmd) + if err == nil { + _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, "Pod description:\n%s\n", podDescription) + } else { + _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, "Failed to describe controller pod: %s\n", err) + } } } From 564d25bac03fdd52e09035dde48aeb9d1ced4cf8 Mon Sep 17 00:00:00 2001 From: emmaaroche Date: Tue, 26 May 2026 10:19:11 +0100 Subject: [PATCH 3/3] improve test helper error logging Signed-off-by: emmaaroche --- test/e2e/test_helpers.go | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/test/e2e/test_helpers.go b/test/e2e/test_helpers.go index 20bc60f..fc08300 100644 --- a/test/e2e/test_helpers.go +++ b/test/e2e/test_helpers.go @@ -61,20 +61,26 @@ func CleanupNamespaces(ownerNamespace, consumerNamespace, kuadrantNamespace stri ginkgo.By("cleaning up kuadrant namespace") cmd := exec.Command("kubectl", "delete", "ns", kuadrantNamespace, "--wait=false") output, err := utils.Run(cmd) - gomega.Expect(err).NotTo(gomega.HaveOccurred(), - "Failed to delete kuadrant namespace %s: %s", kuadrantNamespace, output) + if err != nil { + _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, + "Failed to delete kuadrant namespace %s: %v\n%s\n", kuadrantNamespace, err, output) + } ginkgo.By("cleaning up owner namespace") cmd = exec.Command("kubectl", "delete", "ns", ownerNamespace, "--wait=false") output, err = utils.Run(cmd) - gomega.Expect(err).NotTo(gomega.HaveOccurred(), - "Failed to delete owner namespace %s: %s", ownerNamespace, output) + if err != nil { + _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, + "Failed to delete owner namespace %s: %v\n%s\n", ownerNamespace, err, output) + } ginkgo.By("cleaning up consumer namespace") cmd = exec.Command("kubectl", "delete", "ns", consumerNamespace, "--wait=false") output, err = utils.Run(cmd) - gomega.Expect(err).NotTo(gomega.HaveOccurred(), - "Failed to delete consumer namespace %s: %s", consumerNamespace, output) + if err != nil { + _, _ = fmt.Fprintf(ginkgo.GinkgoWriter, + "Failed to delete consumer namespace %s: %v\n%s\n", consumerNamespace, err, output) + } } // LogDebugInfoOnFailure logs controller logs and events when a test fails