test: migrate e2e/authz to system tests (#21819)

This commit is contained in:
Akhil Kumar P
2024-10-01 08:16:04 +00:00
committed by GitHub
parent 3a20261c78
commit 8eeb3ff6a9
7 changed files with 913 additions and 1266 deletions
+849
View File
@@ -0,0 +1,849 @@
//go:build system_test
package systemtests
import (
"fmt"
"os"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tidwall/gjson"
)
const (
msgSendTypeURL = `/cosmos.bank.v1beta1.MsgSend`
msgDelegateTypeURL = `/cosmos.staking.v1beta1.MsgDelegate`
msgVoteTypeURL = `/cosmos.gov.v1.MsgVote`
msgUndelegateTypeURL = `/cosmos.staking.v1beta1.MsgUndelegate`
msgRedelegateTypeURL = `/cosmos.staking.v1beta1.MsgBeginRedelegate`
sendAuthzTypeURL = `/cosmos.bank.v1beta1.SendAuthorization`
genericAuthzTypeURL = `/cosmos.authz.v1beta1.GenericAuthorization`
testDenom = "stake"
)
func TestAuthzGrantTxCmd(t *testing.T) {
// scenario: test authz grant command
// given a running chain
sut.ResetChain(t)
cli := NewCLIWrapper(t, sut, verbose)
// get validator address which will be used as granter
granterAddr := cli.GetKeyAddr("node0")
require.NotEmpty(t, granterAddr)
// add grantee keys which will be used for each valid transaction
grantee1Addr := cli.AddKey("grantee1")
grantee2Addr := cli.AddKey("grantee2")
require.NotEqual(t, granterAddr, grantee2Addr)
grantee3Addr := cli.AddKey("grantee3")
require.NotEqual(t, granterAddr, grantee3Addr)
grantee4Addr := cli.AddKey("grantee4")
require.NotEqual(t, granterAddr, grantee4Addr)
grantee5Addr := cli.AddKey("grantee5")
require.NotEqual(t, granterAddr, grantee5Addr)
grantee6Addr := cli.AddKey("grantee6")
require.NotEqual(t, granterAddr, grantee6Addr)
sut.StartChain(t)
// query validator operator address
rsp := cli.CustomQuery("q", "staking", "validators")
valOperAddr := gjson.Get(rsp, "validators.#.operator_address").Array()[0].String()
grantCmdArgs := []string{"tx", "authz", "grant", "--from", granterAddr}
expirationTime := time.Now().Add(time.Hour).Unix()
// test grant command
testCases := []struct {
name string
grantee string
cmdArgs []string
expErrMsg string
queryTx bool
}{
{
"invalid authorization type",
grantee1Addr,
[]string{"spend"},
"invalid authorization type",
false,
},
{
"send authorization without spend-limit",
grantee1Addr,
[]string{"send"},
"spend-limit should be greater than zero",
false,
},
{
"generic authorization without msg type",
grantee1Addr,
[]string{"generic"},
"msg type cannot be empty",
true,
},
{
"delegate authorization without allow or deny list",
grantee1Addr,
[]string{"delegate"},
"both allowed & deny list cannot be empty",
false,
},
{
"delegate authorization with invalid allowed validator address",
grantee1Addr,
[]string{"delegate", "--allowed-validators=invalid"},
"decoding bech32 failed",
false,
},
{
"delegate authorization with invalid deny validator address",
grantee1Addr,
[]string{"delegate", "--deny-validators=invalid"},
"decoding bech32 failed",
false,
},
{
"unbond authorization without allow or deny list",
grantee1Addr,
[]string{"unbond"},
"both allowed & deny list cannot be empty",
false,
},
{
"unbond authorization with invalid allowed validator address",
grantee1Addr,
[]string{"unbond", "--allowed-validators=invalid"},
"decoding bech32 failed",
false,
},
{
"unbond authorization with invalid deny validator address",
grantee1Addr,
[]string{"unbond", "--deny-validators=invalid"},
"decoding bech32 failed",
false,
},
{
"redelegate authorization without allow or deny list",
grantee1Addr,
[]string{"redelegate"},
"both allowed & deny list cannot be empty",
false,
},
{
"redelegate authorization with invalid allowed validator address",
grantee1Addr,
[]string{"redelegate", "--allowed-validators=invalid"},
"decoding bech32 failed",
false,
},
{
"redelegate authorization with invalid deny validator address",
grantee1Addr,
[]string{"redelegate", "--deny-validators=invalid"},
"decoding bech32 failed",
false,
},
{
"valid send authorization",
grantee1Addr,
[]string{"send", "--spend-limit=1000" + testDenom},
"",
false,
},
{
"valid send authorization with expiration",
grantee2Addr,
[]string{"send", "--spend-limit=1000" + testDenom, fmt.Sprintf("--expiration=%d", expirationTime)},
"",
false,
},
{
"valid generic authorization",
grantee3Addr,
[]string{"generic", "--msg-type=" + msgVoteTypeURL},
"",
false,
},
{
"valid delegate authorization",
grantee4Addr,
[]string{"delegate", "--allowed-validators=" + valOperAddr},
"",
false,
},
{
"valid unbond authorization",
grantee5Addr,
[]string{"unbond", "--deny-validators=" + valOperAddr},
"",
false,
},
{
"valid redelegate authorization",
grantee6Addr,
[]string{"redelegate", "--allowed-validators=" + valOperAddr},
"",
false,
},
}
grantsCount := 0
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
cmd := append(append(grantCmdArgs, tc.grantee), tc.cmdArgs...)
if tc.expErrMsg != "" {
if tc.queryTx {
rsp := cli.Run(cmd...)
RequireTxFailure(t, rsp)
require.Contains(t, rsp, tc.expErrMsg)
} else {
assertErr := func(_ assert.TestingT, gotErr error, gotOutputs ...interface{}) bool {
require.Len(t, gotOutputs, 1)
output := gotOutputs[0].(string)
require.Contains(t, output, tc.expErrMsg)
return false
}
_ = cli.WithRunErrorMatcher(assertErr).Run(cmd...)
}
return
}
rsp := cli.RunAndWait(cmd...)
RequireTxSuccess(t, rsp)
// query granter-grantee grants
resp := cli.CustomQuery("q", "authz", "grants", granterAddr, tc.grantee)
grants := gjson.Get(resp, "grants").Array()
// check grants length equal to 1 to confirm grant created successfully
require.Len(t, grants, 1)
grantsCount++
})
}
// query grants-by-granter
resp := cli.CustomQuery("q", "authz", "grants-by-granter", granterAddr)
grants := gjson.Get(resp, "grants").Array()
require.Len(t, grants, grantsCount)
}
func TestAuthzExecSendAuthorization(t *testing.T) {
// scenario: test authz exec send authorization
// given a running chain
sut.ResetChain(t)
cli := NewCLIWrapper(t, sut, verbose)
// get validator address which will be used as granter
granterAddr := cli.GetKeyAddr("node0")
require.NotEmpty(t, granterAddr)
// add grantee keys which will be used for each valid transaction
granteeAddr := cli.AddKey("grantee")
require.NotEqual(t, granterAddr, granteeAddr)
allowedAddr := cli.AddKey("allowed")
require.NotEqual(t, granteeAddr, allowedAddr)
notAllowedAddr := cli.AddKey("notAllowed")
require.NotEqual(t, granteeAddr, notAllowedAddr)
newAccount := cli.AddKey("newAccount")
require.NotEqual(t, granteeAddr, newAccount)
var initialAmount int64 = 10000000
initialBalance := fmt.Sprintf("%d%s", initialAmount, testDenom)
sut.ModifyGenesisCLI(t,
[]string{"genesis", "add-genesis-account", granteeAddr, initialBalance},
[]string{"genesis", "add-genesis-account", allowedAddr, initialBalance},
[]string{"genesis", "add-genesis-account", newAccount, initialBalance},
)
sut.StartChain(t)
// query balances
granterBal := cli.QueryBalance(granterAddr, testDenom)
granteeBal := cli.QueryBalance(granteeAddr, testDenom)
require.Equal(t, initialAmount, granteeBal)
allowedAddrBal := cli.QueryBalance(allowedAddr, testDenom)
require.Equal(t, initialAmount, allowedAddrBal)
var spendLimitAmount int64 = 1000
expirationTime := time.Now().Add(time.Second * 10).Unix()
// test exec send authorization
// create send authorization grant
rsp := cli.RunAndWait("tx", "authz", "grant", granteeAddr, "send",
"--spend-limit="+fmt.Sprintf("%d%s", spendLimitAmount, testDenom),
"--allow-list="+allowedAddr,
"--expiration="+fmt.Sprintf("%d", expirationTime),
"--fees=1"+testDenom,
"--from", granterAddr)
RequireTxSuccess(t, rsp)
// reduce fees of above tx from granter balance
granterBal--
testCases := []struct {
name string
grantee string
toAddr string
amount int64
expErrMsg string
}{
{
"valid exec transaction",
granteeAddr,
allowedAddr,
20,
"",
},
{
"send to not allowed address",
granteeAddr,
notAllowedAddr,
10,
"cannot send to",
},
{
"amount greater than spend limit",
granteeAddr,
allowedAddr,
spendLimitAmount + 5,
"requested amount is more than spend limit",
},
{
"no grant found",
newAccount,
granteeAddr,
20,
"authorization not found",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
// msg send
cmd := msgSendExec(t, granterAddr, tc.grantee, tc.toAddr, testDenom, tc.amount)
if tc.expErrMsg != "" {
rsp := cli.Run(cmd...)
RequireTxFailure(t, rsp)
require.Contains(t, rsp, tc.expErrMsg)
return
}
rsp := cli.RunAndWait(cmd...)
RequireTxSuccess(t, rsp)
// check granter balance equals to granterBal - transferredAmount
expGranterBal := granterBal - tc.amount
require.Equal(t, expGranterBal, cli.QueryBalance(granterAddr, testDenom))
granterBal = expGranterBal
// check allowed addr balance equals to allowedAddrBal + transferredAmount
expAllowAddrBal := allowedAddrBal + tc.amount
require.Equal(t, expAllowAddrBal, cli.QueryBalance(allowedAddr, testDenom))
allowedAddrBal = expAllowAddrBal
})
}
// test grant expiry
time.Sleep(time.Second * 10)
execSendCmd := msgSendExec(t, granterAddr, granteeAddr, allowedAddr, testDenom, 10)
rsp = cli.Run(execSendCmd...)
RequireTxFailure(t, rsp)
require.Contains(t, rsp, "authorization not found")
}
func TestAuthzExecGenericAuthorization(t *testing.T) {
// scenario: test authz exec generic authorization
// given a running chain
cli, granterAddr, granteeAddr := setupChain(t)
allowedAddr := cli.AddKey("allowedAddr")
require.NotEqual(t, granterAddr, allowedAddr)
// query balances
granterBal := cli.QueryBalance(granterAddr, testDenom)
expirationTime := time.Now().Add(time.Second * 5).Unix()
execSendCmd := msgSendExec(t, granterAddr, granteeAddr, allowedAddr, testDenom, 10)
// create generic authorization grant
rsp := cli.RunAndWait("tx", "authz", "grant", granteeAddr, "generic",
"--msg-type="+msgSendTypeURL,
"--expiration="+fmt.Sprintf("%d", expirationTime),
"--fees=1"+testDenom,
"--from", granterAddr)
RequireTxSuccess(t, rsp)
granterBal--
rsp = cli.RunAndWait(execSendCmd...)
RequireTxSuccess(t, rsp)
// check granter balance equals to granterBal - transferredAmount
expGranterBal := granterBal - 10
require.Equal(t, expGranterBal, cli.QueryBalance(granterAddr, testDenom))
time.Sleep(time.Second * 5)
// check grants after expiration
resp := cli.CustomQuery("q", "authz", "grants", granterAddr, granteeAddr)
grants := gjson.Get(resp, "grants").Array()
require.Len(t, grants, 0)
}
func TestAuthzExecDelegateAuthorization(t *testing.T) {
// scenario: test authz exec delegate authorization
// given a running chain
cli, granterAddr, granteeAddr := setupChain(t)
// query balances
granterBal := cli.QueryBalance(granterAddr, testDenom)
// query validator operator address
rsp := cli.CustomQuery("q", "staking", "validators")
validators := gjson.Get(rsp, "validators.#.operator_address").Array()
require.GreaterOrEqual(t, len(validators), 2)
val1Addr := validators[0].String()
val2Addr := validators[1].String()
var spendLimitAmount int64 = 1000
require.Greater(t, granterBal, spendLimitAmount)
rsp = cli.RunAndWait("tx", "authz", "grant", granteeAddr, "delegate",
"--spend-limit="+fmt.Sprintf("%d%s", spendLimitAmount, testDenom),
"--allowed-validators="+val1Addr,
"--fees=1"+testDenom,
"--from", granterAddr)
RequireTxSuccess(t, rsp)
// reduce fees of above tx from granter balance
granterBal--
delegateTestCases := []struct {
name string
grantee string
valAddr string
amount int64
expErrMsg string
}{
{
"valid txn: (delegate half tokens)",
granteeAddr,
val1Addr,
spendLimitAmount / 2,
"",
},
{
"amount greater than spend limit",
granteeAddr,
val1Addr,
spendLimitAmount + 5,
"negative coin amount",
},
{
"delegate to not allowed address",
granteeAddr,
val2Addr,
10,
"cannot delegate",
},
{
"valid txn: (delegate remaining half tokens)",
granteeAddr,
val1Addr,
spendLimitAmount / 2,
"",
},
{
"no authorization found as grant prunes",
granteeAddr,
val1Addr,
spendLimitAmount / 2,
"authorization not found",
},
}
execCmdArgs := []string{"tx", "authz", "exec"}
for _, tc := range delegateTestCases {
t.Run(tc.name, func(t *testing.T) {
delegateTx := fmt.Sprintf(`{"@type":"%s","delegator_address":"%s","validator_address":"%s","amount":{"denom":"%s","amount":"%d"}}`,
msgDelegateTypeURL, granterAddr, tc.valAddr, testDenom, tc.amount)
execMsg := WriteToTempJSONFile(t, delegateTx)
cmd := append(append(execCmdArgs, execMsg.Name()), "--from="+tc.grantee)
if tc.expErrMsg != "" {
rsp := cli.Run(cmd...)
RequireTxFailure(t, rsp)
require.Contains(t, rsp, tc.expErrMsg)
return
}
rsp := cli.RunAndWait(cmd...)
RequireTxSuccess(t, rsp)
// check granter balance equals to granterBal - transferredAmount
expGranterBal := granterBal - tc.amount
require.Equal(t, expGranterBal, cli.QueryBalance(granterAddr, testDenom))
granterBal = expGranterBal
})
}
}
func TestAuthzExecUndelegateAuthorization(t *testing.T) {
// scenario: test authz exec undelegate authorization
// given a running chain
cli, granterAddr, granteeAddr := setupChain(t)
// query validator operator address
rsp := cli.CustomQuery("q", "staking", "validators")
validators := gjson.Get(rsp, "validators.#.operator_address").Array()
require.GreaterOrEqual(t, len(validators), 2)
val1Addr := validators[0].String()
val2Addr := validators[1].String()
// delegate some tokens
rsp = cli.RunAndWait("tx", "staking", "delegate", val1Addr, "10000"+testDenom, "--from="+granterAddr)
RequireTxSuccess(t, rsp)
// query delegated tokens count
resp := cli.CustomQuery("q", "staking", "delegation", granterAddr, val1Addr)
delegatedAmount := gjson.Get(resp, "delegation_response.balance.amount").Int()
rsp = cli.RunAndWait("tx", "authz", "grant", granteeAddr, "unbond",
"--allowed-validators="+val1Addr,
"--fees=1"+testDenom,
"--from", granterAddr)
RequireTxSuccess(t, rsp)
undelegateTestCases := []struct {
name string
grantee string
valAddr string
amount int64
expErrMsg string
}{
{
"valid transaction",
granteeAddr,
val1Addr,
10,
"",
},
{
"undelegate to not allowed address",
granteeAddr,
val2Addr,
10,
"cannot delegate/undelegate",
},
}
for _, tc := range undelegateTestCases {
t.Run(tc.name, func(t *testing.T) {
undelegateTx := fmt.Sprintf(`{"@type":"%s","delegator_address":"%s","validator_address":"%s","amount":{"denom":"%s","amount":"%d"}}`,
msgUndelegateTypeURL, granterAddr, tc.valAddr, testDenom, tc.amount)
execMsg := WriteToTempJSONFile(t, undelegateTx)
cmd := []string{"tx", "authz", "exec", execMsg.Name(), "--from=" + tc.grantee}
if tc.expErrMsg != "" {
rsp := cli.Run(cmd...)
RequireTxFailure(t, rsp)
require.Contains(t, rsp, tc.expErrMsg)
return
}
rsp := cli.RunAndWait(cmd...)
RequireTxSuccess(t, rsp)
// query delegation and check balance reduced
expectedAmount := delegatedAmount - tc.amount
resp = cli.CustomQuery("q", "staking", "delegation", granterAddr, val1Addr)
delegatedAmount = gjson.Get(resp, "delegation_response.balance.amount").Int()
require.Equal(t, expectedAmount, delegatedAmount)
})
}
// revoke existing grant
rsp = cli.RunAndWait("tx", "authz", "revoke", granteeAddr, msgUndelegateTypeURL, "--from", granterAddr)
RequireTxSuccess(t, rsp)
// check grants between granter and grantee after revoking
resp = cli.CustomQuery("q", "authz", "grants", granterAddr, granteeAddr)
grants := gjson.Get(resp, "grants").Array()
require.Len(t, grants, 0)
}
func TestAuthzExecRedelegateAuthorization(t *testing.T) {
// scenario: test authz exec redelegate authorization
// given a running chain
cli, granterAddr, granteeAddr := setupChain(t)
// query validator operator address
rsp := cli.CustomQuery("q", "staking", "validators")
validators := gjson.Get(rsp, "validators.#.operator_address").Array()
require.GreaterOrEqual(t, len(validators), 2)
val1Addr := validators[0].String()
val2Addr := validators[1].String()
// delegate some tokens
rsp = cli.RunAndWait("tx", "staking", "delegate", val1Addr, "10000"+testDenom, "--from="+granterAddr)
RequireTxSuccess(t, rsp)
// test exec redelegate authorization
rsp = cli.RunAndWait("tx", "authz", "grant", granteeAddr, "redelegate",
fmt.Sprintf("--allowed-validators=%s,%s", val1Addr, val2Addr),
"--fees=1"+testDenom,
"--from", granterAddr)
RequireTxSuccess(t, rsp)
var redelegationAmount int64 = 10
redelegateTx := fmt.Sprintf(`{"@type":"%s","delegator_address":"%s","validator_src_address":"%s","validator_dst_address":"%s","amount":{"denom":"%s","amount":"%d"}}`,
msgRedelegateTypeURL, granterAddr, val1Addr, val2Addr, testDenom, redelegationAmount)
execMsg := WriteToTempJSONFile(t, redelegateTx)
redelegateCmd := []string{"tx", "authz", "exec", execMsg.Name(), "--from=" + granteeAddr, "--gas=auto"}
rsp = cli.RunAndWait(redelegateCmd...)
RequireTxSuccess(t, rsp)
// query new delegation and check balance increased
resp := cli.CustomQuery("q", "staking", "delegation", granterAddr, val2Addr)
delegatedAmount := gjson.Get(resp, "delegation_response.balance.amount").Int()
require.GreaterOrEqual(t, delegatedAmount, redelegationAmount)
// revoke all existing grants
rsp = cli.RunAndWait("tx", "authz", "revoke-all", "--from", granterAddr)
RequireTxSuccess(t, rsp)
// check grants after revoking
resp = cli.CustomQuery("q", "authz", "grants-by-granter", granterAddr)
grants := gjson.Get(resp, "grants").Array()
require.Len(t, grants, 0)
}
func TestAuthzGRPCQueries(t *testing.T) {
// scenario: test authz grpc gateway queries
// given a running chain
cli, granterAddr, grantee1Addr := setupChain(t)
grantee2Addr := cli.AddKey("grantee2")
require.NotEqual(t, granterAddr, grantee2Addr)
require.NotEqual(t, grantee1Addr, grantee2Addr)
// create few grants
rsp := cli.RunAndWait("tx", "authz", "grant", grantee1Addr, "send",
"--spend-limit=10000"+testDenom,
"--from", granterAddr)
RequireTxSuccess(t, rsp)
grant1 := fmt.Sprintf(`"authorization":{"@type":"%s","spend_limit":[{"denom":"%s","amount":"10000"}],"allow_list":[]},"expiration":null`, sendAuthzTypeURL, testDenom)
rsp = cli.RunAndWait("tx", "authz", "grant", grantee2Addr, "send",
"--spend-limit=1000"+testDenom,
"--from", granterAddr)
RequireTxSuccess(t, rsp)
grant2 := fmt.Sprintf(`"authorization":{"@type":"%s","spend_limit":[{"denom":"%s","amount":"1000"}],"allow_list":[]},"expiration":null`, sendAuthzTypeURL, testDenom)
rsp = cli.RunAndWait("tx", "authz", "grant", grantee2Addr, "generic",
"--msg-type="+msgVoteTypeURL,
"--from", granterAddr)
RequireTxSuccess(t, rsp)
grant3 := fmt.Sprintf(`"authorization":{"@type":"%s","msg":"%s"},"expiration":null`, genericAuthzTypeURL, msgVoteTypeURL)
rsp = cli.RunAndWait("tx", "authz", "grant", grantee2Addr, "generic",
"--msg-type="+msgDelegateTypeURL,
"--from", grantee1Addr)
RequireTxSuccess(t, rsp)
grant4 := fmt.Sprintf(`"authorization":{"@type":"%s","msg":"%s"},"expiration":null`, genericAuthzTypeURL, msgDelegateTypeURL)
baseurl := sut.APIAddress()
// test query grant grpc endpoint
grantURL := baseurl + "/cosmos/authz/v1beta1/grants?granter=%s&grantee=%s&msg_type_url=%s"
bech32FailOutput := `{"code":2, "message":"decoding bech32 failed: invalid separator index -1", "details":[]}`
emptyStrOutput := `{"code":2, "message":"empty address string is not allowed", "details":[]}`
invalidMsgTypeOutput := `{"code":2, "message":"codespace authz code 2: authorization not found: authorization not found for invalidMsg type", "details":[]}`
expGrantOutput := fmt.Sprintf(`{"grants":[{%s}],"pagination":null}`, grant1)
grantTestCases := []GRPCTestCase{
{
"invalid granter address",
fmt.Sprintf(grantURL, "invalid_granter", grantee1Addr, msgSendTypeURL),
bech32FailOutput,
},
{
"invalid grantee address",
fmt.Sprintf(grantURL, granterAddr, "invalid_grantee", msgSendTypeURL),
bech32FailOutput,
},
{
"with empty granter",
fmt.Sprintf(grantURL, "", grantee1Addr, msgSendTypeURL),
emptyStrOutput,
},
{
"with empty grantee",
fmt.Sprintf(grantURL, granterAddr, "", msgSendTypeURL),
emptyStrOutput,
},
{
"invalid msg-type",
fmt.Sprintf(grantURL, granterAddr, grantee1Addr, "invalidMsg"),
invalidMsgTypeOutput,
},
{
"valid grant query",
fmt.Sprintf(grantURL, granterAddr, grantee1Addr, msgSendTypeURL),
expGrantOutput,
},
}
RunGRPCQueries(t, grantTestCases)
// test query grants grpc endpoint
grantsURL := baseurl + "/cosmos/authz/v1beta1/grants?granter=%s&grantee=%s"
grantsTestCases := []GRPCTestCase{
{
"expect single grant",
fmt.Sprintf(grantsURL, granterAddr, grantee1Addr),
fmt.Sprintf(`{"grants":[{%s}],"pagination":{"next_key":null,"total":"1"}}`, grant1),
},
{
"expect two grants",
fmt.Sprintf(grantsURL, granterAddr, grantee2Addr),
fmt.Sprintf(`{"grants":[{%s},{%s}],"pagination":{"next_key":null,"total":"2"}}`, grant2, grant3),
},
{
"expect single grant with pagination",
fmt.Sprintf(grantsURL+"&pagination.limit=1", granterAddr, grantee2Addr),
fmt.Sprintf(`{"grants":[{%s}],"pagination":{"next_key":"L2Nvc21vcy5nb3YudjEuTXNnVm90ZQ==","total":"0"}}`, grant2),
},
{
"expect single grant with pagination limit and offset",
fmt.Sprintf(grantsURL+"&pagination.limit=1&pagination.offset=1", granterAddr, grantee2Addr),
fmt.Sprintf(`{"grants":[{%s}],"pagination":{"next_key":null,"total":"0"}}`, grant3),
},
{
"expect two grants with pagination",
fmt.Sprintf(grantsURL+"&pagination.limit=2", granterAddr, grantee2Addr),
fmt.Sprintf(`{"grants":[{%s},{%s}],"pagination":{"next_key":null,"total":"0"}}`, grant2, grant3),
},
}
RunGRPCQueries(t, grantsTestCases)
// test query grants by granter grpc endpoint
grantsByGranterURL := baseurl + "/cosmos/authz/v1beta1/grants/granter/%s"
decodingFailedOutput := `{"code":2, "message":"decoding bech32 failed: invalid character in string: ' '", "details":[]}`
noAuthorizationsOutput := `{"grants":[],"pagination":{"next_key":null,"total":"0"}}`
granterQueryOutput := fmt.Sprintf(`{"grants":[{"granter":"%s","grantee":"%s",%s}],"pagination":{"next_key":null,"total":"1"}}`,
grantee1Addr, grantee2Addr, grant4)
granterTestCases := []GRPCTestCase{
{
"invalid granter account address",
fmt.Sprintf(grantsByGranterURL, "invalid address"),
decodingFailedOutput,
},
{
"no authorizations found from granter",
fmt.Sprintf(grantsByGranterURL, grantee2Addr),
noAuthorizationsOutput,
},
{
"valid granter query",
fmt.Sprintf(grantsByGranterURL, grantee1Addr),
granterQueryOutput,
},
}
RunGRPCQueries(t, granterTestCases)
// test query grants by grantee grpc endpoint
grantsByGranteeURL := baseurl + "/cosmos/authz/v1beta1/grants/grantee/%s"
grantee1GrantsOutput := fmt.Sprintf(`{"grants":[{"granter":"%s","grantee":"%s",%s}],"pagination":{"next_key":null,"total":"1"}}`, granterAddr, grantee1Addr, grant1)
granteeTestCases := []GRPCTestCase{
{
"invalid grantee account address",
fmt.Sprintf(grantsByGranteeURL, "invalid address"),
decodingFailedOutput,
},
{
"no authorizations found from grantee",
fmt.Sprintf(grantsByGranteeURL, granterAddr),
noAuthorizationsOutput,
},
{
"valid grantee query",
fmt.Sprintf(grantsByGranteeURL, grantee1Addr),
grantee1GrantsOutput,
},
}
RunGRPCQueries(t, granteeTestCases)
}
func setupChain(t *testing.T) (*CLIWrapper, string, string) {
t.Helper()
sut.ResetChain(t)
cli := NewCLIWrapper(t, sut, verbose)
require.GreaterOrEqual(t, cli.nodesCount, 2)
// get validators' address which will be used as granter and grantee
granterAddr := cli.GetKeyAddr("node0")
require.NotEmpty(t, granterAddr)
granteeAddr := cli.GetKeyAddr("node1")
require.NotEmpty(t, granteeAddr)
sut.StartChain(t)
return cli, granterAddr, granteeAddr
}
func msgSendExec(t *testing.T, granter, grantee, toAddr, denom string, amount int64) []string {
t.Helper()
bankTx := fmt.Sprintf(`{
"@type": "%s",
"from_address": "%s",
"to_address": "%s",
"amount": [
{
"denom": "%s",
"amount": "%d"
}
]
}`, msgSendTypeURL, granter, toAddr, denom, amount)
execMsg := WriteToTempJSONFile(t, bankTx)
execSendCmd := []string{"tx", "authz", "exec", execMsg.Name(), "--from=" + grantee}
return execSendCmd
}
// Write the given string to a new temporary json file.
// Returns an file for the test to use.
func WriteToTempJSONFile(tb testing.TB, s string) *os.File {
tb.Helper()
tmpFile, err := os.CreateTemp(tb.TempDir(), "test-*.json")
require.NoError(tb, err)
// Write to the temporary file
_, err = tmpFile.WriteString(s)
require.NoError(tb, err)
// Close the file after writing
err = tmpFile.Close()
require.NoError(tb, err)
return tmpFile
}
+29 -53
View File
@@ -23,7 +23,7 @@ func TestBankSendTxCmd(t *testing.T) {
cli := NewCLIWrapper(t, sut, verbose)
// get validator address
valAddr := gjson.Get(cli.Keys("keys", "list"), "1.address").String()
valAddr := cli.GetKeyAddr("node0")
require.NotEmpty(t, valAddr)
// add new key
@@ -131,28 +131,24 @@ func TestBankMultiSendTxCmd(t *testing.T) {
testCases := []struct {
name string
cmdArgs []string
expectErr bool
expectedCode uint32
expErrMsg string
}{
{
"valid transaction",
append(multiSendCmdArgs, "--fees=1stake"),
false,
0,
"",
},
{
"not enough arguments",
[]string{"tx", "bank", "multi-send", account1Addr, account2Addr, "1000stake", "--from=" + account1Addr},
true,
0,
"only received 3",
},
{
"chain-id shouldn't be used with offline and generate-only flags",
append(multiSendCmdArgs, "--generate-only", "--offline", "-a=0", "-s=4"),
true,
0,
"chain ID cannot be used",
},
@@ -160,7 +156,7 @@ func TestBankMultiSendTxCmd(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
if tc.expectErr {
if tc.expErrMsg != "" {
assertErr := func(_ assert.TestingT, gotErr error, gotOutputs ...interface{}) bool {
require.Len(t, gotOutputs, 1)
output := gotOutputs[0].(string)
@@ -173,24 +169,24 @@ func TestBankMultiSendTxCmd(t *testing.T) {
return false // always abort
}
_ = cli.WithRunErrorMatcher(assertErr).Run(tc.cmdArgs...)
} else {
rsp := cli.Run(tc.cmdArgs...)
txResult, found := cli.AwaitTxCommitted(rsp)
require.True(t, found)
RequireTxSuccess(t, txResult)
// check account1 balance equals to account1Bal - transferredAmount*no_of_accounts - fees
expAcc1Balance := account1Bal - (1000 * 2) - 1
require.Equal(t, expAcc1Balance, cli.QueryBalance(account1Addr, denom))
account1Bal = expAcc1Balance
// check account2 balance equals to account2Bal + transferredAmount
expAcc2Balance := account2Bal + 1000
require.Equal(t, expAcc2Balance, cli.QueryBalance(account2Addr, denom))
account2Bal = expAcc2Balance
// check account3 balance equals to account3Bal + transferredAmount
expAcc3Balance := account3Bal + 1000
require.Equal(t, expAcc3Balance, cli.QueryBalance(account3Addr, denom))
account3Bal = expAcc3Balance
return
}
rsp := cli.Run(tc.cmdArgs...)
txResult, found := cli.AwaitTxCommitted(rsp)
require.True(t, found)
RequireTxSuccess(t, txResult)
// check account1 balance equals to account1Bal - transferredAmount*no_of_accounts - fees
expAcc1Balance := account1Bal - (1000 * 2) - 1
require.Equal(t, expAcc1Balance, cli.QueryBalance(account1Addr, denom))
account1Bal = expAcc1Balance
// check account2 balance equals to account2Bal + transferredAmount
expAcc2Balance := account2Bal + 1000
require.Equal(t, expAcc2Balance, cli.QueryBalance(account2Addr, denom))
account2Bal = expAcc2Balance
// check account3 balance equals to account3Bal + transferredAmount
expAcc3Balance := account3Bal + 1000
require.Equal(t, expAcc3Balance, cli.QueryBalance(account3Addr, denom))
account3Bal = expAcc3Balance
})
}
}
@@ -224,7 +220,7 @@ func TestBankGRPCQueries(t *testing.T) {
// start chain
sut.StartChain(t)
baseurl := fmt.Sprintf("http://localhost:%d", apiPortStart)
baseurl := sut.APIAddress()
// test supply grpc endpoint
supplyUrl := baseurl + "/cosmos/bank/v1beta1/supply"
@@ -283,45 +279,31 @@ func TestBankGRPCQueries(t *testing.T) {
// test denom metadata endpoint
denomMetadataUrl := baseurl + "/cosmos/bank/v1beta1/denoms_metadata"
dmTestCases := []struct {
name string
url string
expOut string
}{
dmTestCases := []GRPCTestCase{
{
"test GRPC client metadata",
denomMetadataUrl,
bankDenomMetadata,
fmt.Sprintf(`{"metadatas":%s,"pagination":{"next_key":null,"total":"2"}}`, bankDenomMetadata),
},
{
"test GRPC client metadata of a specific denom",
denomMetadataUrl + "/uatom",
atomDenomMetadata,
fmt.Sprintf(`{"metadata":%s}`, atomDenomMetadata),
},
{
"test GRPC client metadata of a bogus denom",
denomMetadataUrl + "/foobar",
`"details":[]`,
`{"code":5, "message":"client metadata for denom foobar", "details":[]}`,
},
}
for _, tc := range dmTestCases {
t.Run(tc.name, func(t *testing.T) {
resp, err := testutil.GetRequest(tc.url)
require.NoError(t, err)
require.Contains(t, string(resp), tc.expOut)
})
}
RunGRPCQueries(t, dmTestCases)
// test bank balances endpoint
balanceUrl := baseurl + "/cosmos/bank/v1beta1/balances/"
allBalancesOutput := `{"balances":[` + specificDenomOutput + `,{"denom":"stake","amount":"10000000"}],"pagination":{"next_key":null,"total":"2"}}`
balanceTestCases := []struct {
name string
url string
expOut string
}{
balanceTestCases := []GRPCTestCase{
{
"test GRPC total account balance",
balanceUrl + account1Addr,
@@ -330,20 +312,14 @@ func TestBankGRPCQueries(t *testing.T) {
{
"test GRPC account balance of a specific denom",
fmt.Sprintf("%s%s/by_denom?denom=%s", balanceUrl, account1Addr, newDenom),
specificDenomOutput,
fmt.Sprintf(`{"balance":%s}`, specificDenomOutput),
},
{
"test GRPC account balance of a bogus denom",
fmt.Sprintf("%s%s/by_denom?denom=foobar", balanceUrl, account1Addr),
bogusDenomOutput,
fmt.Sprintf(`{"balance":%s}`, bogusDenomOutput),
},
}
for _, tc := range balanceTestCases {
t.Run(tc.name, func(t *testing.T) {
resp, err := testutil.GetRequest(tc.url)
require.NoError(t, err)
require.Contains(t, string(resp), tc.expOut)
})
}
RunGRPCQueries(t, balanceTestCases)
}
+29
View File
@@ -0,0 +1,29 @@
package systemtests
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/testutil"
)
type GRPCTestCase struct {
name string
url string
expOut string
}
// RunGRPCQueries runs given grpc testcases by making requests and
// checking response with expected output
func RunGRPCQueries(t *testing.T, testCases []GRPCTestCase) {
t.Helper()
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
resp, err := testutil.GetRequest(tc.url)
require.NoError(t, err)
require.JSONEq(t, tc.expOut, string(resp))
})
}
}
+6
View File
@@ -53,6 +53,7 @@ type SystemUnderTest struct {
// since Tendermint consensus does not allow specifying it directly.
blockTime time.Duration
rpcAddr string
apiAddr string
initialNodesCount int
nodesCount int
minGasPrice string
@@ -86,6 +87,7 @@ func NewSystemUnderTest(execBinary string, verbose bool, nodesCount int, blockTi
outputDir: "./testnet",
blockTime: blockTime,
rpcAddr: "tcp://localhost:26657",
apiAddr: fmt.Sprintf("http://localhost:%d", apiPortStart),
initialNodesCount: nodesCount,
outBuff: ring.New(100),
errBuff: ring.New(100),
@@ -638,6 +640,10 @@ func (s *SystemUnderTest) RPCClient(t *testing.T) RPCClient {
return NewRPCClient(t, s.rpcAddr)
}
func (s *SystemUnderTest) APIAddress() string {
return s.apiAddr
}
func (s *SystemUnderTest) AllPeers(t *testing.T) []string {
t.Helper()
result := make([]string, s.nodesCount)