github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/configuration/core/config_patch_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  	"testing"
    25  
    26  	"github.com/1aal/kubeblocks/apis/apps/v1alpha1"
    27  	"github.com/1aal/kubeblocks/test/testdata"
    28  )
    29  
    30  func TestCheckExcludeConfigDifference(t *testing.T) {
    31  	type args struct {
    32  		oldVersion map[string]string
    33  		newVersion map[string]string
    34  		keys       []string
    35  	}
    36  	tests := []struct {
    37  		name string
    38  		args args
    39  		want bool
    40  	}{{
    41  		name: "emptyKeys",
    42  		args: args{
    43  			oldVersion: map[string]string{
    44  				"a": "test1",
    45  			},
    46  			newVersion: map[string]string{
    47  				"a": "test1",
    48  			},
    49  		},
    50  		want: false,
    51  	}, {
    52  		name: "emptyKeys",
    53  		args: args{
    54  			oldVersion: map[string]string{
    55  				"a": "test2",
    56  			},
    57  			newVersion: map[string]string{
    58  				"a": "test1",
    59  			},
    60  		},
    61  		want: true,
    62  	}, {
    63  		name: "emptyKeys",
    64  		args: args{
    65  			oldVersion: map[string]string{
    66  				"a": "test1",
    67  			},
    68  			newVersion: map[string]string{
    69  				"b": "test1",
    70  			},
    71  		},
    72  		want: true,
    73  	}, {
    74  		name: "keyTest",
    75  		args: args{
    76  			oldVersion: map[string]string{
    77  				"a": "test1",
    78  				"b": "test2",
    79  			},
    80  			newVersion: map[string]string{
    81  				"a": "test1",
    82  				"b": "test3",
    83  			},
    84  			keys: []string{"b"},
    85  		},
    86  		want: false,
    87  	}, {
    88  		name: "keyTest",
    89  		args: args{
    90  			oldVersion: map[string]string{
    91  				"a": "test1",
    92  				"b": "test2",
    93  			},
    94  			newVersion: map[string]string{
    95  				"a": "test1",
    96  				"b": "test3",
    97  			},
    98  			keys: []string{"a"},
    99  		},
   100  		want: true,
   101  	}, {
   102  		name: "keyTest",
   103  		args: args{
   104  			oldVersion: map[string]string{
   105  				"a": "test1",
   106  				"b": "test2",
   107  			},
   108  			newVersion: map[string]string{
   109  				"a": "test1",
   110  				"b": "test3",
   111  			},
   112  			keys: []string{"a", "b"},
   113  		},
   114  		want: false,
   115  	}, {
   116  		name: "keyCountTest",
   117  		args: args{
   118  			oldVersion: map[string]string{
   119  				"a": "test1",
   120  				"b": "test2",
   121  				"c": "test2",
   122  			},
   123  			newVersion: map[string]string{
   124  				"a": "test1",
   125  				"b": "test3",
   126  			},
   127  			keys: []string{"b"},
   128  		},
   129  		want: true,
   130  	}, {
   131  		name: "notKeyTest",
   132  		args: args{
   133  			oldVersion: map[string]string{
   134  				"a": "test1",
   135  				"b": "test2",
   136  				"c": "test2",
   137  			},
   138  			newVersion: map[string]string{
   139  				"a": "test1",
   140  				"b": "test3",
   141  			},
   142  			keys: []string{"b", "e", "f", "g"},
   143  		},
   144  		want: true,
   145  	}, {
   146  		name: "notKeyTest",
   147  		args: args{
   148  			oldVersion: map[string]string{
   149  				"a": "test1",
   150  				"b": "test2",
   151  				"c": "test2",
   152  			},
   153  			newVersion: map[string]string{
   154  				"a": "test1",
   155  				"b": "test3",
   156  			},
   157  			keys: []string{"b", "c", "f", "g"},
   158  		},
   159  		want: false,
   160  	}}
   161  	for _, tt := range tests {
   162  		t.Run(tt.name, func(t *testing.T) {
   163  			if got := checkExcludeConfigDifference(tt.args.oldVersion, tt.args.newVersion, tt.args.keys); got != tt.want {
   164  				t.Errorf("checkExcludeConfigDifference() = %v, want %v", got, tt.want)
   165  			}
   166  		})
   167  	}
   168  }
   169  
   170  func TestCreateConfigurePatch(t *testing.T) {
   171  	v1 := `
   172  [mysqld]
   173  key_buffer_size=16777216
   174  max_connections=2666
   175  authentication_policy=mysql_native_password,
   176  back_log=5285
   177  binlog_cache_size=32768
   178  binlog_format=MIXED
   179  binlog_order_commits=ON
   180  binlog_row_image=FULL
   181  connect_timeout=10
   182  `
   183  	v2 := `
   184  [mysqld]
   185  authentication_policy=mysql_native_password,
   186  back_log=5285
   187  binlog_cache_size=32768
   188  binlog_format=MIXED
   189  binlog_order_commits=ON
   190  binlog_row_image=FULL
   191  connect_timeout=10
   192  key_buffer_size=18874368
   193  max_connections=666
   194  `
   195  
   196  	type args struct {
   197  		oldVersion        map[string]string
   198  		newVersion        map[string]string
   199  		format            v1alpha1.CfgFileFormat
   200  		keys              []string
   201  		enableExcludeDiff bool
   202  	}
   203  	tests := []struct {
   204  		name        string
   205  		args        args
   206  		want        *ConfigPatchInfo
   207  		excludeDiff bool
   208  		wantErr     bool
   209  	}{{
   210  		name: "patchTestWithoutKeys",
   211  		args: args{
   212  			oldVersion: map[string]string{
   213  				"my.cnf": v1,
   214  			},
   215  			newVersion: map[string]string{
   216  				"my.cnf": v2,
   217  			},
   218  			format:            v1alpha1.Ini,
   219  			enableExcludeDiff: true,
   220  		},
   221  		want:        &ConfigPatchInfo{IsModify: true},
   222  		excludeDiff: false,
   223  	}, {
   224  		name: "failedPatchTestWithoutKeys",
   225  		args: args{
   226  			oldVersion: map[string]string{
   227  				"my.cnf":    v1,
   228  				"other.cnf": "context",
   229  			},
   230  			newVersion: map[string]string{
   231  				"my.cnf":    v2,
   232  				"other.cnf": "context",
   233  			},
   234  			format:            v1alpha1.Ini,
   235  			enableExcludeDiff: true,
   236  		},
   237  		want:        &ConfigPatchInfo{IsModify: true},
   238  		excludeDiff: false,
   239  		wantErr:     true,
   240  	}, {
   241  		name: "patchTest",
   242  		args: args{
   243  			oldVersion: map[string]string{
   244  				"my.cnf":    v1,
   245  				"other.cnf": "context",
   246  			},
   247  			newVersion: map[string]string{
   248  				"my.cnf":    v2,
   249  				"other.cnf": "context",
   250  			},
   251  			keys:              []string{"my.cnf"},
   252  			format:            v1alpha1.Ini,
   253  			enableExcludeDiff: true,
   254  		},
   255  		want:        &ConfigPatchInfo{IsModify: true},
   256  		excludeDiff: false,
   257  	}, {
   258  		name: "patchTest",
   259  		args: args{
   260  			oldVersion: map[string]string{
   261  				"my.cnf":    v1,
   262  				"other.cnf": "context",
   263  			},
   264  			newVersion: map[string]string{
   265  				"my.cnf":    v1,
   266  				"other.cnf": "context difference",
   267  			},
   268  			keys:              []string{"my.cnf"},
   269  			format:            v1alpha1.Ini,
   270  			enableExcludeDiff: true,
   271  		},
   272  		want:        &ConfigPatchInfo{IsModify: false},
   273  		excludeDiff: true,
   274  	}, {
   275  		name: "patchTest",
   276  		args: args{
   277  			oldVersion: map[string]string{
   278  				"my.cnf":    v1,
   279  				"other.cnf": "context",
   280  			},
   281  			newVersion: map[string]string{
   282  				"my.cnf":    v2,
   283  				"other.cnf": "context difference",
   284  			},
   285  			keys:              []string{"my.cnf"},
   286  			format:            v1alpha1.Ini,
   287  			enableExcludeDiff: false,
   288  		},
   289  		want:        &ConfigPatchInfo{IsModify: true},
   290  		excludeDiff: false,
   291  	}}
   292  	for _, tt := range tests {
   293  		t.Run(tt.name, func(t *testing.T) {
   294  			got, excludeDiff, err := CreateConfigPatch(tt.args.oldVersion, tt.args.newVersion, tt.args.format, tt.args.keys, tt.args.enableExcludeDiff)
   295  			if (err != nil) != tt.wantErr {
   296  				t.Errorf("CreateConfigPatch() error = %v, wantErr %v", err, tt.wantErr)
   297  				return
   298  			}
   299  			if !tt.wantErr && got.IsModify != tt.want.IsModify {
   300  				t.Errorf("CreateConfigPatch() got = %v, want %v", got, tt.want)
   301  			}
   302  			if excludeDiff != tt.excludeDiff {
   303  				t.Errorf("CreateConfigPatch() got1 = %v, want %v", excludeDiff, tt.excludeDiff)
   304  			}
   305  		})
   306  	}
   307  }
   308  
   309  func TestLoadRawConfigObject(t *testing.T) {
   310  	getFileContentFn := func(file string) string {
   311  		content, _ := testdata.GetTestDataFileContent(file)
   312  		return string(content)
   313  	}
   314  
   315  	type args struct {
   316  		data         map[string]string
   317  		formatConfig *v1alpha1.FormatterConfig
   318  		keys         []string
   319  	}
   320  	tests := []struct {
   321  		name    string
   322  		args    args
   323  		wantErr bool
   324  	}{{
   325  		name: "test",
   326  		args: args{
   327  			data: map[string]string{"key": getFileContentFn("cue_testdata/mysql.cnf")},
   328  			formatConfig: &v1alpha1.FormatterConfig{
   329  				Format: v1alpha1.Ini,
   330  				FormatterOptions: v1alpha1.FormatterOptions{
   331  					IniConfig: &v1alpha1.IniConfig{
   332  						SectionName: "mysqld",
   333  					}},
   334  			}},
   335  		wantErr: false,
   336  	}, {
   337  		name: "test",
   338  		args: args{
   339  			data: map[string]string{"key": getFileContentFn("cue_testdata/pg14.conf")},
   340  			formatConfig: &v1alpha1.FormatterConfig{
   341  				Format: v1alpha1.Properties,
   342  			}},
   343  		wantErr: false,
   344  	}, {
   345  		name: "test",
   346  		args: args{
   347  			data: map[string]string{
   348  				"key":  getFileContentFn("cue_testdata/pg14.conf"),
   349  				"key2": getFileContentFn("cue_testdata/mysql.cnf"),
   350  			},
   351  			keys: []string{"key"},
   352  			formatConfig: &v1alpha1.FormatterConfig{
   353  				Format: v1alpha1.Properties,
   354  			}},
   355  		wantErr: false,
   356  	}, {
   357  		name: "test-failed",
   358  		args: args{
   359  			data: map[string]string{
   360  				"key": getFileContentFn("cue_testdata/pg14.conf"),
   361  			},
   362  			keys: []string{"key"},
   363  			formatConfig: &v1alpha1.FormatterConfig{
   364  				Format: v1alpha1.XML,
   365  			}},
   366  		wantErr: true,
   367  	}}
   368  	for _, tt := range tests {
   369  		t.Run(tt.name, func(t *testing.T) {
   370  			_, err := LoadRawConfigObject(tt.args.data, tt.args.formatConfig, tt.args.keys)
   371  			if (err != nil) != tt.wantErr {
   372  				t.Errorf("LoadRawConfigObject() error = %v, wantErr %v", err, tt.wantErr)
   373  				return
   374  			}
   375  		})
   376  	}
   377  }
   378  
   379  func TestTransformConfigFileToKeyValueMap(t *testing.T) {
   380  	mysqlConfig := `
   381  [mysqld]
   382  key_buffer_size=16777216
   383  log_error=/data/mysql/logs/mysql.log
   384  `
   385  	mongodbConfig := `
   386  systemLog:
   387    logRotate: reopen
   388    path: /data/mongodb/logs/mongodb.log
   389    verbosity: 0
   390  `
   391  	tests := []struct {
   392  		name         string
   393  		fileName     string
   394  		formatConfig *v1alpha1.FormatterConfig
   395  		configData   []byte
   396  		expected     map[string]string
   397  	}{{
   398  		name:     "mysql-test",
   399  		fileName: "my.cnf",
   400  		formatConfig: &v1alpha1.FormatterConfig{
   401  			Format: v1alpha1.Ini,
   402  			FormatterOptions: v1alpha1.FormatterOptions{
   403  				IniConfig: &v1alpha1.IniConfig{
   404  					SectionName: "mysqld",
   405  				},
   406  			},
   407  		},
   408  		configData: []byte(mysqlConfig),
   409  		expected: map[string]string{
   410  			"key_buffer_size": "16777216",
   411  			"log_error":       "/data/mysql/logs/mysql.log",
   412  		},
   413  	}, {
   414  		name:     "mongodb-test",
   415  		fileName: "mongodb.conf",
   416  		formatConfig: &v1alpha1.FormatterConfig{
   417  			Format: v1alpha1.YAML,
   418  			FormatterOptions: v1alpha1.FormatterOptions{
   419  				IniConfig: &v1alpha1.IniConfig{
   420  					SectionName: "default",
   421  				},
   422  			},
   423  		},
   424  		configData: []byte(mongodbConfig),
   425  		expected: map[string]string{
   426  			"systemLog.logRotate": "reopen",
   427  			"systemLog.path":      "/data/mongodb/logs/mongodb.log",
   428  			"systemLog.verbosity": "0",
   429  		},
   430  	}}
   431  	for _, tt := range tests {
   432  		t.Run(tt.name, func(t *testing.T) {
   433  			res, _ := TransformConfigFileToKeyValueMap(tt.fileName, tt.formatConfig, tt.configData)
   434  			if !reflect.DeepEqual(res, tt.expected) {
   435  				t.Errorf("TransformConfigFileToKeyValueMap() res = %v, res %v", res, tt.expected)
   436  				return
   437  			}
   438  		})
   439  	}
   440  }