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 })