github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/configuration/core/reconfigure_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 "testing" 24 25 "github.com/StudioSol/set" 26 "github.com/stretchr/testify/require" 27 corev1 "k8s.io/api/core/v1" 28 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 29 "sigs.k8s.io/controller-runtime/pkg/client" 30 31 appsv1alpha1 "github.com/1aal/kubeblocks/apis/apps/v1alpha1" 32 "github.com/1aal/kubeblocks/pkg/configuration/util" 33 "github.com/1aal/kubeblocks/pkg/constant" 34 ) 35 36 func TestGetUpdateParameterList(t *testing.T) { 37 testData := `{ 38 "a": "b", 39 "f": 10.2, 40 "c": [ 41 "edcl", 42 "cde" 43 ], 44 "d" : [], 45 "n" : [{}], 46 "xxx" : [ 47 { 48 "test1": 2, 49 "test2": 5 50 } 51 ], 52 "g": { 53 "cd" : "abcd", 54 "msld" : { 55 "cakl": 100, 56 "dg": "abcd" 57 } 58 }} 59 ` 60 expected := set.NewLinkedHashSetString("a", "f", "c", "xxx.test1", "xxx.test2", "g.msld.cakl", "g.msld.dg", "g.cd") 61 params, err := getUpdateParameterList(newCfgDiffMeta(testData, nil, nil), "") 62 require.Nil(t, err) 63 require.True(t, util.EqSet(expected, 64 set.NewLinkedHashSetString(params...)), "param: %v, expected: %v", params, expected.AsSlice()) 65 66 // for trim 67 expected = set.NewLinkedHashSetString("msld.cakl", "msld.dg", "cd") 68 params, err = getUpdateParameterList(newCfgDiffMeta(testData, nil, nil), "g") 69 require.Nil(t, err) 70 require.True(t, util.EqSet(expected, 71 set.NewLinkedHashSetString(params...)), "param: %v, expected: %v", params, expected.AsSlice()) 72 73 } 74 75 func newCfgDiffMeta(testData string, add, delete map[string]interface{}) *ConfigPatchInfo { 76 return &ConfigPatchInfo{ 77 UpdateConfig: map[string][]byte{ 78 "test": []byte(testData), 79 }, 80 AddConfig: add, 81 DeleteConfig: delete, 82 } 83 } 84 85 func TestIsUpdateDynamicParameters(t *testing.T) { 86 type args struct { 87 ccSpec *appsv1alpha1.ConfigConstraintSpec 88 diff *ConfigPatchInfo 89 } 90 tests := []struct { 91 name string 92 args args 93 want bool 94 wantErr bool 95 }{{ 96 name: "test", 97 // null 98 args: args{ 99 ccSpec: &appsv1alpha1.ConfigConstraintSpec{}, 100 diff: newCfgDiffMeta(`null`, nil, nil), 101 }, 102 want: false, 103 wantErr: false, 104 }, { 105 name: "test", 106 // error 107 args: args{ 108 ccSpec: &appsv1alpha1.ConfigConstraintSpec{}, 109 diff: newCfgDiffMeta(`invalid json formatter`, nil, nil), 110 }, 111 want: false, 112 wantErr: true, 113 }, { 114 name: "test", 115 // add/delete config file 116 args: args{ 117 ccSpec: &appsv1alpha1.ConfigConstraintSpec{}, 118 diff: newCfgDiffMeta(`{}`, map[string]interface{}{"a": "b"}, nil), 119 }, 120 want: false, 121 wantErr: false, 122 }, { 123 name: "test", 124 // not set static or dynamic parameters 125 args: args{ 126 ccSpec: &appsv1alpha1.ConfigConstraintSpec{}, 127 diff: newCfgDiffMeta(`{"a":"b"}`, nil, nil), 128 }, 129 want: false, 130 wantErr: false, 131 }, { 132 name: "test", 133 // static parameters contains 134 args: args{ 135 ccSpec: &appsv1alpha1.ConfigConstraintSpec{ 136 StaticParameters: []string{"param1", "param2", "param3"}, 137 }, 138 diff: newCfgDiffMeta(`{"param3":"b"}`, nil, nil), 139 }, 140 want: false, 141 wantErr: false, 142 }, { 143 name: "test", 144 // static parameters not contains 145 args: args{ 146 ccSpec: &appsv1alpha1.ConfigConstraintSpec{ 147 StaticParameters: []string{"param1", "param2", "param3"}, 148 }, 149 diff: newCfgDiffMeta(`{"param4":"b"}`, nil, nil), 150 }, 151 want: true, 152 wantErr: false, 153 }, { 154 name: "test", 155 // dynamic parameters contains 156 args: args{ 157 ccSpec: &appsv1alpha1.ConfigConstraintSpec{ 158 DynamicParameters: []string{"param1", "param2", "param3"}, 159 }, 160 diff: newCfgDiffMeta(`{"param1":"b", "param3": 20}`, nil, nil), 161 }, 162 want: true, 163 wantErr: false, 164 }, { 165 name: "test", 166 // dynamic parameters not contains 167 args: args{ 168 ccSpec: &appsv1alpha1.ConfigConstraintSpec{ 169 DynamicParameters: []string{"param1", "param2", "param3"}, 170 }, 171 diff: newCfgDiffMeta(`{"param1":"b", "param4": 20}`, nil, nil), 172 }, 173 want: false, 174 wantErr: false, 175 }, { 176 name: "test", 177 // dynamic/static parameters not contains 178 args: args{ 179 ccSpec: &appsv1alpha1.ConfigConstraintSpec{ 180 DynamicParameters: []string{"dparam1", "dparam2", "dparam3"}, 181 StaticParameters: []string{"sparam1", "sparam2", "sparam3"}, 182 }, 183 diff: newCfgDiffMeta(`{"a":"b"}`, nil, nil), 184 }, 185 want: false, 186 wantErr: false, 187 }} 188 for _, tt := range tests { 189 t.Run(tt.name, func(t *testing.T) { 190 got, err := IsUpdateDynamicParameters(tt.args.ccSpec, tt.args.diff) 191 if (err != nil) != tt.wantErr { 192 t.Errorf("IsUpdateDynamicParameters() error = %v, wantErr %v", err, tt.wantErr) 193 return 194 } 195 if got != tt.want { 196 t.Errorf("IsUpdateDynamicParameters() got = %v, want %v", got, tt.want) 197 } 198 }) 199 } 200 } 201 202 func TestIsSchedulableConfigResource(t *testing.T) { 203 tests := []struct { 204 name string 205 object client.Object 206 want bool 207 }{{ 208 name: "test", 209 object: &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{}}, 210 want: false, 211 }, { 212 name: "test", 213 object: &corev1.ConfigMap{ 214 ObjectMeta: metav1.ObjectMeta{ 215 Labels: map[string]string{ 216 constant.AppNameLabelKey: "test", 217 constant.AppInstanceLabelKey: "test", 218 constant.KBAppComponentLabelKey: "component", 219 }, 220 }, 221 }, 222 want: false, 223 }, { 224 name: "test", 225 object: &corev1.ConfigMap{ 226 ObjectMeta: metav1.ObjectMeta{ 227 Labels: map[string]string{ 228 constant.AppNameLabelKey: "test", 229 constant.AppInstanceLabelKey: "test", 230 constant.KBAppComponentLabelKey: "component", 231 constant.CMConfigurationTemplateNameLabelKey: "test_config_template", 232 constant.CMConfigurationConstraintsNameLabelKey: "test_config_constraint", 233 constant.CMConfigurationSpecProviderLabelKey: "for_test_config", 234 constant.CMConfigurationTypeLabelKey: constant.ConfigInstanceType, 235 }, 236 }, 237 }, 238 want: true, 239 }} 240 for _, tt := range tests { 241 t.Run(tt.name, func(t *testing.T) { 242 if got := IsSchedulableConfigResource(tt.object); got != tt.want { 243 t.Errorf("IsSchedulableConfigResource() = %v, want %v", got, tt.want) 244 } 245 }) 246 } 247 } 248 249 func TestSetParametersUpdateSource(t *testing.T) { 250 mockConfigMap := func() *corev1.ConfigMap { 251 return &corev1.ConfigMap{ 252 ObjectMeta: metav1.ObjectMeta{ 253 Name: "test", 254 Namespace: "default", 255 Labels: make(map[string]string), 256 }, 257 Data: make(map[string]string), 258 } 259 } 260 261 cm := mockConfigMap() 262 require.False(t, IsParametersUpdateFromManager(cm)) 263 require.False(t, IsNotUserReconfigureOperation(cm)) 264 SetParametersUpdateSource(cm, constant.ReconfigureManagerSource) 265 require.True(t, IsParametersUpdateFromManager(cm)) 266 require.False(t, IsNotUserReconfigureOperation(cm)) 267 268 // check user reconfigure 269 cm.Annotations[constant.CMInsEnableRerenderTemplateKey] = "true" 270 require.True(t, IsNotUserReconfigureOperation(cm)) 271 272 SetParametersUpdateSource(cm, constant.ReconfigureUserSource) 273 require.False(t, IsNotUserReconfigureOperation(cm)) 274 } 275 276 func TestValidateConfigPatch(t *testing.T) { 277 type args struct { 278 patch *ConfigPatchInfo 279 formatCfg *appsv1alpha1.FormatterConfig 280 } 281 tests := []struct { 282 name string 283 args args 284 wantErr bool 285 }{{ 286 name: "test", 287 args: args{ 288 patch: &ConfigPatchInfo{}, 289 formatCfg: &appsv1alpha1.FormatterConfig{Format: appsv1alpha1.YAML}, 290 }, 291 wantErr: false, 292 }, { 293 name: "test", 294 args: args{ 295 patch: &ConfigPatchInfo{ 296 IsModify: true, 297 UpdateConfig: map[string][]byte{ 298 "file1": []byte(`{"a":"b"}`), 299 }, 300 }, 301 formatCfg: &appsv1alpha1.FormatterConfig{Format: appsv1alpha1.YAML}, 302 }, 303 wantErr: false, 304 }, { 305 name: "test-failed", 306 args: args{ 307 patch: &ConfigPatchInfo{ 308 IsModify: true, 309 UpdateConfig: map[string][]byte{ 310 "file1": []byte(`{"a":null}`), 311 }, 312 }, 313 formatCfg: &appsv1alpha1.FormatterConfig{Format: appsv1alpha1.YAML}, 314 }, 315 wantErr: true, 316 }} 317 for _, tt := range tests { 318 t.Run(tt.name, func(t *testing.T) { 319 if err := ValidateConfigPatch(tt.args.patch, tt.args.formatCfg); (err != nil) != tt.wantErr { 320 t.Errorf("ValidateConfigPatch() error = %v, wantErr %v", err, tt.wantErr) 321 } 322 }) 323 } 324 }