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  }