From 7faa8bbac3bbd36a4ee680e6f82460d587186139 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arda=20G=C3=BC=C3=A7l=C3=BC?= Date: Tue, 9 Jan 2024 10:12:42 +0300 Subject: [PATCH] Add e2e test for kubectl interactive delete --- .../k8s.io/kubectl/pkg/cmd/util/helpers.go | 1 - test/e2e/kubectl/delete.go | 114 ++++++++++++++++++ 2 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 test/e2e/kubectl/delete.go diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/util/helpers.go b/staging/src/k8s.io/kubectl/pkg/cmd/util/helpers.go index fe45d118563..42cc67872a1 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/util/helpers.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/util/helpers.go @@ -427,7 +427,6 @@ type FeatureGate string const ( ApplySet FeatureGate = "KUBECTL_APPLYSET" CmdPluginAsSubcommand FeatureGate = "KUBECTL_ENABLE_CMD_SHADOW" - InteractiveDelete FeatureGate = "KUBECTL_INTERACTIVE_DELETE" OpenAPIV3Patch FeatureGate = "KUBECTL_OPENAPIV3_PATCH" RemoteCommandWebsockets FeatureGate = "KUBECTL_REMOTE_COMMAND_WEBSOCKETS" ) diff --git a/test/e2e/kubectl/delete.go b/test/e2e/kubectl/delete.go new file mode 100644 index 00000000000..259a3fea1d5 --- /dev/null +++ b/test/e2e/kubectl/delete.go @@ -0,0 +1,114 @@ +/* +Copyright 2024 The Kubernetes Authors. + +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. +*/ + +// OWNER = sig/cli + +package kubectl + +import ( + "context" + "strings" + "time" + + "github.com/onsi/ginkgo/v2" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/wait" + clientset "k8s.io/client-go/kubernetes" + admissionapi "k8s.io/pod-security-admission/api" + + commonutils "k8s.io/kubernetes/test/e2e/common" + "k8s.io/kubernetes/test/e2e/framework" + e2ekubectl "k8s.io/kubernetes/test/e2e/framework/kubectl" +) + +var _ = SIGDescribe("Kubectl delete", func() { + defer ginkgo.GinkgoRecover() + var deploymentYaml string + f := framework.NewDefaultFramework("kubectl-delete") + f.NamespacePodSecurityLevel = admissionapi.LevelBaseline + deploymentName := "httpd-deployment" + + var ns string + var c clientset.Interface + ginkgo.BeforeEach(func() { + c = f.ClientSet + ns = f.Namespace.Name + deploymentYaml = commonutils.SubstituteImageName(string(readTestFileOrDie(httpdDeployment1Filename))) + }) + + ginkgo.Describe("interactive", func() { + ginkgo.It("based on user confirmation input", func(ctx context.Context) { + ginkgo.By("apply deployment with replicas 2") + e2ekubectl.RunKubectlOrDieInput(ns, deploymentYaml, "apply", "-f", "-") + + ginkgo.By("verifying the deployment is created and running") + err := wait.PollUntilContextTimeout(ctx, 2*time.Second, 30*time.Second, true, func(ctx context.Context) (done bool, err error) { + d, err := c.AppsV1().Deployments(ns).Get(ctx, deploymentName, metav1.GetOptions{}) + if err != nil { + if apierrors.IsNotFound(err) { + return false, nil + } + return false, err + } + if d != nil && d.Status.AvailableReplicas == 2 { + return true, nil + } + + return false, nil + }) + framework.ExpectNoError(err, "waiting for the deployment has 2 available replicas") + + ginkgo.By("check that resource is not deleted when user types no") + output := e2ekubectl.RunKubectlOrDieInput(ns, "n", "delete", "--interactive", "deployment", deploymentName) + expectedOutput := "You are about to delete the following 1 resource(s):" + if !strings.Contains(output, expectedOutput) || + !strings.Contains(output, "deployment.apps/httpd-deployment") || + !strings.Contains(output, "deletion is cancelled") { + framework.Failf("unexpected output %s", output) + } + + ginkgo.By("verify that deployment is not deleted") + d, err := c.AppsV1().Deployments(ns).Get(ctx, deploymentName, metav1.GetOptions{}) + if err != nil { + framework.Failf("Failed getting deployment that shouldn't be deleted %v", err) + } + + if d == nil || d.Status.AvailableReplicas != 2 { + framework.Failf("unexpected available replicas") + } + + ginkgo.By("check that resource is deleted when user types yes") + e2ekubectl.RunKubectlOrDieInput(ns, "y", "delete", "--interactive", "deployment", deploymentName) + + ginkgo.By("ensure that the deployment is deleted successfully") + err = wait.PollUntilContextTimeout(ctx, 2*time.Second, 30*time.Second, true, func(ctx context.Context) (bool, error) { + _, err = c.AppsV1().Deployments(ns).Get(ctx, deploymentName, metav1.GetOptions{}) + if err == nil { + return false, nil + } + + if apierrors.IsNotFound(err) { + return true, nil + } + + return false, err + }) + framework.ExpectNoError(err, "waiting for the deployment that is deleted after getting confirmation by user") + }) + }) +})