github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/configuration/core/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 core 21 22 import ( 23 "reflect" 24 "strings" 25 "testing" 26 27 . "github.com/onsi/ginkgo/v2" 28 . "github.com/onsi/gomega" 29 30 "sigs.k8s.io/controller-runtime/pkg/client" 31 32 "github.com/1aal/kubeblocks/apis/apps/v1alpha1" 33 cfgutil "github.com/1aal/kubeblocks/pkg/configuration/util" 34 testutil "github.com/1aal/kubeblocks/pkg/testutil/k8s" 35 ) 36 37 var _ = Describe("config_util", func() { 38 39 var k8sMockClient *testutil.K8sClientMockHelper 40 41 BeforeEach(func() { 42 // Add any setup steps that needs to be executed before each test 43 k8sMockClient = testutil.NewK8sMockClient() 44 }) 45 46 AfterEach(func() { 47 // Add any teardown steps that needs to be executed after each test 48 k8sMockClient.Finish() 49 }) 50 51 Context("common funcs test", func() { 52 It("GetReloadOptions Should success without error", func() { 53 mockTpl := v1alpha1.ConfigConstraint{ 54 Spec: v1alpha1.ConfigConstraintSpec{ 55 ReloadOptions: &v1alpha1.ReloadOptions{ 56 UnixSignalTrigger: &v1alpha1.UnixSignalTrigger{ 57 Signal: "HUB", 58 ProcessName: "for_test", 59 }, 60 }, 61 }, 62 } 63 tests := []struct { 64 name string 65 tpls []v1alpha1.ComponentConfigSpec 66 want *v1alpha1.ReloadOptions 67 wantErr bool 68 }{{ 69 // empty config templates 70 name: "test", 71 tpls: nil, 72 want: nil, 73 wantErr: false, 74 }, { 75 // empty config templates 76 name: "test", 77 tpls: []v1alpha1.ComponentConfigSpec{}, 78 want: nil, 79 wantErr: false, 80 }, { 81 // config templates without configConstraintObj 82 name: "test", 83 tpls: []v1alpha1.ComponentConfigSpec{{ 84 ComponentTemplateSpec: v1alpha1.ComponentTemplateSpec{ 85 Name: "for_test", 86 }, 87 }, { 88 ComponentTemplateSpec: v1alpha1.ComponentTemplateSpec{ 89 Name: "for_test2", 90 }, 91 }}, 92 want: nil, 93 wantErr: false, 94 }, { 95 // normal 96 name: "test", 97 tpls: []v1alpha1.ComponentConfigSpec{{ 98 ComponentTemplateSpec: v1alpha1.ComponentTemplateSpec{ 99 Name: "for_test", 100 }, 101 ConfigConstraintRef: "eg_v1", 102 }}, 103 want: mockTpl.Spec.ReloadOptions, 104 wantErr: false, 105 }, { 106 // not exist config constraint 107 name: "test", 108 tpls: []v1alpha1.ComponentConfigSpec{{ 109 ComponentTemplateSpec: v1alpha1.ComponentTemplateSpec{ 110 Name: "for_test", 111 }, 112 ConfigConstraintRef: "not_exist", 113 }}, 114 want: nil, 115 wantErr: true, 116 }} 117 118 k8sMockClient.MockGetMethod(testutil.WithGetReturned(func(key client.ObjectKey, obj client.Object) error { 119 if strings.Contains(key.Name, "not_exist") { 120 return MakeError("not exist config!") 121 } 122 testutil.SetGetReturnedObject(obj, &mockTpl) 123 return nil 124 }, testutil.WithMaxTimes(len(tests)))) 125 126 for _, tt := range tests { 127 got, _, err := GetReloadOptions(k8sMockClient.Client(), ctx, tt.tpls) 128 Expect(err != nil).Should(BeEquivalentTo(tt.wantErr)) 129 Expect(reflect.DeepEqual(got, tt.want)).Should(BeTrue()) 130 } 131 }) 132 }) 133 134 }) 135 136 func TestMergeUpdatedConfig(t *testing.T) { 137 type args struct { 138 baseMap map[string]string 139 updatedMap map[string]string 140 } 141 tests := []struct { 142 name string 143 args args 144 want map[string]string 145 }{{ 146 name: "normal_test", 147 args: args{ 148 baseMap: map[string]string{ 149 "key1": "context1", 150 "key2": "context2", 151 "key3": "context3", 152 }, 153 updatedMap: map[string]string{ 154 "key2": "new context", 155 }, 156 }, 157 want: map[string]string{ 158 "key1": "context1", 159 "key2": "new context", 160 "key3": "context3", 161 }, 162 }, { 163 name: "not_expected_update_test", 164 args: args{ 165 baseMap: map[string]string{ 166 "key1": "context1", 167 "key2": "context2", 168 "key3": "context3", 169 }, 170 updatedMap: map[string]string{ 171 "key6": "context6", 172 }, 173 }, 174 want: map[string]string{ 175 "key1": "context1", 176 "key2": "context2", 177 "key3": "context3", 178 }, 179 }} 180 for _, tt := range tests { 181 t.Run(tt.name, func(t *testing.T) { 182 if got := MergeUpdatedConfig(tt.args.baseMap, tt.args.updatedMap); !reflect.DeepEqual(got, tt.want) { 183 t.Errorf("MergeUpdatedConfig() = %v, want %v", got, tt.want) 184 } 185 }) 186 } 187 } 188 189 func TestApplyConfigPatch(t *testing.T) { 190 type args struct { 191 baseCfg []byte 192 updatedParameters map[string]string 193 formatConfig *v1alpha1.FormatterConfig 194 } 195 tests := []struct { 196 name string 197 args args 198 want string 199 wantErr bool 200 }{{ 201 name: "normal_test", 202 args: args{ 203 baseCfg: []byte(`[test] 204 test=test`), 205 updatedParameters: map[string]string{ 206 "a": "b", 207 "max_connections": "600", 208 }, 209 formatConfig: &v1alpha1.FormatterConfig{ 210 Format: v1alpha1.Ini, 211 FormatterOptions: v1alpha1.FormatterOptions{ 212 IniConfig: &v1alpha1.IniConfig{ 213 SectionName: "test", 214 }}}, 215 }, 216 want: `[test] 217 a=b 218 max_connections=600 219 test=test 220 `, 221 wantErr: false, 222 }, { 223 name: "normal_test", 224 args: args{ 225 baseCfg: []byte(` `), 226 updatedParameters: map[string]string{ 227 "a": "b", 228 "c": "d e f g", 229 }, 230 formatConfig: &v1alpha1.FormatterConfig{ 231 Format: v1alpha1.RedisCfg, 232 }, 233 }, 234 want: "a b\nc d e f g", 235 wantErr: false, 236 }, { 237 name: "badcase_test", 238 args: args{ 239 baseCfg: []byte(` `), 240 updatedParameters: map[string]string{ 241 "ENABLE_MODULES": "true", 242 "HUGGINGFACE_APIKEY": "kssdlsdjskwssl", 243 }, 244 formatConfig: &v1alpha1.FormatterConfig{ 245 Format: v1alpha1.Dotenv, 246 }, 247 }, 248 // fix begin 249 // ENABLE_MODULES=0x1400004f130 250 // HUGGINGFACE_APIKEY=0x1400004f140 251 want: "ENABLE_MODULES=true\nHUGGINGFACE_APIKEY=kssdlsdjskwssl\n", 252 wantErr: false, 253 }} 254 for _, tt := range tests { 255 t.Run(tt.name, func(t *testing.T) { 256 got, err := ApplyConfigPatch(tt.args.baseCfg, FromStringPointerMap(tt.args.updatedParameters), tt.args.formatConfig) 257 if (err != nil) != tt.wantErr { 258 t.Errorf("ApplyConfigPatch() error = %v, wantErr %v", err, tt.wantErr) 259 return 260 } 261 if got != tt.want { 262 t.Errorf("ApplyConfigPatch() got = %v, want %v", got, tt.want) 263 } 264 }) 265 } 266 } 267 268 func TestFromValueToString(t *testing.T) { 269 type args struct { 270 val interface{} 271 } 272 tests := []struct { 273 name string 274 args args 275 want string 276 }{{ 277 name: "test", 278 args: args{ 279 val: "testTest", 280 }, 281 want: "testTest", 282 }, { 283 name: "test", 284 args: args{ 285 val: "", 286 }, 287 want: "", 288 }, { 289 name: "test", 290 args: args{ 291 val: nil, 292 }, 293 want: "", 294 }, { 295 name: "test", 296 args: args{ 297 val: "/abdet/sds", 298 }, 299 want: "", 300 }, { 301 name: "test", 302 args: args{ 303 val: "abdet/sds-", 304 }, 305 want: "", 306 }, { 307 name: "test", 308 args: args{ 309 val: "abcdASls-sda_102.382", 310 }, 311 want: "abcdASls-sda_102.382", 312 }} 313 for _, tt := range tests { 314 t.Run(tt.name, func(t *testing.T) { 315 if got := FromValueToString(tt.args.val); got != tt.want { 316 t.Errorf("FromValueToString() = %v, want %v", got, tt.want) 317 } 318 }) 319 } 320 } 321 322 func TestFromStringMap(t *testing.T) { 323 type args struct { 324 m map[string]*string 325 } 326 tests := []struct { 327 name string 328 args args 329 want map[string]interface{} 330 }{{ 331 name: "test", 332 args: args{ 333 m: map[string]*string{ 334 "abcd": cfgutil.ToPointer("test"), 335 "null_field": nil, 336 }, 337 }, 338 want: map[string]interface{}{ 339 "abcd": "test", 340 "null_field": nil, 341 }, 342 }} 343 for _, tt := range tests { 344 t.Run(tt.name, func(t *testing.T) { 345 if got := FromStringMap(tt.args.m); !reflect.DeepEqual(got, tt.want) { 346 t.Errorf("FromStringMap() = %v, want %v", got, tt.want) 347 } 348 }) 349 } 350 }