cosmos-sdk/x/feegrant/keeper/keeper_test.go

258 lines
6.0 KiB
Go

package keeper_test
import (
"testing"
"github.com/stretchr/testify/suite"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/feegrant/types"
)
type KeeperTestSuite struct {
suite.Suite
app *simapp.SimApp
ctx sdk.Context
addrs []sdk.AccAddress
}
func TestKeeperTestSuite(t *testing.T) {
suite.Run(t, new(KeeperTestSuite))
}
func (suite *KeeperTestSuite) SetupTest() {
app := simapp.Setup(false)
ctx := app.BaseApp.NewContext(false, tmproto.Header{})
suite.app = app
suite.ctx = ctx
suite.addrs = simapp.AddTestAddrsIncremental(app, ctx, 4, sdk.NewInt(30000000))
}
func (suite *KeeperTestSuite) TestKeeperCrud() {
ctx := suite.ctx
k := suite.app.FeeGrantKeeper
// some helpers
atom := sdk.NewCoins(sdk.NewInt64Coin("atom", 555))
eth := sdk.NewCoins(sdk.NewInt64Coin("eth", 123))
basic := &types.BasicFeeAllowance{
SpendLimit: atom,
Expiration: types.ExpiresAtHeight(334455),
}
basic2 := &types.BasicFeeAllowance{
SpendLimit: eth,
Expiration: types.ExpiresAtHeight(172436),
}
// let's set up some initial state here
err := k.GrantFeeAllowance(ctx, suite.addrs[0], suite.addrs[1], basic)
suite.Require().NoError(err)
err = k.GrantFeeAllowance(ctx, suite.addrs[0], suite.addrs[2], basic2)
suite.Require().NoError(err)
err = k.GrantFeeAllowance(ctx, suite.addrs[1], suite.addrs[2], basic)
suite.Require().NoError(err)
err = k.GrantFeeAllowance(ctx, suite.addrs[1], suite.addrs[3], basic)
suite.Require().NoError(err)
err = k.GrantFeeAllowance(ctx, suite.addrs[3], suite.addrs[0], basic2)
suite.Require().NoError(err)
// remove some, overwrite other
k.RevokeFeeAllowance(ctx, suite.addrs[0], suite.addrs[1])
k.RevokeFeeAllowance(ctx, suite.addrs[0], suite.addrs[2])
err = k.GrantFeeAllowance(ctx, suite.addrs[0], suite.addrs[2], basic)
suite.Require().NoError(err)
err = k.GrantFeeAllowance(ctx, suite.addrs[1], suite.addrs[2], basic2)
suite.Require().NoError(err)
// end state:
// addr -> addr3 (basic)
// addr2 -> addr3 (basic2), addr4(basic)
// addr4 -> addr (basic2)
// then lots of queries
cases := map[string]struct {
grantee sdk.AccAddress
granter sdk.AccAddress
allowance types.FeeAllowanceI
}{
"addr revoked": {
granter: suite.addrs[0],
grantee: suite.addrs[1],
},
"addr revoked and added": {
granter: suite.addrs[0],
grantee: suite.addrs[2],
allowance: basic,
},
"addr never there": {
granter: suite.addrs[0],
grantee: suite.addrs[3],
},
"addr modified": {
granter: suite.addrs[1],
grantee: suite.addrs[2],
allowance: basic2,
},
}
for name, tc := range cases {
tc := tc
suite.Run(name, func() {
allow := k.GetFeeAllowance(ctx, tc.granter, tc.grantee)
if tc.allowance == nil {
suite.Nil(allow)
return
}
suite.NotNil(allow)
suite.Equal(tc.allowance, allow)
})
}
grant1, err := types.NewFeeAllowanceGrant(suite.addrs[3], suite.addrs[0], basic2)
suite.NoError(err)
grant2, err := types.NewFeeAllowanceGrant(suite.addrs[1], suite.addrs[2], basic2)
suite.NoError(err)
grant3, err := types.NewFeeAllowanceGrant(suite.addrs[0], suite.addrs[2], basic)
suite.NoError(err)
allCases := map[string]struct {
grantee sdk.AccAddress
grants []types.FeeAllowanceGrant
}{
"addr2 has none": {
grantee: suite.addrs[1],
},
"addr has one": {
grantee: suite.addrs[0],
grants: []types.FeeAllowanceGrant{
grant1,
},
},
"addr3 has two": {
grantee: suite.addrs[2],
grants: []types.FeeAllowanceGrant{
grant3,
grant2,
},
},
}
for name, tc := range allCases {
tc := tc
suite.Run(name, func() {
var grants []types.FeeAllowanceGrant
err := k.IterateAllGranteeFeeAllowances(ctx, tc.grantee, func(grant types.FeeAllowanceGrant) bool {
grants = append(grants, grant)
return false
})
suite.NoError(err)
suite.Equal(tc.grants, grants)
})
}
}
func (suite *KeeperTestSuite) TestUseGrantedFee() {
ctx := suite.ctx
k := suite.app.FeeGrantKeeper
// some helpers
atom := sdk.NewCoins(sdk.NewInt64Coin("atom", 555))
eth := sdk.NewCoins(sdk.NewInt64Coin("eth", 123))
future := &types.BasicFeeAllowance{
SpendLimit: atom,
Expiration: types.ExpiresAtHeight(5678),
}
expired := &types.BasicFeeAllowance{
SpendLimit: eth,
Expiration: types.ExpiresAtHeight(55),
}
// for testing limits of the contract
hugeAtom := sdk.NewCoins(sdk.NewInt64Coin("atom", 9999))
_ = hugeAtom
smallAtom := sdk.NewCoins(sdk.NewInt64Coin("atom", 1))
_ = smallAtom
futureAfterSmall := &types.BasicFeeAllowance{
SpendLimit: sdk.NewCoins(sdk.NewInt64Coin("atom", 554)),
Expiration: types.ExpiresAtHeight(5678),
}
// then lots of queries
cases := map[string]struct {
grantee sdk.AccAddress
granter sdk.AccAddress
fee sdk.Coins
allowed bool
final types.FeeAllowanceI
}{
"use entire pot": {
granter: suite.addrs[0],
grantee: suite.addrs[1],
fee: atom,
allowed: true,
final: nil,
},
"expired and removed": {
granter: suite.addrs[0],
grantee: suite.addrs[2],
fee: eth,
allowed: false,
final: nil,
},
"too high": {
granter: suite.addrs[0],
grantee: suite.addrs[1],
fee: hugeAtom,
allowed: false,
final: future,
},
"use a little": {
granter: suite.addrs[0],
grantee: suite.addrs[1],
fee: smallAtom,
allowed: true,
final: futureAfterSmall,
},
}
for name, tc := range cases {
tc := tc
suite.Run(name, func() {
// let's set up some initial state here
// addr -> addr2 (future)
// addr -> addr3 (expired)
err := k.GrantFeeAllowance(ctx, suite.addrs[0], suite.addrs[1], future)
suite.Require().NoError(err)
err = k.GrantFeeAllowance(ctx, suite.addrs[0], suite.addrs[3], expired)
suite.Require().NoError(err)
err = k.UseGrantedFees(ctx, tc.granter, tc.grantee, tc.fee)
if tc.allowed {
suite.NoError(err)
} else {
suite.Error(err)
}
loaded := k.GetFeeAllowance(ctx, tc.granter, tc.grantee)
suite.Equal(tc.final, loaded)
})
}
}