github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/controllerutil/config_util_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 controllerutil 21 22 import ( 23 "encoding/json" 24 "reflect" 25 "testing" 26 27 . "github.com/onsi/ginkgo/v2" 28 . "github.com/onsi/gomega" 29 30 "github.com/StudioSol/set" 31 corev1 "k8s.io/api/core/v1" 32 33 "github.com/1aal/kubeblocks/apis/apps/v1alpha1" 34 "github.com/1aal/kubeblocks/pkg/configuration/core" 35 cfgutil "github.com/1aal/kubeblocks/pkg/configuration/util" 36 "github.com/1aal/kubeblocks/pkg/constant" 37 "github.com/1aal/kubeblocks/pkg/controller/builder" 38 testapps "github.com/1aal/kubeblocks/pkg/testutil/apps" 39 testutil "github.com/1aal/kubeblocks/pkg/testutil/k8s" 40 "github.com/1aal/kubeblocks/test/testdata" 41 ) 42 43 func TestFromUpdatedConfig(t *testing.T) { 44 type args struct { 45 base map[string]string 46 sets *set.LinkedHashSetString 47 } 48 tests := []struct { 49 name string 50 args args 51 want map[string]string 52 }{{ 53 name: "normal_test", 54 args: args{ 55 base: map[string]string{ 56 "key1": "config context1", 57 "key2": "config context2", 58 "key3": "config context2", 59 }, 60 sets: set.NewLinkedHashSetString("key1", "key3"), 61 }, 62 want: map[string]string{ 63 "key1": "config context1", 64 "key3": "config context2", 65 }, 66 }, { 67 name: "none_updated_test", 68 args: args{ 69 base: map[string]string{ 70 "key1": "config context1", 71 "key2": "config context2", 72 "key3": "config context2", 73 }, 74 sets: cfgutil.NewSet(), 75 }, 76 want: map[string]string{}, 77 }} 78 for _, tt := range tests { 79 t.Run(tt.name, func(t *testing.T) { 80 if got := fromUpdatedConfig(tt.args.base, tt.args.sets); !reflect.DeepEqual(got, tt.want) { 81 t.Errorf("fromUpdatedConfig() = %v, want %v", got, tt.want) 82 } 83 }) 84 } 85 } 86 87 func TestIsRerender(t *testing.T) { 88 type args struct { 89 cm *corev1.ConfigMap 90 item v1alpha1.ConfigurationItemDetail 91 } 92 tests := []struct { 93 name string 94 args args 95 want bool 96 }{{ 97 98 name: "test", 99 args: args{ 100 cm: nil, 101 item: v1alpha1.ConfigurationItemDetail{ 102 Name: "test", 103 }, 104 }, 105 want: true, 106 }, { 107 name: "test", 108 args: args{ 109 cm: builder.NewConfigMapBuilder("default", "test").GetObject(), 110 item: v1alpha1.ConfigurationItemDetail{ 111 Name: "test", 112 }, 113 }, 114 want: false, 115 }, { 116 name: "test", 117 args: args{ 118 cm: builder.NewConfigMapBuilder("default", "test"). 119 GetObject(), 120 item: v1alpha1.ConfigurationItemDetail{ 121 Name: "test", 122 Version: "v1", 123 }, 124 }, 125 want: true, 126 }, { 127 name: "test", 128 args: args{ 129 cm: builder.NewConfigMapBuilder("default", "test"). 130 AddAnnotations(constant.CMConfigurationTemplateVersion, "v1"). 131 GetObject(), 132 item: v1alpha1.ConfigurationItemDetail{ 133 Name: "test", 134 Version: "v2", 135 }, 136 }, 137 want: true, 138 }, { 139 name: "test", 140 args: args{ 141 cm: builder.NewConfigMapBuilder("default", "test"). 142 AddAnnotations(constant.CMConfigurationTemplateVersion, "v1"). 143 GetObject(), 144 item: v1alpha1.ConfigurationItemDetail{ 145 Name: "test", 146 Version: "v1", 147 }, 148 }, 149 want: false, 150 }} 151 for _, tt := range tests { 152 t.Run(tt.name, func(t *testing.T) { 153 if got := IsRerender(tt.args.cm, tt.args.item); got != tt.want { 154 t.Errorf("IsRerender() = %v, want %v", got, tt.want) 155 } 156 }) 157 } 158 } 159 160 func TestGetConfigSpecReconcilePhase(t *testing.T) { 161 type args struct { 162 cm *corev1.ConfigMap 163 item v1alpha1.ConfigurationItemDetail 164 status *v1alpha1.ConfigurationItemDetailStatus 165 } 166 tests := []struct { 167 name string 168 args args 169 want v1alpha1.ConfigurationPhase 170 }{{ 171 name: "test", 172 args: args{ 173 cm: nil, 174 item: v1alpha1.ConfigurationItemDetail{ 175 Name: "test", 176 }, 177 }, 178 want: v1alpha1.CCreatingPhase, 179 }, { 180 name: "test", 181 args: args{ 182 cm: builder.NewConfigMapBuilder("default", "test").GetObject(), 183 item: v1alpha1.ConfigurationItemDetail{ 184 Name: "test", 185 }, 186 status: &v1alpha1.ConfigurationItemDetailStatus{ 187 Phase: v1alpha1.CInitPhase, 188 }, 189 }, 190 want: v1alpha1.CPendingPhase, 191 }, { 192 name: "test", 193 args: args{ 194 cm: builder.NewConfigMapBuilder("default", "test"). 195 AddAnnotations(constant.ConfigAppliedVersionAnnotationKey, `{"name":"test"}`). 196 GetObject(), 197 item: v1alpha1.ConfigurationItemDetail{ 198 Name: "test", 199 }, 200 status: &v1alpha1.ConfigurationItemDetailStatus{ 201 Phase: v1alpha1.CUpgradingPhase, 202 }, 203 }, 204 want: v1alpha1.CUpgradingPhase, 205 }} 206 for _, tt := range tests { 207 t.Run(tt.name, func(t *testing.T) { 208 if got := GetConfigSpecReconcilePhase(tt.args.cm, tt.args.item, tt.args.status); got != tt.want { 209 t.Errorf("GetConfigSpecReconcilePhase() = %v, want %v", got, tt.want) 210 } 211 }) 212 } 213 } 214 215 var _ = Describe("config_util", func() { 216 217 var k8sMockClient *testutil.K8sClientMockHelper 218 219 BeforeEach(func() { 220 // Add any setup steps that needs to be executed before each test 221 k8sMockClient = testutil.NewK8sMockClient() 222 }) 223 224 AfterEach(func() { 225 // Add any teardown steps that needs to be executed after each test 226 k8sMockClient.Finish() 227 }) 228 229 Context("MergeAndValidateConfigs", func() { 230 It("Should succeed with no error", func() { 231 type args struct { 232 configConstraint v1alpha1.ConfigConstraintSpec 233 baseCfg map[string]string 234 updatedParams []core.ParamPairs 235 cmKeys []string 236 } 237 238 configConstraintObj := testapps.NewCustomizedObj("resources/mysql-config-constraint.yaml", 239 &v1alpha1.ConfigConstraint{}, func(cc *v1alpha1.ConfigConstraint) { 240 if ccContext, err := testdata.GetTestDataFileContent("cue_testdata/pg14.cue"); err == nil { 241 cc.Spec.ConfigurationSchema = &v1alpha1.CustomParametersValidation{ 242 CUE: string(ccContext), 243 } 244 } 245 cc.Spec.FormatterConfig = &v1alpha1.FormatterConfig{ 246 Format: v1alpha1.Properties, 247 } 248 }) 249 250 cfgContext, err := testdata.GetTestDataFileContent("cue_testdata/pg14.conf") 251 Expect(err).Should(Succeed()) 252 253 tests := []struct { 254 name string 255 args args 256 want map[string]string 257 wantErr bool 258 }{{ 259 name: "pg1_merge", 260 args: args{ 261 configConstraint: configConstraintObj.Spec, 262 baseCfg: map[string]string{ 263 "key": string(cfgContext), 264 "key2": "not support context", 265 }, 266 updatedParams: []core.ParamPairs{ 267 { 268 Key: "key", 269 UpdatedParams: map[string]interface{}{ 270 "max_connections": "200", 271 "shared_buffers": "512M", 272 }, 273 }, 274 }, 275 cmKeys: []string{"key", "key3"}, 276 }, 277 want: map[string]string{ 278 "max_connections": "200", 279 "shared_buffers": "512M", 280 }, 281 }, { 282 name: "not_support_key_updated", 283 args: args{ 284 configConstraint: configConstraintObj.Spec, 285 baseCfg: map[string]string{ 286 "key": string(cfgContext), 287 "key2": "not_support_context", 288 }, 289 updatedParams: []core.ParamPairs{ 290 { 291 Key: "key", 292 UpdatedParams: map[string]interface{}{ 293 "max_connections": "200", 294 "shared_buffers": "512M", 295 }, 296 }, 297 }, 298 cmKeys: []string{"key1", "key2"}, 299 }, 300 wantErr: true, 301 }} 302 for _, tt := range tests { 303 got, err := MergeAndValidateConfigs(tt.args.configConstraint, tt.args.baseCfg, tt.args.cmKeys, tt.args.updatedParams) 304 Expect(err != nil).Should(BeEquivalentTo(tt.wantErr)) 305 if tt.wantErr { 306 continue 307 } 308 309 option := core.CfgOption{ 310 Type: core.CfgTplType, 311 CfgType: tt.args.configConstraint.FormatterConfig.Format, 312 } 313 314 patch, err := core.CreateMergePatch(&core.ConfigResource{ 315 ConfigData: tt.args.baseCfg, 316 }, &core.ConfigResource{ 317 ConfigData: got, 318 }, option) 319 Expect(err).Should(Succeed()) 320 321 var patchJSON map[string]string 322 Expect(json.Unmarshal(patch.UpdateConfig["key"], &patchJSON)).Should(Succeed()) 323 Expect(patchJSON).Should(BeEquivalentTo(tt.want)) 324 } 325 }) 326 }) 327 328 })