github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/controllers/apps/configuration/simple_policy_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 configuration 21 22 import ( 23 . "github.com/onsi/ginkgo/v2" 24 . "github.com/onsi/gomega" 25 26 corev1 "k8s.io/api/core/v1" 27 "k8s.io/apimachinery/pkg/runtime" 28 29 appsv1alpha1 "github.com/1aal/kubeblocks/apis/apps/v1alpha1" 30 "github.com/1aal/kubeblocks/pkg/configuration/core" 31 "github.com/1aal/kubeblocks/pkg/constant" 32 testutil "github.com/1aal/kubeblocks/pkg/testutil/k8s" 33 ) 34 35 var _ = Describe("Reconfigure simplePolicy", func() { 36 37 var ( 38 k8sMockClient *testutil.K8sClientMockHelper 39 simplePolicy = upgradePolicyMap[appsv1alpha1.NormalPolicy] 40 ) 41 42 BeforeEach(func() { 43 k8sMockClient = testutil.NewK8sMockClient() 44 }) 45 46 AfterEach(func() { 47 k8sMockClient.Finish() 48 }) 49 50 updatePodCfgVersion := func(pod *corev1.Pod, configKey, configVersion string) { 51 if pod.Annotations == nil { 52 pod.Annotations = make(map[string]string) 53 } 54 pod.Annotations[core.GenerateUniqKeyWithConfig(constant.UpgradeRestartAnnotationKey, configKey)] = configVersion 55 } 56 57 Context("simple reconfigure policy test", func() { 58 It("Should success without error", func() { 59 Expect(simplePolicy.GetPolicyName()).Should(BeEquivalentTo("simple")) 60 61 mockParam := newMockReconfigureParams("simplePolicy", k8sMockClient.Client(), 62 withMockStatefulSet(2, nil), 63 withConfigSpec("for_test", map[string]string{ 64 "key": "value", 65 }), 66 withClusterComponent(2), 67 withCDComponent(appsv1alpha1.Consensus, []appsv1alpha1.ComponentConfigSpec{{ 68 ComponentTemplateSpec: appsv1alpha1.ComponentTemplateSpec{ 69 Name: "for_test", 70 VolumeName: "test_volume", 71 }}})) 72 73 // mock client update caller 74 updateErr := core.MakeError("update failed!") 75 k8sMockClient.MockPatchMethod( 76 testutil.WithFailed(updateErr, testutil.WithTimes(1)), 77 testutil.WithSucceed(testutil.WithAnyTimes())) 78 k8sMockClient.MockListMethod(testutil.WithListReturned( 79 testutil.WithConstructListSequenceResult([][]runtime.Object{ 80 fromPodObjectList(newMockPodsWithStatefulSet(&mockParam.ComponentUnits[0], 2)), 81 fromPodObjectList(newMockPodsWithStatefulSet(&mockParam.ComponentUnits[0], 2, withReadyPod(0, 2), func(pod *corev1.Pod, index int) { 82 // mock pod-1 restart 83 if index == 1 { 84 updatePodCfgVersion(pod, mockParam.getConfigKey(), mockParam.getTargetVersionHash()) 85 } 86 })), 87 fromPodObjectList(newMockPodsWithStatefulSet(&mockParam.ComponentUnits[0], 2, withReadyPod(0, 2), func(pod *corev1.Pod, index int) { 88 // mock all pod restart 89 updatePodCfgVersion(pod, mockParam.getConfigKey(), mockParam.getTargetVersionHash()) 90 })), 91 }), 92 testutil.WithTimes(3), 93 )) 94 95 status, err := simplePolicy.Upgrade(mockParam) 96 Expect(err).Should(BeEquivalentTo(updateErr)) 97 Expect(status.Status).Should(BeEquivalentTo(ESFailedAndRetry)) 98 99 // first upgrade, not pod is ready 100 status, err = simplePolicy.Upgrade(mockParam) 101 Expect(err).Should(Succeed()) 102 Expect(status.Status).Should(BeEquivalentTo(ESRetry)) 103 Expect(status.SucceedCount).Should(BeEquivalentTo(int32(0))) 104 Expect(status.ExpectedCount).Should(BeEquivalentTo(int32(2))) 105 106 // only one pod ready 107 status, err = simplePolicy.Upgrade(mockParam) 108 Expect(err).Should(Succeed()) 109 Expect(status.Status).Should(BeEquivalentTo(ESRetry)) 110 Expect(status.SucceedCount).Should(BeEquivalentTo(int32(1))) 111 Expect(status.ExpectedCount).Should(BeEquivalentTo(int32(2))) 112 113 // succeed update pod 114 status, err = simplePolicy.Upgrade(mockParam) 115 Expect(err).Should(Succeed()) 116 Expect(status.Status).Should(BeEquivalentTo(ESNone)) 117 Expect(status.SucceedCount).Should(BeEquivalentTo(int32(2))) 118 Expect(status.ExpectedCount).Should(BeEquivalentTo(int32(2))) 119 }) 120 }) 121 122 Context("simple reconfigure policy test with Replication", func() { 123 It("Should success", func() { 124 mockParam := newMockReconfigureParams("simplePolicy", k8sMockClient.Client(), 125 withMockStatefulSet(2, nil), 126 withConfigSpec("for_test", map[string]string{ 127 "key": "value", 128 }), 129 withClusterComponent(2), 130 withCDComponent(appsv1alpha1.Replication, []appsv1alpha1.ComponentConfigSpec{{ 131 ComponentTemplateSpec: appsv1alpha1.ComponentTemplateSpec{ 132 Name: "for_test", 133 VolumeName: "test_volume", 134 }}}), 135 ) 136 137 k8sMockClient.MockPatchMethod(testutil.WithSucceed(testutil.WithAnyTimes())) 138 k8sMockClient.MockListMethod(testutil.WithListReturned( 139 testutil.WithConstructListSequenceResult([][]runtime.Object{ 140 fromPodObjectList(newMockPodsWithStatefulSet(&mockParam.ComponentUnits[0], 2)), 141 fromPodObjectList(newMockPodsWithStatefulSet(&mockParam.ComponentUnits[0], 2, 142 withReadyPod(0, 2), func(pod *corev1.Pod, _ int) { 143 updatePodCfgVersion(pod, mockParam.getConfigKey(), mockParam.getTargetVersionHash()) 144 })), 145 }), 146 testutil.WithAnyTimes(), 147 )) 148 149 status, err := simplePolicy.Upgrade(mockParam) 150 Expect(err).Should(Succeed()) 151 Expect(status.SucceedCount).Should(BeEquivalentTo(int32(0))) 152 153 status, err = simplePolicy.Upgrade(mockParam) 154 Expect(err).Should(Succeed()) 155 Expect(status.SucceedCount).Should(BeEquivalentTo(int32(2))) 156 }) 157 }) 158 159 Context("simple reconfigure policy test for not supported component", func() { 160 It("Should failed", func() { 161 // not support type 162 mockParam := newMockReconfigureParams("simplePolicy", k8sMockClient.Client(), 163 withMockDeployments(2, nil), 164 withConfigSpec("for_test", map[string]string{ 165 "key": "value", 166 }), 167 withClusterComponent(2), 168 withCDComponent(appsv1alpha1.Stateless, []appsv1alpha1.ComponentConfigSpec{{ 169 ComponentTemplateSpec: appsv1alpha1.ComponentTemplateSpec{ 170 Name: "for_test", 171 VolumeName: "test_volume", 172 }}})) 173 174 updateErr := core.MakeError("update failed!") 175 k8sMockClient.MockPatchMethod( 176 testutil.WithFailed(updateErr, testutil.WithTimes(1)), 177 testutil.WithSucceed(testutil.WithAnyTimes())) 178 k8sMockClient.MockListMethod(testutil.WithListReturned( 179 testutil.WithConstructListSequenceResult([][]runtime.Object{ 180 fromPodObjectList(newMockPodsWithDeployment(&mockParam.DeploymentUnits[0], 2)), 181 fromPodObjectList(newMockPodsWithDeployment(&mockParam.DeploymentUnits[0], 2, withReadyPod(0, 2), func(pod *corev1.Pod, index int) { 182 // mock pod-1 restart 183 if index == 1 { 184 updatePodCfgVersion(pod, mockParam.getConfigKey(), mockParam.getTargetVersionHash()) 185 } 186 })), 187 fromPodObjectList(newMockPodsWithDeployment(&mockParam.DeploymentUnits[0], 2, withReadyPod(0, 2), func(pod *corev1.Pod, index int) { 188 // mock all pod restart 189 updatePodCfgVersion(pod, mockParam.getConfigKey(), mockParam.getTargetVersionHash()) 190 })), 191 }), 192 testutil.WithTimes(3), 193 )) 194 195 status, err := simplePolicy.Upgrade(mockParam) 196 Expect(err).Should(BeEquivalentTo(updateErr)) 197 Expect(status.Status).Should(BeEquivalentTo(ESFailedAndRetry)) 198 199 // first upgrade, not pod is ready 200 status, err = simplePolicy.Upgrade(mockParam) 201 Expect(err).Should(Succeed()) 202 Expect(status.Status).Should(BeEquivalentTo(ESRetry)) 203 Expect(status.SucceedCount).Should(BeEquivalentTo(int32(0))) 204 Expect(status.ExpectedCount).Should(BeEquivalentTo(int32(2))) 205 206 // only one pod ready 207 status, err = simplePolicy.Upgrade(mockParam) 208 Expect(err).Should(Succeed()) 209 Expect(status.Status).Should(BeEquivalentTo(ESRetry)) 210 Expect(status.SucceedCount).Should(BeEquivalentTo(int32(1))) 211 Expect(status.ExpectedCount).Should(BeEquivalentTo(int32(2))) 212 213 // succeed update pod 214 status, err = simplePolicy.Upgrade(mockParam) 215 Expect(err).Should(Succeed()) 216 Expect(status.Status).Should(BeEquivalentTo(ESNone)) 217 Expect(status.SucceedCount).Should(BeEquivalentTo(int32(2))) 218 Expect(status.ExpectedCount).Should(BeEquivalentTo(int32(2))) 219 220 }) 221 }) 222 223 // Context("simple reconfigure policy test without not configmap volume", func() { 224 // It("Should failed", func() { 225 // // mock not cc 226 // mockParam := newMockReconfigureParams("simplePolicy", nil, 227 // withMockStatefulSet(2, nil), 228 // withConfigSpec("not_tpl_name", map[string]string{ 229 // "key": "value", 230 // }), 231 // withCDComponent(appsv1alpha1.Consensus, []appsv1alpha1.ComponentConfigSpec{{ 232 // ComponentTemplateSpec: appsv1alpha1.ComponentTemplateSpec{ 233 // Name: "for_test", 234 // VolumeName: "test_volume", 235 // }}})) 236 // status, err := simplePolicy.Upgrade(mockParam) 237 // Expect(err).ShouldNot(Succeed()) 238 // Expect(err.Error()).Should(ContainSubstring("failed to find config meta")) 239 // Expect(status.Status).Should(BeEquivalentTo(ESFailed)) 240 // }) 241 // }) 242 })