github.com/Finschia/finschia-sdk@v0.49.1/x/bank/client/testutil/suite.go (about) 1 package testutil 2 3 import ( 4 "fmt" 5 6 ostcli "github.com/Finschia/ostracon/libs/cli" 7 "github.com/gogo/protobuf/proto" 8 "github.com/stretchr/testify/suite" 9 10 "github.com/Finschia/finschia-sdk/client/flags" 11 clitestutil "github.com/Finschia/finschia-sdk/testutil/cli" 12 "github.com/Finschia/finschia-sdk/testutil/network" 13 sdk "github.com/Finschia/finschia-sdk/types" 14 sdkerrors "github.com/Finschia/finschia-sdk/types/errors" 15 "github.com/Finschia/finschia-sdk/types/query" 16 "github.com/Finschia/finschia-sdk/x/bank/client/cli" 17 "github.com/Finschia/finschia-sdk/x/bank/types" 18 ) 19 20 type IntegrationTestSuite struct { 21 suite.Suite 22 23 cfg network.Config 24 network *network.Network 25 } 26 27 func NewIntegrationTestSuite(cfg network.Config) *IntegrationTestSuite { 28 return &IntegrationTestSuite{cfg: cfg} 29 } 30 31 func (s *IntegrationTestSuite) SetupSuite() { 32 s.T().Log("setting up integration test suite") 33 34 genesisState := s.cfg.GenesisState 35 var bankGenesis types.GenesisState 36 s.Require().NoError(s.cfg.Codec.UnmarshalJSON(genesisState[types.ModuleName], &bankGenesis)) 37 38 bankGenesis.DenomMetadata = []types.Metadata{ 39 { 40 Name: "Cosmos Hub Atom", 41 Symbol: "ATOM", 42 Description: "The native staking token of the Cosmos Hub.", 43 DenomUnits: []*types.DenomUnit{ 44 { 45 Denom: "uatom", 46 Exponent: 0, 47 Aliases: []string{"microatom"}, 48 }, 49 { 50 Denom: "atom", 51 Exponent: 6, 52 Aliases: []string{"ATOM"}, 53 }, 54 }, 55 Base: "uatom", 56 Display: "atom", 57 }, 58 { 59 Name: "Ethereum", 60 Symbol: "ETH", 61 Description: "Ethereum mainnet token", 62 DenomUnits: []*types.DenomUnit{ 63 { 64 Denom: "wei", 65 Exponent: 0, 66 }, 67 { 68 Denom: "eth", 69 Exponent: 6, 70 Aliases: []string{"ETH"}, 71 }, 72 }, 73 Base: "wei", 74 Display: "eth", 75 }, 76 } 77 78 bankGenesisBz, err := s.cfg.Codec.MarshalJSON(&bankGenesis) 79 s.Require().NoError(err) 80 genesisState[types.ModuleName] = bankGenesisBz 81 s.cfg.GenesisState = genesisState 82 83 s.network = network.New(s.T(), s.cfg) 84 85 _, err = s.network.WaitForHeight(1) 86 s.Require().NoError(err) 87 } 88 89 func (s *IntegrationTestSuite) TearDownSuite() { 90 s.T().Log("tearing down integration test suite") 91 s.network.Cleanup() 92 } 93 94 func (s *IntegrationTestSuite) TestGetBalancesCmd() { 95 val := s.network.Validators[0] 96 97 testCases := []struct { 98 name string 99 args []string 100 expectErr bool 101 respType proto.Message 102 expected proto.Message 103 }{ 104 {"no address provided", []string{}, true, nil, nil}, 105 { 106 "total account balance", 107 []string{ 108 val.Address.String(), 109 fmt.Sprintf("--%s=json", ostcli.OutputFlag), 110 fmt.Sprintf("--%s=1", flags.FlagHeight), 111 }, 112 false, 113 &types.QueryAllBalancesResponse{}, 114 &types.QueryAllBalancesResponse{ 115 Balances: sdk.NewCoins( 116 sdk.NewCoin(fmt.Sprintf("%stoken", val.Moniker), s.cfg.AccountTokens), 117 sdk.NewCoin(s.cfg.BondDenom, s.cfg.StakingTokens.Sub(s.cfg.BondedTokens)), 118 ), 119 Pagination: &query.PageResponse{}, 120 }, 121 }, 122 { 123 "total account balance of a specific denom", 124 []string{ 125 val.Address.String(), 126 fmt.Sprintf("--%s=json", ostcli.OutputFlag), 127 fmt.Sprintf("--%s=%s", cli.FlagDenom, s.cfg.BondDenom), 128 fmt.Sprintf("--%s=1", flags.FlagHeight), 129 }, 130 false, 131 &sdk.Coin{}, 132 NewCoin(s.cfg.BondDenom, s.cfg.StakingTokens.Sub(s.cfg.BondedTokens)), 133 }, 134 { 135 "total account balance of a bogus denom", 136 []string{ 137 val.Address.String(), 138 fmt.Sprintf("--%s=foobar", cli.FlagDenom), 139 fmt.Sprintf("--%s=json", ostcli.OutputFlag), 140 }, 141 false, 142 &sdk.Coin{}, 143 NewCoin("foobar", sdk.ZeroInt()), 144 }, 145 } 146 147 for _, tc := range testCases { 148 s.Run(tc.name, func() { 149 cmd := cli.GetBalancesCmd() 150 out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, tc.args) 151 152 if tc.expectErr { 153 s.Require().Error(err) 154 } else { 155 s.Require().NoError(err) 156 s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType)) 157 s.Require().Equal(tc.expected.String(), tc.respType.String()) 158 } 159 }) 160 } 161 } 162 163 func (s *IntegrationTestSuite) TestGetCmdQueryTotalSupply() { 164 val := s.network.Validators[0] 165 166 testCases := []struct { 167 name string 168 args []string 169 expectErr bool 170 respType proto.Message 171 expected proto.Message 172 }{ 173 { 174 name: "total supply", 175 args: []string{ 176 fmt.Sprintf("--%s=1", flags.FlagHeight), 177 fmt.Sprintf("--%s=json", ostcli.OutputFlag), 178 }, 179 respType: &types.QueryTotalSupplyResponse{}, 180 expected: &types.QueryTotalSupplyResponse{ 181 Supply: sdk.NewCoins( 182 sdk.NewCoin(fmt.Sprintf("%stoken", val.Moniker), s.cfg.AccountTokens), 183 sdk.NewCoin(s.cfg.BondDenom, s.cfg.StakingTokens.Add(sdk.NewInt(10))), 184 ), 185 Pagination: &query.PageResponse{Total: 0}, 186 }, 187 }, 188 { 189 name: "total supply of a specific denomination", 190 args: []string{ 191 fmt.Sprintf("--%s=1", flags.FlagHeight), 192 fmt.Sprintf("--%s=%s", cli.FlagDenom, s.cfg.BondDenom), 193 fmt.Sprintf("--%s=json", ostcli.OutputFlag), 194 }, 195 respType: &sdk.Coin{}, 196 expected: &sdk.Coin{ 197 Denom: s.cfg.BondDenom, 198 Amount: s.cfg.StakingTokens.Add(sdk.NewInt(10)), 199 }, 200 }, 201 { 202 name: "total supply of a bogus denom", 203 args: []string{ 204 fmt.Sprintf("--%s=1", flags.FlagHeight), 205 fmt.Sprintf("--%s=foobar", cli.FlagDenom), 206 fmt.Sprintf("--%s=json", ostcli.OutputFlag), 207 }, 208 respType: &sdk.Coin{}, 209 expected: &sdk.Coin{ 210 Denom: "foobar", 211 Amount: sdk.ZeroInt(), 212 }, 213 }, 214 { 215 name: "wrong number of arguments", 216 args: []string{ 217 "extra", 218 fmt.Sprintf("--%s=1", flags.FlagHeight), 219 fmt.Sprintf("--%s=json", ostcli.OutputFlag), 220 }, 221 expectErr: true, 222 }, 223 } 224 225 for _, tc := range testCases { 226 s.Run(tc.name, func() { 227 cmd := cli.GetCmdQueryTotalSupply() 228 clientCtx := val.ClientCtx 229 230 out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) 231 if tc.expectErr { 232 s.Require().Error(err) 233 } else { 234 s.Require().NoError(err) 235 s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType)) 236 s.Require().Equal(tc.expected, tc.respType) 237 } 238 }) 239 } 240 } 241 242 func (s *IntegrationTestSuite) TestGetCmdQueryDenomsMetadata() { 243 val := s.network.Validators[0] 244 245 testCases := []struct { 246 name string 247 args []string 248 expectErr bool 249 respType proto.Message 250 expected proto.Message 251 }{ 252 { 253 name: "all denoms client metadata", 254 args: []string{ 255 fmt.Sprintf("--%s=1", flags.FlagHeight), 256 fmt.Sprintf("--%s=json", ostcli.OutputFlag), 257 }, 258 respType: &types.QueryDenomsMetadataResponse{}, 259 expected: &types.QueryDenomsMetadataResponse{ 260 Metadatas: []types.Metadata{ 261 { 262 Name: "Cosmos Hub Atom", 263 Symbol: "ATOM", 264 Description: "The native staking token of the Cosmos Hub.", 265 DenomUnits: []*types.DenomUnit{ 266 { 267 Denom: "uatom", 268 Exponent: 0, 269 Aliases: []string{"microatom"}, 270 }, 271 { 272 Denom: "atom", 273 Exponent: 6, 274 Aliases: []string{"ATOM"}, 275 }, 276 }, 277 Base: "uatom", 278 Display: "atom", 279 }, 280 { 281 Name: "Ethereum", 282 Symbol: "ETH", 283 Description: "Ethereum mainnet token", 284 DenomUnits: []*types.DenomUnit{ 285 { 286 Denom: "wei", 287 Exponent: 0, 288 Aliases: []string{}, 289 }, 290 { 291 Denom: "eth", 292 Exponent: 6, 293 Aliases: []string{"ETH"}, 294 }, 295 }, 296 Base: "wei", 297 Display: "eth", 298 }, 299 }, 300 Pagination: &query.PageResponse{Total: 2}, 301 }, 302 }, 303 { 304 name: "client metadata of a specific denomination", 305 args: []string{ 306 fmt.Sprintf("--%s=1", flags.FlagHeight), 307 fmt.Sprintf("--%s=%s", cli.FlagDenom, "uatom"), 308 fmt.Sprintf("--%s=json", ostcli.OutputFlag), 309 }, 310 respType: &types.QueryDenomMetadataResponse{}, 311 expected: &types.QueryDenomMetadataResponse{ 312 Metadata: types.Metadata{ 313 Name: "Cosmos Hub Atom", 314 Symbol: "ATOM", 315 Description: "The native staking token of the Cosmos Hub.", 316 DenomUnits: []*types.DenomUnit{ 317 { 318 Denom: "uatom", 319 Exponent: 0, 320 Aliases: []string{"microatom"}, 321 }, 322 { 323 Denom: "atom", 324 Exponent: 6, 325 Aliases: []string{"ATOM"}, 326 }, 327 }, 328 Base: "uatom", 329 Display: "atom", 330 }, 331 }, 332 }, 333 { 334 name: "client metadata of a bogus denom", 335 args: []string{ 336 fmt.Sprintf("--%s=1", flags.FlagHeight), 337 fmt.Sprintf("--%s=foobar", cli.FlagDenom), 338 fmt.Sprintf("--%s=json", ostcli.OutputFlag), 339 }, 340 expectErr: true, 341 respType: &types.QueryDenomMetadataResponse{}, 342 expected: &types.QueryDenomMetadataResponse{ 343 Metadata: types.Metadata{ 344 DenomUnits: []*types.DenomUnit{}, 345 }, 346 }, 347 }, 348 { 349 name: "wrong number of arguments", 350 args: []string{ 351 "extra", 352 fmt.Sprintf("--%s=1", flags.FlagHeight), 353 fmt.Sprintf("--%s=json", ostcli.OutputFlag), 354 }, 355 expectErr: true, 356 respType: &types.QueryDenomMetadataResponse{}, 357 expected: &types.QueryDenomMetadataResponse{ 358 Metadata: types.Metadata{ 359 DenomUnits: []*types.DenomUnit{}, 360 }, 361 }, 362 }, 363 } 364 365 for _, tc := range testCases { 366 s.Run(tc.name, func() { 367 cmd := cli.GetCmdDenomsMetadata() 368 clientCtx := val.ClientCtx 369 370 out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) 371 if tc.expectErr { 372 s.Require().Error(err) 373 } else { 374 s.Require().NoError(err) 375 s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType)) 376 s.Require().Equal(tc.expected, tc.respType) 377 } 378 }) 379 } 380 } 381 382 func (s *IntegrationTestSuite) TestNewSendTxCmdGenOnly() { 383 val := s.network.Validators[0] 384 385 clientCtx := val.ClientCtx 386 387 from := val.Address 388 to := val.Address 389 amount := sdk.NewCoins( 390 sdk.NewCoin(fmt.Sprintf("%stoken", val.Moniker), sdk.NewInt(10)), 391 sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10)), 392 ) 393 args := []string{ 394 fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), 395 fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), 396 fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), 397 fmt.Sprintf("--%s=true", flags.FlagGenerateOnly), 398 } 399 400 bz, err := MsgSendExec(clientCtx, from, to, amount, args...) 401 s.Require().NoError(err) 402 tx, err := s.cfg.TxConfig.TxJSONDecoder()(bz.Bytes()) 403 s.Require().NoError(err) 404 s.Require().Equal([]sdk.Msg{types.NewMsgSend(from, to, amount)}, tx.GetMsgs()) 405 } 406 407 func (s *IntegrationTestSuite) TestNewSendTxCmd() { 408 val := s.network.Validators[0] 409 410 testCases := []struct { 411 name string 412 from, to sdk.AccAddress 413 amount sdk.Coins 414 args []string 415 expectErr bool 416 expectedCode uint32 417 respType proto.Message 418 }{ 419 { 420 "valid transaction", 421 val.Address, 422 val.Address, 423 sdk.NewCoins( 424 sdk.NewCoin(fmt.Sprintf("%stoken", val.Moniker), sdk.NewInt(10)), 425 sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10)), 426 ), 427 []string{ 428 fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), 429 fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), 430 fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), 431 }, 432 false, 0, &sdk.TxResponse{}, 433 }, 434 { 435 "not enough fees", 436 val.Address, 437 val.Address, 438 sdk.NewCoins( 439 sdk.NewCoin(fmt.Sprintf("%stoken", val.Moniker), sdk.NewInt(10)), 440 sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10)), 441 ), 442 []string{ 443 fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), 444 fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), 445 fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(1))).String()), 446 }, 447 false, 448 sdkerrors.ErrInsufficientFee.ABCICode(), 449 &sdk.TxResponse{}, 450 }, 451 { 452 "not enough gas", 453 val.Address, 454 val.Address, 455 sdk.NewCoins( 456 sdk.NewCoin(fmt.Sprintf("%stoken", val.Moniker), sdk.NewInt(10)), 457 sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10)), 458 ), 459 []string{ 460 fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), 461 fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), 462 fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), 463 "--gas=10", 464 }, 465 false, 466 sdkerrors.ErrOutOfGas.ABCICode(), 467 &sdk.TxResponse{}, 468 }, 469 } 470 471 for _, tc := range testCases { 472 s.Run(tc.name, func() { 473 clientCtx := val.ClientCtx 474 475 bz, err := MsgSendExec(clientCtx, tc.from, tc.to, tc.amount, tc.args...) 476 if tc.expectErr { 477 s.Require().Error(err) 478 } else { 479 s.Require().NoError(err) 480 481 s.Require().NoError(clientCtx.Codec.UnmarshalJSON(bz.Bytes(), tc.respType), bz.String()) 482 txResp := tc.respType.(*sdk.TxResponse) 483 s.Require().Equal(tc.expectedCode, txResp.Code) 484 } 485 }) 486 } 487 } 488 489 func NewCoin(denom string, amount sdk.Int) *sdk.Coin { 490 coin := sdk.NewCoin(denom, amount) 491 return &coin 492 }