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 }