github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/unstructured/redis_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 unstructured
    21  
    22  import (
    23  	"reflect"
    24  	"strings"
    25  	"testing"
    26  
    27  	"github.com/stretchr/testify/require"
    28  
    29  	appsv1alpha1 "github.com/1aal/kubeblocks/apis/apps/v1alpha1"
    30  	"github.com/1aal/kubeblocks/test/testdata"
    31  )
    32  
    33  func TestRedisConfig(t *testing.T) {
    34  	c, err := LoadConfig("test", "", appsv1alpha1.RedisCfg)
    35  	require.Nil(t, err)
    36  
    37  	tests := []struct {
    38  		keyArgs   []string
    39  		valueArgs string
    40  		wantErr   bool
    41  		testKey   map[string]string
    42  	}{{
    43  		keyArgs:   []string{"port"},
    44  		valueArgs: "6379",
    45  		wantErr:   false,
    46  		testKey: map[string]string{
    47  			"port": "6379",
    48  		},
    49  	}, {
    50  		keyArgs:   []string{"client-output-buffer-limit", "normal"},
    51  		valueArgs: "0 0 0",
    52  		wantErr:   false,
    53  		testKey: map[string]string{
    54  			"client-output-buffer-limit": "normal 0 0 0",
    55  		},
    56  	}, {
    57  		keyArgs:   []string{"client-output-buffer-limit", "pubsub"},
    58  		valueArgs: "256mb 64mb 60",
    59  		wantErr:   false,
    60  		testKey: map[string]string{
    61  			"client-output-buffer-limit pubsub": "256mb 64mb 60",
    62  		},
    63  	}, {
    64  		keyArgs:   []string{"client-output-buffer-limit", "normal"},
    65  		valueArgs: "128mb 32mb 0",
    66  		wantErr:   false,
    67  		testKey: map[string]string{
    68  			"client-output-buffer-limit normal": "128mb 32mb 0",
    69  			"client-output-buffer-limit pubsub": "256mb 64mb 60",
    70  			"port":                              "6379",
    71  		},
    72  	}}
    73  	for _, tt := range tests {
    74  		t.Run("config_test", func(t *testing.T) {
    75  			if err := c.Update(strings.Join(tt.keyArgs, " "), tt.valueArgs); (err != nil) != tt.wantErr {
    76  				t.Errorf("Update() error = %v, wantErr %v", err, tt.wantErr)
    77  			}
    78  
    79  			for key, value := range tt.testKey {
    80  				v, _ := c.GetString(key)
    81  				if v != value {
    82  					t.Errorf("GetString() param = %v, expected %v", key, value)
    83  				}
    84  			}
    85  		})
    86  	}
    87  }
    88  
    89  func TestRedisConfigGetAllParameters(t *testing.T) {
    90  	type mockfn = func() ConfigObject
    91  
    92  	tests := []struct {
    93  		name string
    94  		fn   mockfn
    95  		want map[string]interface{}
    96  	}{{
    97  		name: "multi field update test",
    98  		fn: func() ConfigObject {
    99  			c, _ := LoadConfig("test", "", appsv1alpha1.RedisCfg)
   100  			_ = c.Update("port", "123")
   101  			_ = c.Update("a b", "123 234")
   102  			_ = c.Update("a c", "345")
   103  			_ = c.Update("a d", "1 2")
   104  			_ = c.Update("a d e", "1 2")
   105  			return c
   106  		},
   107  		want: map[string]interface{}{
   108  			"port":    "123",
   109  			"a b 123": "234",
   110  			"a c 345": "",
   111  			"a d 1":   "2",
   112  			"a d e":   "1 2",
   113  		},
   114  	}, {
   115  		name: "multi field update and delete test",
   116  		fn: func() ConfigObject {
   117  			c, _ := LoadConfig("test", "", appsv1alpha1.RedisCfg)
   118  			_ = c.Update("port", "123")
   119  			_ = c.Update("a b", "123 234")
   120  			_ = c.Update("a c", "345")
   121  			_ = c.Update("a d", "1 2")
   122  			_ = c.Update("a d e", "1 2")
   123  			_ = c.RemoveKey("a d e")
   124  			_ = c.RemoveKey("a b")
   125  			_ = c.RemoveKey("port")
   126  			return c
   127  		},
   128  		want: map[string]interface{}{
   129  			"a c": "345",
   130  			"a d": "1 2",
   131  		},
   132  	}}
   133  	for _, tt := range tests {
   134  		t.Run(tt.name, func(t *testing.T) {
   135  			r := tt.fn()
   136  			if got := r.GetAllParameters(); !reflect.DeepEqual(got, tt.want) {
   137  				t.Errorf("GetAllParameters() = %v, want %v", got, tt.want)
   138  			}
   139  		})
   140  	}
   141  }
   142  
   143  func TestRedisConfig_Marshal(t *testing.T) {
   144  	testDataFn := func(file string) string {
   145  		b, _ := testdata.GetTestDataFileContent(file)
   146  		return string(b)
   147  	}
   148  
   149  	commentsConfig := `# Lists may also be compressed.
   150  # Compress depth is the number of quicklist ziplist nodes from *each* side of
   151  # the list to *exclude* from compression.  The head and tail of the list
   152  # are always uncompressed for fast push/pop operations.  Settings are:
   153  # 0: disable all list compression
   154  # 1: depth 1 means "don't start compressing until after 1 node into the list,
   155  #    going from either the head or tail"
   156  #    So: [head]->node->node->...->node->[tail]
   157  #    [head], [tail] will always be uncompressed; inner nodes will compress.
   158  # 2: [head]->[next]->node->node->...->node->[prev]->[tail]
   159  #    2 here means: don't compress head or head->next or tail->prev or tail,
   160  #    but compress all nodes between them.
   161  # 3: [head]->[next]->[next]->node->node->...->node->[prev]->[prev]->[tail]
   162  # etc.
   163  list-compress-depth 0
   164  
   165  # Sets have a special encoding in just one case: when a set is composed
   166  # of just strings that happen to be integers in radix 10 in the range
   167  # of 64 bit signed integers.
   168  # The following configuration setting sets the limit in the size of the
   169  # set in order to use this special memory saving encoding.
   170  set-max-intset-entries 512
   171  
   172  # Similarly to hashes and lists, sorted sets are also specially encoded in
   173  # order to save a lot of space. This encoding is only used when the length and
   174  # elements of a sorted set are below the following limits:
   175  zset-max-listpack-entries 128
   176  zset-max-listpack-value 64`
   177  
   178  	tests := []struct {
   179  		name    string
   180  		input   string
   181  		want    string
   182  		updated map[string]interface{}
   183  		wantErr bool
   184  	}{{
   185  		name:  "redis_cont_test",
   186  		input: testDataFn("config_encoding/redis.conf"),
   187  		want:  testDataFn("config_encoding/redis.conf"),
   188  	}, {
   189  		name:  "redis_cont_test",
   190  		input: commentsConfig,
   191  		want:  commentsConfig,
   192  		updated: map[string]interface{}{
   193  			"zset-max-listpack-entries": 128,
   194  		},
   195  	}}
   196  	for _, tt := range tests {
   197  		t.Run(tt.name, func(t *testing.T) {
   198  			config, err := LoadConfig(tt.name, tt.input, appsv1alpha1.RedisCfg)
   199  			if (err != nil) != tt.wantErr {
   200  				t.Errorf("Marshal() error = %v, wantErr %v", err, tt.wantErr)
   201  				return
   202  			}
   203  			for key, value := range tt.updated {
   204  				require.Nil(t, config.Update(key, value))
   205  			}
   206  			got, err := config.Marshal()
   207  			require.Nil(t, err)
   208  			if got != tt.want {
   209  				t.Errorf("Marshal() got = %v, want %v", got, tt.want)
   210  			}
   211  		})
   212  	}
   213  }