chore!: Refactor x/bank CLI Tests (#12706)
This commit is contained in:
parent
71035879e4
commit
ccc8003a80
@ -45,6 +45,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
||||
|
||||
### Improvements
|
||||
|
||||
* (x/bank) [#12706](https://github.com/cosmos/cosmos-sdk/pull/12706) Added the `chain-id` flag to the `AddTxFlagsToCmd` API. There is no longer a need to explicitly register this flag on commands whens `AddTxFlagsToCmd` is already called.
|
||||
* [#12791](https://github.com/cosmos/cosmos-sdk/pull/12791) Bump the math library used in the sdk and replace old usages of sdk.*
|
||||
* (x/params) [#12615](https://github.com/cosmos/cosmos-sdk/pull/12615) Add `GetParamSetIfExists` function to params `Subspace` to prevent panics on breaking changes.
|
||||
* [#12717](https://github.com/cosmos/cosmos-sdk/pull/12717) Use injected encoding params in simapp.
|
||||
@ -70,6 +71,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
||||
|
||||
### API Breaking Changes
|
||||
|
||||
* (x/bank) [#12706](https://github.com/cosmos/cosmos-sdk/pull/12706) Removed the `testutil` package from the `x/bank/client` package.
|
||||
* (simapp) [#12747](https://github.com/cosmos/cosmos-sdk/pull/12747) Remove `simapp.MakeTestEncodingConfig`. Please use `moduletestutil.MakeTestEncodingConfig` (`types/module/testutil`) in tests instead.
|
||||
* (x/bank) [#12648](https://github.com/cosmos/cosmos-sdk/pull/12648) `NewSendAuthorization` takes a new argument of an optional list of addresses allowed to receive bank assests via authz MsgSend grant. You can pass `nil` for the same behavior as before, i.e. any recipient is allowed.
|
||||
* (x/bank) [\#12593](https://github.com/cosmos/cosmos-sdk/pull/12593) Add `SpendableCoin` method to `BaseViewKeeper`
|
||||
|
||||
@ -22,3 +22,26 @@ type AccountRetriever interface {
|
||||
EnsureExists(clientCtx Context, addr sdk.AccAddress) error
|
||||
GetAccountNumberSequence(clientCtx Context, addr sdk.AccAddress) (accNum uint64, accSeq uint64, err error)
|
||||
}
|
||||
|
||||
var _ AccountRetriever = (*MockAccountRetriever)(nil)
|
||||
|
||||
// MockAccountRetriever defines a no-op basic AccountRetriever that can be used
|
||||
// in mocked contexts. Tests or context that need more sophisticated testing
|
||||
// state should implement their own mock AccountRetriever.
|
||||
type MockAccountRetriever struct{}
|
||||
|
||||
func (mar MockAccountRetriever) GetAccount(_ Context, _ sdk.AccAddress) (Account, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (mar MockAccountRetriever) GetAccountWithHeight(_ Context, _ sdk.AccAddress) (Account, int64, error) {
|
||||
return nil, 0, nil
|
||||
}
|
||||
|
||||
func (mar MockAccountRetriever) EnsureExists(_ Context, _ sdk.AccAddress) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mar MockAccountRetriever) GetAccountNumberSequence(_ Context, _ sdk.AccAddress) (uint64, uint64, error) {
|
||||
return 0, 0, nil
|
||||
}
|
||||
|
||||
@ -7,14 +7,10 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
rpcclient "github.com/tendermint/tendermint/rpc/client"
|
||||
"github.com/spf13/viper"
|
||||
"google.golang.org/grpc"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
@ -26,7 +22,7 @@ import (
|
||||
// handling and queries.
|
||||
type Context struct {
|
||||
FromAddress sdk.AccAddress
|
||||
Client rpcclient.Client
|
||||
Client TendermintRPC
|
||||
GRPCClient *grpc.ClientConn
|
||||
ChainID string
|
||||
Codec codec.Codec
|
||||
@ -128,7 +124,7 @@ func (ctx Context) WithHeight(height int64) Context {
|
||||
|
||||
// WithClient returns a copy of the context with an updated RPC client
|
||||
// instance.
|
||||
func (ctx Context) WithClient(client rpcclient.Client) Context {
|
||||
func (ctx Context) WithClient(client TendermintRPC) Context {
|
||||
ctx.Client = client
|
||||
return ctx
|
||||
}
|
||||
|
||||
@ -79,6 +79,7 @@ const (
|
||||
FlagReverse = "reverse"
|
||||
FlagTip = "tip"
|
||||
FlagAux = "aux"
|
||||
FlagOutput = tmcli.OutputFlag
|
||||
|
||||
// Tendermint logging flags
|
||||
FlagLogLevel = "log_level"
|
||||
@ -93,7 +94,7 @@ var LineBreak = &cobra.Command{Run: func(*cobra.Command, []string) {}}
|
||||
func AddQueryFlagsToCmd(cmd *cobra.Command) {
|
||||
cmd.Flags().String(FlagNode, "tcp://localhost:26657", "<host>:<port> to Tendermint RPC interface for this chain")
|
||||
cmd.Flags().Int64(FlagHeight, 0, "Use a specific height to query state at (this can error if the node is pruning state)")
|
||||
cmd.Flags().StringP(tmcli.OutputFlag, "o", "text", "Output format (text|json)")
|
||||
cmd.Flags().StringP(FlagOutput, "o", "text", "Output format (text|json)")
|
||||
|
||||
// some base commands does not require chainID e.g `simd testnet` while subcommands do
|
||||
// hence the flag should not be required for those commands
|
||||
@ -102,7 +103,7 @@ func AddQueryFlagsToCmd(cmd *cobra.Command) {
|
||||
|
||||
// AddTxFlagsToCmd adds common flags to a module tx command.
|
||||
func AddTxFlagsToCmd(cmd *cobra.Command) {
|
||||
cmd.Flags().StringP(tmcli.OutputFlag, "o", "json", "Output format (text|json)")
|
||||
cmd.Flags().StringP(FlagOutput, "o", "json", "Output format (text|json)")
|
||||
cmd.Flags().String(FlagKeyringDir, "", "The client Keyring directory; if omitted, the default 'home' directory will be used")
|
||||
cmd.Flags().String(FlagFrom, "", "Name or address of private key with which to sign")
|
||||
cmd.Flags().Uint64P(FlagAccountNumber, "a", 0, "The account number of the signing account (offline mode only)")
|
||||
@ -125,6 +126,7 @@ func AddTxFlagsToCmd(cmd *cobra.Command) {
|
||||
cmd.Flags().String(FlagFeeGranter, "", "Fee granter grants fees for the transaction")
|
||||
cmd.Flags().String(FlagTip, "", "Tip is the amount that is going to be transferred to the fee payer on the target chain. This flag is only valid when used with --aux, and is ignored if the target chain didn't enable the TipDecorator")
|
||||
cmd.Flags().Bool(FlagAux, false, "Generate aux signer data instead of sending a tx")
|
||||
cmd.Flags().String(FlagChainID, "", "The network chain ID")
|
||||
|
||||
// --gas can accept integers and "auto"
|
||||
cmd.Flags().String(FlagGas, "", fmt.Sprintf("gas limit to set per-transaction; set to %q to calculate sufficient gas automatically (default %d)", GasFlagAuto, DefaultGasLimit))
|
||||
|
||||
@ -7,10 +7,11 @@ import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
"google.golang.org/grpc/encoding"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
|
||||
gogogrpc "github.com/gogo/protobuf/grpc"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
@ -6,12 +6,11 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
tmbytes "github.com/tendermint/tendermint/libs/bytes"
|
||||
rpcclient "github.com/tendermint/tendermint/rpc/client"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/store/rootmulti"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
@ -20,7 +19,7 @@ import (
|
||||
|
||||
// GetNode returns an RPC client. If the context's client is not defined, an
|
||||
// error is returned.
|
||||
func (ctx Context) GetNode() (rpcclient.Client, error) {
|
||||
func (ctx Context) GetNode() (TendermintRPC, error) {
|
||||
if ctx.Client == nil {
|
||||
return nil, errors.New("no RPC client is defined in offline mode")
|
||||
}
|
||||
|
||||
28
client/tendermint.go
Normal file
28
client/tendermint.go
Normal file
@ -0,0 +1,28 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/tendermint/tendermint/libs/bytes"
|
||||
rpcclient "github.com/tendermint/tendermint/rpc/client"
|
||||
"github.com/tendermint/tendermint/rpc/coretypes"
|
||||
)
|
||||
|
||||
// TendermintRPC defines the interface of a Tendermint RPC client needed for
|
||||
// queries and transaction handling.
|
||||
type TendermintRPC interface {
|
||||
rpcclient.ABCIClient
|
||||
|
||||
Validators(ctx context.Context, height *int64, page, perPage *int) (*coretypes.ResultValidators, error)
|
||||
Status(context.Context) (*coretypes.ResultStatus, error)
|
||||
Block(ctx context.Context, height *int64) (*coretypes.ResultBlock, error)
|
||||
BlockchainInfo(ctx context.Context, minHeight, maxHeight int64) (*coretypes.ResultBlockchainInfo, error)
|
||||
Tx(ctx context.Context, hash bytes.HexBytes, prove bool) (*coretypes.ResultTx, error)
|
||||
TxSearch(
|
||||
ctx context.Context,
|
||||
query string,
|
||||
prove bool,
|
||||
page, perPage *int,
|
||||
orderBy string,
|
||||
) (*coretypes.ResultTxSearch, error)
|
||||
}
|
||||
@ -392,7 +392,6 @@ func (f Factory) getSimPK() (cryptotypes.PubKey, error) {
|
||||
// the updated fields will be returned.
|
||||
func (f Factory) Prepare(clientCtx client.Context) (Factory, error) {
|
||||
fc := f
|
||||
|
||||
from := clientCtx.GetFromAddress()
|
||||
|
||||
if err := fc.accountRetriever.EnsureExists(clientCtx, from); err != nil {
|
||||
|
||||
@ -20,14 +20,11 @@ import (
|
||||
func Execute(rootCmd *cobra.Command, envPrefix string, defaultHome string) error {
|
||||
// Create and set a client.Context on the command's Context. During the pre-run
|
||||
// of the root command, a default initialized client.Context is provided to
|
||||
// seed child command execution with values such as AccountRetriver, Keyring,
|
||||
// seed child command execution with values such as AccountRetriever, Keyring,
|
||||
// and a Tendermint RPC. This requires the use of a pointer reference when
|
||||
// getting and setting the client.Context. Ideally, we utilize
|
||||
// https://github.com/spf13/cobra/pull/1118.
|
||||
srvCtx := server.NewDefaultContext()
|
||||
ctx := context.Background()
|
||||
ctx = context.WithValue(ctx, client.ClientContextKey, &client.Context{})
|
||||
ctx = context.WithValue(ctx, server.ServerContextKey, srvCtx)
|
||||
ctx := CreateExecuteContext(context.Background())
|
||||
|
||||
rootCmd.PersistentFlags().String(flags.FlagLogLevel, zerolog.InfoLevel.String(), "The logging level (trace|debug|info|warn|error|fatal|panic)")
|
||||
rootCmd.PersistentFlags().String(flags.FlagLogFormat, tmlog.LogFormatPlain, "The logging format (json|plain)")
|
||||
@ -35,3 +32,13 @@ func Execute(rootCmd *cobra.Command, envPrefix string, defaultHome string) error
|
||||
executor := tmcli.PrepareBaseCmd(rootCmd, envPrefix, defaultHome)
|
||||
return executor.ExecuteContext(ctx)
|
||||
}
|
||||
|
||||
// CreateExecuteContext returns a base Context with server and client context
|
||||
// values initialized.
|
||||
func CreateExecuteContext(ctx context.Context) context.Context {
|
||||
srvCtx := server.NewDefaultContext()
|
||||
ctx = context.WithValue(ctx, client.ClientContextKey, &client.Context{})
|
||||
ctx = context.WithValue(ctx, server.ServerContextKey, srvCtx)
|
||||
|
||||
return ctx
|
||||
}
|
||||
|
||||
@ -216,7 +216,6 @@ func queryCommand() *cobra.Command {
|
||||
)
|
||||
|
||||
simapp.ModuleBasics.AddQueryCommands(cmd)
|
||||
cmd.PersistentFlags().String(flags.FlagChainID, "", "The network chain ID")
|
||||
|
||||
return cmd
|
||||
}
|
||||
@ -243,7 +242,6 @@ func txCommand() *cobra.Command {
|
||||
)
|
||||
|
||||
simapp.ModuleBasics.AddTxCommands(cmd)
|
||||
cmd.PersistentFlags().String(flags.FlagChainID, "", "The network chain ID")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
@ -76,7 +76,7 @@ func GetAuxToFeeCommand() *cobra.Command {
|
||||
}
|
||||
|
||||
flags.AddTxFlagsToCmd(cmd)
|
||||
cmd.Flags().String(flags.FlagChainID, "", "network chain ID")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
|
||||
@ -65,7 +65,6 @@ The SIGN_MODE_DIRECT sign mode is not supported.'
|
||||
cmd.Flags().String(flags.FlagOutputDocument, "", "The document is written to the given file instead of STDOUT")
|
||||
cmd.Flags().Bool(flagAmino, false, "Generate Amino-encoded JSON suitable for submitting to the txs REST endpoint")
|
||||
flags.AddTxFlagsToCmd(cmd)
|
||||
cmd.Flags().String(flags.FlagChainID, "", "network chain ID")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
@ -54,7 +54,6 @@ account key. It implies --signature-only.
|
||||
cmd.Flags().String(flagMultisig, "", "Address or key name of the multisig account on behalf of which the transaction shall be signed")
|
||||
cmd.Flags().String(flags.FlagOutputDocument, "", "The document will be written to the given file instead of STDOUT")
|
||||
cmd.Flags().Bool(flagSigOnly, true, "Print only the generated signature, then exit")
|
||||
cmd.Flags().String(flags.FlagChainID, "", "network chain ID")
|
||||
flags.AddTxFlagsToCmd(cmd)
|
||||
|
||||
cmd.MarkFlagRequired(flags.FlagFrom)
|
||||
@ -192,7 +191,6 @@ be generated via the 'multisign' command.
|
||||
cmd.Flags().Bool(flagOverwrite, false, "Overwrite existing signatures with a new one. If disabled, new signature will be appended")
|
||||
cmd.Flags().Bool(flagSigOnly, false, "Print only the signatures")
|
||||
cmd.Flags().String(flags.FlagOutputDocument, "", "The document will be written to the given file instead of STDOUT")
|
||||
cmd.Flags().String(flags.FlagChainID, "", "The network chain ID")
|
||||
cmd.Flags().Bool(flagAmino, false, "Generate Amino encoded JSON suitable for submiting to the txs REST endpoint")
|
||||
flags.AddTxFlagsToCmd(cmd)
|
||||
|
||||
|
||||
@ -30,7 +30,6 @@ transaction will be not be performed as that will require RPC communication with
|
||||
Args: cobra.ExactArgs(1),
|
||||
}
|
||||
|
||||
cmd.Flags().String(flags.FlagChainID, "", "The network chain ID")
|
||||
flags.AddTxFlagsToCmd(cmd)
|
||||
|
||||
return cmd
|
||||
|
||||
@ -59,6 +59,7 @@ Example:
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
denom, err := cmd.Flags().GetString(FlagDenom)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -75,17 +76,22 @@ Example:
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx := cmd.Context()
|
||||
|
||||
if denom == "" {
|
||||
params := types.NewQueryAllBalancesRequest(addr, pageReq)
|
||||
|
||||
res, err := queryClient.AllBalances(ctx, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return clientCtx.PrintProto(res)
|
||||
}
|
||||
|
||||
params := types.NewQueryBalanceRequest(addr, denom)
|
||||
|
||||
res, err := queryClient.Balance(ctx, params)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -125,6 +131,7 @@ To query for the client metadata of a specific coin denomination use:
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
denom, err := cmd.Flags().GetString(FlagDenom)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -178,6 +185,7 @@ To query for the total supply of a specific coin denomination use:
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
denom, err := cmd.Flags().GetString(FlagDenom)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -190,6 +198,7 @@ To query for the total supply of a specific coin denomination use:
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if denom == "" {
|
||||
res, err := queryClient.TotalSupply(ctx, &types.QueryTotalSupplyRequest{Pagination: pageReq})
|
||||
if err != nil {
|
||||
|
||||
362
x/bank/client/cli/query_test.go
Normal file
362
x/bank/client/cli/query_test.go
Normal file
@ -0,0 +1,362 @@
|
||||
package cli_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
svrcmd "github.com/cosmos/cosmos-sdk/server/cmd"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank/client/cli"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||
)
|
||||
|
||||
func (s *CLITestSuite) TestGetBalancesCmd() {
|
||||
accounts := s.createKeyringAccounts(1)
|
||||
|
||||
cmd := cli.GetBalancesCmd()
|
||||
cmd.SetOutput(io.Discard)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
ctxGen func() client.Context
|
||||
args []string
|
||||
expectResult proto.Message
|
||||
expectErr bool
|
||||
}{
|
||||
{
|
||||
"valid query",
|
||||
func() client.Context {
|
||||
bz, _ := s.encCfg.Codec.Marshal(&types.QueryAllBalancesResponse{})
|
||||
c := newMockTendermintRPC(abci.ResponseQuery{
|
||||
Value: bz,
|
||||
})
|
||||
return s.baseCtx.WithClient(c)
|
||||
},
|
||||
[]string{
|
||||
accounts[0].address.String(),
|
||||
fmt.Sprintf("--%s=json", flags.FlagOutput),
|
||||
},
|
||||
&types.QueryAllBalancesResponse{},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"valid query with denom",
|
||||
func() client.Context {
|
||||
bz, _ := s.encCfg.Codec.Marshal(&types.QueryBalanceResponse{
|
||||
Balance: &sdk.Coin{},
|
||||
})
|
||||
c := newMockTendermintRPC(abci.ResponseQuery{
|
||||
Value: bz,
|
||||
})
|
||||
return s.baseCtx.WithClient(c)
|
||||
},
|
||||
[]string{
|
||||
accounts[0].address.String(),
|
||||
fmt.Sprintf("--%s=photon", cli.FlagDenom),
|
||||
fmt.Sprintf("--%s=json", flags.FlagOutput),
|
||||
},
|
||||
&sdk.Coin{},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"invalid address",
|
||||
func() client.Context {
|
||||
return s.baseCtx
|
||||
},
|
||||
[]string{
|
||||
"foo",
|
||||
},
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"invalid denom",
|
||||
func() client.Context {
|
||||
c := newMockTendermintRPC(abci.ResponseQuery{
|
||||
Code: 1,
|
||||
})
|
||||
return s.baseCtx.WithClient(c)
|
||||
},
|
||||
[]string{
|
||||
accounts[0].address.String(),
|
||||
fmt.Sprintf("--%s=foo", cli.FlagDenom),
|
||||
},
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
|
||||
s.Run(tc.name, func() {
|
||||
var outBuf bytes.Buffer
|
||||
|
||||
clientCtx := tc.ctxGen().WithOutput(&outBuf)
|
||||
ctx := svrcmd.CreateExecuteContext(context.Background())
|
||||
|
||||
cmd.SetContext(ctx)
|
||||
cmd.SetArgs(tc.args)
|
||||
|
||||
s.Require().NoError(client.SetCmdClientContextHandler(clientCtx, cmd))
|
||||
|
||||
err := cmd.Execute()
|
||||
if tc.expectErr {
|
||||
s.Require().Error(err)
|
||||
} else {
|
||||
s.Require().NoError(s.encCfg.Codec.UnmarshalJSON(outBuf.Bytes(), tc.expectResult))
|
||||
s.Require().NoError(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *CLITestSuite) TestGetCmdDenomsMetadata() {
|
||||
cmd := cli.GetCmdDenomsMetadata()
|
||||
cmd.SetOutput(io.Discard)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
ctxGen func() client.Context
|
||||
args []string
|
||||
expectResult proto.Message
|
||||
expectErr bool
|
||||
}{
|
||||
{
|
||||
"valid query",
|
||||
func() client.Context {
|
||||
bz, _ := s.encCfg.Codec.Marshal(&types.QueryDenomsMetadataResponse{})
|
||||
c := newMockTendermintRPC(abci.ResponseQuery{
|
||||
Value: bz,
|
||||
})
|
||||
return s.baseCtx.WithClient(c)
|
||||
},
|
||||
[]string{
|
||||
fmt.Sprintf("--%s=json", flags.FlagOutput),
|
||||
},
|
||||
&types.QueryDenomsMetadataResponse{},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"valid query with denom",
|
||||
func() client.Context {
|
||||
bz, _ := s.encCfg.Codec.Marshal(&types.QueryDenomMetadataResponse{})
|
||||
c := newMockTendermintRPC(abci.ResponseQuery{
|
||||
Value: bz,
|
||||
})
|
||||
return s.baseCtx.WithClient(c)
|
||||
},
|
||||
[]string{
|
||||
fmt.Sprintf("--%s=photon", cli.FlagDenom),
|
||||
fmt.Sprintf("--%s=json", flags.FlagOutput),
|
||||
},
|
||||
&types.QueryDenomMetadataResponse{},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"invalid query with denom",
|
||||
func() client.Context {
|
||||
c := newMockTendermintRPC(abci.ResponseQuery{
|
||||
Code: 1,
|
||||
})
|
||||
return s.baseCtx.WithClient(c)
|
||||
},
|
||||
[]string{
|
||||
fmt.Sprintf("--%s=foo", cli.FlagDenom),
|
||||
},
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
|
||||
s.Run(tc.name, func() {
|
||||
var outBuf bytes.Buffer
|
||||
|
||||
clientCtx := tc.ctxGen().WithOutput(&outBuf)
|
||||
ctx := svrcmd.CreateExecuteContext(context.Background())
|
||||
|
||||
cmd.SetContext(ctx)
|
||||
cmd.SetArgs(tc.args)
|
||||
|
||||
s.Require().NoError(client.SetCmdClientContextHandler(clientCtx, cmd))
|
||||
|
||||
err := cmd.Execute()
|
||||
if tc.expectErr {
|
||||
s.Require().Error(err)
|
||||
} else {
|
||||
s.Require().NoError(s.encCfg.Codec.UnmarshalJSON(outBuf.Bytes(), tc.expectResult))
|
||||
s.Require().NoError(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *CLITestSuite) TestGetCmdQueryTotalSupply() {
|
||||
cmd := cli.GetCmdQueryTotalSupply()
|
||||
cmd.SetOutput(io.Discard)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
ctxGen func() client.Context
|
||||
args []string
|
||||
expectResult proto.Message
|
||||
expectErr bool
|
||||
}{
|
||||
{
|
||||
"valid query",
|
||||
func() client.Context {
|
||||
bz, _ := s.encCfg.Codec.Marshal(&types.QueryTotalSupplyResponse{})
|
||||
c := newMockTendermintRPC(abci.ResponseQuery{
|
||||
Value: bz,
|
||||
})
|
||||
return s.baseCtx.WithClient(c)
|
||||
},
|
||||
[]string{
|
||||
fmt.Sprintf("--%s=json", flags.FlagOutput),
|
||||
},
|
||||
&types.QueryTotalSupplyResponse{},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"valid query with denom",
|
||||
func() client.Context {
|
||||
bz, _ := s.encCfg.Codec.Marshal(&types.QuerySupplyOfResponse{
|
||||
Amount: sdk.Coin{},
|
||||
})
|
||||
c := newMockTendermintRPC(abci.ResponseQuery{
|
||||
Value: bz,
|
||||
})
|
||||
return s.baseCtx.WithClient(c)
|
||||
},
|
||||
[]string{
|
||||
fmt.Sprintf("--%s=photon", cli.FlagDenom),
|
||||
fmt.Sprintf("--%s=json", flags.FlagOutput),
|
||||
},
|
||||
&sdk.Coin{},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"invalid query with denom",
|
||||
func() client.Context {
|
||||
c := newMockTendermintRPC(abci.ResponseQuery{
|
||||
Code: 1,
|
||||
})
|
||||
return s.baseCtx.WithClient(c)
|
||||
},
|
||||
[]string{
|
||||
fmt.Sprintf("--%s=foo", cli.FlagDenom),
|
||||
fmt.Sprintf("--%s=json", flags.FlagOutput),
|
||||
},
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
|
||||
s.Run(tc.name, func() {
|
||||
var outBuf bytes.Buffer
|
||||
|
||||
clientCtx := tc.ctxGen().WithOutput(&outBuf)
|
||||
ctx := svrcmd.CreateExecuteContext(context.Background())
|
||||
|
||||
cmd.SetContext(ctx)
|
||||
cmd.SetArgs(tc.args)
|
||||
|
||||
s.Require().NoError(client.SetCmdClientContextHandler(clientCtx, cmd))
|
||||
|
||||
err := cmd.Execute()
|
||||
if tc.expectErr {
|
||||
s.Require().Error(err)
|
||||
} else {
|
||||
s.Require().NoError(s.encCfg.Codec.UnmarshalJSON(outBuf.Bytes(), tc.expectResult))
|
||||
s.Require().NoError(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *CLITestSuite) TestGetCmdQuerySendEnabled() {
|
||||
cmd := cli.GetCmdQuerySendEnabled()
|
||||
cmd.SetOutput(io.Discard)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
ctxGen func() client.Context
|
||||
args []string
|
||||
expectResult proto.Message
|
||||
expectErr bool
|
||||
}{
|
||||
{
|
||||
"valid query",
|
||||
func() client.Context {
|
||||
bz, _ := s.encCfg.Codec.Marshal(&types.QuerySendEnabledResponse{
|
||||
SendEnabled: []*types.SendEnabled{},
|
||||
})
|
||||
c := newMockTendermintRPC(abci.ResponseQuery{
|
||||
Value: bz,
|
||||
})
|
||||
return s.baseCtx.WithClient(c)
|
||||
},
|
||||
[]string{
|
||||
fmt.Sprintf("--%s=json", flags.FlagOutput),
|
||||
},
|
||||
&types.QuerySendEnabledResponse{},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"valid query with denoms",
|
||||
func() client.Context {
|
||||
bz, _ := s.encCfg.Codec.Marshal(&types.QuerySendEnabledResponse{
|
||||
SendEnabled: []*types.SendEnabled{},
|
||||
})
|
||||
c := newMockTendermintRPC(abci.ResponseQuery{
|
||||
Value: bz,
|
||||
})
|
||||
return s.baseCtx.WithClient(c)
|
||||
},
|
||||
[]string{
|
||||
"photon",
|
||||
"stake",
|
||||
fmt.Sprintf("--%s=json", flags.FlagOutput),
|
||||
},
|
||||
&types.QuerySendEnabledResponse{},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
|
||||
s.Run(tc.name, func() {
|
||||
var outBuf bytes.Buffer
|
||||
|
||||
clientCtx := tc.ctxGen().WithOutput(&outBuf)
|
||||
ctx := svrcmd.CreateExecuteContext(context.Background())
|
||||
|
||||
cmd.SetContext(ctx)
|
||||
cmd.SetArgs(tc.args)
|
||||
|
||||
s.Require().NoError(client.SetCmdClientContextHandler(clientCtx, cmd))
|
||||
|
||||
err := cmd.Execute()
|
||||
if tc.expectErr {
|
||||
s.Require().Error(err)
|
||||
} else {
|
||||
s.Require().NoError(s.encCfg.Codec.UnmarshalJSON(outBuf.Bytes(), tc.expectResult))
|
||||
s.Require().NoError(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
96
x/bank/client/cli/suite_test.go
Normal file
96
x/bank/client/cli/suite_test.go
Normal file
@ -0,0 +1,96 @@
|
||||
package cli_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/libs/bytes"
|
||||
rpcclient "github.com/tendermint/tendermint/rpc/client"
|
||||
rpcclientmock "github.com/tendermint/tendermint/rpc/client/mock"
|
||||
"github.com/tendermint/tendermint/rpc/coretypes"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/hd"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
testutilmod "github.com/cosmos/cosmos-sdk/types/module/testutil"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
)
|
||||
|
||||
var _ client.TendermintRPC = (*mockTendermintRPC)(nil)
|
||||
|
||||
type mockTendermintRPC struct {
|
||||
rpcclientmock.Client
|
||||
|
||||
responseQuery abci.ResponseQuery
|
||||
}
|
||||
|
||||
func newMockTendermintRPC(respQuery abci.ResponseQuery) mockTendermintRPC {
|
||||
return mockTendermintRPC{responseQuery: respQuery}
|
||||
}
|
||||
|
||||
func (_ mockTendermintRPC) BroadcastTxSync(context.Context, tmtypes.Tx) (*coretypes.ResultBroadcastTx, error) {
|
||||
return &coretypes.ResultBroadcastTx{Code: 0}, nil
|
||||
}
|
||||
|
||||
func (m mockTendermintRPC) ABCIQueryWithOptions(
|
||||
_ context.Context,
|
||||
_ string, _ bytes.HexBytes,
|
||||
_ rpcclient.ABCIQueryOptions,
|
||||
) (*coretypes.ResultABCIQuery, error) {
|
||||
return &coretypes.ResultABCIQuery{Response: m.responseQuery}, nil
|
||||
}
|
||||
|
||||
type account struct {
|
||||
name string
|
||||
address sdk.AccAddress
|
||||
}
|
||||
|
||||
type CLITestSuite struct {
|
||||
suite.Suite
|
||||
|
||||
kr keyring.Keyring
|
||||
encCfg testutilmod.TestEncodingConfig
|
||||
baseCtx client.Context
|
||||
}
|
||||
|
||||
func TestMigrateTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(CLITestSuite))
|
||||
}
|
||||
|
||||
func (s *CLITestSuite) SetupSuite() {
|
||||
s.encCfg = testutilmod.MakeTestEncodingConfig(bank.AppModuleBasic{})
|
||||
s.kr = keyring.NewInMemory(s.encCfg.Codec)
|
||||
s.baseCtx = client.Context{}.
|
||||
WithKeyring(s.kr).
|
||||
WithTxConfig(s.encCfg.TxConfig).
|
||||
WithCodec(s.encCfg.Codec).
|
||||
WithClient(mockTendermintRPC{Client: rpcclientmock.New()}).
|
||||
WithAccountRetriever(client.MockAccountRetriever{}).
|
||||
WithOutput(io.Discard)
|
||||
}
|
||||
|
||||
func (s *CLITestSuite) createKeyringAccounts(num int) []account {
|
||||
accounts := make([]account, num)
|
||||
for i := range accounts {
|
||||
record, _, err := s.kr.NewMnemonic(
|
||||
fmt.Sprintf("key-%d", i),
|
||||
keyring.English,
|
||||
sdk.FullFundraiserPath,
|
||||
keyring.DefaultBIP39Passphrase,
|
||||
hd.Secp256k1)
|
||||
s.Require().NoError(err)
|
||||
|
||||
addr, err := record.GetAddress()
|
||||
s.Require().NoError(err)
|
||||
|
||||
accounts[i] = account{name: record.Name, address: addr}
|
||||
}
|
||||
|
||||
return accounts
|
||||
}
|
||||
@ -138,7 +138,6 @@ When using '--dry-run' a key name cannot be used, only a bech32 address.
|
||||
}
|
||||
|
||||
cmd.Flags().Bool(FlagSplit, false, "Send the equally split token amount to each address")
|
||||
|
||||
flags.AddTxFlagsToCmd(cmd)
|
||||
|
||||
return cmd
|
||||
|
||||
211
x/bank/client/cli/tx_test.go
Normal file
211
x/bank/client/cli/tx_test.go
Normal file
@ -0,0 +1,211 @@
|
||||
package cli_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
svrcmd "github.com/cosmos/cosmos-sdk/server/cmd"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank/client/cli"
|
||||
)
|
||||
|
||||
func (s *CLITestSuite) TestSendTxCmd() {
|
||||
accounts := s.createKeyringAccounts(1)
|
||||
cmd := cli.NewSendTxCmd()
|
||||
cmd.SetOutput(io.Discard)
|
||||
|
||||
extraArgs := []string{
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin("photon", sdk.NewInt(10))).String()),
|
||||
fmt.Sprintf("--%s=test-chain", flags.FlagChainID),
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
ctxGen func() client.Context
|
||||
from, to sdk.AccAddress
|
||||
amount sdk.Coins
|
||||
extraArgs []string
|
||||
expectErr bool
|
||||
}{
|
||||
{
|
||||
"valid transaction",
|
||||
func() client.Context {
|
||||
return s.baseCtx
|
||||
},
|
||||
accounts[0].address,
|
||||
accounts[0].address,
|
||||
sdk.NewCoins(
|
||||
sdk.NewCoin("stake", sdk.NewInt(10)),
|
||||
sdk.NewCoin("photon", sdk.NewInt(40)),
|
||||
),
|
||||
extraArgs,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"invalid to address",
|
||||
func() client.Context {
|
||||
return s.baseCtx
|
||||
},
|
||||
accounts[0].address,
|
||||
sdk.AccAddress{},
|
||||
sdk.NewCoins(
|
||||
sdk.NewCoin("stake", sdk.NewInt(10)),
|
||||
sdk.NewCoin("photon", sdk.NewInt(40)),
|
||||
),
|
||||
extraArgs,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"invalid coins",
|
||||
func() client.Context {
|
||||
return s.baseCtx
|
||||
},
|
||||
accounts[0].address,
|
||||
accounts[0].address,
|
||||
nil,
|
||||
extraArgs,
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
s.Run(tc.name, func() {
|
||||
ctx := svrcmd.CreateExecuteContext(context.Background())
|
||||
|
||||
cmd.SetContext(ctx)
|
||||
cmd.SetArgs(append([]string{tc.from.String(), tc.to.String(), tc.amount.String()}, tc.extraArgs...))
|
||||
|
||||
s.Require().NoError(client.SetCmdClientContextHandler(tc.ctxGen(), cmd))
|
||||
|
||||
err := cmd.Execute()
|
||||
if tc.expectErr {
|
||||
s.Require().Error(err)
|
||||
} else {
|
||||
s.Require().NoError(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *CLITestSuite) TestMultiSendTxCmd() {
|
||||
accounts := s.createKeyringAccounts(3)
|
||||
|
||||
cmd := cli.NewMultiSendTxCmd()
|
||||
cmd.SetOutput(io.Discard)
|
||||
|
||||
extraArgs := []string{
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin("photon", sdk.NewInt(10))).String()),
|
||||
fmt.Sprintf("--%s=test-chain", flags.FlagChainID),
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
ctxGen func() client.Context
|
||||
from string
|
||||
to []string
|
||||
amount sdk.Coins
|
||||
extraArgs []string
|
||||
expectErr bool
|
||||
}{
|
||||
{
|
||||
"valid transaction",
|
||||
func() client.Context {
|
||||
return s.baseCtx
|
||||
},
|
||||
accounts[0].address.String(),
|
||||
[]string{
|
||||
accounts[1].address.String(),
|
||||
accounts[2].address.String(),
|
||||
},
|
||||
sdk.NewCoins(
|
||||
sdk.NewCoin("stake", sdk.NewInt(10)),
|
||||
sdk.NewCoin("photon", sdk.NewInt(40)),
|
||||
),
|
||||
extraArgs,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"invalid from address",
|
||||
func() client.Context {
|
||||
return s.baseCtx
|
||||
},
|
||||
"foo",
|
||||
[]string{
|
||||
accounts[1].address.String(),
|
||||
accounts[2].address.String(),
|
||||
},
|
||||
sdk.NewCoins(
|
||||
sdk.NewCoin("stake", sdk.NewInt(10)),
|
||||
sdk.NewCoin("photon", sdk.NewInt(40)),
|
||||
),
|
||||
extraArgs,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"invalid recipients",
|
||||
func() client.Context {
|
||||
return s.baseCtx
|
||||
},
|
||||
accounts[0].address.String(),
|
||||
[]string{
|
||||
accounts[1].address.String(),
|
||||
"bar",
|
||||
},
|
||||
sdk.NewCoins(
|
||||
sdk.NewCoin("stake", sdk.NewInt(10)),
|
||||
sdk.NewCoin("photon", sdk.NewInt(40)),
|
||||
),
|
||||
extraArgs,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"invalid amount",
|
||||
func() client.Context {
|
||||
return s.baseCtx
|
||||
},
|
||||
accounts[0].address.String(),
|
||||
[]string{
|
||||
accounts[1].address.String(),
|
||||
accounts[2].address.String(),
|
||||
},
|
||||
nil,
|
||||
extraArgs,
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
s.Run(tc.name, func() {
|
||||
ctx := svrcmd.CreateExecuteContext(context.Background())
|
||||
|
||||
var args []string
|
||||
args = append(args, tc.from)
|
||||
args = append(args, tc.to...)
|
||||
args = append(args, tc.amount.String())
|
||||
args = append(args, tc.extraArgs...)
|
||||
|
||||
cmd.SetContext(ctx)
|
||||
cmd.SetArgs(args)
|
||||
|
||||
s.Require().NoError(client.SetCmdClientContextHandler(tc.ctxGen(), cmd))
|
||||
|
||||
err := cmd.Execute()
|
||||
if tc.expectErr {
|
||||
s.Require().Error(err)
|
||||
} else {
|
||||
s.Require().NoError(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
package testutil
|
||||
@ -209,7 +209,6 @@ $ %s gentx my-key-name 1000000stake --home=/path/to/home/dir --keyring-backend=o
|
||||
|
||||
cmd.Flags().String(flags.FlagHome, defaultNodeHome, "The application home directory")
|
||||
cmd.Flags().String(flags.FlagOutputDocument, "", "Write the genesis transaction JSON document to the given file instead of the default location")
|
||||
cmd.Flags().String(flags.FlagChainID, "", "The network chain ID")
|
||||
cmd.Flags().AddFlagSet(fsCreateValidator)
|
||||
flags.AddTxFlagsToCmd(cmd)
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user