Change:
<ins> /* Copyright 2023 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. */ package storage import ( "context" "fmt" "time" storagev1 "k8s.io/api/storage/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" types "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/util/retry" "k8s.io/kubernetes/test/e2e/framework" "k8s.io/kubernetes/test/e2e/storage/utils" admissionapi "k8s.io/pod-security-admission/api" "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" ) var _ = utils.SIGDescribe("StorageClasses", func() { f := framework.NewDefaultFramework("csi-storageclass") f.NamespacePodSecurityLevel = admissionapi.LevelBaseline ginkgo.Describe("CSI Conformance", func() { ginkgo.It("should run through the lifecycle of a StorageClass", func(ctx context.Context) { scClient := f.ClientSet.StorageV1().StorageClasses() var initialSC, replacementSC *storagev1.StorageClass initialSC = &storagev1.StorageClass{ TypeMeta: metav1.TypeMeta{ Kind: "StorageClass", }, ObjectMeta: metav1.ObjectMeta{ GenerateName: "e2e-", }, Provisioner: "e2e-fake-provisioner", } ginkgo.By("Creating a StorageClass") createdStorageClass, err := scClient.Create(ctx, initialSC, metav1.CreateOptions{}) framework.ExpectNoError(err, "failed to create the requested StorageClass") ginkgo.By(fmt.Sprintf("Get StorageClass %q", createdStorageClass.Name)) retrievedStorageClass, err := scClient.Get(ctx, createdStorageClass.Name, metav1.GetOptions{}) framework.ExpectNoError(err, "failed to get StorageClass %q", createdStorageClass.Name) ginkgo.By(fmt.Sprintf("Patching the StorageClass %q", retrievedStorageClass.Name)) payload := "{"metadata":{"labels":{"" + retrievedStorageClass.Name + "":"patched"}}}" patchedStorageClass, err := scClient.Patch(ctx, retrievedStorageClass.Name, types.StrategicMergePatchType, []byte(payload), metav1.PatchOptions{}) framework.ExpectNoError(err, "failed to patch StorageClass %q", retrievedStorageClass.Name) gomega.Expect(patchedStorageClass.Labels).To(gomega.HaveKeyWithValue(patchedStorageClass.Name, "patched"), "checking that patched label has been applied") ginkgo.By(fmt.Sprintf("Delete StorageClass %q", patchedStorageClass.Name)) err = scClient.Delete(ctx, patchedStorageClass.Name, metav1.DeleteOptions{}) framework.ExpectNoError(err, "failed to delete StorageClass %q", patchedStorageClass.Name) ginkgo.By(fmt.Sprintf("Confirm deletion of StorageClass %q", patchedStorageClass.Name)) scSelector := labels.Set{patchedStorageClass.Name: "patched"}.AsSelector().String() type state struct { StorageClasses []storagev1.StorageClass } err = framework.Gomega().Eventually(ctx, framework.HandleRetry(func(ctx context.Context) (*state, error) { scList, err := scClient.List(ctx, metav1.ListOptions{LabelSelector: scSelector}) if err != nil { return nil, fmt.Errorf("failed to list StorageClass: %w", err) } return &state{ StorageClasses: scList.Items, }, nil })).WithTimeout(30 * time.Second).Should(framework.MakeMatcher(func(s *state) (func() string, error) { if len(s.StorageClasses) == 0 { return nil, nil } return func() string { return fmt.Sprintf("expected StorageClass to be deleted, found %q", s.StorageClasses[0].Name) }, nil })) framework.ExpectNoError(err, "timeout while waiting to confirm StorageClass %q deletion", patchedStorageClass.Name) ginkgo.By("Create a replacement StorageClass") replacementSC = &storagev1.StorageClass{ TypeMeta: metav1.TypeMeta{ Kind: "StorageClass", }, ObjectMeta: metav1.ObjectMeta{ GenerateName: "e2e-v2-", }, Provisioner: "e2e-fake-provisioner", } replacementStorageClass, err := scClient.Create(ctx, replacementSC, metav1.CreateOptions{}) framework.ExpectNoError(err, "failed to create replacement StorageClass") ginkgo.By(fmt.Sprintf("Updating StorageClass %q", replacementStorageClass.Name)) var updatedStorageClass *storagev1.StorageClass err = retry.RetryOnConflict(retry.DefaultRetry, func() error { sc, err := scClient.Get(ctx, replacementStorageClass.Name, metav1.GetOptions{}) framework.ExpectNoError(err, "unable to get Storage %q", replacementStorageClass.Name) sc.Labels = map[string]string{replacementStorageClass.Name: "updated"} updatedStorageClass, err = scClient.Update(ctx, sc, metav1.UpdateOptions{}) return err }) framework.ExpectNoError(err, "failed to update StorageClass %q", replacementStorageClass.Name) gomega.Expect(updatedStorageClass.Labels).To(gomega.HaveKeyWithValue(replacementStorageClass.Name, "updated"), "checking that updated label has been applied") scSelector = labels.Set{replacementStorageClass.Name: "updated"}.AsSelector().String() ginkgo.By(fmt.Sprintf("Listing all StorageClass with the labelSelector: %q", scSelector)) scList, err := scClient.List(ctx, metav1.ListOptions{LabelSelector: scSelector}) framework.ExpectNoError(err, "failed to list StorageClasses with the labelSelector: %q", scSelector) gomega.Expect(scList.Items).To(gomega.HaveLen(1)) ginkgo.By(fmt.Sprintf("Deleting StorageClass %q via DeleteCollection", updatedStorageClass.Name)) err = scClient.DeleteCollection(ctx, metav1.DeleteOptions{}, metav1.ListOptions{LabelSelector: scSelector}) framework.ExpectNoError(err, "failed to delete StorageClass %q", updatedStorageClass.Name) ginkgo.By(fmt.Sprintf("Confirm deletion of StorageClass %q", updatedStorageClass.Name)) err = framework.Gomega().Eventually(ctx, framework.HandleRetry(func(ctx context.Context) (*state, error) { scList, err := scClient.List(ctx, metav1.ListOptions{LabelSelector: scSelector}) if err != nil { return nil, fmt.Errorf("failed to list StorageClass: %w", err) } return &state{ StorageClasses: scList.Items, }, nil })).WithTimeout(30 * time.Second).Should(framework.MakeMatcher(func(s *state) (func() string, error) { if len(s.StorageClasses) == 0 { return nil, nil } return func() string { return fmt.Sprintf("expected StorageClass to be deleted, found %q", s.StorageClasses[0].Name) }, nil })) framework.ExpectNoError(err, "timeout while waiting to confirm StorageClass %q deletion", updatedStorageClass.Name) }) }) }) </ins>

Discussion:
[X] test approval issue : [X] test pr : [X] two weeks soak end date : 22 Sept 2023 [X] test promotion pr : [X] remove endpoint from According to following APIsnoop query, there are three StorageClass endpoints that are untested. Using a number of existing e2e test practices a new has been created to provide future Conformance coverage for the 7 endpoints. The e2e logs for this test are listed below. This query shows the following StorageClass endpoints are hit within a short period of running this e2e test. If a test with these calls gets merged, test coverage will go up by 7 points This test is also created with the goal of conformance promotion. /sig testing /sig architecture /area conformance
/triage accepted /cc
/sig storage
/reopen For tracking the rest of the steps to Promotion
Reopened this issue. <detailsIn response to : /reopen For tracking the rest of the steps to Promotion Instructions for interacting with me using PR comments are available . If you have questions or suggestions related to my behavior, please file an issue against the repository. </details