Skip to content

Commit

Permalink
Task: Get config cmd (#3552)
Browse files Browse the repository at this point in the history
* Task: Return error from keep alive methods within httputil pkg

* Initial commit for get config task

* Add unit tests

* Remove output package, change case default to last statement within switch, improve test setup

* modify test

* Add jsonString method

* make json string unexported

* Remove message struct and return endpoint data directly

* Add wrapped erorr

* use ExactValidArgs()

Co-authored-by: dustinxie <[email protected]>
Co-authored-by: huof6890 <[email protected]>
  • Loading branch information
3 people authored Jul 21, 2022
1 parent bc03a0e commit 23c6de5
Show file tree
Hide file tree
Showing 5 changed files with 207 additions and 12 deletions.
2 changes: 2 additions & 0 deletions ioctl/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ var (
ErrConfigNotMatch = fmt.Errorf("no matching config")
// ErrEmptyEndpoint indicates error for empty endpoint
ErrEmptyEndpoint = fmt.Errorf("no endpoint has been set")
// ErrConfigDefaultAccountNotSet indicates an error for the default account not being set
ErrConfigDefaultAccountNotSet = fmt.Errorf("default account not set")
)

// Language type used to enumerate supported language of ioctl
Expand Down
63 changes: 51 additions & 12 deletions ioctl/newcmd/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
package config

import (
"encoding/json"
"fmt"
"os"
"path"
"path/filepath"
"regexp"
"strconv"
Expand Down Expand Up @@ -95,7 +95,7 @@ func InitConfig() (config.Config, string, error) {
}
}
// Set language for ioctl
if info.isSupportedLanguage(info.readConfig.Language) == -1 {
if isSupportedLanguage(info.readConfig.Language) == -1 {
fmt.Printf("Warn: Language %s is not supported, English instead.\n", info.readConfig.Language)
}
return info.readConfig, info.defaultConfigFile, nil
Expand All @@ -111,7 +111,7 @@ func newInfo(readConfig config.Config, defaultConfigFile string) *info {

// reset resets all values of config
func (c *info) reset() error {
c.readConfig.Wallet = path.Dir(c.defaultConfigFile)
c.readConfig.Wallet = filepath.Dir(c.defaultConfigFile)
c.readConfig.Endpoint = ""
c.readConfig.SecureConnect = true
c.readConfig.DefaultAccount = *new(config.Context)
Expand All @@ -128,17 +128,34 @@ func (c *info) reset() error {
return nil
}

// isSupportedLanguage checks if the language is a supported option and returns index when supported
func (c *info) isSupportedLanguage(arg string) config.Language {
if index, err := strconv.Atoi(arg); err == nil && index >= 0 && index < len(_supportedLanguage) {
return config.Language(index)
}
for i, lang := range _supportedLanguage {
if strings.EqualFold(arg, lang) {
return config.Language(i)
// get retrieves a config item from its key.
func (c *info) get(arg string) (string, error) {
switch arg {
case "endpoint":
if c.readConfig.Endpoint == "" {
return "", config.ErrEmptyEndpoint
}
return fmt.Sprintf("%s secure connect(TLS): %t", c.readConfig.Endpoint, c.readConfig.SecureConnect), nil
case "wallet":
return c.readConfig.Wallet, nil
case "defaultacc":
if c.readConfig.DefaultAccount.AddressOrAlias == "" {
return "", config.ErrConfigDefaultAccountNotSet
}
return jsonString(c.readConfig.DefaultAccount)
case "explorer":
return c.readConfig.Explorer, nil
case "language":
return c.readConfig.Language, nil
case "nsv2height":
return strconv.FormatUint(c.readConfig.Nsv2height, 10), nil
case "analyserEndpoint":
return c.readConfig.AnalyserEndpoint, nil
case "all":
return jsonString(c.readConfig)
default:
return "", config.ErrConfigNotMatch
}
return config.Language(-1)
}

// writeConfig writes to config file
Expand All @@ -164,3 +181,25 @@ func (c *info) loadConfig() error {
}
return nil
}

// isSupportedLanguage checks if the language is a supported option and returns index when supported
func isSupportedLanguage(arg string) config.Language {
if index, err := strconv.Atoi(arg); err == nil && index >= 0 && index < len(_supportedLanguage) {
return config.Language(index)
}
for i, lang := range _supportedLanguage {
if strings.EqualFold(arg, lang) {
return config.Language(i)
}
}
return config.Language(-1)
}

// jsonString returns json string for message
func jsonString(input interface{}) (string, error) {
byteAsJSON, err := json.MarshalIndent(input, "", " ")
if err != nil {
return "", errors.Wrap(err, "failed to JSON marshal config field")
}
return fmt.Sprint(string(byteAsJSON)), nil
}
50 changes: 50 additions & 0 deletions ioctl/newcmd/config/config_get.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,53 @@
// License 2.0 that can be found in the LICENSE file.

package config

import (
"fmt"
"strings"

"github.com/pkg/errors"
"github.com/spf13/cobra"

"github.com/iotexproject/iotex-core/ioctl"
"github.com/iotexproject/iotex-core/ioctl/config"
)

var (
_configGetUse = map[config.Language]string{
config.English: "get VARIABLE",
config.Chinese: "get 变量",
}
_configGetUseCmdShorts = map[config.Language]string{
config.English: "Get config fields from ioctl",
config.Chinese: "从 ioctl 获取配置字段",
}
_configGetUseCmdLong = map[config.Language]string{
config.English: "Get config fields from ioctl\nValid Variables: [" + strings.Join(_validGetArgs, ", ") + "]",
config.Chinese: "从 ioctl 获取配置字段\n有效变量: [" + strings.Join(_validGetArgs, ", ") + "]",
}
)

// NewConfigGetCmd is a command to get config fields from iotcl.
func NewConfigGetCmd(client ioctl.Client) *cobra.Command {
use, _ := client.SelectTranslation(_configGetUse)
short, _ := client.SelectTranslation(_configGetUseCmdShorts)
long, _ := client.SelectTranslation(_configGetUseCmdLong)

return &cobra.Command{
Use: use,
Short: short,
Long: long,
ValidArgs: _validGetArgs,
Args: cobra.ExactValidArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
cmd.SilenceUsage = true
result, err := newInfo(client.Config(), client.ConfigFilePath()).get(args[0])
if err != nil {
return errors.Wrap(err, fmt.Sprintf("issue fetching config value %s", args[0]))
}
cmd.Println(result)
return nil
},
}
}
43 changes: 43 additions & 0 deletions ioctl/newcmd/config/config_get_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package config

import (
"fmt"
"testing"

"github.com/golang/mock/gomock"
"github.com/stretchr/testify/require"

"github.com/iotexproject/iotex-core/ioctl/config"
"github.com/iotexproject/iotex-core/ioctl/util"
"github.com/iotexproject/iotex-core/test/mock/mock_ioctlclient"
)

func TestNewConfigGetCmd(t *testing.T) {
require := require.New(t)
ctrl := gomock.NewController(t)
defer ctrl.Finish()
client := mock_ioctlclient.NewMockClient(ctrl)
client.EXPECT().Config().Return(config.Config{Endpoint: "test"}).AnyTimes()
client.EXPECT().SelectTranslation(gomock.Any()).Return("config reset", config.English).AnyTimes()

t.Run("get config value", func(t *testing.T) {
client.EXPECT().ConfigFilePath().Return(fmt.Sprintf("%s/%s", t.TempDir(), "config.file"))
cmd := NewConfigGetCmd(client)
result, err := util.ExecuteCmd(cmd, "endpoint")
require.NoError(err)
require.Contains(result, "test")
})

t.Run("get unknown config value", func(t *testing.T) {
cmd := NewConfigGetCmd(client)
_, err := util.ExecuteCmd(cmd, "random-args")
require.Contains(err.Error(), "invalid argument \"random-args\"")
})

t.Run("config value error", func(t *testing.T) {
client.EXPECT().ConfigFilePath().Return(fmt.Sprintf("%s/%s", t.TempDir(), "config.file"))
cmd := NewConfigGetCmd(client)
_, err := util.ExecuteCmd(cmd, "defaultacc")
require.Contains(err.Error(), "issue fetching config value defaultacc: default account not set")
})
}
61 changes: 61 additions & 0 deletions ioctl/newcmd/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,67 @@ func TestInitConfig(t *testing.T) {
require.Equal(filepath.Join(testPath, _defaultConfigFileName), cfgFilePath)
}

func TestConfigGet(t *testing.T) {
require := require.New(t)
testPath := t.TempDir()
info := newInfo(config.Config{
Wallet: testPath,
SecureConnect: true,
Aliases: make(map[string]string),
DefaultAccount: config.Context{AddressOrAlias: "test"},
Explorer: "iotexscan",
Language: "English",
AnalyserEndpoint: "testAnalyser",
}, testPath)

tcs := []struct {
arg string
expected string
}{
{
"endpoint",
"no endpoint has been set",
},
{
"wallet",
testPath,
},
{
"defaultacc",
"{\n \"addressOrAlias\": \"test\"\n}",
},
{
"explorer",
"iotexscan",
},
{
"language",
"English",
},
{
"nsv2height",
"0",
},
{
"analyserEndpoint",
"testAnalyser",
},
{
"all",
"\"endpoint\": \"\",\n \"secureConnect\": true,\n \"aliases\": {},\n \"defaultAccount\": {\n \"addressOrAlias\": \"test\"\n },\n \"explorer\": \"iotexscan\",\n \"language\": \"English\",\n \"nsv2height\": 0,\n \"analyserEndpoint\": \"testAnalyser\"\n}",
},
}

for _, tc := range tcs {
cfgItem, err := info.get(tc.arg)
if err != nil {
require.Contains(err.Error(), tc.expected)
} else {
require.Contains(cfgItem, tc.expected)
}
}
}

func TestConfigReset(t *testing.T) {
require := require.New(t)
cfgDir := t.TempDir()
Expand Down

0 comments on commit 23c6de5

Please sign in to comment.