trpc.group/trpc-go/trpc-go@v1.0.3/config/config_test.go (about)

     1  //
     2  //
     3  // Tencent is pleased to support the open source community by making tRPC available.
     4  //
     5  // Copyright (C) 2023 THL A29 Limited, a Tencent company.
     6  // All rights reserved.
     7  //
     8  // If you have downloaded a copy of the tRPC source code from Tencent,
     9  // please note that tRPC source code is licensed under the  Apache 2.0 License,
    10  // A copy of the Apache 2.0 License is included in this file.
    11  //
    12  //
    13  
    14  package config_test
    15  
    16  import (
    17  	"bytes"
    18  	"context"
    19  	"encoding/json"
    20  	"fmt"
    21  	"sync"
    22  	"testing"
    23  
    24  	"github.com/stretchr/testify/assert"
    25  	"github.com/stretchr/testify/require"
    26  
    27  	"trpc.group/trpc-go/trpc-go/client"
    28  	"trpc.group/trpc-go/trpc-go/config"
    29  
    30  	trpc "trpc.group/trpc-go/trpc-go"
    31  )
    32  
    33  type mockResponse struct {
    34  	val string
    35  }
    36  
    37  func (r *mockResponse) Value() string {
    38  	return r.val
    39  }
    40  
    41  func (r *mockResponse) MetaData() map[string]string {
    42  	return nil
    43  }
    44  
    45  func (r *mockResponse) Event() config.EventType {
    46  	return config.EventTypeNull
    47  }
    48  
    49  type mockKV struct {
    50  	mu sync.RWMutex
    51  	db map[string]string
    52  }
    53  
    54  // Put mocks putting key and value into kv storage.
    55  func (kv *mockKV) Put(ctx context.Context, key, val string, opts ...config.Option) error {
    56  	kv.mu.Lock()
    57  	kv.db[key] = val
    58  	kv.mu.Unlock()
    59  	return nil
    60  }
    61  
    62  // Get mocks getting value from kv storage by key.
    63  func (kv *mockKV) Get(ctx context.Context, key string, opts ...config.Option) (config.Response, error) {
    64  	kv.mu.RLock()
    65  	defer kv.mu.RUnlock()
    66  	if val, ok := kv.db[key]; ok {
    67  		v := &mockResponse{val: val}
    68  		return v, nil
    69  	}
    70  
    71  	return nil, fmt.Errorf("invalid key")
    72  }
    73  
    74  // Watch makes mockKV satisfy the KV interface, this method
    75  // is empty.
    76  func (kv *mockKV) Watch(ctx context.Context, key string, opts ...config.Option) (<-chan config.Response, error) {
    77  	return nil, nil
    78  }
    79  
    80  func (kv *mockKV) Name() string {
    81  	return "mock"
    82  }
    83  
    84  // Del makes mockKV satisfy the KV interface, this method
    85  // is empty.
    86  func (kv *mockKV) Del(ctx context.Context, key string, opts ...config.Option) error {
    87  	return nil
    88  }
    89  
    90  type mockValue struct {
    91  	Age  int
    92  	Name string
    93  }
    94  
    95  func TestGlobalKV(t *testing.T) {
    96  	kv := config.GlobalKV()
    97  
    98  	mock := "foo"
    99  
   100  	err := kv.Put(context.Background(), "mockString", mock)
   101  	assert.Nil(t, err)
   102  
   103  	val, err := kv.Get(context.Background(), "mockString")
   104  	assert.NotNil(t, err)
   105  	assert.Nil(t, val)
   106  
   107  	err = kv.Del(context.Background(), "mockString")
   108  	assert.Nil(t, err)
   109  
   110  	config.SetGlobalKV(&mockKV{})
   111  	assert.NotNil(t, config.GlobalKV())
   112  }
   113  
   114  func TestGetConfigInfo(t *testing.T) {
   115  	c := &mockKV{
   116  		db: make(map[string]string),
   117  	}
   118  	config.SetGlobalKV(c)
   119  	config.Register(c)
   120  
   121  	{
   122  		tmp := `
   123  age: 20
   124  name: 'foo'
   125  `
   126  		err := c.Put(context.Background(), "mockYAMLKey", tmp)
   127  		assert.Nil(t, err)
   128  
   129  		v := &mockValue{}
   130  		err = config.GetYAML("mockYAMLKey", v)
   131  		assert.Nil(t, err)
   132  		assert.Equal(t, 20, v.Age)
   133  		assert.Equal(t, "foo", v.Name)
   134  		err = config.GetYAMLWithProvider("mockYAMLKey", v, "mock")
   135  		assert.Nil(t, err)
   136  		assert.Equal(t, 20, v.Age)
   137  		assert.Equal(t, "foo", v.Name)
   138  		err = config.GetYAMLWithProvider("mockYAMLKey", v, "mockNotExist")
   139  		assert.NotNil(t, err)
   140  	}
   141  
   142  	// Test GetJson
   143  	{
   144  		tmp := &mockValue{
   145  			Age:  20,
   146  			Name: "foo",
   147  		}
   148  		tmpStr, err := json.Marshal(tmp)
   149  		assert.Nil(t, err)
   150  		err = c.Put(context.Background(), "mockJsonKey", string(tmpStr))
   151  		assert.Nil(t, err)
   152  
   153  		v := &mockValue{}
   154  		err = config.GetJSON("mockJsonKey", v)
   155  		assert.Nil(t, err)
   156  		assert.Equal(t, 20, v.Age)
   157  		assert.Equal(t, "foo", v.Name)
   158  		err = config.GetJSONWithProvider("mockJsonKey", v, "mock")
   159  		assert.Nil(t, err)
   160  		assert.Equal(t, 20, v.Age)
   161  		assert.Equal(t, "foo", v.Name)
   162  		err = config.GetJSONWithProvider("mockJsonKey", v, "mockNotExist")
   163  		assert.NotNil(t, err)
   164  
   165  		codec := &config.JSONCodec{}
   166  		out := make(map[string]string)
   167  		codec.Unmarshal(tmpStr, &out)
   168  	}
   169  
   170  	// Test GetWithUnmarshal
   171  	{
   172  
   173  		v := &mockValue{}
   174  		err := config.GetWithUnmarshal("mockJsonKey1", v, "json")
   175  		assert.NotNil(t, err)
   176  	}
   177  
   178  	// Test GetToml
   179  	{
   180  		tmp := `
   181  age = 20
   182  name = "foo"
   183  `
   184  		err := c.Put(context.Background(), "mockTomlKey", tmp)
   185  		assert.Nil(t, err)
   186  
   187  		v := &mockValue{}
   188  		err = config.GetTOML("mockTomlKey", v)
   189  		assert.Nil(t, err)
   190  		assert.Equal(t, 20, v.Age)
   191  		assert.Equal(t, "foo", v.Name)
   192  		err = config.GetTOMLWithProvider("mockTomlKey", v, "mock")
   193  		assert.Nil(t, err)
   194  		assert.Equal(t, 20, v.Age)
   195  		assert.Equal(t, "foo", v.Name)
   196  		err = config.GetTOMLWithProvider("mockTomlKey", v, "mockNotExist")
   197  		assert.NotNil(t, err)
   198  	}
   199  
   200  	// Test GetString
   201  	{
   202  		mock := "foo"
   203  		c.Put(context.Background(), "mockString", mock)
   204  		val, err := config.GetString("mockString")
   205  		assert.Nil(t, err)
   206  		assert.Equal(t, mock, val)
   207  		_, err = config.GetString("mockString1")
   208  		assert.NotNil(t, err)
   209  	}
   210  	{
   211  		mock := 1
   212  		c.Put(context.Background(), "mockInt", fmt.Sprint(mock))
   213  		val, err := config.GetInt("mockInt")
   214  		assert.Nil(t, err)
   215  		assert.Equal(t, mock, val)
   216  		_, err = config.GetInt("mockInt1")
   217  		assert.NotNil(t, err)
   218  	}
   219  
   220  	// Test Get
   221  	{
   222  		c := config.Get("mock")
   223  		assert.NotNil(t, c)
   224  	}
   225  }
   226  
   227  // TestGetConfigGetDefault tests getting default value when
   228  // key is absent.
   229  func TestGetConfigGetDefault(t *testing.T) {
   230  	c := &mockKV{
   231  		db: make(map[string]string),
   232  	}
   233  	config.SetGlobalKV(c)
   234  	config.Register(c)
   235  
   236  	// Test GetStringWithDefault
   237  	{
   238  		// get key successfully.
   239  		mock := "foo"
   240  		c.Put(context.Background(), "mockString", mock)
   241  		val := config.GetStringWithDefault("mockString", "otherValue")
   242  		assert.Equal(t, mock, val)
   243  
   244  		// key is absent, get default value.
   245  		def := "myDefaultValue"
   246  		val = config.GetStringWithDefault("whatever", def)
   247  		assert.Equal(t, val, def)
   248  	}
   249  	// Test GetIntWithDefault
   250  	{
   251  		// get key successfully.
   252  		mockint := 555
   253  		c.Put(context.Background(), "mockInt", fmt.Sprint(mockint))
   254  		val := config.GetIntWithDefault("mockInt", 123)
   255  		assert.Equal(t, mockint, val)
   256  
   257  		// key is absent, get default value.
   258  		def := 888
   259  		val = config.GetIntWithDefault("whatever", def)
   260  		assert.Equal(t, val, def)
   261  
   262  		// key exists, but fail to transfers to target type,
   263  		// get default value.
   264  		mockstr := "foo"
   265  		c.Put(context.Background(), "whatever", mockstr)
   266  		val = config.GetIntWithDefault("whatever", def)
   267  		assert.Equal(t, val, def)
   268  	}
   269  }
   270  
   271  func TestLoadYaml(t *testing.T) {
   272  	require := require.New(t)
   273  	err := config.Reload("../testdata/trpc_go.yaml", config.WithCodec("yaml"))
   274  	require.NotNil(err)
   275  
   276  	_, err = config.Load("../testdata/trpc_go.yaml.1", config.WithCodec("yaml"))
   277  	require.NotNil(err)
   278  
   279  	c, err := config.Load("../testdata/trpc_go.yaml", config.WithCodec("yaml"))
   280  	require.Nil(err, "failed to load config")
   281  	// out := &T{}
   282  	out := c.GetString("server.app", "")
   283  	t.Logf("return %+v", out)
   284  	require.Equal(out, "test", "app name is wrong")
   285  
   286  	buf := c.Bytes()
   287  	require.NotNil(buf)
   288  	bytes.Contains(buf, []byte("test"))
   289  
   290  	err = config.Reload("../testdata/trpc_go.yaml")
   291  	require.Nil(err)
   292  
   293  	require.Implements((*config.Config)(nil), c)
   294  }
   295  
   296  func TestLoadToml(t *testing.T) {
   297  	require := require.New(t)
   298  	rightPath := "../testdata/custom.toml"
   299  	wrongPath := "../testdata/custom.toml.1"
   300  
   301  	err := config.Reload(rightPath, config.WithCodec("toml"))
   302  	require.NotNil(err)
   303  
   304  	_, err = config.Load(wrongPath, config.WithCodec("toml"))
   305  	require.NotNil(err, "path not exist")
   306  	t.Logf("load with not exist path, err:%v", err)
   307  
   308  	c, err := config.Load(rightPath, config.WithCodec("toml"))
   309  	require.Nil(err, "failed to load config")
   310  	// out := &T{}
   311  	out := c.GetString("server.app", "")
   312  	t.Logf("return %s", out)
   313  	require.Equal(out, "test", "app name is wrong")
   314  
   315  	buf := c.Bytes()
   316  	require.NotNil(buf)
   317  	bytes.Contains(buf, []byte("test"))
   318  
   319  	obj := struct {
   320  		Server struct {
   321  			App      string
   322  			P        int `toml:"port"`
   323  			Protocol []string
   324  		}
   325  	}{}
   326  
   327  	err = c.Unmarshal(&obj)
   328  	require.Nil(err, "unmarshal should succ")
   329  	t.Logf("unmarshal struct:%+v", obj)
   330  	require.Equal(obj.Server.P, 1000)
   331  	require.Equal(len(obj.Server.Protocol), 2)
   332  
   333  	err = config.Reload("../testdata/custom.toml", config.WithCodec("toml"))
   334  	require.Nil(err)
   335  
   336  	require.Implements((*config.Config)(nil), c)
   337  }
   338  
   339  func TestLoadUnmarshal(t *testing.T) {
   340  	require := require.New(t)
   341  	config, err := config.Load("../testdata/trpc_go.yaml", config.WithCodec("yaml"))
   342  	require.Nil(err, "failed to load config")
   343  
   344  	out := &trpc.Config{}
   345  	err = config.Unmarshal(out)
   346  
   347  	require.Nil(err, "failed to load config")
   348  	t.Logf("return %+v", *out)
   349  }
   350  
   351  func TestLoadUnmarshalClient(t *testing.T) {
   352  	require := require.New(t)
   353  	config, err := config.Load("../testdata/client.yaml", config.WithCodec("yaml"))
   354  	require.Nil(err, "failed to load config")
   355  
   356  	out := client.DefaultClientConfig()
   357  	err = config.Unmarshal(&out)
   358  	t.Logf("return %+v %s", out["Test.HelloServer"], err)
   359  	require.Nil(err, "failed to load client config")
   360  }
   361  
   362  func TestGetString(t *testing.T) {
   363  	require := require.New(t)
   364  	c, err := config.Load("../testdata/trpc_go.yaml", config.WithCodec("yaml"))
   365  	require.Nil(err, "failed to load config")
   366  
   367  	out := c.GetString("server.app", "cc")
   368  	t.Logf("return %+v", out)
   369  	require.Equal("test", out, "app name is wrong")
   370  
   371  	out = c.GetString("server.app1", "cc")
   372  	t.Logf("return %+v", out)
   373  	require.Equal("cc", out, "app name is wrong")
   374  
   375  	out = c.GetString("server.admin.port", "cc")
   376  	t.Logf("return %+v", out)
   377  	require.Equal("9528", out, "app name is wrong")
   378  
   379  	out = c.GetString("server.admin", "cc")
   380  	t.Logf("return %+v", out)
   381  	require.Equal("cc", out, "app name is wrong")
   382  }
   383  
   384  func TestGetBool(t *testing.T) {
   385  	require := require.New(t)
   386  	c, err := config.Load("../testdata/trpc_go.yaml", config.WithCodec("yaml"))
   387  	require.Nil(err, "failed to load config")
   388  
   389  	out := c.GetBool("server.admin_port123", false)
   390  	t.Logf("return %+v", out)
   391  	require.Equal(false, out)
   392  
   393  	out = c.GetBool("server.app", false)
   394  	t.Logf("return %+v", out)
   395  	require.Equal(false, out)
   396  }
   397  
   398  func TestGet(t *testing.T) {
   399  	require := require.New(t)
   400  	c, err := config.Load("../testdata/trpc_go.yaml", config.WithCodec("yaml"))
   401  	require.Nil(err, "failed to load config")
   402  
   403  	out := c.Get("server.admin_port123", 10001)
   404  	t.Logf("return %+v", out)
   405  	require.Equal(10001, out)
   406  }
   407  
   408  func TestGetUint(t *testing.T) {
   409  	require := require.New(t)
   410  	c, err := config.Load("../testdata/trpc_go.yaml", config.WithCodec("yaml"))
   411  	require.Nil(err, "failed to load config")
   412  
   413  	{
   414  		actual := uint(9528)
   415  		dft := uint(10001)
   416  
   417  		out := c.GetUint("server.admin.port", dft)
   418  		t.Logf("return %+v", out)
   419  		require.Equal(actual, out)
   420  
   421  		out = c.GetUint("server.admin_port123", dft)
   422  		t.Logf("return %+v", out)
   423  		require.Equal(dft, out)
   424  
   425  		out = c.GetUint("server.app", dft)
   426  		t.Logf("return %+v", out)
   427  		require.Equal(dft, out)
   428  	}
   429  
   430  	{
   431  		actual := uint32(9528)
   432  		dft := uint32(10001)
   433  
   434  		out := c.GetUint32("server.admin.port", dft)
   435  		t.Logf("return %+v", out)
   436  		require.Equal(actual, out)
   437  
   438  		out = c.GetUint32("server.admin_port123", dft)
   439  		t.Logf("return %+v", out)
   440  		require.Equal(dft, out)
   441  
   442  		out = c.GetUint32("server.app", dft)
   443  		t.Logf("return %+v", out)
   444  		require.Equal(dft, out)
   445  	}
   446  
   447  	{
   448  		actual := uint64(9528)
   449  		dft := uint64(10001)
   450  
   451  		out := c.GetUint64("server.admin.port", dft)
   452  		t.Logf("return %+v", out)
   453  		require.Equal(actual, out)
   454  
   455  		out = c.GetUint64("server.admin_port123", dft)
   456  		t.Logf("return %+v", out)
   457  		require.Equal(dft, out)
   458  
   459  		out = c.GetUint64("server.app", dft)
   460  		t.Logf("return %+v", out)
   461  		require.Equal(dft, out)
   462  	}
   463  
   464  }
   465  
   466  func TestGetInt(t *testing.T) {
   467  	require := require.New(t)
   468  	c, err := config.Load("../testdata/trpc_go.yaml", config.WithCodec("yaml"))
   469  	require.Nil(err, "failed to load config")
   470  
   471  	{
   472  		actual := 9528
   473  		dft := 10001
   474  
   475  		out := c.GetInt("server.admin.port", dft)
   476  		t.Logf("return %+v", out)
   477  		require.Equal(actual, out)
   478  
   479  		out = c.GetInt("server.admin_port123", dft)
   480  		t.Logf("return %+v", out)
   481  		require.Equal(dft, out)
   482  
   483  		out = c.GetInt("server.app", dft)
   484  		t.Logf("return %+v", out)
   485  		require.Equal(dft, out)
   486  	}
   487  
   488  	{
   489  		actual := int32(9528)
   490  		dft := int32(10001)
   491  
   492  		out := c.GetInt32("server.admin.port", dft)
   493  		t.Logf("return %+v", out)
   494  		require.Equal(actual, out)
   495  
   496  		out = c.GetInt32("server.admin_port123", dft)
   497  		t.Logf("return %+v", out)
   498  		require.Equal(dft, out)
   499  
   500  		out = c.GetInt32("server.app", dft)
   501  		t.Logf("return %+v", out)
   502  		require.Equal(dft, out)
   503  	}
   504  
   505  	{
   506  		actual := int64(9528)
   507  		dft := int64(10001)
   508  
   509  		out := c.GetInt64("server.admin.port", dft)
   510  		t.Logf("return %+v", out)
   511  		require.Equal(actual, out)
   512  
   513  		out = c.GetInt64("server.admin_port123", dft)
   514  		t.Logf("return %+v", out)
   515  		require.Equal(dft, out)
   516  
   517  		out = c.GetInt64("server.app", dft)
   518  		t.Logf("return %+v", out)
   519  		require.Equal(dft, out)
   520  	}
   521  
   522  }
   523  
   524  func TestGetFloat(t *testing.T) {
   525  	require := require.New(t)
   526  	c, err := config.Load("../testdata/trpc_go.yaml", config.WithCodec("yaml"))
   527  	require.Nil(err, "failed to load config")
   528  
   529  	{
   530  		actual := float64(9528)
   531  		dft := float64(1.0)
   532  
   533  		out := c.GetFloat64("server.admin.port", dft)
   534  		t.Logf("return %+v", out)
   535  		require.Equal(actual, out)
   536  
   537  		out = c.GetFloat64("server.admin_port123", dft)
   538  		t.Logf("return %+v", out)
   539  		require.Equal(dft, out)
   540  
   541  		out = c.GetFloat64("server.app", dft)
   542  		t.Logf("return %+v", out)
   543  		require.Equal(dft, out)
   544  
   545  	}
   546  
   547  	{
   548  		actual := float32(9528)
   549  		dft := float32(1.0)
   550  
   551  		out := c.GetFloat32("server.admin.port", dft)
   552  		t.Logf("return %+v", out)
   553  		require.Equal(actual, out)
   554  
   555  		out = c.GetFloat32("server.admin_port123", dft)
   556  		t.Logf("return %+v", out)
   557  		require.Equal(dft, out)
   558  
   559  		out = c.GetFloat32("server.app", dft)
   560  		t.Logf("return %+v", out)
   561  		require.Equal(dft, out)
   562  
   563  	}
   564  }
   565  
   566  func TestIsSet(t *testing.T) {
   567  	require := require.New(t)
   568  	c, err := config.Load("../testdata/trpc_go.yaml", config.WithCodec("yaml"))
   569  	require.Nil(err, "failed to load config")
   570  
   571  	out := c.IsSet("server.admin.port")
   572  	require.Equal(true, out)
   573  	out = c.IsSet("server.admin_port1")
   574  	require.Equal(false, out)
   575  }
   576  
   577  func TestUnmarshal(t *testing.T) {
   578  	require := require.New(t)
   579  	c, err := config.Load("../testdata/trpc_go.yaml", config.WithCodec("yaml"), config.WithProvider("file"))
   580  	require.Nil(err, "failed to load config")
   581  	var b struct {
   582  		Server struct {
   583  			App string
   584  		}
   585  	}
   586  	err = c.Unmarshal(&b)
   587  	require.Nil(err)
   588  	require.Equal("test", b.Server.App, "failed to read item")
   589  }
   590  
   591  func TestLoad(t *testing.T) {
   592  	c, err := config.Load("../testdata/trpc_go.yaml2", config.WithCodec("yaml"), config.WithProvider("file"))
   593  	assert.NotNil(t, err)
   594  	assert.Nil(t, c)
   595  
   596  	c, err = config.Load("../testdata/trpc_go.yaml", config.WithCodec("yaml1"))
   597  	assert.NotNil(t, err)
   598  	assert.Nil(t, c)
   599  
   600  	c, err = config.Load("../testdata/trpc_go.yaml", config.WithProvider("etcd"))
   601  	assert.NotNil(t, err)
   602  	assert.Nil(t, c)
   603  }
   604  
   605  func TestProvider(t *testing.T) {
   606  	require := require.New(t)
   607  	p := &config.FileProvider{}
   608  	require.Equal("file", p.Name())
   609  	config.RegisterProvider(p)
   610  	pp := config.GetProvider("file")
   611  	require.Equal(p, pp)
   612  }