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