github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/configuration/config_manager/handler_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 configmanager 21 22 import ( 23 "context" 24 "strings" 25 "testing" 26 27 . "github.com/onsi/ginkgo/v2" 28 . "github.com/onsi/gomega" 29 "github.com/stretchr/testify/assert" 30 31 corev1 "k8s.io/api/core/v1" 32 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 33 "sigs.k8s.io/controller-runtime/pkg/client" 34 35 appsv1alpha1 "github.com/1aal/kubeblocks/apis/apps/v1alpha1" 36 cfgutil "github.com/1aal/kubeblocks/pkg/configuration/core" 37 testutil "github.com/1aal/kubeblocks/pkg/testutil/k8s" 38 ) 39 40 func TestIsSupportReload(t *testing.T) { 41 type args struct { 42 reload *appsv1alpha1.ReloadOptions 43 } 44 tests := []struct { 45 name string 46 args args 47 want bool 48 }{{ 49 name: "reload_test", 50 args: args{ 51 reload: nil, 52 }, 53 want: false, 54 }, { 55 name: "reload_test", 56 args: args{ 57 reload: &appsv1alpha1.ReloadOptions{}, 58 }, 59 want: false, 60 }, { 61 name: "reload_test", 62 args: args{ 63 reload: &appsv1alpha1.ReloadOptions{ 64 UnixSignalTrigger: &appsv1alpha1.UnixSignalTrigger{ 65 ProcessName: "test", 66 Signal: appsv1alpha1.SIGHUP, 67 }, 68 }, 69 }, 70 want: true, 71 }, { 72 name: "reload_test", 73 args: args{ 74 reload: &appsv1alpha1.ReloadOptions{ 75 ShellTrigger: &appsv1alpha1.ShellTrigger{ 76 Command: strings.Fields("pg_ctl reload"), 77 }, 78 }, 79 }, 80 want: true, 81 }, { 82 name: "reload_test", 83 args: args{ 84 reload: &appsv1alpha1.ReloadOptions{ 85 TPLScriptTrigger: &appsv1alpha1.TPLScriptTrigger{ 86 ScriptConfig: appsv1alpha1.ScriptConfig{ 87 ScriptConfigMapRef: "cm", 88 Namespace: "default", 89 }, 90 }, 91 }, 92 }, 93 want: true, 94 }} 95 for _, tt := range tests { 96 t.Run(tt.name, func(t *testing.T) { 97 if got := IsSupportReload(tt.args.reload); got != tt.want { 98 t.Errorf("IsSupportReload() = %v, want %v", got, tt.want) 99 } 100 }) 101 } 102 } 103 104 var _ = Describe("Handler Util Test", func() { 105 106 var mockK8sCli *testutil.K8sClientMockHelper 107 108 BeforeEach(func() { 109 // Add any setup steps that needs to be executed before each test 110 mockK8sCli = testutil.NewK8sMockClient() 111 }) 112 113 AfterEach(func() { 114 DeferCleanup(mockK8sCli.Finish) 115 }) 116 117 mockConfigConstraint := func(ccName string, reloadOptions *appsv1alpha1.ReloadOptions) *appsv1alpha1.ConfigConstraint { 118 return &appsv1alpha1.ConfigConstraint{ 119 ObjectMeta: metav1.ObjectMeta{ 120 Name: ccName, 121 }, 122 Spec: appsv1alpha1.ConfigConstraintSpec{ 123 ReloadOptions: reloadOptions, 124 FormatterConfig: &appsv1alpha1.FormatterConfig{ 125 Format: appsv1alpha1.Properties, 126 }, 127 }} 128 } 129 130 mockConfigSpec := func(ccName string) appsv1alpha1.ComponentConfigSpec { 131 return appsv1alpha1.ComponentConfigSpec{ 132 ComponentTemplateSpec: appsv1alpha1.ComponentTemplateSpec{ 133 Name: "test", 134 TemplateRef: "config_template", 135 Namespace: "default", 136 VolumeName: "for_test", 137 }, 138 ConfigConstraintRef: ccName, 139 } 140 } 141 142 Context("TestValidateReloadOptions", func() { 143 It("Should succeed with no error", func() { 144 mockK8sCli.MockGetMethod( 145 testutil.WithFailed(cfgutil.MakeError("failed to get resource."), testutil.WithTimes(1)), 146 testutil.WithSucceed(testutil.WithTimes(1)), 147 ) 148 149 type args struct { 150 reloadOptions *appsv1alpha1.ReloadOptions 151 cli client.Client 152 ctx context.Context 153 } 154 tests := []struct { 155 name string 156 args args 157 wantErr bool 158 }{{ 159 name: "unixSignalTest", 160 args: args{ 161 reloadOptions: &appsv1alpha1.ReloadOptions{ 162 UnixSignalTrigger: &appsv1alpha1.UnixSignalTrigger{ 163 Signal: appsv1alpha1.SIGHUP, 164 }}, 165 }, 166 wantErr: false, 167 }, { 168 name: "unixSignalTest", 169 args: args{ 170 reloadOptions: &appsv1alpha1.ReloadOptions{ 171 UnixSignalTrigger: &appsv1alpha1.UnixSignalTrigger{ 172 Signal: "SIGNOEXIST", 173 }}, 174 }, 175 wantErr: true, 176 }, { 177 name: "shellTest", 178 args: args{ 179 reloadOptions: &appsv1alpha1.ReloadOptions{ 180 ShellTrigger: &appsv1alpha1.ShellTrigger{ 181 Command: nil, 182 }}, 183 }, 184 wantErr: true, 185 }, { 186 name: "shellTest", 187 args: args{ 188 reloadOptions: &appsv1alpha1.ReloadOptions{ 189 ShellTrigger: &appsv1alpha1.ShellTrigger{ 190 Command: strings.Fields("go"), 191 }}, 192 }, 193 wantErr: false, 194 }, { 195 name: "TPLScriptTest", 196 args: args{ 197 reloadOptions: &appsv1alpha1.ReloadOptions{ 198 TPLScriptTrigger: &appsv1alpha1.TPLScriptTrigger{ 199 ScriptConfig: appsv1alpha1.ScriptConfig{ 200 ScriptConfigMapRef: "test", 201 }, 202 }}, 203 cli: mockK8sCli.Client(), 204 ctx: context.TODO(), 205 }, 206 wantErr: true, 207 }, { 208 name: "TPLScriptTest", 209 args: args{ 210 reloadOptions: &appsv1alpha1.ReloadOptions{ 211 TPLScriptTrigger: &appsv1alpha1.TPLScriptTrigger{ 212 ScriptConfig: appsv1alpha1.ScriptConfig{ 213 ScriptConfigMapRef: "test", 214 }, 215 }}, 216 cli: mockK8sCli.Client(), 217 ctx: context.TODO(), 218 }, 219 wantErr: false, 220 }} 221 for _, tt := range tests { 222 By(tt.name) 223 err := ValidateReloadOptions(tt.args.reloadOptions, tt.args.cli, tt.args.ctx) 224 Expect(err != nil).Should(BeEquivalentTo(tt.wantErr)) 225 } 226 }) 227 }) 228 229 Context("TestGetSupportReloadConfigSpecs", func() { 230 It("not support reload", func() { 231 configSpecs, err := GetSupportReloadConfigSpecs([]appsv1alpha1.ComponentConfigSpec{{ 232 ComponentTemplateSpec: appsv1alpha1.ComponentTemplateSpec{ 233 Name: "test", 234 }}}, nil, nil) 235 Expect(err).Should(Succeed()) 236 Expect(len(configSpecs)).Should(BeEquivalentTo(0)) 237 }) 238 239 It("not ConfigConstraint ", func() { 240 configSpecs, err := GetSupportReloadConfigSpecs([]appsv1alpha1.ComponentConfigSpec{{ 241 ComponentTemplateSpec: appsv1alpha1.ComponentTemplateSpec{ 242 Name: "test", 243 TemplateRef: "config_template", 244 Namespace: "default", 245 }}}, nil, nil) 246 Expect(err).Should(Succeed()) 247 Expect(len(configSpecs)).Should(BeEquivalentTo(0)) 248 }) 249 250 It("not support reload", func() { 251 ccName := "config_constraint" 252 mockK8sCli.MockGetMethod(testutil.WithGetReturned(testutil.WithConstructSimpleGetResult([]client.Object{ 253 mockConfigConstraint(ccName, nil), 254 }), testutil.WithTimes(1))) 255 256 configSpecs, err := GetSupportReloadConfigSpecs( 257 []appsv1alpha1.ComponentConfigSpec{mockConfigSpec(ccName)}, 258 mockK8sCli.Client(), ctx) 259 260 Expect(err).Should(Succeed()) 261 Expect(len(configSpecs)).Should(BeEquivalentTo(0)) 262 }) 263 264 It("normal test", func() { 265 ccName := "config_constraint" 266 cc := mockConfigConstraint(ccName, &appsv1alpha1.ReloadOptions{ 267 UnixSignalTrigger: &appsv1alpha1.UnixSignalTrigger{ 268 ProcessName: "test", 269 Signal: appsv1alpha1.SIGHUP, 270 }, 271 }) 272 mockK8sCli.MockGetMethod(testutil.WithGetReturned( 273 testutil.WithConstructSimpleGetResult([]client.Object{cc}), 274 testutil.WithTimes(1))) 275 276 configSpecs, err := GetSupportReloadConfigSpecs( 277 []appsv1alpha1.ComponentConfigSpec{mockConfigSpec(ccName)}, 278 mockK8sCli.Client(), ctx) 279 280 Expect(err).Should(Succeed()) 281 Expect(len(configSpecs)).Should(BeEquivalentTo(1)) 282 Expect(configSpecs[0].ConfigSpec).Should(BeEquivalentTo(mockConfigSpec(ccName))) 283 Expect(configSpecs[0].ReloadType).Should(BeEquivalentTo(appsv1alpha1.UnixSignalType)) 284 Expect(configSpecs[0].FormatterConfig).Should(BeEquivalentTo(*cc.Spec.FormatterConfig)) 285 }) 286 }) 287 288 Context("TestFromReloadTypeConfig", func() { 289 It("TestSignalTrigger", func() { 290 Expect(appsv1alpha1.UnixSignalType).Should(BeEquivalentTo(FromReloadTypeConfig(&appsv1alpha1.ReloadOptions{ 291 UnixSignalTrigger: &appsv1alpha1.UnixSignalTrigger{ 292 ProcessName: "test", 293 Signal: appsv1alpha1.SIGHUP, 294 }}))) 295 }) 296 297 It("TestShellTrigger", func() { 298 Expect(appsv1alpha1.ShellType).Should(BeEquivalentTo(FromReloadTypeConfig(&appsv1alpha1.ReloadOptions{ 299 ShellTrigger: &appsv1alpha1.ShellTrigger{ 300 Command: []string{"/bin/true"}, 301 }}))) 302 }) 303 304 It("TestTplScriptsTrigger", func() { 305 Expect(appsv1alpha1.TPLScriptType).Should(BeEquivalentTo(FromReloadTypeConfig(&appsv1alpha1.ReloadOptions{ 306 TPLScriptTrigger: &appsv1alpha1.TPLScriptTrigger{ 307 ScriptConfig: appsv1alpha1.ScriptConfig{ 308 ScriptConfigMapRef: "test", 309 Namespace: "default", 310 }, 311 }}))) 312 }) 313 314 It("TestInvalidTrigger", func() { 315 Expect("").Should(BeEquivalentTo(FromReloadTypeConfig(&appsv1alpha1.ReloadOptions{}))) 316 }) 317 }) 318 319 Context("TestValidateReloadOptions", func() { 320 It("TestSignalTrigger", func() { 321 Expect(ValidateReloadOptions(&appsv1alpha1.ReloadOptions{ 322 UnixSignalTrigger: &appsv1alpha1.UnixSignalTrigger{ 323 ProcessName: "test", 324 Signal: appsv1alpha1.SIGHUP, 325 }}, nil, nil), 326 ).Should(Succeed()) 327 }) 328 329 It("TestShellTrigger", func() { 330 Expect(ValidateReloadOptions(&appsv1alpha1.ReloadOptions{ 331 ShellTrigger: &appsv1alpha1.ShellTrigger{ 332 Command: []string{"/bin/true"}, 333 }}, nil, nil), 334 ).Should(Succeed()) 335 }) 336 337 It("TestTplScriptsTrigger", func() { 338 ns := "default" 339 testName1 := "test1" 340 testName2 := "not_test1" 341 mockK8sCli.MockGetMethod(testutil.WithGetReturned(testutil.WithConstructSimpleGetResult([]client.Object{ 342 &corev1.ConfigMap{ 343 ObjectMeta: metav1.ObjectMeta{ 344 Name: testName1, 345 Namespace: ns, 346 }, 347 }, 348 }), testutil.WithTimes(2))) 349 350 By("Test valid") 351 Expect(ValidateReloadOptions(&appsv1alpha1.ReloadOptions{ 352 TPLScriptTrigger: &appsv1alpha1.TPLScriptTrigger{ 353 ScriptConfig: appsv1alpha1.ScriptConfig{ 354 ScriptConfigMapRef: testName1, 355 Namespace: ns, 356 }, 357 }}, mockK8sCli.Client(), ctx), 358 ).Should(Succeed()) 359 360 By("Test invalid") 361 Expect(ValidateReloadOptions(&appsv1alpha1.ReloadOptions{ 362 TPLScriptTrigger: &appsv1alpha1.TPLScriptTrigger{ 363 ScriptConfig: appsv1alpha1.ScriptConfig{ 364 ScriptConfigMapRef: testName2, 365 Namespace: ns, 366 }, 367 }}, mockK8sCli.Client(), ctx), 368 ).ShouldNot(Succeed()) 369 }) 370 371 It("TestInvalidTrigger", func() { 372 Expect(ValidateReloadOptions(&appsv1alpha1.ReloadOptions{}, nil, nil)).ShouldNot(Succeed()) 373 }) 374 }) 375 }) 376 377 func TestFilterSubPathVolumeMount(t *testing.T) { 378 createConfigMeta := func(volumeName string, reloadType appsv1alpha1.CfgReloadType) ConfigSpecMeta { 379 return ConfigSpecMeta{ConfigSpecInfo: ConfigSpecInfo{ 380 ReloadType: reloadType, 381 ConfigSpec: appsv1alpha1.ComponentConfigSpec{ 382 ComponentTemplateSpec: appsv1alpha1.ComponentTemplateSpec{ 383 VolumeName: volumeName, 384 }}}} 385 } 386 387 type args struct { 388 metas []ConfigSpecMeta 389 volumes []corev1.VolumeMount 390 } 391 tests := []struct { 392 name string 393 args args 394 want []ConfigSpecMeta 395 }{{ 396 name: "test1", 397 args: args{ 398 metas: []ConfigSpecMeta{ 399 createConfigMeta("test1", appsv1alpha1.UnixSignalType), 400 createConfigMeta("test2", appsv1alpha1.ShellType), 401 createConfigMeta("test3", appsv1alpha1.TPLScriptType), 402 }, 403 volumes: []corev1.VolumeMount{ 404 {Name: "test1", SubPath: "test1"}, 405 {Name: "test2", SubPath: "test2"}, 406 {Name: "test3", SubPath: "test3"}, 407 }, 408 }, 409 want: []ConfigSpecMeta{ 410 createConfigMeta("test3", appsv1alpha1.TPLScriptType), 411 }, 412 }, { 413 name: "test2", 414 args: args{ 415 metas: []ConfigSpecMeta{ 416 createConfigMeta("test1", appsv1alpha1.UnixSignalType), 417 createConfigMeta("test2", appsv1alpha1.ShellType), 418 createConfigMeta("test3", appsv1alpha1.TPLScriptType), 419 }, 420 volumes: []corev1.VolumeMount{ 421 {Name: "test1"}, 422 {Name: "test2"}, 423 {Name: "test3"}, 424 }, 425 }, 426 want: []ConfigSpecMeta{ 427 createConfigMeta("test1", appsv1alpha1.UnixSignalType), 428 createConfigMeta("test2", appsv1alpha1.ShellType), 429 createConfigMeta("test3", appsv1alpha1.TPLScriptType), 430 }, 431 }, { 432 name: "test3", 433 args: args{ 434 metas: []ConfigSpecMeta{ 435 createConfigMeta("test1", appsv1alpha1.UnixSignalType), 436 createConfigMeta("test2", appsv1alpha1.ShellType), 437 createConfigMeta("test3", appsv1alpha1.TPLScriptType), 438 }, 439 volumes: []corev1.VolumeMount{}, 440 }, 441 want: []ConfigSpecMeta{ 442 createConfigMeta("test1", appsv1alpha1.UnixSignalType), 443 createConfigMeta("test2", appsv1alpha1.ShellType), 444 createConfigMeta("test3", appsv1alpha1.TPLScriptType), 445 }, 446 }} 447 for _, tt := range tests { 448 t.Run(tt.name, func(t *testing.T) { 449 assert.Equalf(t, tt.want, FilterSubPathVolumeMount(tt.args.metas, tt.args.volumes), "FilterSubPathVolumeMount(%v, %v)", tt.args.metas, tt.args.volumes) 450 }) 451 } 452 }