test(gov): Migrate e2e to system test (#21927)

This commit is contained in:
Hieu Vu 2024-09-30 21:29:12 +07:00 committed by GitHub
parent 91b47cb5e6
commit d493145644
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 416 additions and 573 deletions

View File

@ -1,37 +0,0 @@
//go:build e2e
// +build e2e
package gov
import (
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"cosmossdk.io/simapp"
v1 "cosmossdk.io/x/gov/types/v1"
"github.com/cosmos/cosmos-sdk/testutil/network"
)
func TestE2ETestSuite(t *testing.T) {
cfg := network.DefaultConfig(simapp.NewTestNetworkFixture)
cfg.NumValidators = 1
suite.Run(t, NewE2ETestSuite(cfg))
}
func TestDepositTestSuite(t *testing.T) {
cfg := network.DefaultConfig(simapp.NewTestNetworkFixture)
cfg.NumValidators = 1
genesisState := v1.DefaultGenesisState()
maxDepPeriod := time.Duration(20) * time.Second
votingPeriod := time.Duration(8) * time.Second
genesisState.Params.MaxDepositPeriod = &maxDepPeriod
genesisState.Params.VotingPeriod = &votingPeriod
bz, err := cfg.Codec.MarshalJSON(genesisState)
require.NoError(t, err)
cfg.GenesisState["gov"] = bz
suite.Run(t, NewDepositTestSuite(cfg))
}

View File

@ -1,164 +0,0 @@
package gov
import (
"fmt"
"strconv"
"time"
"github.com/stretchr/testify/suite"
"cosmossdk.io/math"
"cosmossdk.io/x/gov/client/cli"
govclitestutil "cosmossdk.io/x/gov/client/testutil"
v1 "cosmossdk.io/x/gov/types/v1"
"cosmossdk.io/x/gov/types/v1beta1"
"github.com/cosmos/cosmos-sdk/testutil"
"github.com/cosmos/cosmos-sdk/testutil/network"
sdk "github.com/cosmos/cosmos-sdk/types"
)
type DepositTestSuite struct {
suite.Suite
cfg network.Config
network network.NetworkI
}
func NewDepositTestSuite(cfg network.Config) *DepositTestSuite {
return &DepositTestSuite{cfg: cfg}
}
func (s *DepositTestSuite) SetupSuite() {
s.T().Log("setting up test suite")
var err error
s.network, err = network.New(s.T(), s.T().TempDir(), s.cfg)
s.Require().NoError(err)
}
func (s *DepositTestSuite) submitProposal(val network.ValidatorI, initialDeposit sdk.Coin, name string) uint64 {
var exactArgs []string
if !initialDeposit.IsZero() {
exactArgs = append(exactArgs, fmt.Sprintf("--%s=%s", cli.FlagDeposit, initialDeposit.String()))
}
_, err := govclitestutil.MsgSubmitLegacyProposal(
val.GetClientCtx(),
val.GetAddress().String(),
fmt.Sprintf("Text Proposal %s", name),
"Where is the title!?",
v1beta1.ProposalTypeText,
exactArgs...,
)
s.Require().NoError(err)
s.Require().NoError(s.network.WaitForNextBlock())
// query proposals, return the last's id
res, err := testutil.GetRequest(fmt.Sprintf("%s/cosmos/gov/v1/proposals", val.GetAPIAddress()))
s.Require().NoError(err)
var proposals v1.QueryProposalsResponse
err = s.cfg.Codec.UnmarshalJSON(res, &proposals)
s.Require().NoError(err)
s.Require().GreaterOrEqual(len(proposals.Proposals), 1)
return proposals.Proposals[len(proposals.Proposals)-1].Id
}
func (s *DepositTestSuite) TearDownSuite() {
s.T().Log("tearing down test suite")
s.network.Cleanup()
}
func (s *DepositTestSuite) TestQueryDepositsWithInitialDeposit() {
val := s.network.GetValidators()[0]
depositAmount := sdk.NewCoin(s.cfg.BondDenom, v1.DefaultMinDepositTokens)
// submit proposal with an initial deposit
id := s.submitProposal(val, depositAmount, "TestQueryDepositsWithInitialDeposit")
proposalID := strconv.FormatUint(id, 10)
// query deposit
deposit := s.queryDeposit(val, proposalID, false, "")
s.Require().NotNil(deposit)
s.Require().Equal(depositAmount.String(), sdk.Coins(deposit.Deposit.Amount).String())
// query deposits
deposits := s.queryDeposits(val, proposalID, false, "")
s.Require().NotNil(deposits)
s.Require().Len(deposits.Deposits, 1)
// verify initial deposit
s.Require().Equal(depositAmount.String(), sdk.Coins(deposits.Deposits[0].Amount).String())
}
func (s *DepositTestSuite) TestQueryProposalAfterVotingPeriod() {
val := s.network.GetValidators()[0]
depositAmount := sdk.NewCoin(s.cfg.BondDenom, v1.DefaultMinDepositTokens.Sub(math.NewInt(50)))
// submit proposal with an initial deposit
id := s.submitProposal(val, depositAmount, "TestQueryProposalAfterVotingPeriod")
proposalID := strconv.FormatUint(id, 10)
resp, err := testutil.GetRequest(fmt.Sprintf("%s/cosmos/gov/v1/proposals", val.GetAPIAddress()))
s.Require().NoError(err)
var proposals v1.QueryProposalsResponse
err = s.cfg.Codec.UnmarshalJSON(resp, &proposals)
s.Require().NoError(err)
s.Require().GreaterOrEqual(len(proposals.Proposals), 1)
// query proposal
resp, err = testutil.GetRequest(fmt.Sprintf("%s/cosmos/gov/v1/proposals/%s", val.GetAPIAddress(), proposalID))
s.Require().NoError(err)
var proposal v1.QueryProposalResponse
err = s.cfg.Codec.UnmarshalJSON(resp, &proposal)
s.Require().NoError(err)
// waiting for deposit and voting period to end
time.Sleep(25 * time.Second)
// query proposal
resp, err = testutil.GetRequest(fmt.Sprintf("%s/cosmos/gov/v1/proposals/%s", val.GetAPIAddress(), proposalID))
s.Require().NoError(err)
s.Require().Contains(string(resp), fmt.Sprintf("proposal %s doesn't exist", proposalID))
// query deposits
deposits := s.queryDeposits(val, proposalID, false, "")
s.Require().Len(deposits.Deposits, 0)
}
func (s *DepositTestSuite) queryDeposits(val network.ValidatorI, proposalID string, exceptErr bool, message string) *v1.QueryDepositsResponse {
s.Require().NoError(s.network.WaitForNextBlock())
resp, err := testutil.GetRequest(fmt.Sprintf("%s/cosmos/gov/v1/proposals/%s/deposits", val.GetAPIAddress(), proposalID))
s.Require().NoError(err)
if exceptErr {
s.Require().Contains(string(resp), message)
return nil
}
var depositsRes v1.QueryDepositsResponse
err = val.GetClientCtx().Codec.UnmarshalJSON(resp, &depositsRes)
s.Require().NoError(err)
return &depositsRes
}
func (s *DepositTestSuite) queryDeposit(val network.ValidatorI, proposalID string, exceptErr bool, message string) *v1.QueryDepositResponse {
s.Require().NoError(s.network.WaitForNextBlock())
resp, err := testutil.GetRequest(fmt.Sprintf("%s/cosmos/gov/v1/proposals/%s/deposits/%s", val.GetAPIAddress(), proposalID, val.GetAddress().String()))
s.Require().NoError(err)
if exceptErr {
s.Require().Contains(string(resp), message)
return nil
}
var depositRes v1.QueryDepositResponse
err = val.GetClientCtx().Codec.UnmarshalJSON(resp, &depositRes)
s.Require().NoError(err)
return &depositRes
}

View File

@ -1,372 +0,0 @@
package gov
import (
"encoding/base64"
"fmt"
"github.com/cosmos/gogoproto/proto"
"github.com/stretchr/testify/suite"
"cosmossdk.io/math"
"cosmossdk.io/x/gov/client/cli"
govclitestutil "cosmossdk.io/x/gov/client/testutil"
"cosmossdk.io/x/gov/types"
v1 "cosmossdk.io/x/gov/types/v1"
"cosmossdk.io/x/gov/types/v1beta1"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/testutil"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
"github.com/cosmos/cosmos-sdk/testutil/network"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
)
type E2ETestSuite struct {
suite.Suite
cfg network.Config
network network.NetworkI
}
func NewE2ETestSuite(cfg network.Config) *E2ETestSuite {
return &E2ETestSuite{cfg: cfg}
}
func (s *E2ETestSuite) SetupSuite() {
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)
s.Require().NoError(s.network.WaitForNextBlock())
val := s.network.GetValidators()[0]
clientCtx := val.GetClientCtx()
var resp sdk.TxResponse
// create a proposal with deposit
out, err := govclitestutil.MsgSubmitLegacyProposal(val.GetClientCtx(), val.GetAddress().String(),
"Text Proposal 1", "Where is the title!?", v1beta1.ProposalTypeText,
fmt.Sprintf("--%s=%s", cli.FlagDeposit, sdk.NewCoin(s.cfg.BondDenom, v1.DefaultMinDepositTokens).String()))
s.Require().NoError(err)
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &resp), out.String())
s.Require().NoError(clitestutil.CheckTxCode(s.network, clientCtx, resp.TxHash, 0))
// vote for proposal
out, err = govclitestutil.MsgVote(val.GetClientCtx(), val.GetAddress().String(), "1", "yes")
s.Require().NoError(err)
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &resp), out.String())
s.Require().NoError(clitestutil.CheckTxCode(s.network, clientCtx, resp.TxHash, 0))
// create a proposal with a small deposit
minimumAcceptedDep := v1.DefaultMinDepositTokens.ToLegacyDec().Mul(v1.DefaultMinDepositRatio).Ceil().TruncateInt()
out, err = govclitestutil.MsgSubmitLegacyProposal(val.GetClientCtx(), val.GetAddress().String(),
"Text Proposal 2", "Where is the title!?", v1beta1.ProposalTypeText,
fmt.Sprintf("--%s=%s", cli.FlagDeposit, sdk.NewCoin(s.cfg.BondDenom, minimumAcceptedDep).String()))
s.Require().NoError(err)
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &resp), out.String())
s.Require().NoError(clitestutil.CheckTxCode(s.network, clientCtx, resp.TxHash, 0))
// create a proposal3 with deposit
out, err = govclitestutil.MsgSubmitLegacyProposal(val.GetClientCtx(), val.GetAddress().String(),
"Text Proposal 3", "Where is the title!?", v1beta1.ProposalTypeText,
fmt.Sprintf("--%s=%s", cli.FlagDeposit, sdk.NewCoin(s.cfg.BondDenom, v1.DefaultMinDepositTokens).String()))
s.Require().NoError(err)
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &resp), out.String())
s.Require().NoError(clitestutil.CheckTxCode(s.network, clientCtx, resp.TxHash, 0))
// create a proposal4 with deposit to check the cancel proposal cli tx
out, err = govclitestutil.MsgSubmitLegacyProposal(val.GetClientCtx(), val.GetAddress().String(),
"Text Proposal 4", "Where is the title!?", v1beta1.ProposalTypeText,
fmt.Sprintf("--%s=%s", cli.FlagDeposit, sdk.NewCoin(s.cfg.BondDenom, v1.DefaultMinDepositTokens).String()))
s.Require().NoError(err)
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &resp), out.String())
s.Require().NoError(clitestutil.CheckTxCode(s.network, clientCtx, resp.TxHash, 0))
// vote for proposal3 as val
out, err = govclitestutil.MsgVote(val.GetClientCtx(), val.GetAddress().String(), "3", "yes=0.6,no=0.3,abstain=0.05,no_with_veto=0.05")
s.Require().NoError(err)
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &resp), out.String())
s.Require().NoError(clitestutil.CheckTxCode(s.network, clientCtx, resp.TxHash, 0))
}
func (s *E2ETestSuite) TearDownSuite() {
s.T().Log("tearing down e2e test suite")
s.network.Cleanup()
}
func (s *E2ETestSuite) TestNewCmdSubmitProposal() {
val := s.network.GetValidators()[0]
// Create a legacy proposal JSON, make sure it doesn't pass this new CLI
// command.
invalidProp := `{
"title": "",
"description": "Where is the title!?",
"type": "Text",
"deposit": "-324foocoin"
}`
invalidPropFile := testutil.WriteToNewTempFile(s.T(), invalidProp)
defer invalidPropFile.Close()
// Create a valid new proposal JSON.
propMetadata := []byte{42}
validProp := fmt.Sprintf(`
{
"messages": [
{
"@type": "/cosmos.gov.v1.MsgExecLegacyContent",
"authority": "%s",
"content": {
"@type": "/cosmos.gov.v1beta1.TextProposal",
"title": "My awesome title",
"description": "My awesome description"
}
}
],
"title": "My awesome title",
"summary": "My awesome description",
"metadata": "%s",
"deposit": "%s"
}`, authtypes.NewModuleAddress(types.ModuleName), base64.StdEncoding.EncodeToString(propMetadata), sdk.NewCoin(s.cfg.BondDenom, math.NewInt(100000)))
validPropFile := testutil.WriteToNewTempFile(s.T(), validProp)
defer validPropFile.Close()
testCases := []struct {
name string
args []string
expectErr bool
expectedCode uint32
respType proto.Message
}{
{
"invalid proposal",
[]string{
invalidPropFile.Name(),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
},
true, 0, nil,
},
{
"valid proposal",
[]string{
validPropFile.Name(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.GetAddress().String()),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
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()),
},
false, 0, &sdk.TxResponse{},
},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
cmd := cli.NewCmdSubmitProposal()
clientCtx := val.GetClientCtx()
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String())
txResp := tc.respType.(*sdk.TxResponse)
s.Require().NoError(clitestutil.CheckTxCode(s.network, clientCtx, txResp.TxHash, tc.expectedCode))
}
})
}
}
func (s *E2ETestSuite) TestNewCmdSubmitLegacyProposal() {
val := s.network.GetValidators()[0]
invalidProp := `{
"title": "",
"description": "Where is the title!?",
"type": "Text",
"deposit": "-324foocoin"
}`
invalidPropFile := testutil.WriteToNewTempFile(s.T(), invalidProp)
defer invalidPropFile.Close()
validProp := fmt.Sprintf(`{
"title": "Text Proposal",
"description": "Hello, World!",
"type": "Text",
"deposit": "%s"
}`, sdk.NewCoin(s.cfg.BondDenom, math.NewInt(154310)))
validPropFile := testutil.WriteToNewTempFile(s.T(), validProp)
defer validPropFile.Close()
testCases := []struct {
name string
args []string
expectErr bool
expectedCode uint32
respType proto.Message
}{
{
"invalid proposal (file)",
[]string{
fmt.Sprintf("--%s=%s", cli.FlagProposal, invalidPropFile.Name()), //nolint:staticcheck // we are intentionally using a deprecated flag here.
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.GetAddress().String()),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
},
true, 0, nil,
},
{
"invalid proposal",
[]string{
fmt.Sprintf("--%s='Where is the title!?'", cli.FlagDescription), //nolint:staticcheck // we are intentionally using a deprecated flag here.
fmt.Sprintf("--%s=%s", cli.FlagProposalType, v1beta1.ProposalTypeText), //nolint:staticcheck // we are intentionally using a deprecated flag here.
fmt.Sprintf("--%s=%s", cli.FlagDeposit, sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10000)).String()),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.GetAddress().String()),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
},
true, 0, nil,
},
{
"valid transaction (file)",
//nolint:staticcheck // we are intentionally using a deprecated flag here.
[]string{
fmt.Sprintf("--%s=%s", cli.FlagProposal, validPropFile.Name()),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.GetAddress().String()),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
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()),
},
false, 0, &sdk.TxResponse{},
},
{
"valid transaction",
[]string{
fmt.Sprintf("--%s='Text Proposal'", cli.FlagTitle),
fmt.Sprintf("--%s='Where is the title!?'", cli.FlagDescription), //nolint:staticcheck // we are intentionally using a deprecated flag here.
fmt.Sprintf("--%s=%s", cli.FlagProposalType, v1beta1.ProposalTypeText), //nolint:staticcheck // we are intentionally using a deprecated flag here.
fmt.Sprintf("--%s=%s", cli.FlagDeposit, sdk.NewCoin(s.cfg.BondDenom, math.NewInt(100000)).String()),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.GetAddress().String()),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
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()),
},
false, 0, &sdk.TxResponse{},
},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
cmd := cli.NewCmdSubmitLegacyProposal()
clientCtx := val.GetClientCtx()
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String())
txResp := tc.respType.(*sdk.TxResponse)
s.Require().NoError(clitestutil.CheckTxCode(s.network, clientCtx, txResp.TxHash, tc.expectedCode))
}
})
}
}
func (s *E2ETestSuite) TestNewCmdWeightedVote() {
val := s.network.GetValidators()[0]
testCases := []struct {
name string
args []string
expectErr bool
expectedCode uint32
}{
{
"invalid vote",
[]string{},
true, 0,
},
{
"vote for invalid proposal",
[]string{
"10",
"yes",
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.GetAddress().String()),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
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()),
},
false, 3,
},
{
"valid vote",
[]string{
"1",
"yes",
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.GetAddress().String()),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
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()),
},
false, 0,
},
{
"valid vote with metadata",
[]string{
"1",
"yes",
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.GetAddress().String()),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--metadata=%s", "AQ=="),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()),
},
false, 0,
},
{
"invalid valid split vote string",
[]string{
"1",
"yes/0.6,no/0.3,abstain/0.05,no_with_veto/0.05",
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.GetAddress().String()),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
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()),
},
true, 0,
},
{
"valid split vote",
[]string{
"1",
"yes=0.6,no=0.3,abstain=0.05,no_with_veto=0.05",
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.GetAddress().String()),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
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()),
},
false, 0,
},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
cmd := cli.NewCmdWeightedVote()
clientCtx := val.GetClientCtx()
var txResp sdk.TxResponse
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &txResp), out.String())
s.Require().NoError(clitestutil.CheckTxCode(s.network, clientCtx, txResp.TxHash, tc.expectedCode))
}
})
}
}

View File

@ -0,0 +1,411 @@
//go:build system_test
package systemtests
import (
"encoding/base64"
"fmt"
"testing"
"time"
"cosmossdk.io/math"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/testutil"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tidwall/gjson"
)
func TestSubmitProposal(t *testing.T) {
// given a running chain
sut.ResetChain(t)
cli := NewCLIWrapper(t, sut, verbose)
// get validator address
valAddr := gjson.Get(cli.Keys("keys", "list"), "0.address").String()
require.NotEmpty(t, valAddr)
sut.StartChain(t)
// get gov module address
resp := cli.CustomQuery("q", "auth", "module-account", "gov")
govAddress := gjson.Get(resp, "account.value.address").String()
invalidProp := `{
"title": "",
"description": "Where is the title!?",
"type": "Text",
"deposit": "-324foocoin"
}`
invalidPropFile := testutil.WriteToNewTempFile(t, invalidProp)
defer invalidPropFile.Close()
// Create a valid new proposal JSON.
propMetadata := []byte{42}
validProp := fmt.Sprintf(`
{
"messages": [
{
"@type": "/cosmos.gov.v1.MsgExecLegacyContent",
"authority": "%s",
"content": {
"@type": "/cosmos.gov.v1beta1.TextProposal",
"title": "My awesome title",
"description": "My awesome description"
}
}
],
"title": "My awesome title",
"summary": "My awesome description",
"metadata": "%s",
"deposit": "%s"
}`, govAddress, base64.StdEncoding.EncodeToString(propMetadata), sdk.NewCoin("stake", math.NewInt(100000)))
validPropFile := testutil.WriteToNewTempFile(t, validProp)
defer validPropFile.Close()
testCases := []struct {
name string
args []string
expectErr bool
errMsg string
}{
{
"invalid proposal",
[]string{
"tx", "gov", "submit-proposal",
invalidPropFile.Name(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, valAddr),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(10))).String()),
},
true,
"invalid character in coin string",
},
{
"valid proposal",
[]string{
"tx", "gov", "submit-proposal",
validPropFile.Name(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, valAddr),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(10))).String()),
},
false,
"",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
if tc.expectErr {
assertOutput := func(_ assert.TestingT, gotErr error, gotOutputs ...interface{}) bool {
require.Contains(t, gotOutputs[0], tc.errMsg)
return false
}
cli.WithRunErrorMatcher(assertOutput).Run(tc.args...)
} else {
rsp := cli.Run(tc.args...)
txResult, found := cli.AwaitTxCommitted(rsp)
require.True(t, found)
RequireTxSuccess(t, txResult)
}
})
}
}
func TestSubmitLegacyProposal(t *testing.T) {
// given a running chain
sut.ResetChain(t)
cli := NewCLIWrapper(t, sut, verbose)
// get validator address
valAddr := gjson.Get(cli.Keys("keys", "list"), "0.address").String()
require.NotEmpty(t, valAddr)
sut.StartChain(t)
invalidProp := `{
"title": "",
"description": "Where is the title!?",
"type": "Text",
"deposit": "-324foocoin"
}`
invalidPropFile := testutil.WriteToNewTempFile(t, invalidProp)
defer invalidPropFile.Close()
validProp := fmt.Sprintf(`{
"title": "Text Proposal",
"description": "Hello, World!",
"type": "Text",
"deposit": "%s"
}`, sdk.NewCoin("stake", math.NewInt(154310)))
validPropFile := testutil.WriteToNewTempFile(t, validProp)
defer validPropFile.Close()
testCases := []struct {
name string
args []string
expectErr bool
errMsg string
}{
{
"invalid proposal (file)",
[]string{
"tx", "gov", "submit-legacy-proposal",
fmt.Sprintf("--%s=%s", "proposal", invalidPropFile.Name()),
fmt.Sprintf("--%s=%s", flags.FlagFrom, valAddr),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(10))).String()),
},
true,
"proposal title is required",
},
{
"invalid proposal",
[]string{
"tx", "gov", "submit-legacy-proposal",
fmt.Sprintf("--%s='Where is the title!?'", "description"),
fmt.Sprintf("--%s=%s", "type", "Text"),
fmt.Sprintf("--%s=%s", "deposit", sdk.NewCoin("stake", math.NewInt(10000)).String()),
fmt.Sprintf("--%s=%s", flags.FlagFrom, valAddr),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(10))).String()),
},
true,
"proposal title is required",
},
{
"valid transaction (file)",
[]string{
"tx", "gov", "submit-legacy-proposal",
fmt.Sprintf("--%s=%s", "proposal", validPropFile.Name()),
fmt.Sprintf("--%s=%s", flags.FlagFrom, valAddr),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(10))).String()),
},
false,
"",
},
{
"valid transaction",
[]string{
"tx", "gov", "submit-legacy-proposal",
fmt.Sprintf("--%s='Text Proposal'", "title"),
fmt.Sprintf("--%s='Where is the title!?'", "description"),
fmt.Sprintf("--%s=%s", "type", "Text"),
fmt.Sprintf("--%s=%s", "deposit", sdk.NewCoin("stake", math.NewInt(100000)).String()),
fmt.Sprintf("--%s=%s", flags.FlagFrom, valAddr),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(10))).String()),
},
false,
"",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
if tc.expectErr {
assertOutput := func(_ assert.TestingT, gotErr error, gotOutputs ...interface{}) bool {
fmt.Println("gotOut", gotOutputs)
require.Contains(t, gotOutputs[0], tc.errMsg)
return false
}
cli.WithRunErrorMatcher(assertOutput).Run(tc.args...)
} else {
rsp := cli.Run(tc.args...)
txResult, found := cli.AwaitTxCommitted(rsp)
require.True(t, found)
RequireTxSuccess(t, txResult)
}
})
}
}
func TestNewCmdWeightedVote(t *testing.T) {
// given a running chain
sut.ResetChain(t)
cli := NewCLIWrapper(t, sut, verbose)
// get validator address
valAddr := gjson.Get(cli.Keys("keys", "list"), "0.address").String()
require.NotEmpty(t, valAddr)
sut.StartChain(t)
// Submit a new proposal for voting
proposalArgs := []string{
"tx", "gov", "submit-legacy-proposal",
fmt.Sprintf("--%s='Text Proposal'", "title"),
fmt.Sprintf("--%s='Where is the title!?'", "description"),
fmt.Sprintf("--%s=%s", "type", "Text"),
fmt.Sprintf("--%s=%s", "deposit", sdk.NewCoin("stake", math.NewInt(10_000_000)).String()),
fmt.Sprintf("--%s=%s", flags.FlagFrom, valAddr),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(10))).String())}
rsp := cli.Run(proposalArgs...)
txResult, found := cli.AwaitTxCommitted(rsp)
require.True(t, found)
RequireTxSuccess(t, txResult)
proposalsResp := cli.CustomQuery("q", "gov", "proposals")
proposals := gjson.Get(proposalsResp, "proposals.#.id").Array()
require.NotEmpty(t, proposals)
proposal1 := cli.CustomQuery("q", "gov", "proposal", "1")
fmt.Println("first proposal", proposal1)
testCases := []struct {
name string
args []string
expectErr bool
expectedCode uint32
broadcasted bool
errMsg string
}{
{
"vote for invalid proposal",
[]string{
"tx", "gov", "weighted-vote",
"10",
"yes",
fmt.Sprintf("--%s=%s", flags.FlagFrom, valAddr),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(10))).String()),
},
true, 3, true,
"inactive proposal",
},
{
"valid vote",
[]string{
"tx", "gov", "weighted-vote",
"1",
"yes",
fmt.Sprintf("--%s=%s", flags.FlagFrom, valAddr),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(10))).String()),
},
false, 0, true,
"",
},
{
"valid vote with metadata",
[]string{
"tx", "gov", "weighted-vote",
"1",
"yes",
fmt.Sprintf("--%s=%s", flags.FlagFrom, valAddr),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--metadata=%s", "AQ=="),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(10))).String()),
},
false, 0, true,
"",
},
{
"invalid valid split vote string",
[]string{
"tx", "gov", "weighted-vote",
"1",
"yes/0.6,no/0.3,abstain/0.05,no_with_veto/0.05",
fmt.Sprintf("--%s=%s", flags.FlagFrom, valAddr),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(10))).String()),
},
true, 0, false,
"is not a valid vote option",
},
{
"valid split vote",
[]string{
"tx", "gov", "weighted-vote",
"1",
"yes=0.6,no=0.3,abstain=0.05,no_with_veto=0.05",
fmt.Sprintf("--%s=%s", flags.FlagFrom, valAddr),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(10))).String()),
},
false, 0, true,
"",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
if !tc.broadcasted {
assertOutput := func(_ assert.TestingT, gotErr error, gotOutputs ...interface{}) bool {
require.Contains(t, gotOutputs[0], tc.errMsg)
return false
}
cli.WithRunErrorMatcher(assertOutput).Run(tc.args...)
} else {
rsp := cli.Run(tc.args...)
if tc.expectErr {
RequireTxFailure(t, rsp)
} else {
cli.AwaitTxCommitted(rsp)
}
}
})
}
}
func TestQueryDeposit(t *testing.T) {
// given a running chain
sut.ResetChain(t)
cli := NewCLIWrapper(t, sut, verbose)
// get validator address
valAddr := gjson.Get(cli.Keys("keys", "list"), "0.address").String()
require.NotEmpty(t, valAddr)
sut.StartChain(t)
// Submit a new proposal for voting
proposalArgs := []string{
"tx", "gov", "submit-legacy-proposal",
fmt.Sprintf("--%s='Text Proposal'", "title"),
fmt.Sprintf("--%s='Where is the title!?'", "description"),
fmt.Sprintf("--%s=%s", "type", "Text"),
fmt.Sprintf("--%s=%s", "deposit", sdk.NewCoin("stake", math.NewInt(10_000_000)).String()),
fmt.Sprintf("--%s=%s", flags.FlagFrom, valAddr),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin("stake", math.NewInt(10))).String())}
rsp := cli.Run(proposalArgs...)
txResult, found := cli.AwaitTxCommitted(rsp)
require.True(t, found)
RequireTxSuccess(t, txResult)
// Query initial deposit
resp := cli.CustomQuery("q", "gov", "deposit", "1", valAddr)
depositAmount := gjson.Get(resp, "deposit.amount.0.amount").Int()
require.Equal(t, depositAmount, int64(10_000_000))
resp = cli.CustomQuery("q", "gov", "deposits", "1")
deposits := gjson.Get(resp, "deposits").Array()
require.Equal(t, len(deposits), 1)
time.Sleep(time.Second * 8)
resp = cli.CustomQuery("q", "gov", "deposits", "1")
deposits = gjson.Get(resp, "deposits").Array()
require.Equal(t, len(deposits), 0)
}

View File

@ -132,6 +132,11 @@ func (s *SystemUnderTest) SetupChain() {
if err != nil {
panic(fmt.Sprintf("failed set block max gas: %s", err))
}
// Short period for gov
genesisBz, err = sjson.SetRawBytes(genesisBz, "app_state.gov.params.voting_period", []byte(fmt.Sprintf(`"%s"`, "8s")))
if err != nil {
panic(fmt.Sprintf("failed set block max gas: %s", err))
}
s.withEachNodeHome(func(i int, home string) {
if err := saveGenesis(home, genesisBz); err != nil {
panic(err)