github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/config/config_test.go (about)

     1  /*
     2   * Copyright (C) 2019 The "MysteriumNetwork/node" Authors.
     3   *
     4   * This program is free software: you can redistribute it and/or modify
     5   * it under the terms of the GNU General Public License as published by
     6   * the Free Software Foundation, either version 3 of the License, or
     7   * (at your option) any later version.
     8   *
     9   * This program is distributed in the hope that it will be useful,
    10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12   * GNU General Public License for more details.
    13   *
    14   * You should have received a copy of the GNU General Public License
    15   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16   */
    17  
    18  package config
    19  
    20  import (
    21  	"flag"
    22  	"os"
    23  	"strings"
    24  	"testing"
    25  
    26  	"github.com/mysteriumnetwork/node/services/datatransfer"
    27  	"github.com/mysteriumnetwork/node/services/dvpn"
    28  	"github.com/mysteriumnetwork/node/services/scraping"
    29  
    30  	"github.com/stretchr/testify/assert"
    31  	"github.com/urfave/cli/v2"
    32  )
    33  
    34  // This only tests user configuration, not the merging between multiple option sources
    35  func TestUserConfig_Load(t *testing.T) {
    36  	// given
    37  	configFileName := NewTempFileName(t)
    38  	defer os.Remove(configFileName)
    39  
    40  	toml := `
    41  		[openvpn]
    42  		port = 31338
    43  	`
    44  	err := os.WriteFile(configFileName, []byte(toml), 0700)
    45  	assert.NoError(t, err)
    46  
    47  	// when
    48  	cfg := NewConfig()
    49  	// then
    50  	assert.Nil(t, cfg.Get("openvpn.port"))
    51  
    52  	// when
    53  	err = cfg.LoadUserConfig(configFileName)
    54  	// then
    55  	assert.NoError(t, err)
    56  	assert.Equal(t, 31338, cfg.GetInt("openvpn.port"))
    57  }
    58  
    59  func TestUserConfig_Save(t *testing.T) {
    60  	// given
    61  	configFileName := NewTempFileName(t)
    62  	defer os.Remove(configFileName)
    63  
    64  	cfg := NewConfig()
    65  	err := cfg.LoadUserConfig(configFileName)
    66  	assert.NoError(t, err)
    67  
    68  	// when: app is configured with defaults + user + CLI values
    69  	cfg.SetDefault("openvpn.proto", "tcp")
    70  	cfg.SetDefault("openvpn.port", 55)
    71  	cfg.SetUser("openvpn.port", 22822)
    72  	cfg.SetCLI("openvpn.port", 40000)
    73  	// then: CLI values are prioritized over user over defaults
    74  	assert.Equal(t, "tcp", cfg.GetString("openvpn.proto"))
    75  	assert.Equal(t, 40000, cfg.GetInt("openvpn.port"))
    76  
    77  	// when: user configuration is saved
    78  	err = cfg.SaveUserConfig()
    79  	// then: only user configuration values are stored
    80  	assert.NoError(t, err)
    81  	tomlContent, err := os.ReadFile(configFileName)
    82  	assert.NoError(t, err)
    83  	assert.Contains(t, string(tomlContent), "port = 22822")
    84  	assert.NotContains(t, string(tomlContent), `proto = "tcp"`)
    85  }
    86  
    87  func NewTempFileName(t *testing.T) string {
    88  	file, err := os.CreateTemp("", "*")
    89  	assert.NoError(t, err)
    90  	return file.Name()
    91  }
    92  
    93  func TestConfig_ParseStringSliceFlag(t *testing.T) {
    94  	var tests = []struct {
    95  		name     string
    96  		args     string
    97  		defaults *cli.StringSlice
    98  		values   []string
    99  	}{
   100  		{
   101  			name:     "parse single value",
   102  			defaults: cli.NewStringSlice("api", "broker"),
   103  			args:     "--discovery.type broker",
   104  			values:   []string{"broker"},
   105  		},
   106  		{
   107  			name:     "parse multiple values",
   108  			defaults: cli.NewStringSlice("api", "broker"),
   109  			args:     "--discovery.type api --discovery.type broker",
   110  			values:   []string{"api", "broker"},
   111  		},
   112  		{
   113  			name:     "empty args use defaults",
   114  			defaults: cli.NewStringSlice("api", "broker"),
   115  			args:     "",
   116  			values:   []string{"api", "broker"},
   117  		},
   118  		{
   119  			name:   "nil default returns empty slice",
   120  			args:   "",
   121  			values: nil,
   122  		},
   123  	}
   124  
   125  	for _, tc := range tests {
   126  		t.Run(tc.name, func(t *testing.T) {
   127  			// given
   128  			sliceFlag := cli.StringSliceFlag{
   129  				Name:  "discovery.type",
   130  				Usage: `Proposal discovery adapter(s) separated by comma. Options: { "api", "broker", "api,broker" }`,
   131  				Value: tc.defaults,
   132  			}
   133  			cfg := NewConfig()
   134  			flagSet := flag.NewFlagSet("", flag.ContinueOnError)
   135  			must(t, sliceFlag.Apply(flagSet))
   136  			ctx := cli.NewContext(nil, flagSet, nil)
   137  			must(t, flagSet.Parse(strings.Split(tc.args, " ")))
   138  
   139  			// when
   140  			cfg.ParseStringSliceFlag(ctx, sliceFlag)
   141  			value := cfg.GetStringSlice(sliceFlag.Name)
   142  
   143  			// then
   144  			assert.Equal(t, tc.values, value)
   145  		})
   146  	}
   147  }
   148  
   149  // this can happen when updating config via tequilapi - json unmarshal
   150  // translates json number to float64 by default if target type is interface{}
   151  func TestSimilarTypeMerge(t *testing.T) {
   152  	// given
   153  	cfg := NewConfig()
   154  	cfg.SetDefault("openvpn.port", 1001)
   155  
   156  	// when
   157  	cfg.SetUser("openvpn.port", 55.00)
   158  
   159  	// then
   160  	assert.Equal(t, 55, cfg.GetInt("openvpn.port"))
   161  
   162  	actual, ok := cfg.GetConfig()["openvpn"]
   163  	assert.True(t, ok)
   164  
   165  	actual, ok = actual.(map[string]interface{})["port"]
   166  	assert.True(t, ok)
   167  
   168  	assert.Equal(t, 55.0, actual)
   169  }
   170  
   171  func TestUserConfig_Get(t *testing.T) {
   172  	cfg := NewConfig()
   173  
   174  	// when
   175  	cfg.SetDefault("openvpn.port", 1001)
   176  	// then
   177  	assert.Equal(t, 1001, cfg.Get("openvpn.port"))
   178  
   179  	// when
   180  	cfg.SetUser("openvpn.port", 1002)
   181  	// then
   182  	assert.Equal(t, 1002, cfg.Get("openvpn.port"))
   183  
   184  	// when
   185  	cfg.SetCLI("openvpn.port", 1003)
   186  	// then
   187  	assert.Equal(t, 1003, cfg.Get("openvpn.port"))
   188  }
   189  
   190  func TestUserConfig_GetConfig(t *testing.T) {
   191  	cfg := NewConfig()
   192  
   193  	// when
   194  	cfg.SetDefault("enabled", false)
   195  	cfg.SetDefault("openvpn.port", 1001)
   196  	// then
   197  	assert.Equal(
   198  		t,
   199  		map[string]interface{}{
   200  			"enabled": false,
   201  			"openvpn": map[string]interface{}{
   202  				"port": 1001,
   203  			},
   204  		},
   205  		cfg.GetConfig(),
   206  	)
   207  
   208  	// when
   209  	cfg.SetUser("openvpn.port", 1002)
   210  	// then
   211  	assert.Equal(
   212  		t,
   213  		map[string]interface{}{
   214  			"enabled": false,
   215  			"openvpn": map[string]interface{}{
   216  				"port": 1002,
   217  			},
   218  		},
   219  		cfg.GetConfig(),
   220  	)
   221  
   222  	// when
   223  	cfg.SetCLI("enabled", true)
   224  	cfg.SetCLI("openvpn.port", 1003)
   225  	// then
   226  	assert.Equal(
   227  		t,
   228  		map[string]interface{}{
   229  			"enabled": true,
   230  			"openvpn": map[string]interface{}{
   231  				"port": 1003,
   232  			},
   233  		},
   234  		cfg.GetConfig(),
   235  	)
   236  }
   237  
   238  func TestHardcodedServicesNameFlagValues(t *testing.T) {
   239  	// importing these constants into config package create cyclic dependency
   240  	assert.Equal(t, strings.Join([]string{scraping.ServiceType, datatransfer.ServiceType, dvpn.ServiceType}, ","), FlagActiveServices.Value)
   241  }
   242  
   243  func must(t *testing.T, err error) {
   244  	assert.NoError(t, err)
   245  }