github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/controllers/storage/storageprovider_controller_test.go (about)

     1  /*
     2  Copyright (C) 2022-2023 ApeCloud Co., Ltd
     3  
     4  This file is part of KubeBlocks project
     5  
     6  This program is free software: you can redistribute it and/or modify
     7  it under the terms of the GNU Affero General Public License as published by
     8  the Free Software Foundation, either version 3 of the License, or
     9  (at your option) any later version.
    10  
    11  This program is distributed in the hope that it will be useful
    12  but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  GNU Affero General Public License for more details.
    15  
    16  You should have received a copy of the GNU Affero General Public License
    17  along with this program.  If not, see <http://www.gnu.org/licenses/>.
    18  */
    19  
    20  package storage
    21  
    22  import (
    23  	. "github.com/onsi/ginkgo/v2"
    24  	. "github.com/onsi/gomega"
    25  
    26  	storagev1 "k8s.io/api/storage/v1"
    27  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    28  	"k8s.io/apimachinery/pkg/api/meta"
    29  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    30  	"k8s.io/apimachinery/pkg/types"
    31  	"sigs.k8s.io/controller-runtime/pkg/client"
    32  
    33  	storagev1alpha1 "github.com/1aal/kubeblocks/apis/storage/v1alpha1"
    34  	"github.com/1aal/kubeblocks/pkg/constant"
    35  	intctrlutil "github.com/1aal/kubeblocks/pkg/generics"
    36  	testapps "github.com/1aal/kubeblocks/pkg/testutil/apps"
    37  	viper "github.com/1aal/kubeblocks/pkg/viperx"
    38  )
    39  
    40  var _ = Describe("StorageProvider controller", func() {
    41  	cleanEnv := func() {
    42  		// must wait till resources deleted and no longer existed before the testcases start,
    43  		// otherwise if later it needs to create some new resource objects with the same name,
    44  		// in race conditions, it will find the existence of old objects, resulting failure to
    45  		// create the new objects.
    46  		By("clean resources")
    47  		// non-namespaced
    48  		ml := client.HasLabels{testCtx.TestObjLabelKey}
    49  		testapps.ClearResourcesWithRemoveFinalizerOption(&testCtx, intctrlutil.StorageProviderSignature, true, ml)
    50  		testapps.ClearResources(&testCtx, intctrlutil.CSIDriverSignature, ml)
    51  
    52  		// namespaced
    53  		inNS := client.InNamespace(viper.GetString(constant.CfgKeyCtrlrMgrNS))
    54  
    55  		// delete rest mocked objects
    56  		testapps.ClearResources(&testCtx, intctrlutil.ConfigMapSignature, inNS, ml)
    57  		testapps.ClearResources(&testCtx, intctrlutil.SecretSignature, inNS, ml)
    58  
    59  		// By("deleting the Namespace to perform the tests")
    60  		// Eventually(func(g Gomega) {
    61  		// 	namespace := testCtx.GetNamespaceObj()
    62  		// 	err := testCtx.Cli.Delete(testCtx.Ctx, &namespace)
    63  		// 	g.Expect(client.IgnoreNotFound(err)).To(Not(HaveOccurred()))
    64  		// 	g.Expect(client.IgnoreNotFound(testCtx.Cli.Get(
    65  		// 		testCtx.Ctx, testCtx.GetNamespaceKey(), &namespace))).To(Not(HaveOccurred()))
    66  		// }).Should(Succeed())
    67  	}
    68  
    69  	BeforeEach(func() {
    70  		cleanEnv()
    71  	})
    72  
    73  	AfterEach(func() {
    74  		cleanEnv()
    75  	})
    76  
    77  	Context("StorageProvider controller test", func() {
    78  		var key types.NamespacedName
    79  		BeforeEach(func() {
    80  			cleanEnv()
    81  			Expect(client.IgnoreAlreadyExists(testCtx.CreateNamespace())).To(Not(HaveOccurred()))
    82  		})
    83  
    84  		AfterEach(func() {
    85  			cleanEnv()
    86  		})
    87  
    88  		createStorageProviderSpec := func(driverName string) {
    89  			obj := &storagev1alpha1.StorageProvider{}
    90  			obj.GenerateName = "storageprovider-"
    91  			obj.Spec.CSIDriverName = driverName
    92  			provider := testapps.CreateK8sResource(&testCtx, obj)
    93  			key = types.NamespacedName{
    94  				Name: provider.GetName(),
    95  			}
    96  		}
    97  
    98  		createCSIDriverObjectSpec := func(driverName string) {
    99  			obj := &storagev1.CSIDriver{}
   100  			obj.Name = driverName
   101  			testapps.CreateK8sResource(&testCtx, obj)
   102  		}
   103  
   104  		deleteCSIDriverObject := func(driverName string) {
   105  			Eventually(func(g Gomega) {
   106  				obj := &storagev1.CSIDriver{}
   107  				obj.Name = driverName
   108  				ExpectWithOffset(2, testCtx.Cli.Delete(testCtx.Ctx, obj)).ShouldNot(HaveOccurred())
   109  			}).Should(Succeed())
   110  		}
   111  
   112  		getProvider := func(g Gomega) *storagev1alpha1.StorageProvider {
   113  			provider := &storagev1alpha1.StorageProvider{}
   114  			g.ExpectWithOffset(1, testCtx.Cli.Get(ctx, key, provider)).To(Not(HaveOccurred()))
   115  			return provider
   116  		}
   117  
   118  		shouldReady := func(g Gomega, provider *storagev1alpha1.StorageProvider) {
   119  			g.ExpectWithOffset(1, provider.Status.Phase).Should(BeEquivalentTo(storagev1alpha1.StorageProviderReady))
   120  
   121  			val := meta.IsStatusConditionTrue(provider.Status.Conditions,
   122  				storagev1alpha1.ConditionTypeCSIDriverInstalled)
   123  			g.ExpectWithOffset(1, val).Should(BeTrue())
   124  		}
   125  
   126  		shouldNotReady := func(g Gomega, provider *storagev1alpha1.StorageProvider) {
   127  			g.ExpectWithOffset(1, provider.Status.Phase).Should(BeEquivalentTo(storagev1alpha1.StorageProviderNotReady))
   128  
   129  			val := meta.IsStatusConditionPresentAndEqual(
   130  				provider.Status.Conditions,
   131  				storagev1alpha1.ConditionTypeCSIDriverInstalled,
   132  				metav1.ConditionUnknown)
   133  			g.ExpectWithOffset(1, val).Should(BeTrue())
   134  		}
   135  
   136  		It("should reconcile a StorageProvider to Ready status if it doesn't specify csiDriverName", func() {
   137  			By("creating a StorageProvider with an empty csiDriverName")
   138  			createStorageProviderSpec("")
   139  
   140  			By("checking status.phase and status.conditions")
   141  			Eventually(func(g Gomega) {
   142  				shouldReady(g, getProvider(g))
   143  			}).Should(Succeed())
   144  		})
   145  
   146  		It("should reconcile a StorageProvider to Ready status if the specified csiDriverName is present", func() {
   147  			By("creating a StorageProvider with csi1")
   148  			createCSIDriverObjectSpec("csi1")
   149  			createStorageProviderSpec("csi1")
   150  
   151  			By("checking status.phase and status.conditions")
   152  			Eventually(func(g Gomega) {
   153  				provider := getProvider(g)
   154  				g.Expect(provider.Status.Phase).Should(BeEquivalentTo(storagev1alpha1.StorageProviderReady))
   155  
   156  				val := meta.IsStatusConditionTrue(provider.Status.Conditions,
   157  					storagev1alpha1.ConditionTypeCSIDriverInstalled)
   158  				g.Expect(val).Should(BeTrue())
   159  			}).Should(Succeed())
   160  		})
   161  
   162  		It("should reconcile a StorageProvider base on the status of the CSI driver object", func() {
   163  			By("creating a StorageProvider with csi2")
   164  			createStorageProviderSpec("csi2")
   165  			By("checking status.phase, it should be NotReady because CSI driver is not installed yet")
   166  			Eventually(func(g Gomega) {
   167  				shouldNotReady(g, getProvider(g))
   168  			}).Should(Succeed())
   169  
   170  			By("creating CSI driver object csi2")
   171  			createCSIDriverObjectSpec("csi2")
   172  			By("checking status.phase, it should become Ready")
   173  			Eventually(func(g Gomega) {
   174  				shouldReady(g, getProvider(g))
   175  			}).Should(Succeed())
   176  
   177  			By("deleting CSI driver object csi2")
   178  			deleteCSIDriverObject("csi2")
   179  			By("checking status.phase, it should become NotReady")
   180  			Eventually(func(g Gomega) {
   181  				shouldNotReady(g, getProvider(g))
   182  			}).Should(Succeed())
   183  		})
   184  
   185  		It("should able to delete a StorageProvider", func() {
   186  			By("creating a StorageProvider with csi3")
   187  			createStorageProviderSpec("csi3")
   188  
   189  			By("checking StorageProvider object")
   190  			Eventually(testapps.CheckObj(&testCtx, key, func(g Gomega, provider *storagev1alpha1.StorageProvider) {
   191  				g.Expect(provider.GetFinalizers()).To(ContainElement(storageFinalizerName))
   192  			})).Should(Succeed())
   193  
   194  			By("deleting StorageProvider object")
   195  			Eventually(func(g Gomega) {
   196  				provider := &storagev1alpha1.StorageProvider{}
   197  				err := testCtx.Cli.Get(ctx, key, provider)
   198  				if apierrors.IsNotFound(err) {
   199  					return
   200  				}
   201  				g.Expect(err).ToNot(HaveOccurred())
   202  				Expect(testCtx.Cli.Delete(testCtx.Ctx, provider)).ToNot(HaveOccurred())
   203  			}).Should(Succeed())
   204  		})
   205  	})
   206  })