From 7ebbfa0b300ca54f6b0e7dcbdf351965dd7569d4 Mon Sep 17 00:00:00 2001 From: likhita-809 <78951027+likhita-809@users.noreply.github.com> Date: Mon, 19 Sep 2022 18:31:49 +0530 Subject: [PATCH] refactor(nft): CLI tests using Tendermint Mock (#13256) * wip: move nft cli tests to e2e tests * wip: add cli tests using Tendermint Mock * cleanup genutil test file * remove unncessary test cases * address review comments Co-authored-by: Julien Robert Co-authored-by: Marko Co-authored-by: Aleksandr Bezobchuk --- .../e2e/nft/{client/testutil => }/cli_test.go | 6 +- .../client/testutil => tests/e2e/nft}/grpc.go | 2 +- .../testutil => tests/e2e/nft}/query.go | 2 +- .../testutil => tests/e2e/nft}/test_helper.go | 2 +- .../client/testutil => tests/e2e/nft}/tx.go | 6 +- x/genutil/client/cli/validate_genesis_test.go | 3 - x/nft/client/cli/query_test.go | 303 ++++++++++++++++++ x/nft/client/cli/tx_test.go | 226 +++++++++++++ 8 files changed, 538 insertions(+), 12 deletions(-) rename tests/e2e/nft/{client/testutil => }/cli_test.go (67%) rename {x/nft/client/testutil => tests/e2e/nft}/grpc.go (99%) rename {x/nft/client/testutil => tests/e2e/nft}/query.go (99%) rename {x/nft/client/testutil => tests/e2e/nft}/test_helper.go (99%) rename {x/nft/client/testutil => tests/e2e/nft}/tx.go (96%) create mode 100644 x/nft/client/cli/query_test.go create mode 100644 x/nft/client/cli/tx_test.go diff --git a/tests/e2e/nft/client/testutil/cli_test.go b/tests/e2e/nft/cli_test.go similarity index 67% rename from tests/e2e/nft/client/testutil/cli_test.go rename to tests/e2e/nft/cli_test.go index dbc2dde0bb..0a76010a64 100644 --- a/tests/e2e/nft/client/testutil/cli_test.go +++ b/tests/e2e/nft/cli_test.go @@ -1,7 +1,7 @@ //go:build e2e // +build e2e -package testutil +package nft import ( "testing" @@ -9,12 +9,12 @@ import ( "github.com/stretchr/testify/suite" "cosmossdk.io/simapp" + "github.com/cosmos/cosmos-sdk/testutil/network" - clienttestutil "github.com/cosmos/cosmos-sdk/x/nft/client/testutil" ) func TestIntegrationTestSuite(t *testing.T) { cfg := network.DefaultConfig(simapp.NewTestNetworkFixture) cfg.NumValidators = 1 - suite.Run(t, clienttestutil.NewIntegrationTestSuite(cfg)) + suite.Run(t, NewIntegrationTestSuite(cfg)) } diff --git a/x/nft/client/testutil/grpc.go b/tests/e2e/nft/grpc.go similarity index 99% rename from x/nft/client/testutil/grpc.go rename to tests/e2e/nft/grpc.go index 11ba5b7772..718793f0b8 100644 --- a/x/nft/client/testutil/grpc.go +++ b/tests/e2e/nft/grpc.go @@ -1,4 +1,4 @@ -package testutil +package nft import ( "fmt" diff --git a/x/nft/client/testutil/query.go b/tests/e2e/nft/query.go similarity index 99% rename from x/nft/client/testutil/query.go rename to tests/e2e/nft/query.go index ecc9660d2a..56e0265fbf 100644 --- a/x/nft/client/testutil/query.go +++ b/tests/e2e/nft/query.go @@ -1,4 +1,4 @@ -package testutil +package nft import ( "github.com/cosmos/cosmos-sdk/x/nft" diff --git a/x/nft/client/testutil/test_helper.go b/tests/e2e/nft/test_helper.go similarity index 99% rename from x/nft/client/testutil/test_helper.go rename to tests/e2e/nft/test_helper.go index 20edd5cbfc..ca3958c916 100644 --- a/x/nft/client/testutil/test_helper.go +++ b/tests/e2e/nft/test_helper.go @@ -1,4 +1,4 @@ -package testutil +package nft import ( "fmt" diff --git a/x/nft/client/testutil/tx.go b/tests/e2e/nft/tx.go similarity index 96% rename from x/nft/client/testutil/tx.go rename to tests/e2e/nft/tx.go index a605824129..919e8e8bb9 100644 --- a/x/nft/client/testutil/tx.go +++ b/tests/e2e/nft/tx.go @@ -1,4 +1,4 @@ -package testutil +package nft import ( "fmt" @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/suite" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/testutil/cli" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" "github.com/cosmos/cosmos-sdk/testutil/network" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/nft" @@ -160,6 +160,6 @@ func (s *IntegrationTestSuite) initAccount() { s.Require().NoError(err) amount := sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(200))) - _, err = cli.MsgSendExec(ctx, val.Address, s.owner, amount, args...) + _, err = clitestutil.MsgSendExec(ctx, val.Address, s.owner, amount, args...) s.Require().NoError(err) } diff --git a/x/genutil/client/cli/validate_genesis_test.go b/x/genutil/client/cli/validate_genesis_test.go index 73e1aab3a3..f981f172b8 100644 --- a/x/genutil/client/cli/validate_genesis_test.go +++ b/x/genutil/client/cli/validate_genesis_test.go @@ -67,9 +67,6 @@ var v040Valid = `{ }` func (s *CLITestSuite) TestValidateGenesis() { - // accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 1) - // val0 := accounts[0] - testCases := []struct { name string genesis string diff --git a/x/nft/client/cli/query_test.go b/x/nft/client/cli/query_test.go new file mode 100644 index 0000000000..b8e6b33a6f --- /dev/null +++ b/x/nft/client/cli/query_test.go @@ -0,0 +1,303 @@ +package cli_test + +import ( + "fmt" + + tmcli "github.com/tendermint/tendermint/libs/cli" + + "github.com/cosmos/cosmos-sdk/testutil" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + "github.com/cosmos/cosmos-sdk/x/nft" + "github.com/cosmos/cosmos-sdk/x/nft/client/cli" +) + +func (s *CLITestSuite) TestQueryClass() { + testCases := []struct { + name string + args struct { + ClassID string + } + expectErr bool + }{ + { + name: "valid case", + args: struct { + ClassID string + }{ + ClassID: testClassID, + }, + expectErr: false, + }, + } + + for _, tc := range testCases { + s.Run(tc.name, func() { + cmd := cli.GetCmdQueryClass() + var args []string + args = append(args, tc.args.ClassID) + args = append(args, fmt.Sprintf("--%s=json", tmcli.OutputFlag)) + out, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, args) + + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + var result nft.QueryClassResponse + err = s.clientCtx.Codec.UnmarshalJSON(out.Bytes(), &result) + s.Require().NoError(err) + } + }) + } +} + +func (s *CLITestSuite) TestQueryClasses() { + testCases := []struct { + name string + expectErr bool + }{ + { + name: "no params", + expectErr: false, + }, + } + + for _, tc := range testCases { + s.Run(tc.name, func() { + cmd := cli.GetCmdQueryClasses() + var args []string + args = append(args, fmt.Sprintf("--%s=json", tmcli.OutputFlag)) + out, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, args) + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + var result nft.QueryClassesResponse + err = s.clientCtx.Codec.UnmarshalJSON(out.Bytes(), &result) + s.Require().NoError(err) + } + }) + } +} + +func (s *CLITestSuite) TestQueryNFT() { + testCases := []struct { + name string + args struct { + ClassID string + ID string + } + expectErr bool + }{ + { + name: "valid case", + args: struct { + ClassID string + ID string + }{ + ClassID: testClassID, + ID: testID, + }, + expectErr: false, + }, + } + + for _, tc := range testCases { + s.Run(tc.name, func() { + cmd := cli.GetCmdQueryNFT() + var args []string + args = append(args, tc.args.ClassID) + args = append(args, tc.args.ID) + args = append(args, fmt.Sprintf("--%s=json", tmcli.OutputFlag)) + + out, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, args) + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + var result nft.QueryNFTResponse + err = s.clientCtx.Codec.UnmarshalJSON(out.Bytes(), &result) + s.Require().NoError(err) + } + }) + } +} + +func (s *CLITestSuite) TestQueryNFTs() { + accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 1) + + testCases := []struct { + name string + args struct { + ClassID string + Owner string + } + expectErr bool + }{ + { + name: "empty class id and owner", + args: struct { + ClassID string + Owner string + }{}, + expectErr: true, + }, + { + name: "valid case", + args: struct { + ClassID string + Owner string + }{ + ClassID: testClassID, + Owner: accounts[0].Address.String(), + }, + expectErr: false, + }, + } + + for _, tc := range testCases { + s.Run(tc.name, func() { + cmd := cli.GetCmdQueryNFTs() + var args []string + args = append(args, fmt.Sprintf("--%s=%s", cli.FlagClassID, tc.args.ClassID)) + args = append(args, fmt.Sprintf("--%s=%s", cli.FlagOwner, tc.args.Owner)) + args = append(args, fmt.Sprintf("--%s=json", tmcli.OutputFlag)) + + out, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, args) + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + var result nft.QueryNFTsResponse + err = s.clientCtx.Codec.UnmarshalJSON(out.Bytes(), &result) + s.Require().NoError(err) + } + }) + } +} + +func (s *CLITestSuite) TestQueryOwner() { + testCases := []struct { + name string + args struct { + ClassID string + ID string + } + expectErr bool + }{ + { + name: "valid case", + args: struct { + ClassID string + ID string + }{ + ClassID: testClassID, + ID: testID, + }, + expectErr: false, + }, + } + + for _, tc := range testCases { + s.Run(tc.name, func() { + cmd := cli.GetCmdQueryOwner() + var args []string + args = append(args, tc.args.ClassID) + args = append(args, tc.args.ID) + args = append(args, fmt.Sprintf("--%s=json", tmcli.OutputFlag)) + + out, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, args) + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + var result nft.QueryOwnerResponse + err = s.clientCtx.Codec.UnmarshalJSON(out.Bytes(), &result) + s.Require().NoError(err) + } + }) + } +} + +func (s *CLITestSuite) TestQueryBalance() { + accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 1) + + testCases := []struct { + name string + args struct { + ClassID string + Owner string + } + expectErr bool + }{ + { + name: "valid case", + args: struct { + ClassID string + Owner string + }{ + ClassID: testClassID, + Owner: accounts[0].Address.String(), + }, + expectErr: false, + }, + } + + for _, tc := range testCases { + s.Run(tc.name, func() { + cmd := cli.GetCmdQueryBalance() + var args []string + args = append(args, tc.args.Owner) + args = append(args, tc.args.ClassID) + args = append(args, fmt.Sprintf("--%s=json", tmcli.OutputFlag)) + + out, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, args) + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + var result nft.QueryBalanceResponse + err = s.clientCtx.Codec.UnmarshalJSON(out.Bytes(), &result) + s.Require().NoError(err) + } + }) + } +} + +func (s *CLITestSuite) TestQuerySupply() { + testCases := []struct { + name string + args struct { + ClassID string + } + expectErr bool + }{ + { + name: "valid case", + args: struct { + ClassID string + }{ + ClassID: testClassID, + }, + expectErr: false, + }, + } + + for _, tc := range testCases { + s.Run(tc.name, func() { + cmd := cli.GetCmdQuerySupply() + var args []string + args = append(args, tc.args.ClassID) + args = append(args, fmt.Sprintf("--%s=json", tmcli.OutputFlag)) + + out, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, args) + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + var result nft.QuerySupplyResponse + err = s.clientCtx.Codec.UnmarshalJSON(out.Bytes(), &result) + s.Require().NoError(err) + } + }) + } +} diff --git a/x/nft/client/cli/tx_test.go b/x/nft/client/cli/tx_test.go new file mode 100644 index 0000000000..9113147f52 --- /dev/null +++ b/x/nft/client/cli/tx_test.go @@ -0,0 +1,226 @@ +package cli_test + +import ( + "bytes" + "context" + "fmt" + "io" + "testing" + + "github.com/stretchr/testify/suite" + abci "github.com/tendermint/tendermint/abci/types" + tmbytes "github.com/tendermint/tendermint/libs/bytes" + rpcclient "github.com/tendermint/tendermint/rpc/client" + rpcclientmock "github.com/tendermint/tendermint/rpc/client/mock" + coretypes "github.com/tendermint/tendermint/rpc/core/types" + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + svrcmd "github.com/cosmos/cosmos-sdk/server/cmd" + "github.com/cosmos/cosmos-sdk/testutil" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + "github.com/cosmos/cosmos-sdk/testutil/network" + sdk "github.com/cosmos/cosmos-sdk/types" + testutilmod "github.com/cosmos/cosmos-sdk/types/module/testutil" + "github.com/cosmos/cosmos-sdk/x/genutil" + "github.com/cosmos/cosmos-sdk/x/nft" + "github.com/cosmos/cosmos-sdk/x/nft/client/cli" + nfttestutil "github.com/cosmos/cosmos-sdk/x/nft/testutil" +) + +const ( + OwnerName = "owner" + Owner = "cosmos1kznrznww4pd6gx0zwrpthjk68fdmqypjpkj5hp" + OwnerArmor = `-----BEGIN TENDERMINT PRIVATE KEY----- +salt: C3586B75587D2824187D2CDA22B6AFB6 +type: secp256k1 +kdf: bcrypt + +1+15OrCKgjnwym1zO3cjo/SGe3PPqAYChQ5wMHjdUbTZM7mWsH3/ueL6swgjzI3b +DDzEQAPXBQflzNW6wbne9IfT651zCSm+j1MWaGk= +=wEHs +-----END TENDERMINT PRIVATE KEY-----` + + testClassID = "kitty" + testClassName = "Crypto Kitty" + testClassSymbol = "kitty" + testClassDescription = "Crypto Kitty" + testClassURI = "class uri" + testID = "kitty1" + testURI = "kitty uri" +) + +var ( + ExpClass = nft.Class{ + Id: testClassID, + Name: testClassName, + Symbol: testClassSymbol, + Description: testClassDescription, + Uri: testClassURI, + } + + ExpNFT = nft.NFT{ + ClassId: testClassID, + Id: testID, + Uri: testURI, + } +) + +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) BroadcastTxCommit(_ context.Context, _ tmtypes.Tx) (*coretypes.ResultBroadcastTxCommit, error) { + return &coretypes.ResultBroadcastTxCommit{}, nil +} + +func (m mockTendermintRPC) ABCIQueryWithOptions( + _ context.Context, + _ string, _ tmbytes.HexBytes, + _ rpcclient.ABCIQueryOptions, +) (*coretypes.ResultABCIQuery, error) { + return &coretypes.ResultABCIQuery{Response: m.responseQuery}, nil +} + +type CLITestSuite struct { + suite.Suite + + kr keyring.Keyring + encCfg testutilmod.TestEncodingConfig + baseCtx client.Context + clientCtx client.Context + ctx context.Context + + owner sdk.AccAddress +} + +func TestCLITestSuite(t *testing.T) { + suite.Run(t, new(CLITestSuite)) +} + +func (s *CLITestSuite) SetupSuite() { + s.encCfg = testutilmod.MakeTestEncodingConfig(genutil.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.Client{}}). + WithAccountRetriever(client.MockAccountRetriever{}). + WithOutput(io.Discard). + WithChainID("test-chain") + + s.ctx = svrcmd.CreateExecuteContext(context.Background()) + var outBuf bytes.Buffer + ctxGen := func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + } + s.clientCtx = ctxGen().WithOutput(&outBuf) + + cfg, err := network.DefaultConfigWithAppConfig(nfttestutil.AppConfig) + s.Require().NoError(err) + + genesisState := cfg.GenesisState + nftGenesis := nft.GenesisState{ + Classes: []*nft.Class{&ExpClass}, + Entries: []*nft.Entry{{ + Owner: Owner, + Nfts: []*nft.NFT{&ExpNFT}, + }}, + } + + nftDataBz, err := s.encCfg.Codec.MarshalJSON(&nftGenesis) + s.Require().NoError(err) + genesisState[nft.ModuleName] = nftDataBz + + s.initAccount() +} + +func (s *CLITestSuite) TestCLITxSend() { + accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 1) + + args := []string{ + fmt.Sprintf("--%s=%s", flags.FlagFrom, OwnerName), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(10))).String()), + } + + testCases := []struct { + name string + args []string + expectedCode uint32 + expectErr bool + }{ + { + "valid transaction", + []string{ + testClassID, + testID, + accounts[0].Address.String(), + }, + 0, + false, + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + + args = append(args, tc.args...) + cmd := cli.NewCmdSend() + cmd.SetContext(s.ctx) + cmd.SetArgs(args) + + s.Require().NoError(client.SetCmdClientContextHandler(s.clientCtx, cmd)) + + out, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, args) + if tc.expectErr { + s.Require().Error(err) + } else { + var txResp sdk.TxResponse + s.Require().NoError(err) + s.Require().NoError(s.clientCtx.Codec.UnmarshalJSON(out.Bytes(), &txResp), out.String()) + s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) + } + }) + } +} + +func (s *CLITestSuite) initAccount() { + ctx := s.clientCtx + err := ctx.Keyring.ImportPrivKey(OwnerName, OwnerArmor, "1234567890") + s.Require().NoError(err) + accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 1) + + keyinfo, err := ctx.Keyring.Key(OwnerName) + s.Require().NoError(err) + + args := []string{ + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(10))).String()), + } + + s.owner, err = keyinfo.GetAddress() + s.Require().NoError(err) + + amount := sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(200))) + _, err = clitestutil.MsgSendExec(ctx, accounts[0].Address, s.owner, amount, args...) + s.Require().NoError(err) +}