github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/controllers/apps/configuration/parallel_upgrade_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 "github.com/golang/mock/gomock" 27 28 appsv1alpha1 "github.com/1aal/kubeblocks/apis/apps/v1alpha1" 29 cfgcore "github.com/1aal/kubeblocks/pkg/configuration/core" 30 cfgproto "github.com/1aal/kubeblocks/pkg/configuration/proto" 31 mock_proto "github.com/1aal/kubeblocks/pkg/configuration/proto/mocks" 32 testutil "github.com/1aal/kubeblocks/pkg/testutil/k8s" 33 ) 34 35 var parallelPolicy = parallelUpgradePolicy{} 36 37 var _ = Describe("Reconfigure ParallelPolicy", func() { 38 39 var ( 40 k8sMockClient *testutil.K8sClientMockHelper 41 reconfigureClient *mock_proto.MockReconfigureClient 42 ) 43 44 BeforeEach(func() { 45 k8sMockClient = testutil.NewK8sMockClient() 46 reconfigureClient = mock_proto.NewMockReconfigureClient(k8sMockClient.Controller()) 47 }) 48 49 AfterEach(func() { 50 k8sMockClient.Finish() 51 }) 52 53 Context("parallel reconfigure policy test", func() { 54 It("Should success without error", func() { 55 Expect(parallelPolicy.GetPolicyName()).Should(BeEquivalentTo("parallel")) 56 57 // mock client update caller 58 k8sMockClient.MockPatchMethod(testutil.WithSucceed(testutil.WithTimes(3))) 59 60 reconfigureClient.EXPECT().StopContainer(gomock.Any(), gomock.Any()).Return( 61 &cfgproto.StopContainerResponse{}, nil). 62 Times(3) 63 64 mockParam := newMockReconfigureParams("parallelPolicy", k8sMockClient.Client(), 65 withGRPCClient(func(addr string) (cfgproto.ReconfigureClient, error) { 66 return reconfigureClient, nil 67 }), 68 withMockStatefulSet(3, nil), 69 withClusterComponent(3), 70 withConfigSpec("for_test", map[string]string{ 71 "a": "b", 72 }), 73 withCDComponent(appsv1alpha1.Consensus, []appsv1alpha1.ComponentConfigSpec{{ 74 ComponentTemplateSpec: appsv1alpha1.ComponentTemplateSpec{ 75 Name: "for_test", 76 VolumeName: "test_volume", 77 }, 78 }})) 79 80 k8sMockClient.MockListMethod(testutil.WithListReturned( 81 testutil.WithConstructListReturnedResult(fromPodObjectList( 82 newMockPodsWithStatefulSet(&mockParam.ComponentUnits[0], 3), 83 )))) 84 85 status, err := parallelPolicy.Upgrade(mockParam) 86 Expect(err).Should(Succeed()) 87 Expect(status.Status).Should(BeEquivalentTo(ESNone)) 88 }) 89 }) 90 91 Context("parallel reconfigure policy test with List pods failed", func() { 92 It("Should failed", func() { 93 mockParam := newMockReconfigureParams("parallelPolicy", k8sMockClient.Client(), 94 withGRPCClient(func(addr string) (cfgproto.ReconfigureClient, error) { 95 return reconfigureClient, nil 96 }), 97 withMockStatefulSet(3, nil), 98 withClusterComponent(3), 99 withConfigSpec("for_test", map[string]string{ 100 "a": "b", 101 }), 102 withCDComponent(appsv1alpha1.Consensus, []appsv1alpha1.ComponentConfigSpec{{ 103 ComponentTemplateSpec: appsv1alpha1.ComponentTemplateSpec{ 104 Name: "for_test", 105 VolumeName: "test_volume", 106 }, 107 }})) 108 109 // first failed 110 getPodsError := cfgcore.MakeError("for grpc failed.") 111 k8sMockClient.MockListMethod(testutil.WithFailed(getPodsError)) 112 113 status, err := parallelPolicy.Upgrade(mockParam) 114 // first failed 115 Expect(err).Should(BeEquivalentTo(getPodsError)) 116 Expect(status.Status).Should(BeEquivalentTo(ESFailedAndRetry)) 117 }) 118 }) 119 120 Context("parallel reconfigure policy test with stop container failed", func() { 121 It("Should failed", func() { 122 stopError := cfgcore.MakeError("failed to stop!") 123 reconfigureClient.EXPECT().StopContainer(gomock.Any(), gomock.Any()).Return( 124 &cfgproto.StopContainerResponse{}, stopError). 125 Times(1) 126 127 reconfigureClient.EXPECT().StopContainer(gomock.Any(), gomock.Any()).Return( 128 &cfgproto.StopContainerResponse{ 129 ErrMessage: "failed to stop container.", 130 }, nil). 131 Times(1) 132 133 mockParam := newMockReconfigureParams("parallelPolicy", k8sMockClient.Client(), 134 withGRPCClient(func(addr string) (cfgproto.ReconfigureClient, error) { 135 return reconfigureClient, nil 136 }), 137 withMockStatefulSet(3, nil), 138 withClusterComponent(3), 139 withConfigSpec("for_test", map[string]string{ 140 "a": "b", 141 }), 142 withCDComponent(appsv1alpha1.Consensus, []appsv1alpha1.ComponentConfigSpec{{ 143 ComponentTemplateSpec: appsv1alpha1.ComponentTemplateSpec{ 144 Name: "for_test", 145 VolumeName: "test_volume", 146 }}})) 147 148 k8sMockClient.MockListMethod(testutil.WithListReturned( 149 testutil.WithConstructListReturnedResult( 150 fromPodObjectList(newMockPodsWithStatefulSet(&mockParam.ComponentUnits[0], 3))), testutil.WithTimes(2), 151 )) 152 153 status, err := parallelPolicy.Upgrade(mockParam) 154 // first failed 155 Expect(err).Should(BeEquivalentTo(stopError)) 156 Expect(status.Status).Should(BeEquivalentTo(ESFailedAndRetry)) 157 158 status, err = parallelPolicy.Upgrade(mockParam) 159 Expect(err).ShouldNot(Succeed()) 160 Expect(err.Error()).Should(ContainSubstring("failed to stop container")) 161 Expect(status.Status).Should(BeEquivalentTo(ESFailedAndRetry)) 162 }) 163 }) 164 165 Context("parallel reconfigure policy test with patch failed", func() { 166 It("Should failed", func() { 167 // mock client update caller 168 patchError := cfgcore.MakeError("update failed!") 169 k8sMockClient.MockPatchMethod(testutil.WithFailed(patchError, testutil.WithTimes(1))) 170 171 reconfigureClient.EXPECT().StopContainer(gomock.Any(), gomock.Any()).Return( 172 &cfgproto.StopContainerResponse{}, nil). 173 Times(1) 174 175 mockParam := newMockReconfigureParams("parallelPolicy", k8sMockClient.Client(), 176 withGRPCClient(func(addr string) (cfgproto.ReconfigureClient, error) { 177 return reconfigureClient, nil 178 }), 179 withMockStatefulSet(3, nil), 180 withClusterComponent(3), 181 withConfigSpec("for_test", map[string]string{ 182 "a": "b", 183 }), 184 withCDComponent(appsv1alpha1.Consensus, []appsv1alpha1.ComponentConfigSpec{{ 185 ComponentTemplateSpec: appsv1alpha1.ComponentTemplateSpec{ 186 Name: "for_test", 187 VolumeName: "test_volume", 188 }}})) 189 190 setPods := newMockPodsWithStatefulSet(&mockParam.ComponentUnits[0], 5) 191 k8sMockClient.MockListMethod(testutil.WithListReturned( 192 testutil.WithConstructListReturnedResult(fromPodObjectList(setPods)), testutil.WithAnyTimes(), 193 )) 194 195 status, err := parallelPolicy.Upgrade(mockParam) 196 // first failed 197 Expect(err).Should(BeEquivalentTo(patchError)) 198 Expect(status.Status).Should(BeEquivalentTo(ESFailedAndRetry)) 199 }) 200 }) 201 202 Context("parallel reconfigure policy test for not supported component", func() { 203 It("Should failed", func() { 204 // not support type 205 mockParam := newMockReconfigureParams("parallelPolicy", nil, 206 withMockStatefulSet(2, nil), 207 withConfigSpec("for_test", map[string]string{ 208 "key": "value", 209 }), 210 withClusterComponent(2), 211 withCDComponent(appsv1alpha1.Stateless, []appsv1alpha1.ComponentConfigSpec{{ 212 ComponentTemplateSpec: appsv1alpha1.ComponentTemplateSpec{ 213 Name: "for_test", 214 VolumeName: "test_volume", 215 }}})) 216 status, err := parallelPolicy.Upgrade(mockParam) 217 Expect(err).ShouldNot(Succeed()) 218 Expect(err.Error()).Should(ContainSubstring("not supported component workload type")) 219 Expect(status.Status).Should(BeEquivalentTo(ESNotSupport)) 220 }) 221 }) 222 })