github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/configuration/core/config_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 "context" 24 "encoding/json" 25 "sort" 26 "strings" 27 "testing" 28 29 "github.com/StudioSol/set" 30 "github.com/bhmj/jsonslice" 31 "github.com/stretchr/testify/require" 32 "sigs.k8s.io/controller-runtime/pkg/client" 33 "sigs.k8s.io/controller-runtime/pkg/log" 34 35 appsv1alpha1 "github.com/1aal/kubeblocks/apis/apps/v1alpha1" 36 "github.com/1aal/kubeblocks/pkg/configuration/util" 37 ) 38 39 var iniConfig = ` 40 [mysqld] 41 innodb-buffer-pool-size=512M 42 log-bin=master-bin 43 gtid_mode=OFF 44 consensus_auto_leader_transfer=ON 45 46 log_error=/data/mysql/log/mysqld.err 47 character-sets-dir=/usr/share/mysql-8.0/charsets 48 datadir=/data/mysql/data 49 port=3306 50 general_log=1 51 general_log_file=/data/mysql/mysqld.log 52 pid-file=/data/mysql/run/mysqld.pid 53 server-id=1 54 slow_query_log=1 55 #slow_query_log_file=/data/mysql/mysqld-slow.log2 56 slow_query_log_file=/data/mysql/mysqld-slow.log 57 socket=/data/mysql/tmp/mysqld.sock 58 ssl-ca=/data/mysql/std_data/cacert.pem 59 ssl-cert=/data/mysql/std_data/server-cert.pem 60 ssl-key=/data/mysql/std_data/server-key.pem 61 tmpdir=/data/mysql/tmp/ 62 loose-sha256_password_auto_generate_rsa_keys=0 63 loose-caching_sha2_password_auto_generate_rsa_keys=0 64 secure-file-priv=/data/mysql 65 66 [client] 67 socket=/data/mysql/tmp/mysqld.sock 68 host=localhost 69 ` 70 71 func TestConfigMapConfig(t *testing.T) { 72 cfg, err := NewConfigLoader(CfgOption{ 73 Type: CfgCmType, 74 Log: log.FromContext(context.Background()), 75 CfgType: appsv1alpha1.Ini, 76 ConfigResource: &ConfigResource{ 77 CfgKey: client.ObjectKey{ 78 Name: "xxxx", // set cm name 79 Namespace: "default", // set cm namespace 80 }, 81 ResourceReader: func(key client.ObjectKey) (map[string]string, error) { 82 return map[string]string{ 83 "my.cnf": iniConfig, 84 "my_test.cnf": iniConfig, 85 }, nil 86 }, 87 }, 88 }) 89 90 require.Nil(t, err) 91 log.Log.Info("cfg option: %v", cfg.Option) 92 93 require.Equal(t, cfg.fileCount, 2) 94 require.NotNil(t, cfg.getConfigObject(NewCfgOptions("my.cnf"))) 95 require.Nil(t, cfg.getConfigObject(NewCfgOptions("my2.cnf"))) 96 97 res, err := cfg.Query("$..slow_query_log_file", NewCfgOptions("")) 98 require.Nil(t, err) 99 require.NotNil(t, res) 100 101 require.Equal(t, "[\"/data/mysql/mysqld-slow.log\"]", string(res)) 102 103 // patch 104 { 105 106 ctx := NewCfgOptions("my.cnf", 107 func(ctx *CfgOpOption) { 108 ctx.IniContext = &IniContext{ 109 SectionName: "mysqld", 110 } 111 }) 112 113 require.Nil(t, 114 cfg.MergeFrom(map[string]interface{}{ 115 "slow_query_log": 0, 116 "general_log": 0, 117 }, ctx)) 118 119 content, _ := cfg.ToCfgContent() 120 patch, err := CreateMergePatch(&ConfigResource{ 121 ConfigData: map[string]string{ 122 "my.cnf": iniConfig, 123 "my2.cnf": iniConfig, 124 }, 125 }, FromConfigData(content, nil), cfg.Option) 126 127 require.Nil(t, err) 128 require.NotNil(t, patch) 129 130 // add config: my_test.cnf 131 // delete config: my2.cnf 132 133 _, ok := patch.AddConfig["my_test.cnf"] 134 require.True(t, ok) 135 136 _, ok = patch.DeleteConfig["my2.cnf"] 137 require.True(t, ok) 138 139 updated, ok := patch.UpdateConfig["my.cnf"] 140 require.True(t, ok) 141 142 // update my.cnf 143 // update slow_query_log 0 144 res, _ := jsonslice.Get(updated, "$.mysqld.slow_query_log") 145 require.Equal(t, []byte(`"0"`), res) 146 147 // update general_log 0 148 res, _ = jsonslice.Get(updated, "$.mysqld.general_log") 149 require.Equal(t, []byte(`"0"`), res) 150 } 151 } 152 153 func TestGenerateVisualizedParamsList(t *testing.T) { 154 type args struct { 155 configPatch *ConfigPatchInfo 156 formatConfig *appsv1alpha1.FormatterConfig 157 sets *set.LinkedHashSetString 158 } 159 160 var ( 161 testJSON any 162 fileUpdatedParams = []byte(`{"mysqld": { "max_connections": "666", "read_buffer_size": "55288" }}`) 163 testUpdatedParams = []byte(`{"mysqld": { "max_connections": "666", "read_buffer_size": "55288", "delete_params": null }}`) 164 ) 165 166 require.Nil(t, json.Unmarshal(fileUpdatedParams, &testJSON)) 167 tests := []struct { 168 name string 169 args args 170 want []VisualizedParam 171 }{{ 172 name: "visualizedParamsTest", 173 args: args{ 174 configPatch: &ConfigPatchInfo{ 175 IsModify: false, 176 }, 177 }, 178 want: nil, 179 }, { 180 name: "visualizedParamsTest", 181 args: args{ 182 configPatch: &ConfigPatchInfo{ 183 IsModify: true, 184 UpdateConfig: map[string][]byte{"key": testUpdatedParams}}, 185 }, 186 want: []VisualizedParam{{ 187 Key: "key", 188 UpdateType: UpdatedType, 189 Parameters: []ParameterPair{ 190 { 191 Key: "mysqld.max_connections", 192 Value: util.ToPointer("666"), 193 }, { 194 Key: "mysqld.read_buffer_size", 195 Value: util.ToPointer("55288"), 196 }, { 197 Key: "mysqld.delete_params", 198 Value: nil, 199 }}, 200 }}, 201 }, { 202 name: "visualizedParamsTest", 203 args: args{ 204 configPatch: &ConfigPatchInfo{ 205 IsModify: true, 206 UpdateConfig: map[string][]byte{"key": testUpdatedParams}}, 207 formatConfig: &appsv1alpha1.FormatterConfig{ 208 Format: appsv1alpha1.Ini, 209 FormatterOptions: appsv1alpha1.FormatterOptions{IniConfig: &appsv1alpha1.IniConfig{ 210 SectionName: "mysqld", 211 }}, 212 }, 213 }, 214 want: []VisualizedParam{{ 215 Key: "key", 216 UpdateType: UpdatedType, 217 Parameters: []ParameterPair{ 218 { 219 Key: "max_connections", 220 Value: util.ToPointer("666"), 221 }, { 222 Key: "read_buffer_size", 223 Value: util.ToPointer("55288"), 224 }, { 225 Key: "delete_params", 226 Value: nil, 227 }}, 228 }}, 229 }, { 230 name: "addFileTest", 231 args: args{ 232 configPatch: &ConfigPatchInfo{ 233 IsModify: true, 234 AddConfig: map[string]interface{}{"key": testJSON}, 235 }, 236 formatConfig: &appsv1alpha1.FormatterConfig{ 237 Format: appsv1alpha1.Ini, 238 FormatterOptions: appsv1alpha1.FormatterOptions{IniConfig: &appsv1alpha1.IniConfig{ 239 SectionName: "mysqld", 240 }}, 241 }, 242 }, 243 want: []VisualizedParam{{ 244 Key: "key", 245 UpdateType: AddedType, 246 Parameters: []ParameterPair{ 247 { 248 Key: "max_connections", 249 Value: util.ToPointer("666"), 250 }, { 251 Key: "read_buffer_size", 252 Value: util.ToPointer("55288"), 253 }}, 254 }}, 255 }, { 256 name: "deleteFileTest", 257 args: args{ 258 configPatch: &ConfigPatchInfo{ 259 IsModify: true, 260 DeleteConfig: map[string]interface{}{"key": testJSON}, 261 }, 262 formatConfig: &appsv1alpha1.FormatterConfig{ 263 Format: appsv1alpha1.Ini, 264 FormatterOptions: appsv1alpha1.FormatterOptions{IniConfig: &appsv1alpha1.IniConfig{ 265 SectionName: "mysqld", 266 }}, 267 }, 268 }, 269 want: []VisualizedParam{{ 270 Key: "key", 271 UpdateType: DeletedType, 272 Parameters: []ParameterPair{ 273 { 274 Key: "max_connections", 275 Value: util.ToPointer("666"), 276 }, { 277 Key: "read_buffer_size", 278 Value: util.ToPointer("55288"), 279 }}, 280 }}, 281 }} 282 for _, tt := range tests { 283 t.Run(tt.name, func(t *testing.T) { 284 got := GenerateVisualizedParamsList(tt.args.configPatch, tt.args.formatConfig, tt.args.sets) 285 sortParams(got) 286 sortParams(tt.want) 287 require.Equal(t, got, tt.want) 288 }) 289 } 290 } 291 292 func sortParams(param []VisualizedParam) { 293 for _, v := range param { 294 sort.SliceStable(v.Parameters, func(i, j int) bool { 295 return strings.Compare(v.Parameters[i].Key, v.Parameters[j].Key) <= 0 296 }) 297 } 298 if len(param) > 0 { 299 sort.SliceStable(param, func(i, j int) bool { 300 return strings.Compare(param[i].Key, param[j].Key) <= 0 301 }) 302 } 303 }