package commands import ( "fmt" "os" "path/filepath" "strconv" "testing" "github.com/spf13/cobra" "github.com/spf13/viper" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" cfg "github.com/cometbft/cometbft/config" "github.com/cometbft/cometbft/libs/cli" cmtos "github.com/cometbft/cometbft/libs/os" ) // clearConfig clears env vars, the given root dir, and resets viper. func clearConfig(t *testing.T, dir string) { os.Clearenv() err := os.RemoveAll(dir) require.NoError(t, err) viper.Reset() config = cfg.DefaultConfig() } // prepare new rootCmd func testRootCmd() *cobra.Command { rootCmd := &cobra.Command{ Use: RootCmd.Use, PersistentPreRunE: RootCmd.PersistentPreRunE, Run: func(cmd *cobra.Command, args []string) {}, } registerFlagsRootCmd(rootCmd) var l string rootCmd.PersistentFlags().String("log", l, "Log") return rootCmd } func testSetup(t *testing.T, root string, args []string, env map[string]string) error { clearConfig(t, root) rootCmd := testRootCmd() cmd := cli.PrepareBaseCmd(rootCmd, "CMT", root) // run with the args and env args = append([]string{rootCmd.Use}, args...) return cli.RunWithArgs(cmd, args, env) } func TestRootHome(t *testing.T) { tmpDir := os.TempDir() root := filepath.Join(tmpDir, "adir") newRoot := filepath.Join(tmpDir, "something-else") defer clearConfig(t, root) defer clearConfig(t, newRoot) cases := []struct { args []string env map[string]string root string }{ {nil, nil, root}, {[]string{"--home", newRoot}, nil, newRoot}, {nil, map[string]string{"TMHOME": newRoot}, newRoot}, // XXX: Deprecated. {nil, map[string]string{"CMTHOME": newRoot}, newRoot}, } for i, tc := range cases { idxString := "idx: " + strconv.Itoa(i) err := testSetup(t, root, tc.args, tc.env) require.Nil(t, err, idxString) assert.Equal(t, tc.root, config.RootDir, idxString) assert.Equal(t, tc.root, config.P2P.RootDir, idxString) assert.Equal(t, tc.root, config.Consensus.RootDir, idxString) assert.Equal(t, tc.root, config.Mempool.RootDir, idxString) } } func TestRootFlagsEnv(t *testing.T) { // defaults defaults := cfg.DefaultConfig() defaultLogLvl := defaults.LogLevel cases := []struct { args []string env map[string]string logLevel string }{ {[]string{"--log", "debug"}, nil, defaultLogLvl}, // wrong flag {[]string{"--log_level", "debug"}, nil, "debug"}, // right flag {nil, map[string]string{"TM_LOW": "debug"}, defaultLogLvl}, // wrong env flag {nil, map[string]string{"MT_LOG_LEVEL": "debug"}, defaultLogLvl}, // wrong env prefix {nil, map[string]string{"TM_LOG_LEVEL": "debug"}, defaultLogLvl}, // right, but deprecated env {nil, map[string]string{"CMT_LOW": "debug"}, defaultLogLvl}, // wrong env flag {nil, map[string]string{"TMC_LOG_LEVEL": "debug"}, defaultLogLvl}, // wrong env prefix {nil, map[string]string{"CMT_LOG_LEVEL": "debug"}, "debug"}, // right env } for i, tc := range cases { idxString := strconv.Itoa(i) root := filepath.Join(os.TempDir(), "adir2_"+idxString) idxString = "idx: " + idxString defer clearConfig(t, root) err := testSetup(t, root, tc.args, tc.env) require.Nil(t, err, idxString) assert.Equal(t, tc.logLevel, config.LogLevel, idxString) } } func TestRootConfig(t *testing.T) { // write non-default config nonDefaultLogLvl := "abc:debug" cvals := map[string]string{ "log_level": nonDefaultLogLvl, } cases := []struct { args []string env map[string]string logLvl string }{ {nil, nil, nonDefaultLogLvl}, // should load config {[]string{"--log_level=abc:info"}, nil, "abc:info"}, // flag over rides {nil, map[string]string{"TM_LOG_LEVEL": "abc:info"}, nonDefaultLogLvl}, // env over rides //XXX: Deprecated {nil, map[string]string{"CMT_LOG_LEVEL": "abc:info"}, "abc:info"}, // env over rides } for i, tc := range cases { idxString := strconv.Itoa(i) root := filepath.Join(os.TempDir(), "adir3_"+idxString) idxString = "idx: " + idxString defer clearConfig(t, root) // XXX: path must match cfg.defaultConfigPath configFilePath := filepath.Join(root, "config") err := cmtos.EnsureDir(configFilePath, 0o700) require.Nil(t, err) // write the non-defaults to a different path // TODO: support writing sub configs so we can test that too err = WriteConfigVals(configFilePath, cvals) require.Nil(t, err) rootCmd := testRootCmd() cmd := cli.PrepareBaseCmd(rootCmd, "CMT", root) // run with the args and env tc.args = append([]string{rootCmd.Use}, tc.args...) err = cli.RunWithArgs(cmd, tc.args, tc.env) require.Nil(t, err, idxString) assert.Equal(t, tc.logLvl, config.LogLevel, idxString) } } // WriteConfigVals writes a toml file with the given values. // It returns an error if writing was impossible. func WriteConfigVals(dir string, vals map[string]string) error { data := "" for k, v := range vals { data += fmt.Sprintf("%s = \"%s\"\n", k, v) } cfile := filepath.Join(dir, "config.toml") return os.WriteFile(cfile, []byte(data), 0o600) }