From b57ca602776c2e288e597610f1d7e0cec1e1db0b Mon Sep 17 00:00:00 2001 From: Prathamesh Musale Date: Fri, 1 Mar 2024 11:52:37 +0530 Subject: [PATCH 01/14] Create setup for e2e CLI tests --- Makefile | 3 ++ README.md | 6 ++- scripts/protocgen.sh | 1 - tests/Makefile | 4 +- tests/e2e/auction/cli_test.go | 16 ++++++++ tests/e2e/auction/suite.go | 76 +++++++++++++++++++++++++++++++++++ tests/e2e/common.go | 63 +++++++++++++++++++++++++++++ 7 files changed, 166 insertions(+), 3 deletions(-) create mode 100644 tests/e2e/auction/cli_test.go create mode 100644 tests/e2e/auction/suite.go create mode 100644 tests/e2e/common.go diff --git a/Makefile b/Makefile index 6ce6a9da..6617ec11 100644 --- a/Makefile +++ b/Makefile @@ -88,3 +88,6 @@ lint-fix: test-integration: $(MAKE) -C tests test-integration + +test-e2e: + $(MAKE) -C tests test-e2e diff --git a/README.md b/README.md index ab165b07..6648efc8 100644 --- a/README.md +++ b/README.md @@ -10,11 +10,15 @@ Install and run `laconic2d`: make init # start the chain - laconic2d start + laconic2d start --gql-playground --gql-server ``` Run tests: ```bash + # integration tests make test-integration + + # e2e tests + make test-e2e ``` diff --git a/scripts/protocgen.sh b/scripts/protocgen.sh index a18fcb37..6acf722a 100755 --- a/scripts/protocgen.sh +++ b/scripts/protocgen.sh @@ -16,7 +16,6 @@ for dir in $proto_dirs; do done done -# TODO: Check if required echo "Generating pulsar proto code" buf generate --template buf.gen.pulsar.yaml diff --git a/tests/Makefile b/tests/Makefile index 3ed7cfec..d992d555 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,2 +1,4 @@ test-integration: - go test -mod=readonly ./integration/... -test.v -timeout 10m + +test-e2e: + go test ./e2e/... -mod=readonly -test.v -timeout 10m diff --git a/tests/e2e/auction/cli_test.go b/tests/e2e/auction/cli_test.go new file mode 100644 index 00000000..6fe03c4d --- /dev/null +++ b/tests/e2e/auction/cli_test.go @@ -0,0 +1,16 @@ +package auction + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/testutil/network" + "github.com/stretchr/testify/suite" + + "git.vdb.to/cerc-io/laconic2d/tests/e2e" +) + +func TestE2ETestSuite(t *testing.T) { + cfg := network.DefaultConfig(e2e.NewTestNetworkFixture) + cfg.NumValidators = 2 + suite.Run(t, NewE2ETestSuite(cfg)) +} diff --git a/tests/e2e/auction/suite.go b/tests/e2e/auction/suite.go new file mode 100644 index 00000000..ef929af5 --- /dev/null +++ b/tests/e2e/auction/suite.go @@ -0,0 +1,76 @@ +package auction + +import ( + "fmt" + + "cosmossdk.io/math" + "github.com/stretchr/testify/suite" + + "github.com/cosmos/cosmos-sdk/client/flags" + addresscodec "github.com/cosmos/cosmos-sdk/codec/address" + "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + "github.com/cosmos/cosmos-sdk/testutil/network" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +var ( + ownerAccount = "owner" + bidderAccount = "bidder" + ownerAddress string + bidderAddress string +) + +type E2ETestSuite struct { + suite.Suite + + cfg network.Config + network *network.Network +} + +func NewE2ETestSuite(cfg network.Config) *E2ETestSuite { + return &E2ETestSuite{cfg: cfg} +} + +func (s *E2ETestSuite) SetupSuite() { //nolint: all + s.T().Log("setting up e2e test suite") + + var err error + + s.network, err = network.New(s.T(), s.T().TempDir(), s.cfg) + s.Require().NoError(err) + + _, err = s.network.WaitForHeight(1) + s.Require().NoError(err) + + // setting up random owner and bidder accounts + s.createAccountWithBalance(ownerAccount, &ownerAddress) + s.createAccountWithBalance(bidderAccount, &bidderAddress) + + // s.defaultAuctionID = s.createAuctionAndBid(true, false) +} + +func (s *E2ETestSuite) createAccountWithBalance(accountName string, accountAddress *string) { + val := s.network.Validators[0] + sr := s.Require() + + info, _, err := val.ClientCtx.Keyring.NewMnemonic(accountName, keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1) + sr.NoError(err) + + newAddr, _ := info.GetAddress() + _, err = clitestutil.MsgSendExec( + val.ClientCtx, + val.Address, + newAddr, + sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(200000))), + addresscodec.NewBech32Codec("laconic"), + fmt.Sprintf("--%s=%s", flags.FlagFrom, accountName), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=json", flags.FlagOutput), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()), + ) + sr.NoError(err) + *accountAddress = newAddr.String() +} diff --git a/tests/e2e/common.go b/tests/e2e/common.go new file mode 100644 index 00000000..5d446527 --- /dev/null +++ b/tests/e2e/common.go @@ -0,0 +1,63 @@ +package e2e + +import ( + "fmt" + "os" + + "cosmossdk.io/log" + pruningtypes "cosmossdk.io/store/pruning/types" + + dbm "github.com/cosmos/cosmos-db" + bam "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/client/flags" + servertypes "github.com/cosmos/cosmos-sdk/server/types" + "github.com/cosmos/cosmos-sdk/testutil/network" + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" + "github.com/cosmos/cosmos-sdk/types/module/testutil" + "github.com/cosmos/cosmos-sdk/x/auth" + + laconicApp "git.vdb.to/cerc-io/laconic2d/app" + auctionmodule "git.vdb.to/cerc-io/laconic2d/x/auction/module" + bondmodule "git.vdb.to/cerc-io/laconic2d/x/bond/module" + registrymodule "git.vdb.to/cerc-io/laconic2d/x/registry/module" +) + +// NewTestNetworkFixture returns a new simapp AppConstructor for network simulation tests +func NewTestNetworkFixture() network.TestFixture { + dir, err := os.MkdirTemp("", "simapp") + if err != nil { + panic(fmt.Sprintf("failed creating temporary directory: %v", err)) + } + defer os.RemoveAll(dir) + + app, err := laconicApp.NewLaconicApp(log.NewNopLogger(), dbm.NewMemDB(), nil, true, simtestutil.NewAppOptionsWithFlagHome(dir)) + if err != nil { + panic(fmt.Sprintf("failed to create laconic app: %v", err)) + } + + appCtr := func(val network.ValidatorI) servertypes.Application { + app, err := laconicApp.NewLaconicApp( + val.GetCtx().Logger, dbm.NewMemDB(), nil, true, + simtestutil.NewAppOptionsWithFlagHome(val.GetCtx().Config.RootDir), + bam.SetPruning(pruningtypes.NewPruningOptionsFromString(val.GetAppConfig().Pruning)), + bam.SetMinGasPrices(val.GetAppConfig().MinGasPrices), + bam.SetChainID(val.GetCtx().Viper.GetString(flags.FlagChainID)), + ) + if err != nil { + panic(fmt.Sprintf("failed creating temporary directory: %v", err)) + } + + return app + } + + return network.TestFixture{ + AppConstructor: appCtr, + GenesisState: app.DefaultGenesis(), + EncodingConfig: testutil.MakeTestEncodingConfig( + auth.AppModuleBasic{}, + auctionmodule.AppModule{}, + bondmodule.AppModule{}, + registrymodule.AppModule{}, + ), + } +} -- 2.45.2 From eefaa42eeca2f7ffb295866fe842074d9f971076 Mon Sep 17 00:00:00 2001 From: Prathamesh Musale Date: Fri, 1 Mar 2024 14:56:08 +0530 Subject: [PATCH 02/14] Add a test for params gRPC request --- tests/e2e/auction/cli_test.go | 3 ++- tests/e2e/auction/grpc.go | 26 ++++++++++++++++++++++++++ tests/e2e/common.go | 10 ++++++++-- 3 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 tests/e2e/auction/grpc.go diff --git a/tests/e2e/auction/cli_test.go b/tests/e2e/auction/cli_test.go index 6fe03c4d..2ba78f32 100644 --- a/tests/e2e/auction/cli_test.go +++ b/tests/e2e/auction/cli_test.go @@ -11,6 +11,7 @@ import ( func TestE2ETestSuite(t *testing.T) { cfg := network.DefaultConfig(e2e.NewTestNetworkFixture) - cfg.NumValidators = 2 + cfg.NumValidators = 1 + suite.Run(t, NewE2ETestSuite(cfg)) } diff --git a/tests/e2e/auction/grpc.go b/tests/e2e/auction/grpc.go new file mode 100644 index 00000000..332bc103 --- /dev/null +++ b/tests/e2e/auction/grpc.go @@ -0,0 +1,26 @@ +package auction + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/testutil" + + auctiontypes "git.vdb.to/cerc-io/laconic2d/x/auction" +) + +func (ets *E2ETestSuite) TestQueryParamsGrpc() { + val := ets.network.Validators[0] + sr := ets.Require() + reqURL := fmt.Sprintf("%s/cerc/auction/v1/params", val.APIAddress) + + ets.Run("valid request to get auction params", func() { + resp, err := testutil.GetRequest(reqURL) + ets.Require().NoError(err) + + var params auctiontypes.QueryParamsResponse + err = val.ClientCtx.Codec.UnmarshalJSON(resp, ¶ms) + + sr.NoError(err) + sr.Equal(*params.GetParams(), auctiontypes.DefaultParams()) + }) +} diff --git a/tests/e2e/common.go b/tests/e2e/common.go index 5d446527..12adbffc 100644 --- a/tests/e2e/common.go +++ b/tests/e2e/common.go @@ -15,16 +15,18 @@ import ( simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" "github.com/cosmos/cosmos-sdk/types/module/testutil" "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/staking" laconicApp "git.vdb.to/cerc-io/laconic2d/app" + "git.vdb.to/cerc-io/laconic2d/app/params" auctionmodule "git.vdb.to/cerc-io/laconic2d/x/auction/module" bondmodule "git.vdb.to/cerc-io/laconic2d/x/bond/module" registrymodule "git.vdb.to/cerc-io/laconic2d/x/registry/module" ) -// NewTestNetworkFixture returns a new simapp AppConstructor for network simulation tests +// NewTestNetworkFixture returns a new LaconicApp AppConstructor for network simulation tests func NewTestNetworkFixture() network.TestFixture { - dir, err := os.MkdirTemp("", "simapp") + dir, err := os.MkdirTemp("", "laconic") if err != nil { panic(fmt.Sprintf("failed creating temporary directory: %v", err)) } @@ -50,11 +52,15 @@ func NewTestNetworkFixture() network.TestFixture { return app } + // Update prefixes + params.SetAddressPrefixes() + return network.TestFixture{ AppConstructor: appCtr, GenesisState: app.DefaultGenesis(), EncodingConfig: testutil.MakeTestEncodingConfig( auth.AppModuleBasic{}, + staking.AppModuleBasic{}, auctionmodule.AppModule{}, bondmodule.AppModule{}, registrymodule.AppModule{}, -- 2.45.2 From fd755d1c27f718697333b745cd53d15b19f3122d Mon Sep 17 00:00:00 2001 From: Prathamesh Musale Date: Fri, 1 Mar 2024 15:21:36 +0530 Subject: [PATCH 03/14] Add a test for auctions gRPC request --- tests/Makefile | 1 + tests/e2e/auction/grpc.go | 46 ++++++++++++++++++++ tests/e2e/auction/query.go | 45 ++++++++++++++++++++ tests/e2e/auction/suite.go | 79 ++++++++++++++++++++++++++++------- x/auction/client/cli/query.go | 35 ++++++++++++++++ x/auction/client/cli/tx.go | 58 +++++++++++++++++++++++++ x/auction/msgs.go | 21 ++++++++++ 7 files changed, 270 insertions(+), 15 deletions(-) create mode 100644 tests/e2e/auction/query.go create mode 100644 x/auction/client/cli/query.go diff --git a/tests/Makefile b/tests/Makefile index d992d555..0349dfc1 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,4 +1,5 @@ test-integration: + go test -mod=readonly ./integration/... -test.v -timeout 10m test-e2e: go test ./e2e/... -mod=readonly -test.v -timeout 10m diff --git a/tests/e2e/auction/grpc.go b/tests/e2e/auction/grpc.go index 332bc103..0491698b 100644 --- a/tests/e2e/auction/grpc.go +++ b/tests/e2e/auction/grpc.go @@ -8,6 +8,12 @@ import ( auctiontypes "git.vdb.to/cerc-io/laconic2d/x/auction" ) +const ( + randomAuctionID = "randomAuctionID" + randomBidderAddress = "randomBidderAddress" + randomOwnerAddress = "randomOwnerAddress" +) + func (ets *E2ETestSuite) TestQueryParamsGrpc() { val := ets.network.Validators[0] sr := ets.Require() @@ -24,3 +30,43 @@ func (ets *E2ETestSuite) TestQueryParamsGrpc() { sr.Equal(*params.GetParams(), auctiontypes.DefaultParams()) }) } + +func (ets *E2ETestSuite) TestGetAllAuctionsGrpc() { + val := ets.network.Validators[0] + sr := ets.Require() + reqURL := fmt.Sprintf("%s/cerc/auction/v1/auctions", val.APIAddress) + + testCases := []struct { + msg string + url string + errorMsg string + isErrorExpected bool + }{ + { + "invalid request to get all auctions", + reqURL + randomAuctionID, + "", + true, + }, + { + "valid request to get all auctions", + reqURL, + "", + false, + }, + } + for _, tc := range testCases { + ets.Run(tc.msg, func() { + resp, err := testutil.GetRequest(tc.url) + if tc.isErrorExpected { + sr.Contains(string(resp), tc.errorMsg) + } else { + sr.NoError(err) + var auctions auctiontypes.QueryAuctionsResponse + err = val.ClientCtx.Codec.UnmarshalJSON(resp, &auctions) + sr.NoError(err) + sr.NotZero(len(auctions.Auctions.Auctions)) + } + }) + } +} diff --git a/tests/e2e/auction/query.go b/tests/e2e/auction/query.go new file mode 100644 index 00000000..fcca2de1 --- /dev/null +++ b/tests/e2e/auction/query.go @@ -0,0 +1,45 @@ +package auction + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/client/flags" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + + types "git.vdb.to/cerc-io/laconic2d/x/auction" + "git.vdb.to/cerc-io/laconic2d/x/auction/client/cli" +) + +var queryJSONFlag = []string{fmt.Sprintf("--%s=json", flags.FlagOutput)} + +func (ets *E2ETestSuite) TestGetCmdList() { + val := ets.network.Validators[0] + sr := ets.Require() + + testCases := []struct { + msg string + createAuction bool + }{ + { + "list auctions when no auctions exist", + false, + }, + { + "list auctions after creating an auction", + true, + }, + } + + for _, test := range testCases { + ets.Run(fmt.Sprintf("Case %s", test.msg), func() { + out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cli.GetCmdList(), queryJSONFlag) + sr.NoError(err) + var auctions types.QueryAuctionsResponse + err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &auctions) + sr.NoError(err) + if test.createAuction { + sr.NotZero(len(auctions.Auctions.Auctions)) + } + }) + } +} diff --git a/tests/e2e/auction/suite.go b/tests/e2e/auction/suite.go index ef929af5..844c323d 100644 --- a/tests/e2e/auction/suite.go +++ b/tests/e2e/auction/suite.go @@ -13,6 +13,9 @@ import ( clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" "github.com/cosmos/cosmos-sdk/testutil/network" sdk "github.com/cosmos/cosmos-sdk/types" + + types "git.vdb.to/cerc-io/laconic2d/x/auction" + "git.vdb.to/cerc-io/laconic2d/x/auction/client/cli" ) var ( @@ -27,33 +30,40 @@ type E2ETestSuite struct { cfg network.Config network *network.Network + + defaultAuctionId string } func NewE2ETestSuite(cfg network.Config) *E2ETestSuite { return &E2ETestSuite{cfg: cfg} } -func (s *E2ETestSuite) SetupSuite() { //nolint: all - s.T().Log("setting up e2e test suite") +func (ets *E2ETestSuite) SetupSuite() { //nolint: all + ets.T().Log("setting up e2e test suite") var err error - s.network, err = network.New(s.T(), s.T().TempDir(), s.cfg) - s.Require().NoError(err) + ets.network, err = network.New(ets.T(), ets.T().TempDir(), ets.cfg) + ets.Require().NoError(err) - _, err = s.network.WaitForHeight(1) - s.Require().NoError(err) + _, err = ets.network.WaitForHeight(1) + ets.Require().NoError(err) // setting up random owner and bidder accounts - s.createAccountWithBalance(ownerAccount, &ownerAddress) - s.createAccountWithBalance(bidderAccount, &bidderAddress) + ets.createAccountWithBalance(ownerAccount, &ownerAddress) + ets.createAccountWithBalance(bidderAccount, &bidderAddress) - // s.defaultAuctionID = s.createAuctionAndBid(true, false) + ets.defaultAuctionId = ets.createAuctionAndBid(true, false) } -func (s *E2ETestSuite) createAccountWithBalance(accountName string, accountAddress *string) { - val := s.network.Validators[0] - sr := s.Require() +func (ets *E2ETestSuite) TearDownSuite() { + ets.T().Log("tearing down integration test suite") + ets.network.Cleanup() +} + +func (ets *E2ETestSuite) createAccountWithBalance(accountName string, accountAddress *string) { + val := ets.network.Validators[0] + sr := ets.Require() info, _, err := val.ClientCtx.Keyring.NewMnemonic(accountName, keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1) sr.NoError(err) @@ -63,14 +73,53 @@ func (s *E2ETestSuite) createAccountWithBalance(accountName string, accountAddre val.ClientCtx, val.Address, newAddr, - sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(200000))), + sdk.NewCoins(sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(200000))), addresscodec.NewBech32Codec("laconic"), fmt.Sprintf("--%s=%s", flags.FlagFrom, accountName), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=json", flags.FlagOutput), - fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), // TODO + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(10))).String()), ) sr.NoError(err) *accountAddress = newAddr.String() } + +func (ets *E2ETestSuite) createAuctionAndBid(createAuction, createBid bool) string { + val := ets.network.Validators[0] + sr := ets.Require() + auctionId := "" + + err := ets.network.WaitForNextBlock() + sr.NoError(err) + + if createAuction { + auctionArgs := []string{ + sampleCommitTime, sampleRevealTime, + fmt.Sprintf("10%s", ets.cfg.BondDenom), + fmt.Sprintf("10%s", ets.cfg.BondDenom), + fmt.Sprintf("100%s", ets.cfg.BondDenom), + } + + resp, err := ets.executeTx(cli.GetCmdCreateAuction(), auctionArgs, ownerAccount) + sr.NoError(err) + sr.Zero(resp.Code) + out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cli.GetCmdList(), queryJSONFlag) + sr.NoError(err) + var queryResponse types.QueryAuctionsResponse + err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &queryResponse) + sr.NoError(err) + auctionId = queryResponse.Auctions.Auctions[0].Id + } else { + auctionId = ets.defaultAuctionId + } + + if createBid { + bidArgs := []string{auctionId, fmt.Sprintf("200%s", ets.cfg.BondDenom)} + resp, err := ets.executeTx(cli.GetCmdCommitBid(), bidArgs, bidderAccount) + sr.NoError(err) + sr.Zero(resp.Code) + } + + return auctionId +} diff --git a/x/auction/client/cli/query.go b/x/auction/client/cli/query.go new file mode 100644 index 00000000..6cfa10a4 --- /dev/null +++ b/x/auction/client/cli/query.go @@ -0,0 +1,35 @@ +package cli + +import ( + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/spf13/cobra" + + types "git.vdb.to/cerc-io/laconic2d/x/auction" +) + +// GetCmdList queries all auctions. +func GetCmdList() *cobra.Command { + cmd := &cobra.Command{ + Use: "list", + Short: "List auctions.", + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + res, err := queryClient.Auctions(cmd.Context(), &types.QueryAuctionsRequest{}) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + return cmd +} diff --git a/x/auction/client/cli/tx.go b/x/auction/client/cli/tx.go index 90e98030..4c75a403 100644 --- a/x/auction/client/cli/tx.go +++ b/x/auction/client/cli/tx.go @@ -4,6 +4,7 @@ import ( "encoding/hex" "fmt" "os" + "time" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" @@ -128,3 +129,60 @@ func GetCmdRevealBid() *cobra.Command { return cmd } + +func GetCmdCreateAuction() *cobra.Command { + cmd := &cobra.Command{ + Use: "create [commits-duration] [reveals-duration] [commit-fee] [reveal-fee] [minimum-bid]", + Short: "Create auction.", + Args: cobra.ExactArgs(5), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + commitsDuration, err := time.ParseDuration(args[0]) + if err != nil { + return err + } + + revealsDuration, err := time.ParseDuration(args[1]) + if err != nil { + return err + } + + commitFee, err := sdk.ParseCoinNormalized(args[2]) + if err != nil { + return err + } + + revealFee, err := sdk.ParseCoinNormalized(args[3]) + if err != nil { + return err + } + + minimumBid, err := sdk.ParseCoinNormalized(args[4]) + if err != nil { + return err + } + + params := auctiontypes.Params{ + CommitsDuration: commitsDuration, + RevealsDuration: revealsDuration, + CommitFee: commitFee, + RevealFee: revealFee, + MinimumBid: minimumBid, + } + msg := auctiontypes.NewMsgCreateAuction(params, clientCtx.GetFromAddress()) + err = msg.ValidateBasic() + if err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + return cmd +} diff --git a/x/auction/msgs.go b/x/auction/msgs.go index 6aa4f798..a21427fc 100644 --- a/x/auction/msgs.go +++ b/x/auction/msgs.go @@ -33,6 +33,27 @@ func NewMsgCommitBid(auctionId string, commitHash string, signer sdk.AccAddress) } } +// ValidateBasic Implements Msg. +func (msg MsgCreateAuction) ValidateBasic() error { + if msg.Signer == "" { + return errorsmod.Wrap(sdkerrors.ErrInvalidAddress, msg.Signer) + } + + if msg.CommitsDuration <= 0 { + return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "commit phase duration invalid.") + } + + if msg.RevealsDuration <= 0 { + return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "reveal phase duration invalid.") + } + + if !msg.MinimumBid.IsPositive() { + return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "minimum bid should be greater than zero.") + } + + return nil +} + // ValidateBasic Implements Msg. func (msg MsgCommitBid) ValidateBasic() error { if msg.Signer == "" { -- 2.45.2 From f11ae48e6f24c060e81de33ffd16a94d5c38b7d7 Mon Sep 17 00:00:00 2001 From: Prathamesh Musale Date: Sat, 2 Mar 2024 09:27:59 +0530 Subject: [PATCH 04/14] Add tests for remaining auction module gRPC requests --- tests/e2e/auction/grpc.go | 185 ++++++++++++++++++++++++++++++++++++++ tests/e2e/auction/tx.go | 45 ++++++++++ 2 files changed, 230 insertions(+) create mode 100644 tests/e2e/auction/tx.go diff --git a/tests/e2e/auction/grpc.go b/tests/e2e/auction/grpc.go index 0491698b..f4503d49 100644 --- a/tests/e2e/auction/grpc.go +++ b/tests/e2e/auction/grpc.go @@ -70,3 +70,188 @@ func (ets *E2ETestSuite) TestGetAllAuctionsGrpc() { }) } } + +func (ets *E2ETestSuite) TestGetAuctionGrpc() { + val := ets.network.Validators[0] + sr := ets.Require() + reqURL := fmt.Sprintf("%s/cerc/auction/v1/auctions/", val.APIAddress) + + testCases := []struct { + msg string + url string + errorMsg string + isErrorExpected bool + preRun func() string + }{ + { + "invalid request to get an auction", + reqURL + randomAuctionID, + "", + true, + func() string { return "" }, + }, + { + "valid request to get an auction", + reqURL, + "", + false, + func() string { return ets.defaultAuctionId }, + }, + } + for _, tc := range testCases { + ets.Run(tc.msg, func() { + auctionID := tc.preRun() + resp, err := testutil.GetRequest(tc.url + auctionID) + if tc.isErrorExpected { + sr.Contains(string(resp), tc.errorMsg) + } else { + sr.NoError(err) + var auction auctiontypes.QueryAuctionResponse + err = val.ClientCtx.Codec.UnmarshalJSON(resp, &auction) + sr.NoError(err) + sr.Equal(auctionID, auction.Auction.Id) + } + }) + } +} + +func (ets *E2ETestSuite) TestGetBidsGrpc() { + val := ets.network.Validators[0] + sr := ets.Require() + reqURL := fmt.Sprintf("%s/cerc/auction/v1/bids/", val.APIAddress) + testCases := []struct { + msg string + url string + errorMsg string + isErrorExpected bool + preRun func() string + }{ + { + "invalid request to get all bids", + reqURL, + "", + true, + func() string { return "" }, + }, + { + "valid request to get all bids", + reqURL, + "", + false, + func() string { return ets.createAuctionAndBid(false, true) }, + }, + } + + for _, tc := range testCases { + ets.Run(tc.msg, func() { + auctionID := tc.preRun() + tc.url += auctionID + resp, err := testutil.GetRequest(tc.url) + if tc.isErrorExpected { + sr.Contains(string(resp), tc.errorMsg) + } else { + sr.NoError(err) + var bids auctiontypes.QueryBidsResponse + err = val.ClientCtx.Codec.UnmarshalJSON(resp, &bids) + sr.NoError(err) + sr.Equal(auctionID, bids.Bids[0].AuctionId) + } + }) + } +} + +func (ets *E2ETestSuite) TestGetBidGrpc() { + val := ets.network.Validators[0] + sr := ets.Require() + reqURL := fmt.Sprintf("%s/cerc/auction/v1/bids/", val.APIAddress) + testCases := []struct { + msg string + url string + errorMsg string + isErrorExpected bool + }{ + { + "invalid request to get bid", + fmt.Sprintf("%s/%s/", reqURL, randomAuctionID), + "", + true, + }, + { + "valid request to get bid", + fmt.Sprintf("%s/%s/%s", reqURL, randomAuctionID, randomBidderAddress), + "", + false, + }, + } + for _, tc := range testCases { + ets.Run(tc.msg, func() { + resp, err := testutil.GetRequest(tc.url) + if tc.isErrorExpected { + sr.Contains(string(resp), tc.errorMsg) + } else { + sr.NoError(err) + var bid auctiontypes.QueryBidResponse + err = val.ClientCtx.Codec.UnmarshalJSON(resp, &bid) + sr.NoError(err) + } + }) + } +} + +func (ets *E2ETestSuite) TestGetAuctionsByOwnerGrpc() { + val := ets.network.Validators[0] + sr := ets.Require() + reqURL := fmt.Sprintf("%s/cerc/auction/v1/by-owner/", val.APIAddress) + testCases := []struct { + msg string + url string + errorMsg string + isErrorExpected bool + }{ + { + "invalid request to get auctions by owner", + reqURL, + "", + true, + }, + { + "valid request to get auctions by owner", + fmt.Sprintf("%s/%s", reqURL, randomOwnerAddress), // TODO: use ownerAddress? + "", + false, + }, + } + for _, tc := range testCases { + ets.Run(tc.msg, func() { + resp, err := testutil.GetRequest(tc.url) + if tc.isErrorExpected { + sr.Contains(string(resp), tc.errorMsg) + } else { + sr.NoError(err) + var auctions auctiontypes.QueryAuctionsResponse + err = val.ClientCtx.Codec.UnmarshalJSON(resp, &auctions) + sr.NoError(err) + } + }) + } +} + +func (ets *E2ETestSuite) TestQueryBalanceGrpc() { + val := ets.network.Validators[0] + sr := ets.Require() + reqURL := fmt.Sprintf("%s/cerc/auction/v1/balance", val.APIAddress) + msg := "valid request to get the auction module balance" + + ets.createAuctionAndBid(false, true) + + ets.Run(msg, func() { + resp, err := testutil.GetRequest(reqURL) + sr.NoError(err) + + var response auctiontypes.QueryGetAuctionModuleBalanceResponse + err = val.ClientCtx.Codec.UnmarshalJSON(resp, &response) + + sr.NoError(err) + sr.NotZero(len(response.GetBalance())) + }) +} diff --git a/tests/e2e/auction/tx.go b/tests/e2e/auction/tx.go new file mode 100644 index 00000000..419dcbd3 --- /dev/null +++ b/tests/e2e/auction/tx.go @@ -0,0 +1,45 @@ +package auction + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/client/flags" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/spf13/cobra" +) + +const ( + sampleCommitTime = "90s" + sampleRevealTime = "5s" + placeholderAuctionId = "placeholder_auction_id" +) + +func (ets *E2ETestSuite) executeTx(cmd *cobra.Command, args []string, caller string) (sdk.TxResponse, error) { + val := ets.network.Validators[0] + additionalArgs := []string{ + fmt.Sprintf("--%s=%s", flags.FlagFrom, caller), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.cfg.BondDenom)), + } + args = append(args, additionalArgs...) + + out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args) + if err != nil { + return sdk.TxResponse{}, err + } + + var resp sdk.TxResponse + err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &resp) + if err != nil { + return sdk.TxResponse{}, err + } + + err = ets.network.WaitForNextBlock() + if err != nil { + return sdk.TxResponse{}, err + } + + return resp, nil +} -- 2.45.2 From 0e2828d41e7222d1e9208d403ba1f82f33021757 Mon Sep 17 00:00:00 2001 From: Prathamesh Musale Date: Sat, 2 Mar 2024 10:48:27 +0530 Subject: [PATCH 05/14] Add a test for CLI command to commit bid --- tests/e2e/auction/grpc.go | 10 +++++-- tests/e2e/auction/suite.go | 14 +++++---- tests/e2e/auction/tx.go | 60 ++++++++++++++++++++++++++++++++++++++ tests/e2e/common.go | 6 ++-- 4 files changed, 78 insertions(+), 12 deletions(-) diff --git a/tests/e2e/auction/grpc.go b/tests/e2e/auction/grpc.go index f4503d49..ad3cabc2 100644 --- a/tests/e2e/auction/grpc.go +++ b/tests/e2e/auction/grpc.go @@ -169,23 +169,29 @@ func (ets *E2ETestSuite) TestGetBidGrpc() { url string errorMsg string isErrorExpected bool + preRun func() string }{ { "invalid request to get bid", - fmt.Sprintf("%s/%s/", reqURL, randomAuctionID), + reqURL, "", true, + func() string { return randomAuctionID }, }, { "valid request to get bid", - fmt.Sprintf("%s/%s/%s", reqURL, randomAuctionID, randomBidderAddress), + reqURL, "", false, + func() string { return ets.createAuctionAndBid(false, true) }, }, } for _, tc := range testCases { ets.Run(tc.msg, func() { + auctionID := tc.preRun() + tc.url += auctionID + "/" + bidderAddress resp, err := testutil.GetRequest(tc.url) + if tc.isErrorExpected { sr.Contains(string(resp), tc.errorMsg) } else { diff --git a/tests/e2e/auction/suite.go b/tests/e2e/auction/suite.go index 844c323d..5cd1f3dc 100644 --- a/tests/e2e/auction/suite.go +++ b/tests/e2e/auction/suite.go @@ -39,15 +39,16 @@ func NewE2ETestSuite(cfg network.Config) *E2ETestSuite { } func (ets *E2ETestSuite) SetupSuite() { //nolint: all + sr := ets.Require() ets.T().Log("setting up e2e test suite") var err error ets.network, err = network.New(ets.T(), ets.T().TempDir(), ets.cfg) - ets.Require().NoError(err) + sr.NoError(err) _, err = ets.network.WaitForHeight(1) - ets.Require().NoError(err) + sr.NoError(err) // setting up random owner and bidder accounts ets.createAccountWithBalance(ownerAccount, &ownerAddress) @@ -78,11 +79,15 @@ func (ets *E2ETestSuite) createAccountWithBalance(accountName string, accountAdd fmt.Sprintf("--%s=%s", flags.FlagFrom, accountName), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=json", flags.FlagOutput), - fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), // TODO + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(10))).String()), ) sr.NoError(err) *accountAddress = newAddr.String() + + // wait for tx to take effect + err = ets.network.WaitForNextBlock() + sr.NoError(err) } func (ets *E2ETestSuite) createAuctionAndBid(createAuction, createBid bool) string { @@ -90,9 +95,6 @@ func (ets *E2ETestSuite) createAuctionAndBid(createAuction, createBid bool) stri sr := ets.Require() auctionId := "" - err := ets.network.WaitForNextBlock() - sr.NoError(err) - if createAuction { auctionArgs := []string{ sampleCommitTime, sampleRevealTime, diff --git a/tests/e2e/auction/tx.go b/tests/e2e/auction/tx.go index 419dcbd3..1675d25e 100644 --- a/tests/e2e/auction/tx.go +++ b/tests/e2e/auction/tx.go @@ -7,6 +7,9 @@ import ( clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/spf13/cobra" + + auctiontypes "git.vdb.to/cerc-io/laconic2d/x/auction" + "git.vdb.to/cerc-io/laconic2d/x/auction/client/cli" ) const ( @@ -15,6 +18,63 @@ const ( placeholderAuctionId = "placeholder_auction_id" ) +func (ets *E2ETestSuite) TestTxCommitBid() { + val := ets.network.Validators[0] + sr := ets.Require() + testCases := []struct { + msg string + args []string + createAuction bool + }{ + { + "commit bid with missing args", + []string{fmt.Sprintf("200%s", ets.cfg.BondDenom)}, + false, + }, + { + "commit bid with valid args", + []string{ + placeholderAuctionId, + fmt.Sprintf("200%s", ets.cfg.BondDenom), + }, + true, + }, + } + + for _, test := range testCases { + ets.Run(fmt.Sprintf("Case %s", test.msg), func() { + if test.createAuction { + auctionArgs := []string{ + sampleCommitTime, sampleRevealTime, + fmt.Sprintf("10%s", ets.cfg.BondDenom), + fmt.Sprintf("10%s", ets.cfg.BondDenom), + fmt.Sprintf("100%s", ets.cfg.BondDenom), + } + + _, err := ets.executeTx(cli.GetCmdCreateAuction(), auctionArgs, ownerAccount) + sr.NoError(err) + + out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cli.GetCmdList(), + []string{fmt.Sprintf("--%s=json", flags.FlagOutput)}) + sr.NoError(err) + var queryResponse auctiontypes.QueryAuctionsResponse + err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &queryResponse) + sr.NoError(err) + sr.NotNil(queryResponse.GetAuctions()) + test.args[0] = queryResponse.GetAuctions().Auctions[0].Id + } + + resp, err := ets.executeTx(cli.GetCmdCommitBid(), test.args, bidderAccount) + if test.createAuction { + sr.NoError(err) + sr.Zero(resp.Code) + } else { + sr.Error(err) + } + }) + } +} + func (ets *E2ETestSuite) executeTx(cmd *cobra.Command, args []string, caller string) (sdk.TxResponse, error) { val := ets.network.Validators[0] additionalArgs := []string{ diff --git a/tests/e2e/common.go b/tests/e2e/common.go index 12adbffc..7a746eb1 100644 --- a/tests/e2e/common.go +++ b/tests/e2e/common.go @@ -18,10 +18,11 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking" laconicApp "git.vdb.to/cerc-io/laconic2d/app" - "git.vdb.to/cerc-io/laconic2d/app/params" auctionmodule "git.vdb.to/cerc-io/laconic2d/x/auction/module" bondmodule "git.vdb.to/cerc-io/laconic2d/x/bond/module" registrymodule "git.vdb.to/cerc-io/laconic2d/x/registry/module" + + _ "git.vdb.to/cerc-io/laconic2d/app/params" // import for side-effects (see init) ) // NewTestNetworkFixture returns a new LaconicApp AppConstructor for network simulation tests @@ -52,9 +53,6 @@ func NewTestNetworkFixture() network.TestFixture { return app } - // Update prefixes - params.SetAddressPrefixes() - return network.TestFixture{ AppConstructor: appCtr, GenesisState: app.DefaultGenesis(), -- 2.45.2 From 72fb7e5e4674f4130a19055986688d794cf4bdc0 Mon Sep 17 00:00:00 2001 From: Prathamesh Musale Date: Sat, 2 Mar 2024 10:59:01 +0530 Subject: [PATCH 06/14] Remove bid files in test cleanup --- tests/e2e/auction/suite.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/e2e/auction/suite.go b/tests/e2e/auction/suite.go index 5cd1f3dc..d408b253 100644 --- a/tests/e2e/auction/suite.go +++ b/tests/e2e/auction/suite.go @@ -2,6 +2,8 @@ package auction import ( "fmt" + "os" + "path/filepath" "cosmossdk.io/math" "github.com/stretchr/testify/suite" @@ -60,6 +62,8 @@ func (ets *E2ETestSuite) SetupSuite() { //nolint: all func (ets *E2ETestSuite) TearDownSuite() { ets.T().Log("tearing down integration test suite") ets.network.Cleanup() + + ets.cleanupBidFiles() } func (ets *E2ETestSuite) createAccountWithBalance(accountName string, accountAddress *string) { @@ -125,3 +129,20 @@ func (ets *E2ETestSuite) createAuctionAndBid(createAuction, createBid bool) stri return auctionId } + +func (ets *E2ETestSuite) cleanupBidFiles() error { + matches, err := filepath.Glob(fmt.Sprintf("%s-*.json", bidderAccount)) + if err != nil { + fmt.Printf("Error matching bidder files: %v\n", err) + return err + } + + for _, match := range matches { + err := os.Remove(match) + if err != nil { + return err + } + } + + return nil +} -- 2.45.2 From cc6f2070b5c30a9fb86ee8c576aff7f1bd5f9b66 Mon Sep 17 00:00:00 2001 From: Prathamesh Musale Date: Sat, 2 Mar 2024 11:27:46 +0530 Subject: [PATCH 07/14] Setup e2e tests for bond module --- tests/e2e/auction/cli_test.go | 2 +- tests/e2e/auction/suite.go | 2 +- tests/e2e/bond/cli_test.go | 17 ++++++ tests/e2e/bond/grpc.go | 24 ++++++++ tests/e2e/bond/suite.go | 106 ++++++++++++++++++++++++++++++++++ x/bond/client/cli/tx.go | 38 ++++++++++++ x/bond/msgs.go | 17 ++++++ 7 files changed, 204 insertions(+), 2 deletions(-) create mode 100644 tests/e2e/bond/cli_test.go create mode 100644 tests/e2e/bond/grpc.go create mode 100644 tests/e2e/bond/suite.go create mode 100644 x/bond/client/cli/tx.go create mode 100644 x/bond/msgs.go diff --git a/tests/e2e/auction/cli_test.go b/tests/e2e/auction/cli_test.go index 2ba78f32..aac55bcc 100644 --- a/tests/e2e/auction/cli_test.go +++ b/tests/e2e/auction/cli_test.go @@ -9,7 +9,7 @@ import ( "git.vdb.to/cerc-io/laconic2d/tests/e2e" ) -func TestE2ETestSuite(t *testing.T) { +func TestAuctionE2ETestSuite(t *testing.T) { cfg := network.DefaultConfig(e2e.NewTestNetworkFixture) cfg.NumValidators = 1 diff --git a/tests/e2e/auction/suite.go b/tests/e2e/auction/suite.go index d408b253..ce322258 100644 --- a/tests/e2e/auction/suite.go +++ b/tests/e2e/auction/suite.go @@ -133,7 +133,7 @@ func (ets *E2ETestSuite) createAuctionAndBid(createAuction, createBid bool) stri func (ets *E2ETestSuite) cleanupBidFiles() error { matches, err := filepath.Glob(fmt.Sprintf("%s-*.json", bidderAccount)) if err != nil { - fmt.Printf("Error matching bidder files: %v\n", err) + ets.T().Errorf("Error matching bidder files: %v\n", err) return err } diff --git a/tests/e2e/bond/cli_test.go b/tests/e2e/bond/cli_test.go new file mode 100644 index 00000000..c5e5a9f8 --- /dev/null +++ b/tests/e2e/bond/cli_test.go @@ -0,0 +1,17 @@ +package bond + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/testutil/network" + "github.com/stretchr/testify/suite" + + "git.vdb.to/cerc-io/laconic2d/tests/e2e" +) + +func TestBondE2ETestSuite(t *testing.T) { + cfg := network.DefaultConfig(e2e.NewTestNetworkFixture) + cfg.NumValidators = 1 + + suite.Run(t, NewE2ETestSuite(cfg)) +} diff --git a/tests/e2e/bond/grpc.go b/tests/e2e/bond/grpc.go new file mode 100644 index 00000000..e1f6d143 --- /dev/null +++ b/tests/e2e/bond/grpc.go @@ -0,0 +1,24 @@ +package bond + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/testutil" + + bondtypes "git.vdb.to/cerc-io/laconic2d/x/bond" +) + +func (ets *E2ETestSuite) TestGRPCGetParams() { + val := ets.network.Validators[0] + sr := ets.Require() + reqURL := fmt.Sprintf("%s/cerc/bond/v1/params", val.APIAddress) + + resp, err := testutil.GetRequest(reqURL) + ets.Require().NoError(err) + + var params bondtypes.QueryParamsResponse + err = val.ClientCtx.Codec.UnmarshalJSON(resp, ¶ms) + + sr.NoError(err) + sr.Equal(params.GetParams().MaxBondAmount, bondtypes.DefaultParams().MaxBondAmount) +} diff --git a/tests/e2e/bond/suite.go b/tests/e2e/bond/suite.go new file mode 100644 index 00000000..766940ed --- /dev/null +++ b/tests/e2e/bond/suite.go @@ -0,0 +1,106 @@ +package bond + +import ( + "fmt" + + "cosmossdk.io/math" + "github.com/stretchr/testify/suite" + + "github.com/cosmos/cosmos-sdk/client/flags" + addresscodec "github.com/cosmos/cosmos-sdk/codec/address" + "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + "github.com/cosmos/cosmos-sdk/testutil/network" + sdk "github.com/cosmos/cosmos-sdk/types" + + "git.vdb.to/cerc-io/laconic2d/x/bond/client/cli" +) + +type E2ETestSuite struct { + suite.Suite + + cfg network.Config + network *network.Network + + accountName string + accountAddress string +} + +func NewE2ETestSuite(cfg network.Config) *E2ETestSuite { + return &E2ETestSuite{cfg: cfg} +} + +func (ets *E2ETestSuite) SetupSuite() { //nolint: all + sr := ets.Require() + ets.T().Log("setting up e2e test suite") + + var err error + + ets.network, err = network.New(ets.T(), ets.T().TempDir(), ets.cfg) + sr.NoError(err) + + _, err = ets.network.WaitForHeight(1) + sr.NoError(err) + + // setting up random account + ets.accountName = "accountName" + ets.createAccountWithBalance(ets.accountName, &ets.accountAddress) +} + +func (ets *E2ETestSuite) TearDownSuite() { + ets.T().Log("tearing down integration test suite") + ets.network.Cleanup() +} + +func (ets *E2ETestSuite) createAccountWithBalance(accountName string, accountAddress *string) { + val := ets.network.Validators[0] + sr := ets.Require() + + info, _, err := val.ClientCtx.Keyring.NewMnemonic(accountName, keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1) + sr.NoError(err) + + newAddr, _ := info.GetAddress() + _, err = clitestutil.MsgSendExec( + val.ClientCtx, + val.Address, + newAddr, + sdk.NewCoins(sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(200000))), + addresscodec.NewBech32Codec("laconic"), + fmt.Sprintf("--%s=%s", flags.FlagFrom, accountName), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=json", flags.FlagOutput), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(10))).String()), + ) + sr.NoError(err) + *accountAddress = newAddr.String() + + // wait for tx to take effect + err = ets.network.WaitForNextBlock() + sr.NoError(err) +} + +func (ets *E2ETestSuite) createBond() { + val := ets.network.Validators[0] + sr := ets.Require() + createBondCmd := cli.NewCreateBondCmd() + args := []string{ + fmt.Sprintf("10%s", ets.cfg.BondDenom), + fmt.Sprintf("--%s=%s", flags.FlagFrom, ets.accountName), + fmt.Sprintf("--%s=json", flags.FlagOutput), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.cfg.BondDenom)), + } + out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, createBondCmd, args) + sr.NoError(err) + var d sdk.TxResponse + err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &d) + sr.NoError(err) + sr.Zero(d.Code) + + // wait for tx to take effect + err = ets.network.WaitForNextBlock() + sr.NoError(err) +} diff --git a/x/bond/client/cli/tx.go b/x/bond/client/cli/tx.go new file mode 100644 index 00000000..d93f8efb --- /dev/null +++ b/x/bond/client/cli/tx.go @@ -0,0 +1,38 @@ +package cli + +import ( + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/spf13/cobra" + + bondtypes "git.vdb.to/cerc-io/laconic2d/x/bond" +) + +// NewCreateBondCmd is the CLI command for creating a bond. +// Used in e2e tests +func NewCreateBondCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "create [amount]", + Short: "Create bond.", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + coin, err := sdk.ParseCoinNormalized(args[0]) + if err != nil { + return err + } + + msg := bondtypes.NewMsgCreateBond(sdk.NewCoins(coin), clientCtx.GetFromAddress()) + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} diff --git a/x/bond/msgs.go b/x/bond/msgs.go new file mode 100644 index 00000000..c473c612 --- /dev/null +++ b/x/bond/msgs.go @@ -0,0 +1,17 @@ +package bond + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +var ( + _ sdk.Msg = &MsgCreateBond{} +) + +// NewMsgCreateBond is the constructor function for MsgCreateBond. +func NewMsgCreateBond(coins sdk.Coins, signer sdk.AccAddress) MsgCreateBond { + return MsgCreateBond{ + Coins: coins, + Signer: signer.String(), + } +} -- 2.45.2 From 19da88254eb9f5e5ca3bca59e3cc0aaee3b01d50 Mon Sep 17 00:00:00 2001 From: Prathamesh Musale Date: Sat, 2 Mar 2024 11:56:29 +0530 Subject: [PATCH 08/14] Add tests for bond module gRPC requests --- tests/e2e/bond/grpc.go | 159 ++++++++++++++++++++++++++++++++++++ tests/e2e/bond/suite.go | 19 ++++- x/bond/client/cli/query.go | 48 +++++++++++ x/bond/keeper/msg_server.go | 5 +- 4 files changed, 228 insertions(+), 3 deletions(-) create mode 100644 x/bond/client/cli/query.go diff --git a/tests/e2e/bond/grpc.go b/tests/e2e/bond/grpc.go index e1f6d143..48bec960 100644 --- a/tests/e2e/bond/grpc.go +++ b/tests/e2e/bond/grpc.go @@ -22,3 +22,162 @@ func (ets *E2ETestSuite) TestGRPCGetParams() { sr.NoError(err) sr.Equal(params.GetParams().MaxBondAmount, bondtypes.DefaultParams().MaxBondAmount) } + +func (ets *E2ETestSuite) TestGRPCGetBonds() { + val := ets.network.Validators[0] + sr := ets.Require() + reqURL := fmt.Sprintf("%s/cerc/bond/v1/bonds", val.APIAddress) + + testCases := []struct { + name string + url string + expErr bool + errorMsg string + preRun func() string + }{ + { + "invalid request with headers", + reqURL + "asdasdas", + true, + "", + func() string { return "" }, + }, + { + "valid request", + reqURL, + false, + "", + func() string { return ets.createBond() }, + }, + } + for _, tc := range testCases { + ets.Run(tc.name, func() { + tc.preRun() + + resp, _ := testutil.GetRequest(tc.url) + if tc.expErr { + sr.Contains(string(resp), tc.errorMsg) + } else { + var response bondtypes.QueryGetBondsResponse + err := val.ClientCtx.Codec.UnmarshalJSON(resp, &response) + sr.NoError(err) + sr.NotZero(len(response.GetBonds())) + } + }) + } +} + +func (ets *E2ETestSuite) TestGRPCGetBondsByOwner() { + val := ets.network.Validators[0] + sr := ets.Require() + reqURL := val.APIAddress + "/cerc/bond/v1/by-owner/%s" + + testCases := []struct { + name string + url string + expErr bool + preRun func() string + }{ + { + "empty list", + fmt.Sprintf(reqURL, "asdasd"), + true, + func() string { return "" }, + }, + { + "valid request", + fmt.Sprintf(reqURL, ets.accountAddress), + false, + func() string { return ets.createBond() }, + }, + } + + for _, tc := range testCases { + ets.Run(tc.name, func() { + tc.preRun() + + resp, err := testutil.GetRequest(tc.url) + ets.Require().NoError(err) + + var bonds bondtypes.QueryGetBondsByOwnerResponse + err = val.ClientCtx.Codec.UnmarshalJSON(resp, &bonds) + sr.NoError(err) + if tc.expErr { + sr.Empty(bonds.GetBonds()) + } else { + bondsList := bonds.GetBonds() + sr.NotZero(len(bondsList)) + sr.Equal(ets.accountAddress, bondsList[0].GetOwner()) + } + }) + } +} + +func (ets *E2ETestSuite) TestGRPCGetBondByID() { + val := ets.network.Validators[0] + sr := ets.Require() + reqURL := val.APIAddress + "/cerc/bond/v1/bonds/%s" + + testCases := []struct { + name string + url string + expErr bool + preRun func() string + }{ + { + "invalid request", + fmt.Sprintf(reqURL, "asdadad"), + true, + func() string { return "" }, + }, + { + "valid request", + reqURL, + false, + func() string { return ets.createBond() }, + }, + } + for _, tc := range testCases { + ets.Run(tc.name, func() { + var bondID string + if !tc.expErr { + bondID = tc.preRun() + tc.url = fmt.Sprintf(reqURL, bondID) + } + + resp, err := testutil.GetRequest(tc.url) + ets.Require().NoError(err) + + var bonds bondtypes.QueryGetBondByIdResponse + err = val.ClientCtx.Codec.UnmarshalJSON(resp, &bonds) + + if tc.expErr { + sr.Empty(bonds.GetBond().GetId()) + } else { + sr.NoError(err) + sr.NotZero(bonds.GetBond().GetId()) + sr.Equal(bonds.GetBond().GetId(), bondID) + } + }) + } +} + +func (ets *E2ETestSuite) TestGRPCGetBondModuleBalance() { + val := ets.network.Validators[0] + sr := ets.Require() + reqURL := fmt.Sprintf("%s/cerc/bond/v1/balance", val.APIAddress) + + // creating the bond + ets.createBond() + + ets.Run("valid request", func() { + resp, err := testutil.GetRequest(reqURL) + sr.NoError(err) + + var response bondtypes.QueryGetBondModuleBalanceResponse + err = val.ClientCtx.Codec.UnmarshalJSON(resp, &response) + + sr.NoError(err) + sr.False(response.GetBalance().IsZero()) + }) +} diff --git a/tests/e2e/bond/suite.go b/tests/e2e/bond/suite.go index 766940ed..816abc6c 100644 --- a/tests/e2e/bond/suite.go +++ b/tests/e2e/bond/suite.go @@ -14,6 +14,7 @@ import ( "github.com/cosmos/cosmos-sdk/testutil/network" sdk "github.com/cosmos/cosmos-sdk/types" + bondtypes "git.vdb.to/cerc-io/laconic2d/x/bond" "git.vdb.to/cerc-io/laconic2d/x/bond/client/cli" ) @@ -81,7 +82,7 @@ func (ets *E2ETestSuite) createAccountWithBalance(accountName string, accountAdd sr.NoError(err) } -func (ets *E2ETestSuite) createBond() { +func (ets *E2ETestSuite) createBond() string { val := ets.network.Validators[0] sr := ets.Require() createBondCmd := cli.NewCreateBondCmd() @@ -103,4 +104,20 @@ func (ets *E2ETestSuite) createBond() { // wait for tx to take effect err = ets.network.WaitForNextBlock() sr.NoError(err) + + // getting the bonds list and returning the bond-id + clientCtx := val.ClientCtx + cmd := cli.GetQueryBondLists() + args = []string{ + fmt.Sprintf("--%s=json", flags.FlagOutput), + } + out, err = clitestutil.ExecTestCLICmd(clientCtx, cmd, args) + sr.NoError(err) + var queryResponse bondtypes.QueryGetBondsResponse + err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &queryResponse) + sr.NoError(err) + + // extract bond id from bonds list + bond := queryResponse.GetBonds()[0] + return bond.GetId() } diff --git a/x/bond/client/cli/query.go b/x/bond/client/cli/query.go new file mode 100644 index 00000000..9a08e15e --- /dev/null +++ b/x/bond/client/cli/query.go @@ -0,0 +1,48 @@ +package cli + +import ( + "fmt" + "strings" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/version" + "github.com/spf13/cobra" + + bondtypes "git.vdb.to/cerc-io/laconic2d/x/bond" +) + +// GetQueryBondLists implements the bond lists query command. +func GetQueryBondLists() *cobra.Command { + cmd := &cobra.Command{ + Use: "list", + Short: "List bonds.", + Long: strings.TrimSpace( + fmt.Sprintf(`Get bond list . + +Example: +$ %s query %s list +`, + version.AppName, bondtypes.ModuleName, + ), + ), + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := bondtypes.NewQueryClient(clientCtx) + res, err := queryClient.Bonds(cmd.Context(), &bondtypes.QueryGetBondsRequest{}) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/bond/keeper/msg_server.go b/x/bond/keeper/msg_server.go index 2a28cb67..719f17b4 100644 --- a/x/bond/keeper/msg_server.go +++ b/x/bond/keeper/msg_server.go @@ -26,7 +26,8 @@ func (ms msgServer) CreateBond(c context.Context, msg *bond.MsgCreateBond) (*bon if err != nil { return nil, err } - _, err = ms.k.CreateBond(ctx, signerAddress, msg.Coins) + + resp, err := ms.k.CreateBond(ctx, signerAddress, msg.Coins) if err != nil { return nil, err } @@ -44,7 +45,7 @@ func (ms msgServer) CreateBond(c context.Context, msg *bond.MsgCreateBond) (*bon ), }) - return &bond.MsgCreateBondResponse{}, nil + return &bond.MsgCreateBondResponse{Id: resp.Id}, nil } // RefillBond implements bond.MsgServer. -- 2.45.2 From a763d53a3cadfd50d8a0bedfb3be8f3abd431755 Mon Sep 17 00:00:00 2001 From: Prathamesh Musale Date: Sat, 2 Mar 2024 12:53:50 +0530 Subject: [PATCH 09/14] Add a CLI tests for create and list bond commands --- tests/e2e/bond/query.go | 49 +++++++++++++++++++++++++++++ tests/e2e/bond/suite.go | 2 +- tests/e2e/bond/tx.go | 63 ++++++++++++++++++++++++++++++++++++++ x/bond/client/cli/query.go | 4 +-- 4 files changed, 115 insertions(+), 3 deletions(-) create mode 100644 tests/e2e/bond/query.go create mode 100644 tests/e2e/bond/tx.go diff --git a/tests/e2e/bond/query.go b/tests/e2e/bond/query.go new file mode 100644 index 00000000..8c48b6e8 --- /dev/null +++ b/tests/e2e/bond/query.go @@ -0,0 +1,49 @@ +package bond + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/client/flags" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + + bondtypes "git.vdb.to/cerc-io/laconic2d/x/bond" + "git.vdb.to/cerc-io/laconic2d/x/bond/client/cli" +) + +func (ets *E2ETestSuite) TestGetQueryBondList() { + val := ets.network.Validators[0] + sr := ets.Require() + + testCases := []struct { + name string + args []string + createBond bool + preRun func() + }{ + { + "create and get bond lists", + []string{fmt.Sprintf("--%s=json", flags.FlagOutput)}, + true, + func() { + ets.createBond() + }, + }, + } + + for _, tc := range testCases { + ets.Run(fmt.Sprintf("Case %s", tc.name), func() { + clientCtx := val.ClientCtx + if tc.createBond { + tc.preRun() + } + + cmd := cli.GetQueryBondList() + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + sr.NoError(err) + var queryResponse bondtypes.QueryGetBondsResponse + err = clientCtx.Codec.UnmarshalJSON(out.Bytes(), &queryResponse) + sr.NoError(err) + sr.NotZero(len(queryResponse.GetBonds())) + }) + } +} diff --git a/tests/e2e/bond/suite.go b/tests/e2e/bond/suite.go index 816abc6c..ce355443 100644 --- a/tests/e2e/bond/suite.go +++ b/tests/e2e/bond/suite.go @@ -107,7 +107,7 @@ func (ets *E2ETestSuite) createBond() string { // getting the bonds list and returning the bond-id clientCtx := val.ClientCtx - cmd := cli.GetQueryBondLists() + cmd := cli.GetQueryBondList() args = []string{ fmt.Sprintf("--%s=json", flags.FlagOutput), } diff --git a/tests/e2e/bond/tx.go b/tests/e2e/bond/tx.go new file mode 100644 index 00000000..edb3a031 --- /dev/null +++ b/tests/e2e/bond/tx.go @@ -0,0 +1,63 @@ +package bond + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/client/flags" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + sdk "github.com/cosmos/cosmos-sdk/types" + + "git.vdb.to/cerc-io/laconic2d/x/bond/client/cli" +) + +func (ets *E2ETestSuite) TestTxCreateBond() { + val := ets.network.Validators[0] + sr := ets.Require() + + testCases := []struct { + name string + args []string + err bool + }{ + { + "without deposit", + []string{ + fmt.Sprintf("--%s=%s", flags.FlagFrom, ets.accountName), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.cfg.BondDenom)), + }, + true, + }, + { + "create bond", + []string{ + fmt.Sprintf("10%s", ets.cfg.BondDenom), + fmt.Sprintf("--%s=%s", flags.FlagFrom, ets.accountName), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=json", flags.FlagOutput), + fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.cfg.BondDenom)), + }, + false, + }, + } + + for _, tc := range testCases { + ets.Run(fmt.Sprintf("Case %s", tc.name), func() { + clientCtx := val.ClientCtx + cmd := cli.NewCreateBondCmd() + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + if tc.err { + sr.Error(err) + } else { + sr.NoError(err) + var d sdk.TxResponse + err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &d) + sr.Nil(err) + sr.NoError(err) + sr.Zero(d.Code) + } + }) + } +} diff --git a/x/bond/client/cli/query.go b/x/bond/client/cli/query.go index 9a08e15e..019c7d05 100644 --- a/x/bond/client/cli/query.go +++ b/x/bond/client/cli/query.go @@ -12,8 +12,8 @@ import ( bondtypes "git.vdb.to/cerc-io/laconic2d/x/bond" ) -// GetQueryBondLists implements the bond lists query command. -func GetQueryBondLists() *cobra.Command { +// GetQueryBondList implements the bond lists query command. +func GetQueryBondList() *cobra.Command { cmd := &cobra.Command{ Use: "list", Short: "List bonds.", -- 2.45.2 From 9373d9543bd9b5311c67fb529d7d300f2969ebc6 Mon Sep 17 00:00:00 2001 From: Prathamesh Musale Date: Sat, 2 Mar 2024 13:57:05 +0530 Subject: [PATCH 10/14] Setup e2e tests for registry module --- tests/e2e/registry/cli_test.go | 17 ++++++ tests/e2e/registry/grpc.go | 58 +++++++++++++++++++ tests/e2e/registry/suite.go | 102 +++++++++++++++++++++++++++++++++ 3 files changed, 177 insertions(+) create mode 100644 tests/e2e/registry/cli_test.go create mode 100644 tests/e2e/registry/grpc.go create mode 100644 tests/e2e/registry/suite.go diff --git a/tests/e2e/registry/cli_test.go b/tests/e2e/registry/cli_test.go new file mode 100644 index 00000000..198962fa --- /dev/null +++ b/tests/e2e/registry/cli_test.go @@ -0,0 +1,17 @@ +package registry + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/testutil/network" + "github.com/stretchr/testify/suite" + + "git.vdb.to/cerc-io/laconic2d/tests/e2e" +) + +func TestRegistryE2ETestSuite(t *testing.T) { + cfg := network.DefaultConfig(e2e.NewTestNetworkFixture) + cfg.NumValidators = 1 + + suite.Run(t, NewE2ETestSuite(cfg)) +} diff --git a/tests/e2e/registry/grpc.go b/tests/e2e/registry/grpc.go new file mode 100644 index 00000000..bcd19499 --- /dev/null +++ b/tests/e2e/registry/grpc.go @@ -0,0 +1,58 @@ +package registry + +import ( + "time" + + "github.com/cosmos/cosmos-sdk/testutil" + sdk "github.com/cosmos/cosmos-sdk/types" + + registrytypes "git.vdb.to/cerc-io/laconic2d/x/registry" +) + +const badPath = "/asdasd" + +func (ets *E2ETestSuite) TestGRPCQueryParams() { + val := ets.network.Validators[0] + sr := ets.Require() + reqURL := val.APIAddress + "/cerc/registry/v1/params" + + testCases := []struct { + name string + url string + expectErr bool + errorMsg string + }{ + { + "invalid request", + reqURL + badPath, + true, + "", + }, + { + "valid request", + reqURL, + false, + "", + }, + } + + for _, tc := range testCases { + ets.Run(tc.name, func() { + resp, err := testutil.GetRequest(tc.url) + ets.NoError(err) + require := ets.Require() + if tc.expectErr { + require.Contains(string(resp), tc.errorMsg) + } else { + var response registrytypes.QueryParamsResponse + err := val.ClientCtx.Codec.UnmarshalJSON(resp, &response) + sr.NoError(err) + params := registrytypes.DefaultParams() + params.RecordRent = sdk.NewCoin(ets.cfg.BondDenom, registrytypes.DefaultRecordRent) + params.RecordRentDuration = 10 * time.Second + params.AuthorityGracePeriod = 10 * time.Second + sr.Equal(response.GetParams().String(), params.String()) + } + }) + } +} diff --git a/tests/e2e/registry/suite.go b/tests/e2e/registry/suite.go new file mode 100644 index 00000000..1991bb78 --- /dev/null +++ b/tests/e2e/registry/suite.go @@ -0,0 +1,102 @@ +package registry + +import ( + "fmt" + "time" + + "cosmossdk.io/math" + "github.com/stretchr/testify/suite" + + "github.com/cosmos/cosmos-sdk/client/flags" + addresscodec "github.com/cosmos/cosmos-sdk/codec/address" + "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + "github.com/cosmos/cosmos-sdk/testutil/network" + sdk "github.com/cosmos/cosmos-sdk/types" + + bondtypes "git.vdb.to/cerc-io/laconic2d/x/bond" + bondcli "git.vdb.to/cerc-io/laconic2d/x/bond/client/cli" + registrytypes "git.vdb.to/cerc-io/laconic2d/x/registry" +) + +type E2ETestSuite struct { + suite.Suite + + cfg network.Config + network *network.Network + + accountName string + accountAddress string + + bondId string +} + +func NewE2ETestSuite(cfg network.Config) *E2ETestSuite { + return &E2ETestSuite{cfg: cfg} +} + +func (ets *E2ETestSuite) SetupSuite() { + sr := ets.Require() + ets.T().Log("setting up e2e test suite") + + var err error + + genesisState := ets.cfg.GenesisState + var registryGenesis registrytypes.GenesisState + ets.Require().NoError(ets.cfg.Codec.UnmarshalJSON(genesisState[registrytypes.ModuleName], ®istryGenesis)) + + registryGenesis.Params.RecordRent = sdk.NewCoin(ets.cfg.BondDenom, registrytypes.DefaultRecordRent) + registryGenesis.Params.RecordRentDuration = 10 * time.Second + registryGenesis.Params.AuthorityGracePeriod = 10 * time.Second + registryGenesisBz, err := ets.cfg.Codec.MarshalJSON(®istryGenesis) + ets.Require().NoError(err) + genesisState[registrytypes.ModuleName] = registryGenesisBz + ets.cfg.GenesisState = genesisState + + ets.network, err = network.New(ets.T(), ets.T().TempDir(), ets.cfg) + sr.NoError(err) + + _, err = ets.network.WaitForHeight(2) + sr.NoError(err) + + // setting up random account + ets.accountName = "accountName" + ets.createAccountWithBalance(ets.accountName, &ets.accountAddress) + + // ets.bondId = ets.createBond() +} + +func (ets *E2ETestSuite) TearDownSuite() { + ets.T().Log("tearing down e2e test suite") + ets.network.Cleanup() +} + +func (ets *E2ETestSuite) createAccountWithBalance(accountName string, accountAddress *string) { + val := ets.network.Validators[0] + sr := ets.Require() + + info, _, err := val.ClientCtx.Keyring.NewMnemonic(accountName, keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1) + sr.NoError(err) + + newAddr, _ := info.GetAddress() + _, err = clitestutil.MsgSendExec( + val.ClientCtx, + val.Address, + newAddr, + sdk.NewCoins(sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(1000000000000000000))), + addresscodec.NewBech32Codec("laconic"), + fmt.Sprintf("--%s=%s", flags.FlagFrom, accountName), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=json", flags.FlagOutput), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(10))).String()), + ) + sr.NoError(err) + *accountAddress = newAddr.String() + + // wait for tx to take effect + err = ets.network.WaitForNextBlock() + sr.NoError(err) +} + -- 2.45.2 From 6ce73d51db4b5598e2dc12302a420bd991a90c75 Mon Sep 17 00:00:00 2001 From: Prathamesh Musale Date: Sat, 2 Mar 2024 15:21:01 +0530 Subject: [PATCH 11/14] Add test for registry module whois gRPC request --- tests/e2e/bond/suite.go | 2 +- tests/e2e/registry/grpc.go | 59 ++++++++++++++++++++++--- tests/e2e/registry/suite.go | 88 ++++++++++++++++++++++++++++++++++--- x/registry/client/cli/tx.go | 49 +++++++++++++++++++++ x/registry/msgs.go | 22 ++++++++++ 5 files changed, 208 insertions(+), 12 deletions(-) diff --git a/tests/e2e/bond/suite.go b/tests/e2e/bond/suite.go index ce355443..67f435d9 100644 --- a/tests/e2e/bond/suite.go +++ b/tests/e2e/bond/suite.go @@ -50,7 +50,7 @@ func (ets *E2ETestSuite) SetupSuite() { //nolint: all } func (ets *E2ETestSuite) TearDownSuite() { - ets.T().Log("tearing down integration test suite") + ets.T().Log("tearing down e2e test suite") ets.network.Cleanup() } diff --git a/tests/e2e/registry/grpc.go b/tests/e2e/registry/grpc.go index bcd19499..c8f05f29 100644 --- a/tests/e2e/registry/grpc.go +++ b/tests/e2e/registry/grpc.go @@ -1,10 +1,9 @@ package registry import ( - "time" + "fmt" "github.com/cosmos/cosmos-sdk/testutil" - sdk "github.com/cosmos/cosmos-sdk/types" registrytypes "git.vdb.to/cerc-io/laconic2d/x/registry" ) @@ -47,11 +46,59 @@ func (ets *E2ETestSuite) TestGRPCQueryParams() { var response registrytypes.QueryParamsResponse err := val.ClientCtx.Codec.UnmarshalJSON(resp, &response) sr.NoError(err) + params := registrytypes.DefaultParams() - params.RecordRent = sdk.NewCoin(ets.cfg.BondDenom, registrytypes.DefaultRecordRent) - params.RecordRentDuration = 10 * time.Second - params.AuthorityGracePeriod = 10 * time.Second - sr.Equal(response.GetParams().String(), params.String()) + ets.updateParams(¶ms) + sr.Equal(params.String(), response.GetParams().String()) + } + }) + } +} + +func (ets *E2ETestSuite) TestGRPCQueryWhoIs() { + val := ets.network.Validators[0] + sr := ets.Require() + reqUrl := val.APIAddress + "/cerc/registry/v1/whois/%s" + authorityName := "QueryWhoIS" + testCases := []struct { + name string + url string + expectErr bool + errorMsg string + preRun func(authorityName string) + }{ + { + "invalid url", + reqUrl + badPath, + true, + "", + func(authorityName string) { + }, + }, + { + "valid request", + reqUrl, + false, + "", + func(authorityName string) { ets.reserveName(authorityName) }, + }, + } + + for _, tc := range testCases { + ets.Run(tc.name, func() { + tc.preRun(authorityName) + tc.url = fmt.Sprintf(tc.url, authorityName) + + resp, err := testutil.GetRequest(tc.url) + ets.NoError(err) + require := ets.Require() + if tc.expectErr { + require.Contains(string(resp), tc.errorMsg) + } else { + var response registrytypes.QueryWhoisResponse + err := val.ClientCtx.Codec.UnmarshalJSON(resp, &response) + sr.NoError(err) + sr.Equal(registrytypes.AuthorityActive, response.GetNameAuthority().Status) } }) } diff --git a/tests/e2e/registry/suite.go b/tests/e2e/registry/suite.go index 1991bb78..a15652ab 100644 --- a/tests/e2e/registry/suite.go +++ b/tests/e2e/registry/suite.go @@ -18,6 +18,7 @@ import ( bondtypes "git.vdb.to/cerc-io/laconic2d/x/bond" bondcli "git.vdb.to/cerc-io/laconic2d/x/bond/client/cli" registrytypes "git.vdb.to/cerc-io/laconic2d/x/registry" + "git.vdb.to/cerc-io/laconic2d/x/registry/client/cli" ) type E2ETestSuite struct { @@ -46,9 +47,8 @@ func (ets *E2ETestSuite) SetupSuite() { var registryGenesis registrytypes.GenesisState ets.Require().NoError(ets.cfg.Codec.UnmarshalJSON(genesisState[registrytypes.ModuleName], ®istryGenesis)) - registryGenesis.Params.RecordRent = sdk.NewCoin(ets.cfg.BondDenom, registrytypes.DefaultRecordRent) - registryGenesis.Params.RecordRentDuration = 10 * time.Second - registryGenesis.Params.AuthorityGracePeriod = 10 * time.Second + ets.updateParams(®istryGenesis.Params) + registryGenesisBz, err := ets.cfg.Codec.MarshalJSON(®istryGenesis) ets.Require().NoError(err) genesisState[registrytypes.ModuleName] = registryGenesisBz @@ -64,7 +64,7 @@ func (ets *E2ETestSuite) SetupSuite() { ets.accountName = "accountName" ets.createAccountWithBalance(ets.accountName, &ets.accountAddress) - // ets.bondId = ets.createBond() + ets.bondId = ets.createBond() } func (ets *E2ETestSuite) TearDownSuite() { @@ -84,7 +84,7 @@ func (ets *E2ETestSuite) createAccountWithBalance(accountName string, accountAdd val.ClientCtx, val.Address, newAddr, - sdk.NewCoins(sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(1000000000000000000))), + sdk.NewCoins(sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(100000000))), addresscodec.NewBech32Codec("laconic"), fmt.Sprintf("--%s=%s", flags.FlagFrom, accountName), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), @@ -100,3 +100,81 @@ func (ets *E2ETestSuite) createAccountWithBalance(accountName string, accountAdd sr.NoError(err) } +func (ets *E2ETestSuite) createBond() string { + val := ets.network.Validators[0] + sr := ets.Require() + createBondCmd := bondcli.NewCreateBondCmd() + args := []string{ + fmt.Sprintf("1000000%s", ets.cfg.BondDenom), + fmt.Sprintf("--%s=%s", flags.FlagFrom, ets.accountName), + fmt.Sprintf("--%s=json", flags.FlagOutput), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.cfg.BondDenom)), + } + out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, createBondCmd, args) + sr.NoError(err) + var d sdk.TxResponse + err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &d) + sr.NoError(err) + sr.Zero(d.Code) + + // wait for tx to take effect + err = ets.network.WaitForNextBlock() + sr.NoError(err) + + // getting the bonds list and returning the bond-id + clientCtx := val.ClientCtx + cmd := bondcli.GetQueryBondList() + args = []string{ + fmt.Sprintf("--%s=json", flags.FlagOutput), + } + out, err = clitestutil.ExecTestCLICmd(clientCtx, cmd, args) + sr.NoError(err) + var queryResponse bondtypes.QueryGetBondsResponse + err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &queryResponse) + sr.NoError(err) + + // extract bond id from bonds list + bond := queryResponse.GetBonds()[0] + return bond.GetId() +} + +func (ets *E2ETestSuite) reserveName(authorityName string) { + val := ets.network.Validators[0] + sr := ets.Require() + + clientCtx := val.ClientCtx + cmd := cli.GetCmdReserveName() + args := []string{ + authorityName, + fmt.Sprintf("--owner=%s", ets.accountAddress), + fmt.Sprintf("--%s=%s", flags.FlagFrom, ets.accountName), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=json", flags.FlagOutput), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.cfg.BondDenom)), + } + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, args) + sr.NoError(err) + + var d sdk.TxResponse + err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &d) + sr.NoError(err) + sr.Zero(d.Code) + + err = ets.network.WaitForNextBlock() + sr.NoError(err) +} + +func (ets *E2ETestSuite) updateParams(params *registrytypes.Params) { + params.RecordRent = sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(1000)) + params.RecordRentDuration = 10 * time.Second + + params.AuthorityRent = sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(1000)) + params.AuthorityGracePeriod = 10 * time.Second + + params.AuthorityAuctionCommitFee = sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(100)) + params.AuthorityAuctionRevealFee = sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(100)) + params.AuthorityAuctionMinimumBid = sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(500)) +} diff --git a/x/registry/client/cli/tx.go b/x/registry/client/cli/tx.go index 168aeab7..366e9ad2 100644 --- a/x/registry/client/cli/tx.go +++ b/x/registry/client/cli/tx.go @@ -1,11 +1,15 @@ package cli import ( + "fmt" "os" + "strings" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/tx" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/version" "gopkg.in/yaml.v3" "github.com/spf13/cobra" @@ -80,3 +84,48 @@ func GetPayloadFromFile(filePath string) (*registrytypes.ReadablePayload, error) return &payload, nil } + +// GetCmdReserveName is the CLI command for reserving a name. +func GetCmdReserveName() *cobra.Command { + cmd := &cobra.Command{ + Use: "reserve-name [name]", + Short: "Reserve name.", + Long: strings.TrimSpace( + fmt.Sprintf(`Reserver name with owner address . +Example: +$ %s tx %s reserve-name [name] --owner [ownerAddress] +`, + version.AppName, registrytypes.ModuleName, + ), + ), + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + owner, err := cmd.Flags().GetString("owner") + if err != nil { + return err + } + ownerAddress, err := sdk.AccAddressFromBech32(owner) + if err != nil { + return err + } + + msg := registrytypes.NewMsgReserveAuthority(args[0], clientCtx.GetFromAddress(), ownerAddress) + err = msg.ValidateBasic() + if err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg) + }, + } + + cmd.Flags().String("owner", "", "Owner address, if creating a sub-authority.") + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} diff --git a/x/registry/msgs.go b/x/registry/msgs.go index 7a68ded3..882078fb 100644 --- a/x/registry/msgs.go +++ b/x/registry/msgs.go @@ -33,3 +33,25 @@ func (msg MsgSetRecord) ValidateBasic() error { return nil } + +// NewMsgReserveAuthority is the constructor function for MsgReserveName. +func NewMsgReserveAuthority(name string, signer sdk.AccAddress, owner sdk.AccAddress) MsgReserveAuthority { + return MsgReserveAuthority{ + Name: name, + Owner: owner.String(), + Signer: signer.String(), + } +} + +// ValidateBasic Implements Msg. +func (msg MsgReserveAuthority) ValidateBasic() error { + if len(msg.Name) == 0 { + return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "name is required.") + } + + if len(msg.Signer) == 0 { + return errorsmod.Wrap(sdkerrors.ErrInvalidAddress, "invalid signer") + } + + return nil +} -- 2.45.2 From 839e993e024ebb3231d576921dc27463e51e529a Mon Sep 17 00:00:00 2001 From: Prathamesh Musale Date: Sat, 2 Mar 2024 16:25:16 +0530 Subject: [PATCH 12/14] Add tests for registry module gRPC requests --- .../data/examples/example1.yml | 0 .../data/examples/general_record_example.yml | 0 .../examples/service_provider_example.yml | 0 .../examples/website_registration_example.yml | 0 tests/e2e/auction/grpc.go | 24 +- tests/e2e/bond/grpc.go | 10 +- tests/e2e/registry/grpc.go | 324 ++++++++++++++++++ tests/e2e/registry/suite.go | 102 ++++++ tests/e2e/registry/tx.go | 70 ++++ .../registry/keeper/query_server_test.go | 14 +- x/registry/client/cli/query.go | 58 ++++ x/registry/client/cli/tx.go | 63 ++++ x/registry/msgs.go | 35 ++ 13 files changed, 676 insertions(+), 24 deletions(-) rename tests/{integration => }/data/examples/example1.yml (100%) rename tests/{integration => }/data/examples/general_record_example.yml (100%) rename tests/{integration => }/data/examples/service_provider_example.yml (100%) rename tests/{integration => }/data/examples/website_registration_example.yml (100%) create mode 100644 tests/e2e/registry/tx.go create mode 100644 x/registry/client/cli/query.go diff --git a/tests/integration/data/examples/example1.yml b/tests/data/examples/example1.yml similarity index 100% rename from tests/integration/data/examples/example1.yml rename to tests/data/examples/example1.yml diff --git a/tests/integration/data/examples/general_record_example.yml b/tests/data/examples/general_record_example.yml similarity index 100% rename from tests/integration/data/examples/general_record_example.yml rename to tests/data/examples/general_record_example.yml diff --git a/tests/integration/data/examples/service_provider_example.yml b/tests/data/examples/service_provider_example.yml similarity index 100% rename from tests/integration/data/examples/service_provider_example.yml rename to tests/data/examples/service_provider_example.yml diff --git a/tests/integration/data/examples/website_registration_example.yml b/tests/data/examples/website_registration_example.yml similarity index 100% rename from tests/integration/data/examples/website_registration_example.yml rename to tests/data/examples/website_registration_example.yml diff --git a/tests/e2e/auction/grpc.go b/tests/e2e/auction/grpc.go index ad3cabc2..c285fd47 100644 --- a/tests/e2e/auction/grpc.go +++ b/tests/e2e/auction/grpc.go @@ -9,7 +9,7 @@ import ( ) const ( - randomAuctionID = "randomAuctionID" + randomAuctionId = "randomAuctionId" randomBidderAddress = "randomBidderAddress" randomOwnerAddress = "randomOwnerAddress" ) @@ -44,7 +44,7 @@ func (ets *E2ETestSuite) TestGetAllAuctionsGrpc() { }{ { "invalid request to get all auctions", - reqURL + randomAuctionID, + reqURL + randomAuctionId, "", true, }, @@ -85,7 +85,7 @@ func (ets *E2ETestSuite) TestGetAuctionGrpc() { }{ { "invalid request to get an auction", - reqURL + randomAuctionID, + reqURL + randomAuctionId, "", true, func() string { return "" }, @@ -100,8 +100,8 @@ func (ets *E2ETestSuite) TestGetAuctionGrpc() { } for _, tc := range testCases { ets.Run(tc.msg, func() { - auctionID := tc.preRun() - resp, err := testutil.GetRequest(tc.url + auctionID) + auctionId := tc.preRun() + resp, err := testutil.GetRequest(tc.url + auctionId) if tc.isErrorExpected { sr.Contains(string(resp), tc.errorMsg) } else { @@ -109,7 +109,7 @@ func (ets *E2ETestSuite) TestGetAuctionGrpc() { var auction auctiontypes.QueryAuctionResponse err = val.ClientCtx.Codec.UnmarshalJSON(resp, &auction) sr.NoError(err) - sr.Equal(auctionID, auction.Auction.Id) + sr.Equal(auctionId, auction.Auction.Id) } }) } @@ -144,8 +144,8 @@ func (ets *E2ETestSuite) TestGetBidsGrpc() { for _, tc := range testCases { ets.Run(tc.msg, func() { - auctionID := tc.preRun() - tc.url += auctionID + auctionId := tc.preRun() + tc.url += auctionId resp, err := testutil.GetRequest(tc.url) if tc.isErrorExpected { sr.Contains(string(resp), tc.errorMsg) @@ -154,7 +154,7 @@ func (ets *E2ETestSuite) TestGetBidsGrpc() { var bids auctiontypes.QueryBidsResponse err = val.ClientCtx.Codec.UnmarshalJSON(resp, &bids) sr.NoError(err) - sr.Equal(auctionID, bids.Bids[0].AuctionId) + sr.Equal(auctionId, bids.Bids[0].AuctionId) } }) } @@ -176,7 +176,7 @@ func (ets *E2ETestSuite) TestGetBidGrpc() { reqURL, "", true, - func() string { return randomAuctionID }, + func() string { return randomAuctionId }, }, { "valid request to get bid", @@ -188,8 +188,8 @@ func (ets *E2ETestSuite) TestGetBidGrpc() { } for _, tc := range testCases { ets.Run(tc.msg, func() { - auctionID := tc.preRun() - tc.url += auctionID + "/" + bidderAddress + auctionId := tc.preRun() + tc.url += auctionId + "/" + bidderAddress resp, err := testutil.GetRequest(tc.url) if tc.isErrorExpected { diff --git a/tests/e2e/bond/grpc.go b/tests/e2e/bond/grpc.go index 48bec960..b326a51d 100644 --- a/tests/e2e/bond/grpc.go +++ b/tests/e2e/bond/grpc.go @@ -113,7 +113,7 @@ func (ets *E2ETestSuite) TestGRPCGetBondsByOwner() { } } -func (ets *E2ETestSuite) TestGRPCGetBondByID() { +func (ets *E2ETestSuite) TestGRPCGetBondById() { val := ets.network.Validators[0] sr := ets.Require() reqURL := val.APIAddress + "/cerc/bond/v1/bonds/%s" @@ -139,10 +139,10 @@ func (ets *E2ETestSuite) TestGRPCGetBondByID() { } for _, tc := range testCases { ets.Run(tc.name, func() { - var bondID string + var bondId string if !tc.expErr { - bondID = tc.preRun() - tc.url = fmt.Sprintf(reqURL, bondID) + bondId = tc.preRun() + tc.url = fmt.Sprintf(reqURL, bondId) } resp, err := testutil.GetRequest(tc.url) @@ -156,7 +156,7 @@ func (ets *E2ETestSuite) TestGRPCGetBondByID() { } else { sr.NoError(err) sr.NotZero(bonds.GetBond().GetId()) - sr.Equal(bonds.GetBond().GetId(), bondID) + sr.Equal(bonds.GetBond().GetId(), bondId) } }) } diff --git a/tests/e2e/registry/grpc.go b/tests/e2e/registry/grpc.go index c8f05f29..f050b05a 100644 --- a/tests/e2e/registry/grpc.go +++ b/tests/e2e/registry/grpc.go @@ -1,11 +1,15 @@ package registry import ( + "encoding/json" "fmt" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/testutil" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" registrytypes "git.vdb.to/cerc-io/laconic2d/x/registry" + "git.vdb.to/cerc-io/laconic2d/x/registry/client/cli" ) const badPath = "/asdasd" @@ -103,3 +107,323 @@ func (ets *E2ETestSuite) TestGRPCQueryWhoIs() { }) } } + +func (ets *E2ETestSuite) TestGRPCQueryLookup() { + val := ets.network.Validators[0] + sr := ets.Require() + reqURL := val.APIAddress + "/cerc/registry/v1/lookup" + authorityName := "QueryLookUp" + + testCases := []struct { + name string + url string + expectErr bool + errorMsg string + preRun func(authorityName string) + }{ + { + "invalid url", + reqURL + badPath, + true, + "", + func(authorityName string) { + }, + }, + { + "valid request", + fmt.Sprintf(reqURL+"?lrn=lrn://%s/", authorityName), + false, + "", + func(authorityName string) { + // create name record + ets.createNameRecord(authorityName) + }, + }, + } + + for _, tc := range testCases { + ets.Run(tc.name, func() { + tc.preRun(authorityName) + resp, err := testutil.GetRequest(tc.url) + ets.NoError(err) + if tc.expectErr { + sr.Contains(string(resp), tc.errorMsg) + } else { + var response registrytypes.QueryLookupLrnResponse + err := val.ClientCtx.Codec.UnmarshalJSON(resp, &response) + sr.NoError(err) + sr.NotZero(len(response.Name.Latest.Id)) + } + }) + } +} + +func (ets *E2ETestSuite) TestGRPCQueryListRecords() { + val := ets.network.Validators[0] + sr := ets.Require() + reqUrl := val.APIAddress + "/cerc/registry/v1/records" + + testCases := []struct { + name string + url string + expectErr bool + errorMsg string + preRun func(bondId string) + }{ + { + "invalid url", + reqUrl + badPath, + true, + "", + func(bondId string) { + }, + }, + { + "valid request", + reqUrl, + false, + "", + func(bondId string) { ets.createRecord(bondId) }, + }, + } + + for _, tc := range testCases { + ets.Run(tc.name, func() { + tc.preRun(ets.bondId) + resp, err := testutil.GetRequest(tc.url) + ets.NoError(err) + require := ets.Require() + if tc.expectErr { + require.Contains(string(resp), tc.errorMsg) + } else { + var response registrytypes.QueryRecordsResponse + err := val.ClientCtx.Codec.UnmarshalJSON(resp, &response) + sr.NoError(err) + sr.NotZero(len(response.GetRecords())) + sr.Equal(ets.bondId, response.GetRecords()[0].GetBondId()) + } + }) + } +} + +func (ets *E2ETestSuite) TestGRPCQueryGetRecordById() { + val := ets.network.Validators[0] + sr := ets.Require() + reqURL := val.APIAddress + "/cerc/registry/v1/records/%s" + + testCases := []struct { + name string + url string + expectErr bool + errorMsg string + preRun func(bondId string) string + }{ + { + "invalid url", + reqURL + badPath, + true, + "", + func(bondId string) string { + return "" + }, + }, + { + "valid request", + reqURL, + false, + "", + func(bondId string) string { + // creating the record + ets.createRecord(bondId) + + // list the records + clientCtx := val.ClientCtx + cmd := cli.GetCmdList() + args := []string{ + fmt.Sprintf("--%s=json", flags.FlagOutput), + } + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, args) + sr.NoError(err) + var records []registrytypes.ReadableRecord + err = json.Unmarshal(out.Bytes(), &records) + sr.NoError(err) + return records[0].Id + }, + }, + } + + for _, tc := range testCases { + ets.Run(tc.name, func() { + recordId := tc.preRun(ets.bondId) + tc.url = fmt.Sprintf(reqURL, recordId) + + resp, err := testutil.GetRequest(tc.url) + ets.NoError(err) + require := ets.Require() + if tc.expectErr { + require.Contains(string(resp), tc.errorMsg) + } else { + var response registrytypes.QueryRecordByIdResponse + err := val.ClientCtx.Codec.UnmarshalJSON(resp, &response) + sr.NoError(err) + record := response.GetRecord() + sr.NotZero(len(record.GetId())) + sr.Equal(record.GetId(), recordId) + } + }) + } +} + +func (ets *E2ETestSuite) TestGRPCQueryGetRecordByBondId() { + val := ets.network.Validators[0] + sr := ets.Require() + reqURL := val.APIAddress + "/cerc/registry/v1/records-by-bond-id/%s" + + testCases := []struct { + name string + url string + expectErr bool + errorMsg string + preRun func(bondId string) + }{ + { + "invalid url", + reqURL + badPath, + true, + "", + func(bondId string) { + }, + }, + { + "valid request", + reqURL, + false, + "", + func(bondId string) { + // creating the record + ets.createRecord(bondId) + }, + }, + } + + for _, tc := range testCases { + ets.Run(tc.name, func() { + tc.preRun(ets.bondId) + tc.url = fmt.Sprintf(reqURL, ets.bondId) + + resp, err := testutil.GetRequest(tc.url) + ets.NoError(err) + require := ets.Require() + if tc.expectErr { + require.Contains(string(resp), tc.errorMsg) + } else { + var response registrytypes.QueryRecordsByBondIdResponse + err := val.ClientCtx.Codec.UnmarshalJSON(resp, &response) + sr.NoError(err) + records := response.GetRecords() + sr.NotZero(len(records)) + sr.Equal(records[0].GetBondId(), ets.bondId) + } + }) + } +} + +func (ets *E2ETestSuite) TestGRPCQueryGetRegistryModuleBalance() { + val := ets.network.Validators[0] + sr := ets.Require() + reqURL := val.APIAddress + "/cerc/registry/v1/balance" + + testCases := []struct { + name string + url string + expectErr bool + errorMsg string + preRun func(bondId string) + }{ + { + "invalid url", + reqURL + badPath, + true, + "", + func(bondId string) { + }, + }, + { + "Success", + reqURL, + false, + "", + func(bondId string) { + // creating the record + ets.createRecord(bondId) + }, + }, + } + + for _, tc := range testCases { + ets.Run(tc.name, func() { + tc.preRun(ets.bondId) + resp, err := testutil.GetRequest(tc.url) + ets.NoError(err) + require := ets.Require() + if tc.expectErr { + require.Contains(string(resp), tc.errorMsg) + } else { + var response registrytypes.QueryGetRegistryModuleBalanceResponse + err := val.ClientCtx.Codec.UnmarshalJSON(resp, &response) + sr.NoError(err) + sr.NotZero(len(response.GetBalances())) + } + }) + } +} + +func (ets *E2ETestSuite) TestGRPCQueryNamesList() { + val := ets.network.Validators[0] + sr := ets.Require() + reqURL := val.APIAddress + "/cerc/registry/v1/names" + + testCases := []struct { + name string + url string + expectErr bool + errorMsg string + preRun func(authorityName string) + }{ + { + "invalid url", + reqURL + badPath, + true, + "", + func(authorityName string) { + }, + }, + { + "valid request", + reqURL, + false, + "", + func(authorityName string) { + // create name record + ets.createNameRecord(authorityName) + }, + }, + } + + for _, tc := range testCases { + ets.Run(tc.name, func() { + tc.preRun("ListNameRecords") + resp, err := testutil.GetRequest(tc.url) + ets.NoError(err) + require := ets.Require() + if tc.expectErr { + require.Contains(string(resp), tc.errorMsg) + } else { + var response registrytypes.QueryNameRecordsResponse + err := val.ClientCtx.Codec.UnmarshalJSON(resp, &response) + sr.NoError(err) + sr.NotZero(len(response.GetNames())) + } + }) + } +} diff --git a/tests/e2e/registry/suite.go b/tests/e2e/registry/suite.go index a15652ab..058a5ff0 100644 --- a/tests/e2e/registry/suite.go +++ b/tests/e2e/registry/suite.go @@ -2,6 +2,7 @@ package registry import ( "fmt" + "path/filepath" "time" "cosmossdk.io/math" @@ -167,6 +168,107 @@ func (ets *E2ETestSuite) reserveName(authorityName string) { sr.NoError(err) } +func (ets *E2ETestSuite) createNameRecord(authorityName string) { + val := ets.network.Validators[0] + sr := ets.Require() + + // reserving the name + clientCtx := val.ClientCtx + cmd := cli.GetCmdReserveName() + args := []string{ + authorityName, + fmt.Sprintf("--owner=%s", ets.accountAddress), + fmt.Sprintf("--%s=%s", flags.FlagFrom, ets.accountName), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=json", flags.FlagOutput), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.cfg.BondDenom)), + } + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, args) + sr.NoError(err) + var d sdk.TxResponse + err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &d) + sr.NoError(err) + sr.Zero(d.Code) + + err = ets.network.WaitForNextBlock() + sr.NoError(err) + + // Get the bond-id + bondId := ets.bondId + + // adding bond-id to name authority + args = []string{ + authorityName, bondId, + fmt.Sprintf("--%s=%s", flags.FlagFrom, ets.accountName), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=json", flags.FlagOutput), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.cfg.BondDenom)), + } + cmd = cli.GetCmdSetAuthorityBond() + + out, err = clitestutil.ExecTestCLICmd(clientCtx, cmd, args) + sr.NoError(err) + err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &d) + sr.NoError(err) + sr.Zero(d.Code) + + err = ets.network.WaitForNextBlock() + sr.NoError(err) + + args = []string{ + fmt.Sprintf("lrn://%s/", authorityName), + "test_hello_cid", + fmt.Sprintf("--%s=%s", flags.FlagFrom, ets.accountName), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=json", flags.FlagOutput), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.cfg.BondDenom)), + } + + cmd = cli.GetCmdSetName() + + out, err = clitestutil.ExecTestCLICmd(clientCtx, cmd, args) + sr.NoError(err) + err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &d) + sr.NoError(err) + sr.Zero(d.Code) + + err = ets.network.WaitForNextBlock() + sr.NoError(err) +} + +func (ets *E2ETestSuite) createRecord(bondId string) { + val := ets.network.Validators[0] + sr := ets.Require() + + payloadPath := "../../data/examples/service_provider_example.yml" + payloadFilePath, err := filepath.Abs(payloadPath) + sr.NoError(err) + + args := []string{ + fmt.Sprintf("--%s=%s", flags.FlagFrom, ets.accountName), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=json", flags.FlagOutput), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.cfg.BondDenom)), + } + args = append([]string{payloadFilePath, bondId}, args...) + clientCtx := val.ClientCtx + cmd := cli.GetCmdSetRecord() + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, args) + sr.NoError(err) + var d sdk.TxResponse + err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &d) + sr.NoError(err) + sr.Zero(d.Code, d.RawLog) + + err = ets.network.WaitForNextBlock() + sr.NoError(err) +} + func (ets *E2ETestSuite) updateParams(params *registrytypes.Params) { params.RecordRent = sdk.NewCoin(ets.cfg.BondDenom, math.NewInt(1000)) params.RecordRentDuration = 10 * time.Second diff --git a/tests/e2e/registry/tx.go b/tests/e2e/registry/tx.go new file mode 100644 index 00000000..1267728a --- /dev/null +++ b/tests/e2e/registry/tx.go @@ -0,0 +1,70 @@ +package registry + +import ( + "fmt" + "path/filepath" + + "github.com/cosmos/cosmos-sdk/client/flags" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + sdk "github.com/cosmos/cosmos-sdk/types" + + "git.vdb.to/cerc-io/laconic2d/x/registry/client/cli" +) + +func (ets *E2ETestSuite) TestGetCmdSetRecord() { + val := ets.network.Validators[0] + sr := ets.Require() + + bondId := ets.bondId + payloadPath := "../../data/examples/service_provider_example.yml" + payloadFilePath, err := filepath.Abs(payloadPath) + sr.NoError(err) + + testCases := []struct { + name string + args []string + err bool + }{ + { + "invalid request without bond id/without payload", + []string{ + fmt.Sprintf("--%s=%s", flags.FlagFrom, ets.accountName), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=json", flags.FlagOutput), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.cfg.BondDenom)), + }, + true, + }, + { + "success", + []string{ + payloadFilePath, bondId, + fmt.Sprintf("--%s=%s", flags.FlagFrom, ets.accountName), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=json", flags.FlagOutput), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", ets.cfg.BondDenom)), + }, + false, + }, + } + + for _, tc := range testCases { + ets.Run(fmt.Sprintf("Case %s", tc.name), func() { + clientCtx := val.ClientCtx + cmd := cli.GetCmdSetRecord() + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + if tc.err { + sr.Error(err) + } else { + sr.NoError(err) + var d sdk.TxResponse + err = val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &d) + sr.NoError(err) + sr.Zero(d.Code) + } + }) + } +} diff --git a/tests/integration/registry/keeper/query_server_test.go b/tests/integration/registry/keeper/query_server_test.go index 0c527dd8..ee4294e3 100644 --- a/tests/integration/registry/keeper/query_server_test.go +++ b/tests/integration/registry/keeper/query_server_test.go @@ -37,9 +37,9 @@ func (kts *KeeperTestSuite) TestGrpcGetRecordLists() { var recordId string examples := []string{ - "../../data/examples/service_provider_example.yml", - "../../data/examples/website_registration_example.yml", - "../../data/examples/general_record_example.yml", + "../../../data/examples/service_provider_example.yml", + "../../../data/examples/website_registration_example.yml", + "../../../data/examples/general_record_example.yml", } testCases := []struct { msg string @@ -268,7 +268,7 @@ func (kts *KeeperTestSuite) TestGrpcGetRecordLists() { } // Get the records by record id - testCasesByBondID := []struct { + testCasesByBondId := []struct { msg string req *types.QueryRecordsByBondIdRequest createRecord bool @@ -292,7 +292,7 @@ func (kts *KeeperTestSuite) TestGrpcGetRecordLists() { 1, }, } - for _, test := range testCasesByBondID { + for _, test := range testCasesByBondId { kts.Run(fmt.Sprintf("Case %s ", test.msg), func() { resp, err := queryClient.GetRecordsByBondId(context.Background(), test.req) @@ -314,8 +314,8 @@ func (kts *KeeperTestSuite) TestGrpcQueryRegistryModuleBalance() { queryClient, ctx := kts.queryClient, kts.SdkCtx sr := kts.Require() examples := []string{ - "../../data/examples/service_provider_example.yml", - "../../data/examples/website_registration_example.yml", + "../../../data/examples/service_provider_example.yml", + "../../../data/examples/website_registration_example.yml", } testCases := []struct { msg string diff --git a/x/registry/client/cli/query.go b/x/registry/client/cli/query.go new file mode 100644 index 00000000..c13564a2 --- /dev/null +++ b/x/registry/client/cli/query.go @@ -0,0 +1,58 @@ +package cli + +import ( + "encoding/json" + "fmt" + "strings" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/version" + "github.com/spf13/cobra" + + registrytypes "git.vdb.to/cerc-io/laconic2d/x/registry" +) + +// GetCmdList queries all records. +func GetCmdList() *cobra.Command { + cmd := &cobra.Command{ + Use: "list", + Short: "List records.", + Long: strings.TrimSpace( + fmt.Sprintf(`Get the records. +Example: +$ %s query %s list +`, + version.AppName, registrytypes.ModuleName, + ), + ), + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + queryClient := registrytypes.NewQueryClient(clientCtx) + res, err := queryClient.Records(cmd.Context(), ®istrytypes.QueryRecordsRequest{}) + if err != nil { + return err + } + + recordsList := res.GetRecords() + records := make([]registrytypes.ReadableRecord, len(recordsList)) + for i, record := range res.GetRecords() { + records[i] = record.ToReadableRecord() + } + bytesResult, err := json.Marshal(records) + if err != nil { + return err + } + return clientCtx.PrintBytes(bytesResult) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/registry/client/cli/tx.go b/x/registry/client/cli/tx.go index 366e9ad2..2c645d74 100644 --- a/x/registry/client/cli/tx.go +++ b/x/registry/client/cli/tx.go @@ -129,3 +129,66 @@ $ %s tx %s reserve-name [name] --owner [ownerAddress] return cmd } + +// GetCmdSetAuthorityBond is the CLI command for associating a bond with an authority. +func GetCmdSetAuthorityBond() *cobra.Command { + cmd := &cobra.Command{ + Use: "authority-bond [name] [bond-id]", + Short: "Associate authority with bond.", + Long: strings.TrimSpace( + fmt.Sprintf(`Reserver name with owner address . +Example: +$ %s tx %s authority-bond [name] [bond-id] +`, + version.AppName, registrytypes.ModuleName, + ), + ), + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + msg := registrytypes.NewMsgSetAuthorityBond(args[0], args[1], clientCtx.GetFromAddress()) + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +// GetCmdSetName is the CLI command for mapping a name to a CID. +func GetCmdSetName() *cobra.Command { + cmd := &cobra.Command{ + Use: "set-name [crn] [cid]", + Short: "Set CRN to CID mapping.", + Long: strings.TrimSpace( + fmt.Sprintf(`Set name with crn and cid. +Example: +$ %s tx %s set-name [crn] [cid] +`, + version.AppName, registrytypes.ModuleName, + ), + ), + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + msg := registrytypes.NewMsgSetName(args[0], args[1], clientCtx.GetFromAddress()) + err = msg.ValidateBasic() + if err != nil { + return err + } + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} diff --git a/x/registry/msgs.go b/x/registry/msgs.go index 882078fb..93f65743 100644 --- a/x/registry/msgs.go +++ b/x/registry/msgs.go @@ -55,3 +55,38 @@ func (msg MsgReserveAuthority) ValidateBasic() error { return nil } + +// NewMsgSetAuthorityBond is the constructor function for MsgSetAuthorityBond. +func NewMsgSetAuthorityBond(name string, bondID string, signer sdk.AccAddress) MsgSetAuthorityBond { + return MsgSetAuthorityBond{ + Name: name, + Signer: signer.String(), + BondId: bondID, + } +} + +// NewMsgSetName is the constructor function for MsgSetName. +func NewMsgSetName(lrn string, cid string, signer sdk.AccAddress) *MsgSetName { + return &MsgSetName{ + Lrn: lrn, + Cid: cid, + Signer: signer.String(), + } +} + +// ValidateBasic Implements Msg. +func (msg MsgSetName) ValidateBasic() error { + if msg.Lrn == "" { + return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "LRN is required.") + } + + if msg.Cid == "" { + return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "CID is required.") + } + + if len(msg.Signer) == 0 { + return errorsmod.Wrap(sdkerrors.ErrInvalidAddress, "invalid signer") + } + + return nil +} -- 2.45.2 From 6c0e7c6c499bdc1976c9ace22665129683c419b5 Mon Sep 17 00:00:00 2001 From: Prathamesh Musale Date: Sat, 2 Mar 2024 16:28:59 +0530 Subject: [PATCH 13/14] Add a CI workflow to run e2e tests --- .gitea/workflows/test-e2e.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .gitea/workflows/test-e2e.yml diff --git a/.gitea/workflows/test-e2e.yml b/.gitea/workflows/test-e2e.yml new file mode 100644 index 00000000..fe288a48 --- /dev/null +++ b/.gitea/workflows/test-e2e.yml @@ -0,0 +1,19 @@ +name: E2E Tests +on: + pull_request: + push: + branches: + - main + +jobs: + test-e2e: + runs-on: ubuntu-latest + steps: + - uses: actions/setup-go@v3 + with: + go-version: 1.21 + check-latest: true + - uses: actions/checkout@v3 + - name: Test + run: | + make test-e2e -- 2.45.2 From 4abe5569eed343c517b4c20fbe469059cf037c92 Mon Sep 17 00:00:00 2001 From: Prathamesh Musale Date: Mon, 4 Mar 2024 09:20:07 +0530 Subject: [PATCH 14/14] Use valid owner address in get auctions by owner test --- api/cerc/bond/v1/genesis.pulsar.go | 1 - proto/cerc/auction/v1/query.proto | 2 -- proto/cerc/bond/v1/genesis.proto | 1 - tests/e2e/auction/grpc.go | 2 +- x/bond/genesis.pb.go | 1 - 5 files changed, 1 insertion(+), 6 deletions(-) diff --git a/api/cerc/bond/v1/genesis.pulsar.go b/api/cerc/bond/v1/genesis.pulsar.go index 93d1c38e..608c6c79 100644 --- a/api/cerc/bond/v1/genesis.pulsar.go +++ b/api/cerc/bond/v1/genesis.pulsar.go @@ -608,7 +608,6 @@ type GenesisState struct { // params defines all the parameters of the module. Params *Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params,omitempty"` // bonds defines all the bonds - // TODO: Add nullable = false ? Bonds []*Bond `protobuf:"bytes,2,rep,name=bonds,proto3" json:"bonds,omitempty"` } diff --git a/proto/cerc/auction/v1/query.proto b/proto/cerc/auction/v1/query.proto index cd88fc20..d4afe85b 100644 --- a/proto/cerc/auction/v1/query.proto +++ b/proto/cerc/auction/v1/query.proto @@ -123,8 +123,6 @@ message QueryAuctionsByBidderRequest { message QueryAuctionsByBidderResponse { // List of auctions Auctions auctions = 1; - - // TODO: Add pagination? } // AuctionsByOwnerRequest is the format for querying all auctions created by an owner diff --git a/proto/cerc/bond/v1/genesis.proto b/proto/cerc/bond/v1/genesis.proto index c37ba129..b6f922fb 100644 --- a/proto/cerc/bond/v1/genesis.proto +++ b/proto/cerc/bond/v1/genesis.proto @@ -13,6 +13,5 @@ message GenesisState { Params params = 1 [(gogoproto.nullable) = false]; // bonds defines all the bonds - // TODO: Add nullable = false ? repeated Bond bonds = 2 [(gogoproto.moretags) = "json:\"bonds\" yaml:\"bonds\""]; } diff --git a/tests/e2e/auction/grpc.go b/tests/e2e/auction/grpc.go index c285fd47..1f9c4ade 100644 --- a/tests/e2e/auction/grpc.go +++ b/tests/e2e/auction/grpc.go @@ -222,7 +222,7 @@ func (ets *E2ETestSuite) TestGetAuctionsByOwnerGrpc() { }, { "valid request to get auctions by owner", - fmt.Sprintf("%s/%s", reqURL, randomOwnerAddress), // TODO: use ownerAddress? + fmt.Sprintf("%s/%s", reqURL, ownerAddress), "", false, }, diff --git a/x/bond/genesis.pb.go b/x/bond/genesis.pb.go index 3b841b38..8d55cf9e 100644 --- a/x/bond/genesis.pb.go +++ b/x/bond/genesis.pb.go @@ -28,7 +28,6 @@ type GenesisState struct { // params defines all the parameters of the module. Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` // bonds defines all the bonds - // TODO: Add nullable = false ? Bonds []*Bond `protobuf:"bytes,2,rep,name=bonds,proto3" json:"bonds,omitempty" json:"bonds" yaml:"bonds"` } -- 2.45.2