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  }