github.com/iotexproject/iotex-core@v1.14.1-rc1/ioctl/client_test.go (about)

     1  // Copyright (c) 2022 IoTeX Foundation
     2  // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability
     3  // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed.
     4  // This source code is governed by Apache License 2.0 that can be found in the LICENSE file.
     5  
     6  package ioctl
     7  
     8  import (
     9  	"context"
    10  	"fmt"
    11  	"os"
    12  	"strings"
    13  	"testing"
    14  
    15  	"github.com/stretchr/testify/require"
    16  	"gopkg.in/yaml.v2"
    17  
    18  	"github.com/iotexproject/iotex-core/ioctl/config"
    19  )
    20  
    21  func TestStop(t *testing.T) {
    22  	r := require.New(t)
    23  	c := NewClient(config.Config{}, "", EnableCryptoSm2())
    24  	c.SetEndpointWithFlag(func(p *string, _ string, _ string, _ string) {
    25  		*p = "127.0.0.1:14014"
    26  	})
    27  	c.SetInsecureWithFlag(func(p *bool, _ string, _ bool, _ string) {
    28  		*p = true
    29  	})
    30  	_, err := c.APIServiceClient()
    31  	r.NoError(err)
    32  	err = c.Stop(context.Background())
    33  	r.NoError(err)
    34  }
    35  
    36  func TestAskToConfirm(t *testing.T) {
    37  	r := require.New(t)
    38  	c := NewClient(config.Config{}, "")
    39  	defer c.Stop(context.Background())
    40  	confirmed, err := c.AskToConfirm("test")
    41  	// no input
    42  	r.Equal("EOF", err.Error())
    43  	r.False(confirmed)
    44  }
    45  
    46  func TestAPIServiceClient(t *testing.T) {
    47  	r := require.New(t)
    48  	c := NewClient(config.Config{}, "")
    49  	defer c.Stop(context.Background())
    50  
    51  	apiServiceClient, err := c.APIServiceClient()
    52  	r.Contains(err.Error(), `use "ioctl config set endpoint" to config endpoint first`)
    53  	r.Nil(apiServiceClient)
    54  
    55  	c.SetEndpointWithFlag(func(p *string, _ string, _ string, _ string) {
    56  		*p = "127.0.0.1:14011"
    57  	})
    58  	c.SetInsecureWithFlag(func(p *bool, _ string, _ bool, _ string) {
    59  		*p = true
    60  	})
    61  	apiServiceClient, err = c.APIServiceClient()
    62  	r.NoError(err)
    63  	r.NotNil(apiServiceClient)
    64  
    65  	c.SetEndpointWithFlag(func(p *string, _ string, _ string, _ string) {
    66  		*p = "127.0.0.1:14014"
    67  	})
    68  	c.SetInsecureWithFlag(func(p *bool, _ string, _ bool, _ string) {
    69  		*p = false
    70  	})
    71  	apiServiceClient, err = c.APIServiceClient()
    72  	r.NoError(err)
    73  	r.NotNil(apiServiceClient)
    74  }
    75  
    76  func TestGetAddress(t *testing.T) {
    77  	type Data struct {
    78  		cfg    config.Config
    79  		in     string
    80  		out    string
    81  		errMsg string
    82  	}
    83  
    84  	tests := []Data{
    85  		{
    86  			config.Config{
    87  				Aliases:        map[string]string{"": ""},
    88  				DefaultAccount: config.Context{AddressOrAlias: "abcdef"},
    89  			}, "abcdef", "", "cannot find address from",
    90  		},
    91  
    92  		{
    93  			config.Config{
    94  				Aliases: map[string]string{
    95  					"000io187evpmjdankjh0g5dfz83w2z3p23ljhn4s9jw7": "io1cjh35tq9k8fu0gqcsat4px7yr8trh75c95hc5r",
    96  					"bbb": "io1cjh35tq9k8fu0gqcsat4px7yr8trh75c95hbbb",
    97  				},
    98  				DefaultAccount: config.Context{AddressOrAlias: "000io187evpmjdankjh0g5dfz83w2z3p23ljhn4s9jw7"},
    99  			}, "000io187evpmjdankjh0g5dfz83w2z3p23ljhn4s9jw7", "", "invalid IoTeX address",
   100  		},
   101  
   102  		{
   103  			config.Config{
   104  				Aliases: map[string]string{
   105  					"bbb": "io1cjh35tq9k8fu0gqcsat4px7yr8trh75c95hbbb",
   106  				},
   107  				DefaultAccount: config.Context{AddressOrAlias: ""},
   108  			}, "", "", `use "ioctl config set defaultacc ADDRESS|ALIAS" to config default account first`,
   109  		},
   110  
   111  		{
   112  			config.Config{
   113  				Aliases: map[string]string{
   114  					"abcdef": "io1cjh35tq9k8fu0gqcsat4px7yr8trh75c95hc5r",
   115  					"bbb":    "io1cjh35tq9k8fu0gqcsat4px7yr8trh75c95hbbb",
   116  				},
   117  				DefaultAccount: config.Context{AddressOrAlias: ""},
   118  			}, "abcdef", "io1cjh35tq9k8fu0gqcsat4px7yr8trh75c95hc5r", "",
   119  		},
   120  
   121  		{
   122  			config.Config{
   123  				Aliases: map[string]string{
   124  					"ccc": "io1cjh35tq9k8fu0gqcsat4px7yr8trh75c95hccc",
   125  					"abc": "io1cjh35tq9k8fu0gqcsat4px7yr8trh75c95aabc",
   126  					"bbb": "io1cjh35tq9k8fu0gqcsat4px7yr8trh75c95hbbb",
   127  				},
   128  				DefaultAccount: config.Context{AddressOrAlias: "abc"},
   129  			}, "abc", "io1cjh35tq9k8fu0gqcsat4px7yr8trh75c95aabc", "",
   130  		},
   131  	}
   132  
   133  	for _, test := range tests {
   134  		r := require.New(t)
   135  		configFilePath := writeTempConfig(t, &test.cfg)
   136  		cfgload := loadTempConfig(t, configFilePath)
   137  		r.Equal(test.cfg, cfgload)
   138  
   139  		c := NewClient(cfgload, configFilePath)
   140  		out, err := c.AddressWithDefaultIfNotExist(test.in)
   141  		if err != nil {
   142  			r.Contains(err.Error(), test.errMsg)
   143  		}
   144  		r.Equal(test.out, out)
   145  	}
   146  }
   147  
   148  func TestNewKeyStore(t *testing.T) {
   149  	r := require.New(t)
   150  	testWallet := t.TempDir()
   151  
   152  	c := NewClient(config.Config{
   153  		Wallet: testWallet,
   154  	}, testWallet+"/config.default")
   155  	defer c.Stop(context.Background())
   156  
   157  	ks := c.NewKeyStore()
   158  	acc, err := ks.NewAccount("test")
   159  	r.NoError(err)
   160  	_, err = os.Stat(acc.URL.Path)
   161  	r.NoError(err)
   162  	r.True(strings.HasPrefix(acc.URL.Path, testWallet))
   163  	r.True(ks.HasAddress(acc.Address))
   164  }
   165  
   166  func TestAliasMap(t *testing.T) {
   167  	r := require.New(t)
   168  	cfg := config.Config{
   169  		Aliases: map[string]string{
   170  			"aaa": "io1cjh35tq9k8fu0gqcsat4px7yr8trh75c95haaa",
   171  			"bbb": "io1cjh35tq9k8fu0gqcsat4px7yr8trh75c95hbbb",
   172  			"ccc": "io1cjh35tq9k8fu0gqcsat4px7yr8trh75c95hccc",
   173  		},
   174  	}
   175  
   176  	configFilePath := writeTempConfig(t, &cfg)
   177  	cfgload := loadTempConfig(t, configFilePath)
   178  	r.Equal(cfg, cfgload)
   179  
   180  	exprAliases := map[string]string{
   181  		"io1cjh35tq9k8fu0gqcsat4px7yr8trh75c95haaa": "aaa",
   182  		"io1cjh35tq9k8fu0gqcsat4px7yr8trh75c95hbbb": "bbb",
   183  		"io1cjh35tq9k8fu0gqcsat4px7yr8trh75c95hccc": "ccc",
   184  	}
   185  	c := NewClient(cfgload, configFilePath)
   186  	defer c.Stop(context.Background())
   187  	result := c.AliasMap()
   188  	r.Equal(exprAliases, result)
   189  }
   190  
   191  func TestAlias(t *testing.T) {
   192  	r := require.New(t)
   193  	cfg := config.Config{
   194  		Aliases: map[string]string{
   195  			"aaa": "io1cjh35tq9k8fu0gqcsat4px7yr8trh75c95hc5r",
   196  			"bbb": "io187evpmjdankjh0g5dfz83w2z3p23ljhn4s9jw7",
   197  		},
   198  	}
   199  	configFilePath := writeTempConfig(t, &cfg)
   200  	cfgload := loadTempConfig(t, configFilePath)
   201  	r.Equal(cfg, cfgload)
   202  
   203  	c := NewClient(cfgload, configFilePath)
   204  	defer c.Stop(context.Background())
   205  	for alias, addr := range cfg.Aliases {
   206  		result, err := c.Alias(addr)
   207  		r.NoError(err)
   208  		r.Equal(alias, result)
   209  	}
   210  }
   211  
   212  func TestSetAlias(t *testing.T) {
   213  	type Data struct {
   214  		cfg   config.Config
   215  		alias string
   216  		addr  string
   217  	}
   218  	tests := []Data{
   219  		{
   220  			config.Config{
   221  				Endpoint:      "127.1.1.1:1234",
   222  				SecureConnect: true,
   223  				Aliases: map[string]string{
   224  					"aaa": "io1cjh35tq9k8fu0gqcsat4px7yr8trh75c95haaa",
   225  					"bbb": "io1cjh35tq9k8fu0gqcsat4px7yr8trh75c95haaa",
   226  					"ccc": "io1cjh35tq9k8fu0gqcsat4px7yr8trcccccccccc",
   227  				},
   228  				DefaultAccount: config.Context{AddressOrAlias: "ddd"},
   229  			},
   230  			"ddd",
   231  			"io1cjh35tq9k8fu0gqcsat4px7yr8trh75c95haaa",
   232  		},
   233  		{
   234  			config.Config{
   235  				Endpoint:      "127.1.1.1:1234",
   236  				SecureConnect: true,
   237  				Aliases: map[string]string{
   238  					"aaa": "io1cjh35tq9k8fu0gqcsat4px7yr8trh75c95haaa",
   239  					"bbb": "io1cjh35tq9k8fu0gqcsat4px7yr8trh75c95hbbb",
   240  					"ccc": "io1cjh35tq9k8fu0gqcsat4px7yr8trh75c95hccc",
   241  				},
   242  				DefaultAccount: config.Context{AddressOrAlias: "ddd"},
   243  			},
   244  			"ddd",
   245  			"io1cjh35tq9k8fu0gqcsat4px7yr8trhddddddddd",
   246  		},
   247  		{
   248  			config.Config{
   249  				Aliases: map[string]string{
   250  					"": "",
   251  				},
   252  				DefaultAccount: config.Context{AddressOrAlias: ""},
   253  			},
   254  			"ddd",
   255  			"",
   256  		},
   257  		{
   258  			config.Config{
   259  				Aliases: map[string]string{
   260  					"eee": "",
   261  				},
   262  				DefaultAccount: config.Context{AddressOrAlias: ""},
   263  			},
   264  			"",
   265  			"",
   266  		},
   267  		{
   268  			config.Config{
   269  				Aliases: map[string]string{
   270  					"": "io1cjh35tq9k8fu0gqcsat4px7yr8trhddddddddd",
   271  				},
   272  				DefaultAccount: config.Context{AddressOrAlias: ""},
   273  			},
   274  			"ddd",
   275  			"io1cjh35tq9k8fu0gqcsat4px7yr8trhddddddddd",
   276  		},
   277  	}
   278  
   279  	r := require.New(t)
   280  	testPathd := t.TempDir()
   281  
   282  	for _, test := range tests {
   283  		configFilePath := testPathd + "/config.default"
   284  		c := NewClient(test.cfg, configFilePath)
   285  		r.NoError(c.SetAliasAndSave(test.alias, test.addr))
   286  		cfgload := loadTempConfig(t, configFilePath)
   287  		count := 0
   288  		for _, v := range cfgload.Aliases {
   289  			if v == test.addr {
   290  				count++
   291  			}
   292  		}
   293  		r.Equal(1, count)
   294  		r.Equal(test.addr, cfgload.Aliases[test.alias])
   295  		r.Equal(test.cfg.Endpoint, cfgload.Endpoint)
   296  		r.Equal(test.cfg.SecureConnect, cfgload.SecureConnect)
   297  		r.Equal(test.cfg.DefaultAccount, cfgload.DefaultAccount)
   298  	}
   299  }
   300  
   301  func TestDeleteAlias(t *testing.T) {
   302  	type Data struct {
   303  		cfg   config.Config
   304  		alias string
   305  	}
   306  	tests := []Data{
   307  		{
   308  			config.Config{
   309  				Endpoint:      "127.1.1.1:1234",
   310  				SecureConnect: true,
   311  				Aliases: map[string]string{
   312  					"aaa": "io1cjh35tq9k8fu0gqcsat4px7yr8trh75c95haaa",
   313  					"bbb": "io1cjh35tq9k8fu0gqcsat4px7yr8trh75c95haaa",
   314  					"ccc": "io1cjh35tq9k8fu0gqcsat4px7yr8trcccccccccc",
   315  				},
   316  				DefaultAccount: config.Context{AddressOrAlias: "ddd"},
   317  			},
   318  			"aaa",
   319  		},
   320  		{
   321  			config.Config{
   322  				Endpoint:      "127.1.1.1:1234",
   323  				SecureConnect: true,
   324  				Aliases: map[string]string{
   325  					"aaa": "io1cjh35tq9k8fu0gqcsat4px7yr8trh75c95haaa",
   326  					"bbb": "io1cjh35tq9k8fu0gqcsat4px7yr8trh75c95hbbb",
   327  					"ccc": "io1cjh35tq9k8fu0gqcsat4px7yr8trh75c95hccc",
   328  				},
   329  				DefaultAccount: config.Context{AddressOrAlias: "ddd"},
   330  			},
   331  			"ddd",
   332  		},
   333  		{
   334  			config.Config{
   335  				Aliases: map[string]string{
   336  					"": "",
   337  				},
   338  			},
   339  			"ddd",
   340  		},
   341  	}
   342  
   343  	r := require.New(t)
   344  	testPathd := t.TempDir()
   345  
   346  	for _, test := range tests {
   347  		configFilePath := testPathd + "/config.default"
   348  		c := NewClient(test.cfg, configFilePath)
   349  		r.NoError(c.DeleteAlias(test.alias))
   350  		cfgload := loadTempConfig(t, configFilePath)
   351  		r.NotContains(cfgload.Aliases, test.alias)
   352  		r.Equal(test.cfg.Endpoint, cfgload.Endpoint)
   353  		r.Equal(test.cfg.SecureConnect, cfgload.SecureConnect)
   354  		r.Equal(test.cfg.DefaultAccount, cfgload.DefaultAccount)
   355  	}
   356  }
   357  
   358  func TestHdwalletMnemonic(t *testing.T) {
   359  	r := require.New(t)
   360  	testPathWallet := t.TempDir()
   361  	c := NewClient(config.Config{
   362  		Wallet: testPathWallet,
   363  	}, testPathWallet+"/config.default")
   364  	mnemonic := "lake stove quarter shove dry matrix hire split wide attract argue core"
   365  	password := "123"
   366  	r.NoError(c.WriteHdWalletConfigFile(mnemonic, password))
   367  	result, err := c.HdwalletMnemonic(password)
   368  	r.NoError(err)
   369  	r.Equal(mnemonic, result)
   370  }
   371  
   372  func TestWriteHdWalletConfigFile(t *testing.T) {
   373  	r := require.New(t)
   374  	testPathWallet := t.TempDir()
   375  
   376  	c := NewClient(config.Config{
   377  		Wallet: testPathWallet,
   378  	}, testPathWallet+"/config.default")
   379  	mnemonic := "lake stove quarter shove dry matrix hire split wide attract argue core"
   380  	password := "123"
   381  	r.NoError(c.WriteHdWalletConfigFile(mnemonic, password))
   382  }
   383  
   384  func TestClient_ConfigFilePath(t *testing.T) {
   385  	r := require.New(t)
   386  	testConfigPath := fmt.Sprintf("%s/%s", t.TempDir(), "/config.test")
   387  
   388  	c := NewClient(config.Config{}, testConfigPath)
   389  
   390  	r.Equal(testConfigPath, c.ConfigFilePath())
   391  }
   392  
   393  func writeTempConfig(t *testing.T, cfg *config.Config) string {
   394  	r := require.New(t)
   395  	configFilePath := t.TempDir() + "/config.default"
   396  	out, err := yaml.Marshal(cfg)
   397  	r.NoError(err)
   398  	r.NoError(os.WriteFile(configFilePath, out, 0600))
   399  	return configFilePath
   400  }
   401  
   402  func loadTempConfig(t *testing.T, configFilePath string) config.Config {
   403  	r := require.New(t)
   404  	cfg := config.Config{
   405  		Aliases: make(map[string]string),
   406  	}
   407  	in, err := os.ReadFile(configFilePath)
   408  	r.NoError(err)
   409  	r.NoError(yaml.Unmarshal(in, &cfg))
   410  	return cfg
   411  }