github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/common/viperutil/config_test.go (about)

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package viperutil
     8  
     9  import (
    10  	"fmt"
    11  	"io/ioutil"
    12  	"os"
    13  	"strings"
    14  	"testing"
    15  	"time"
    16  
    17  	"github.com/Shopify/sarama"
    18  	"github.com/hechain20/hechain/bccsp/factory"
    19  	"github.com/hechain20/hechain/orderer/mocks/util"
    20  	"github.com/stretchr/testify/require"
    21  )
    22  
    23  const (
    24  	testConfigName = "viperutil"
    25  	testEnvPrefix  = "VIPERUTIL"
    26  )
    27  
    28  func TestEnvSlice(t *testing.T) {
    29  	type testSlice struct {
    30  		Inner struct {
    31  			Slice []string
    32  		}
    33  	}
    34  
    35  	envVar := testEnvPrefix + "_INNER_SLICE"
    36  	os.Setenv(envVar, "[a, b, c]")
    37  	defer os.Unsetenv(envVar)
    38  
    39  	data := "---\nInner:\n    Slice: [d,e,f]"
    40  
    41  	config := New()
    42  	config.SetConfigName(testConfigName)
    43  	err := config.ReadConfig(strings.NewReader(data))
    44  	require.NoError(t, err, "error reading %s plugin config", testConfigName)
    45  
    46  	var uconf testSlice
    47  	err = config.EnhancedExactUnmarshal(&uconf)
    48  	require.NoError(t, err, "failed to unmarshal")
    49  
    50  	expected := []string{"a", "b", "c"}
    51  	require.Exactly(t, expected, uconf.Inner.Slice, "did not get the expected slice")
    52  }
    53  
    54  func TestKafkaVersionDecode(t *testing.T) {
    55  	type testKafkaVersion struct {
    56  		Inner struct {
    57  			Version sarama.KafkaVersion
    58  		}
    59  	}
    60  
    61  	testCases := []struct {
    62  		data        string
    63  		expected    sarama.KafkaVersion
    64  		errExpected bool
    65  	}{
    66  		{"0.8", sarama.KafkaVersion{}, true},
    67  		{"0.8.2.0", sarama.V0_8_2_0, false},
    68  		{"0.8.2.1", sarama.V0_8_2_1, false},
    69  		{"0.8.2.2", sarama.V0_8_2_2, false},
    70  		{"0.9.0.0", sarama.V0_9_0_0, false},
    71  		{"0.9", sarama.V0_9_0_0, false},
    72  		{"0.9.0", sarama.V0_9_0_0, false},
    73  		{"0.9.0.1", sarama.V0_9_0_1, false},
    74  		{"0.9.0.3", sarama.V0_9_0_1, false},
    75  		{"0.10.0.0", sarama.V0_10_0_0, false},
    76  		{"0.10", sarama.V0_10_0_0, false},
    77  		{"0.10.0", sarama.V0_10_0_0, false},
    78  		{"0.10.0.1", sarama.V0_10_0_1, false},
    79  		{"0.10.1.0", sarama.V0_10_1_0, false},
    80  		{"0.10.2.0", sarama.V0_10_2_0, false},
    81  		{"0.10.2.1", sarama.V0_10_2_0, false},
    82  		{"0.10.2.2", sarama.V0_10_2_0, false},
    83  		{"0.10.2.3", sarama.V0_10_2_0, false},
    84  		{"0.11", sarama.V0_11_0_0, false},
    85  		{"0.11.0", sarama.V0_11_0_0, false},
    86  		{"0.11.0.0", sarama.V0_11_0_0, false},
    87  		{"1", sarama.V1_0_0_0, false},
    88  		{"1.0", sarama.V1_0_0_0, false},
    89  		{"1.0.0", sarama.V1_0_0_0, false},
    90  		{"1.0.1", sarama.V1_0_0_0, false},
    91  		{"2.0.0", sarama.V1_0_0_0, false},
    92  		{"Malformed", sarama.KafkaVersion{}, true},
    93  	}
    94  
    95  	for _, tc := range testCases {
    96  		t.Run(tc.data, func(t *testing.T) {
    97  			data := fmt.Sprintf("---\nInner:\n    Version: '%s'", tc.data)
    98  
    99  			config := New()
   100  			err := config.ReadConfig(strings.NewReader(data))
   101  			require.NoError(t, err, "error reading config")
   102  
   103  			var uconf testKafkaVersion
   104  			err = config.EnhancedExactUnmarshal(&uconf)
   105  			if tc.errExpected {
   106  				require.Error(t, err, "unmarshal did not fail")
   107  			} else {
   108  				require.NoError(t, err, "unmarshal failed")
   109  				require.Exactly(t, tc.expected, uconf.Inner.Version, "incorrect kafka version")
   110  			}
   111  		})
   112  	}
   113  }
   114  
   115  type testByteSize struct {
   116  	Inner struct {
   117  		ByteSize uint32
   118  	}
   119  }
   120  
   121  func TestByteSize(t *testing.T) {
   122  	testCases := []struct {
   123  		data     string
   124  		expected uint32
   125  	}{
   126  		{"", 0},
   127  		{"42", 42},
   128  		{"42k", 42 * 1024},
   129  		{"42kb", 42 * 1024},
   130  		{"42K", 42 * 1024},
   131  		{"42KB", 42 * 1024},
   132  		{"42 K", 42 * 1024},
   133  		{"42 KB", 42 * 1024},
   134  		{"42m", 42 * 1024 * 1024},
   135  		{"42mb", 42 * 1024 * 1024},
   136  		{"42M", 42 * 1024 * 1024},
   137  		{"42MB", 42 * 1024 * 1024},
   138  		{"42 M", 42 * 1024 * 1024},
   139  		{"42 MB", 42 * 1024 * 1024},
   140  		{"3g", 3 * 1024 * 1024 * 1024},
   141  		{"3gb", 3 * 1024 * 1024 * 1024},
   142  		{"3G", 3 * 1024 * 1024 * 1024},
   143  		{"3GB", 3 * 1024 * 1024 * 1024},
   144  		{"3 G", 3 * 1024 * 1024 * 1024},
   145  		{"3 GB", 3 * 1024 * 1024 * 1024},
   146  	}
   147  
   148  	for _, tc := range testCases {
   149  		t.Run(tc.data, func(t *testing.T) {
   150  			data := fmt.Sprintf("---\nInner:\n    ByteSize: %s", tc.data)
   151  
   152  			config := New()
   153  			err := config.ReadConfig(strings.NewReader(data))
   154  			require.NoError(t, err, "error reading config")
   155  
   156  			var uconf testByteSize
   157  			err = config.EnhancedExactUnmarshal(&uconf)
   158  			require.NoError(t, err, "failed to unmarshal")
   159  			require.Exactly(t, tc.expected, uconf.Inner.ByteSize, "incorrect byte size")
   160  		})
   161  	}
   162  }
   163  
   164  func TestByteSizeOverflow(t *testing.T) {
   165  	data := "---\nInner:\n    ByteSize: 4GB"
   166  
   167  	config := New()
   168  	err := config.ReadConfig(strings.NewReader(data))
   169  	require.NoError(t, err, "error reading config")
   170  
   171  	var uconf testByteSize
   172  	err = config.EnhancedExactUnmarshal(&uconf)
   173  	require.Error(t, err)
   174  	require.Contains(t, err.Error(), "Inner.ByteSize")
   175  	require.Contains(t, err.Error(), "value '4GB' overflows uint32")
   176  }
   177  
   178  type stringFromFileConfig struct {
   179  	Inner struct {
   180  		Single   string
   181  		Multiple []string
   182  	}
   183  }
   184  
   185  func TestStringNotFromFile(t *testing.T) {
   186  	yaml := "---\nInner:\n  Single: expected_value\n"
   187  
   188  	config := New()
   189  	err := config.ReadConfig(strings.NewReader(yaml))
   190  	require.NoError(t, err, "error reading config")
   191  
   192  	var uconf stringFromFileConfig
   193  	err = config.EnhancedExactUnmarshal(&uconf)
   194  	require.NoError(t, err, "failed to unmarshal")
   195  	require.Equal(t, "expected_value", uconf.Inner.Single)
   196  }
   197  
   198  func TestStringFromFile(t *testing.T) {
   199  	file, err := ioutil.TempFile(os.TempDir(), "test")
   200  	require.NoError(t, err, "failed to create temp file")
   201  	defer os.Remove(file.Name())
   202  
   203  	expectedValue := "this is the text in the file"
   204  
   205  	err = ioutil.WriteFile(file.Name(), []byte(expectedValue), 0o644)
   206  	require.NoError(t, err, "uname to write temp file")
   207  
   208  	yaml := fmt.Sprintf("---\nInner:\n  Single:\n    File: %s", file.Name())
   209  
   210  	config := New()
   211  	err = config.ReadConfig(strings.NewReader(yaml))
   212  	require.NoError(t, err, "error reading config")
   213  
   214  	var uconf stringFromFileConfig
   215  	err = config.EnhancedExactUnmarshal(&uconf)
   216  	require.NoError(t, err, "unmarshal failed")
   217  	require.Equal(t, expectedValue, uconf.Inner.Single)
   218  }
   219  
   220  func TestPEMBlocksFromFile(t *testing.T) {
   221  	file, err := ioutil.TempFile(os.TempDir(), "test")
   222  	require.NoError(t, err, "failed to create temp file")
   223  	defer os.Remove(file.Name())
   224  
   225  	var pems []byte
   226  	for i := 0; i < 3; i++ {
   227  		publicKeyCert, _, _ := util.GenerateMockPublicPrivateKeyPairPEM(true)
   228  		pems = append(pems, publicKeyCert...)
   229  	}
   230  
   231  	err = ioutil.WriteFile(file.Name(), pems, 0o644)
   232  	require.NoError(t, err, "failed to write temp file")
   233  
   234  	yaml := fmt.Sprintf("---\nInner:\n  Multiple:\n    File: %s", file.Name())
   235  
   236  	config := New()
   237  	err = config.ReadConfig(strings.NewReader(yaml))
   238  	require.NoError(t, err, "error reading config")
   239  
   240  	var uconf stringFromFileConfig
   241  	err = config.EnhancedExactUnmarshal(&uconf)
   242  	require.NoError(t, err, "failed to unmarshal")
   243  	require.Len(t, uconf.Inner.Multiple, 3)
   244  }
   245  
   246  func TestPEMBlocksFromFileEnv(t *testing.T) {
   247  	file, err := ioutil.TempFile(os.TempDir(), "test")
   248  	require.NoError(t, err, "failed to create temp file")
   249  	defer os.Remove(file.Name())
   250  
   251  	var pems []byte
   252  	for i := 0; i < 3; i++ {
   253  		publicKeyCert, _, _ := util.GenerateMockPublicPrivateKeyPairPEM(true)
   254  		pems = append(pems, publicKeyCert...)
   255  	}
   256  
   257  	err = ioutil.WriteFile(file.Name(), pems, 0o644)
   258  	require.NoError(t, err, "failed to write temp file")
   259  
   260  	envVar := testEnvPrefix + "_INNER_MULTIPLE_FILE"
   261  	defer os.Unsetenv(envVar)
   262  	os.Setenv(envVar, file.Name())
   263  
   264  	testCases := []struct {
   265  		name string
   266  		data string
   267  	}{
   268  		{"Override", "---\nInner:\n  Multiple:\n    File: wrong_file"},
   269  		{"NoFileElement", "---\nInner:\n  Multiple:\n"},
   270  	}
   271  
   272  	for _, tc := range testCases {
   273  		t.Run(tc.name, func(t *testing.T) {
   274  			config := New()
   275  			config.SetConfigName(testConfigName)
   276  
   277  			err := config.ReadConfig(strings.NewReader(tc.data))
   278  			require.NoError(t, err, "error reading config")
   279  
   280  			var uconf stringFromFileConfig
   281  			err = config.EnhancedExactUnmarshal(&uconf)
   282  			require.NoError(t, err, "failed to unmarshal")
   283  			require.Len(t, uconf.Inner.Multiple, 3)
   284  		})
   285  	}
   286  }
   287  
   288  func TestStringFromFileNotSpecified(t *testing.T) {
   289  	yaml := "---\nInner:\n  Single:\n    File:\n"
   290  
   291  	config := New()
   292  	err := config.ReadConfig(strings.NewReader(yaml))
   293  	require.NoError(t, err, "error reading config")
   294  
   295  	var uconf stringFromFileConfig
   296  	err = config.EnhancedExactUnmarshal(&uconf)
   297  	require.Error(t, err, "umarshal should fail")
   298  }
   299  
   300  func TestStringFromFileEnv(t *testing.T) {
   301  	expectedValue := "this is the text in the file"
   302  
   303  	file, err := ioutil.TempFile(os.TempDir(), "test")
   304  	require.NoError(t, err, "failed to create temp file")
   305  	defer os.Remove(file.Name())
   306  
   307  	err = ioutil.WriteFile(file.Name(), []byte(expectedValue), 0o644)
   308  	require.NoError(t, err, "failed to write temp file")
   309  
   310  	envVar := testEnvPrefix + "_INNER_SINGLE_FILE"
   311  	defer os.Unsetenv(envVar)
   312  	os.Setenv(envVar, file.Name())
   313  
   314  	testCases := []struct {
   315  		name string
   316  		data string
   317  	}{
   318  		{"Override", "---\nInner:\n  Single:\n    File: wrong_file"},
   319  		{"NoFileElement", "---\nInner:\n  Single:\n"},
   320  	}
   321  
   322  	for _, tc := range testCases {
   323  		t.Run(tc.name, func(t *testing.T) {
   324  			config := New()
   325  			config.SetConfigName(testConfigName)
   326  
   327  			err := config.ReadConfig(strings.NewReader(tc.data))
   328  			require.NoError(t, err, "error reading config")
   329  
   330  			var uconf stringFromFileConfig
   331  			err = config.EnhancedExactUnmarshal(&uconf)
   332  			require.NoError(t, err, "failed to unmarshal")
   333  			require.Exactly(t, expectedValue, uconf.Inner.Single)
   334  		})
   335  	}
   336  }
   337  
   338  func TestDecodeOpaqueField(t *testing.T) {
   339  	yaml := "---\nFoo: bar\nHello:\n  World: 42\n"
   340  
   341  	config := New()
   342  	err := config.ReadConfig(strings.NewReader(yaml))
   343  	require.NoError(t, err, "error reading config")
   344  
   345  	var conf struct {
   346  		Foo   string
   347  		Hello struct{ World int }
   348  	}
   349  	err = config.EnhancedExactUnmarshal(&conf)
   350  	require.NoError(t, err, "failed to unmarshal")
   351  	require.Equal(t, "bar", conf.Foo)
   352  	require.Equal(t, 42, conf.Hello.World)
   353  }
   354  
   355  func TestBCCSPDecodeHookOverride(t *testing.T) {
   356  	yaml := "---\nBCCSP:\n  Default: default-provider\n  SW:\n    Security: 999\n"
   357  
   358  	overrideVar := testEnvPrefix + "_BCCSP_SW_SECURITY"
   359  	os.Setenv(overrideVar, "1111")
   360  	defer os.Unsetenv(overrideVar)
   361  
   362  	config := New()
   363  	config.SetConfigName(testConfigName)
   364  	err := config.ReadConfig(strings.NewReader(yaml))
   365  	require.NoError(t, err, "error reading config")
   366  
   367  	var tc struct {
   368  		BCCSP *factory.FactoryOpts
   369  	}
   370  	err = config.EnhancedExactUnmarshal(&tc)
   371  	require.NoError(t, err, "failed to unmarshal")
   372  	require.NotNil(t, tc.BCCSP)
   373  	require.NotNil(t, tc.BCCSP.SW)
   374  	require.Equal(t, 1111, tc.BCCSP.SW.Security)
   375  }
   376  
   377  func TestDurationDecode(t *testing.T) {
   378  	tests := []struct {
   379  		input    string
   380  		expected time.Duration
   381  	}{
   382  		{"", 0},
   383  		{"100", 100 * time.Nanosecond},
   384  		{"1s", time.Second},
   385  		{"1m", time.Minute},
   386  		{"1m1s", 61 * time.Second},
   387  		{"90s", 90 * time.Second},
   388  	}
   389  	for _, tt := range tests {
   390  		t.Run(tt.expected.String(), func(t *testing.T) {
   391  			yaml := fmt.Sprintf("---\nDuration: %s\n", tt.input)
   392  
   393  			config := New()
   394  			config.SetConfigName(testConfigName)
   395  			err := config.ReadConfig(strings.NewReader(yaml))
   396  			require.NoError(t, err, "error reading config")
   397  
   398  			var conf struct{ Duration time.Duration }
   399  			err = config.EnhancedExactUnmarshal(&conf)
   400  			require.NoError(t, err, "failed to unmarshal")
   401  			require.Equal(t, tt.expected, conf.Duration)
   402  		})
   403  	}
   404  }