Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: add x/circuit system tests (backport #22331) #22355

Merged
merged 1 commit into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
243 changes: 243 additions & 0 deletions tests/systemtests/circuit_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
//go:build system_test

package systemtests

import (
"encoding/json"
"fmt"
"strings"
"testing"
"time"

"github.com/stretchr/testify/require"
"github.com/tidwall/gjson"
)

var someMsgs = []string{"/cosmos.bank.v1beta1.MsgSend", "/cosmos.bank.v1beta1.MsgMultiSend"}

func TestCircuitCommands(t *testing.T) {
// scenario: test circuit commands
// given a running chain

sut.ResetChain(t)
require.GreaterOrEqual(t, sut.NodesCount(), 2)

cli := NewCLIWrapper(t, sut, verbose)

// get validator addresses
superAdmin := cli.GetKeyAddr("node0")
require.NotEmpty(t, superAdmin)

superAdmin2 := cli.GetKeyAddr("node1")
require.NotEmpty(t, superAdmin2)

// short voting period
// update expedited voting period to avoid validation error
sut.ModifyGenesisJSON(
t,
SetGovVotingPeriod(t, time.Second*8),
SetGovExpeditedVotingPeriod(t, time.Second*7),
)

sut.StartChain(t)

allMsgsAcc := cli.AddKey("allMsgsAcc")
require.NotEmpty(t, allMsgsAcc)

someMsgsAcc := cli.AddKey("someMsgsAcc")
require.NotEmpty(t, someMsgsAcc)

// fund tokens to new created addresses
var amount int64 = 100000
denom := "stake"
rsp := cli.FundAddress(allMsgsAcc, fmt.Sprintf("%d%s", amount, denom))
RequireTxSuccess(t, rsp)
require.Equal(t, amount, cli.QueryBalance(allMsgsAcc, denom))

rsp = cli.FundAddress(someMsgsAcc, fmt.Sprintf("%d%s", amount, denom))
RequireTxSuccess(t, rsp)
require.Equal(t, amount, cli.QueryBalance(someMsgsAcc, denom))

// query gov module account address
rsp = cli.CustomQuery("q", "auth", "module-account", "gov")
govModAddr := gjson.Get(rsp, "account.value.address")

// create a proposal to add super admin
validProposal := fmt.Sprintf(`
{
"messages": [
{
"@type": "/cosmos.circuit.v1.MsgAuthorizeCircuitBreaker",
"granter": "%s",
"grantee": "%s",
"permissions": {"level": 3, "limit_type_urls": []}
}
],
"title": "Params update proposal",
"deposit": "10000000stake",
"summary": "A short summary of my proposal"
}`, govModAddr, superAdmin)
proposalFile := StoreTempFile(t, []byte(validProposal))

rsp = cli.RunAndWait("tx", "gov", "submit-proposal", proposalFile.Name(), "--from="+superAdmin)
RequireTxSuccess(t, rsp)

// vote to proposal from two validators
rsp = cli.RunAndWait("tx", "gov", "vote", "1", "yes", "--from="+superAdmin)
RequireTxSuccess(t, rsp)
rsp = cli.RunAndWait("tx", "gov", "vote", "1", "yes", "--from="+superAdmin2)
RequireTxSuccess(t, rsp)

// wait for proposal to pass
time.Sleep(time.Second * 8)

rsp = cli.CustomQuery("q", "circuit", "accounts")

level := gjson.Get(rsp, fmt.Sprintf("accounts.#(address==%s).permissions.level", superAdmin)).String()
require.Equal(t, "LEVEL_SUPER_ADMIN", level)

authorizeTestCases := []struct {
name string
address string
level int
limtTypeURLs []string
expPermission string
}{
{
"set new super admin",
superAdmin2,
3,
[]string{},
"LEVEL_SUPER_ADMIN",
},
{
"set all msgs level to address",
allMsgsAcc,
2,
[]string{},
"LEVEL_ALL_MSGS",
},
{
"set some msgs level to address",
someMsgsAcc,
1,
someMsgs,
"LEVEL_SOME_MSGS",
},
}

for _, tc := range authorizeTestCases {
t.Run(tc.name, func(t *testing.T) {
permissionJSON := fmt.Sprintf(`{"level":%d,"limit_type_urls":[]}`, tc.level)
if len(tc.limtTypeURLs) != 0 {
permissionJSON = fmt.Sprintf(`{"level":%d,"limit_type_urls":["%s"]}`, tc.level, strings.Join(tc.limtTypeURLs[:], `","`))
}
rsp = cli.RunAndWait("tx", "circuit", "authorize", tc.address, permissionJSON, "--from="+superAdmin)
RequireTxSuccess(t, rsp)

// query account permissions
rsp = cli.CustomQuery("q", "circuit", "account", tc.address)
require.Equal(t, tc.expPermission, gjson.Get(rsp, "permission.level").String())
if len(tc.limtTypeURLs) != 0 {
listStr := gjson.Get(rsp, "permission.limit_type_urls").String()

// convert string to array
var msgsList []string
require.NoError(t, json.Unmarshal([]byte(listStr), &msgsList))

require.EqualValues(t, tc.limtTypeURLs, msgsList)
}
})
}

// test disable tx command
testCircuitTxCommand(t, cli, "disable", superAdmin, superAdmin2, allMsgsAcc, someMsgsAcc)

// test reset tx command
testCircuitTxCommand(t, cli, "reset", superAdmin, superAdmin2, allMsgsAcc, someMsgsAcc)
}

func testCircuitTxCommand(t *testing.T, cli *CLIWrapper, txType, superAdmin, superAdmin2, allMsgsAcc, someMsgsAcc string) {
t.Helper()

disableTestCases := []struct {
name string
fromAddr string
disableMsgs []string
executeTxs [][]string
}{
{
txType + " msgs with super admin",
superAdmin,
[]string{"/cosmos.gov.v1.MsgVote"},
[][]string{
{
"tx", "gov", "vote", "3", "yes", "--from=" + superAdmin,
},
},
},
{
txType + " msgs with all msgs level address",
allMsgsAcc,
[]string{"/cosmos.gov.v1.MsgDeposit"},
[][]string{
{
"tx", "gov", "deposit", "3", "1000stake", "--from=" + allMsgsAcc,
},
},
},
{
txType + " msgs with some msgs level address",
someMsgsAcc,
someMsgs,
[][]string{
{
"tx", "bank", "send", superAdmin, someMsgsAcc, "10000stake",
},
{
"tx", "bank", "multi-send", superAdmin, someMsgsAcc, superAdmin2, "10000stake", "--from=" + superAdmin,
},
},
},
}

for _, tc := range disableTestCases {
t.Run(tc.name, func(t *testing.T) {
cmd := []string{"tx", "circuit", txType, "--from=" + tc.fromAddr}
cmd = append(cmd, tc.disableMsgs...)
rsp := cli.RunAndWait(cmd...)
RequireTxSuccess(t, rsp)

// execute given type transaction
rsp = cli.CustomQuery("q", "circuit", "disabled-list")
var list []string
if gjson.Get(rsp, "disabled_list").Exists() {
listJSON := gjson.Get(rsp, "disabled_list").Raw

// convert string to array
require.NoError(t, json.Unmarshal([]byte(listJSON), &list))
}
for _, msg := range tc.disableMsgs {
if txType == "disable" {
require.Contains(t, list, msg)
} else {
require.NotContains(t, list, msg)
}
}

// test given msg transaction to confirm
for _, tx := range tc.executeTxs {
tx = append(tx, "--fees=2stake")
rsp = cli.RunCommandWithArgs(cli.withTXFlags(tx...)...)
if txType == "disable" {
RequireTxFailure(t, rsp)
require.Contains(t, gjson.Get(rsp, "raw_log").String(), "tx type not allowed")
} else {
RequireTxSuccess(t, rsp)
}
// wait for sometime to avoid sequence error
time.Sleep(time.Second * 2)
}
})
}
}
2 changes: 1 addition & 1 deletion x/circuit/autocli.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
"SOME_MSGS" = 1,
"ALL_MSGS" = 2,
"SUPER_ADMIN" = 3,`,
Example: fmt.Sprintf(`%s tx circuit authorize [address] '{"level":1,"limit_type_urls":["/cosmos.bank.v1beta1.MsgSend, /cosmos.bank.v1beta1.MsgMultiSend"]}'"`, version.AppName),
Example: fmt.Sprintf(`%s tx circuit authorize [address] '{"level":1,"limit_type_urls":["/cosmos.bank.v1beta1.MsgSend", "/cosmos.bank.v1beta1.MsgMultiSend"]}'"`, version.AppName),
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "grantee"},
{ProtoField: "permissions"}, // TODO(@julienrbrt) Support flattening msg for setting each field as a positional arg
Expand Down
Loading