cosmos-sdk/modules/roles/middleware_test.go

110 lines
3.5 KiB
Go

package roles_test
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tendermint/go-wire/data"
"github.com/tendermint/basecoin"
"github.com/tendermint/basecoin/modules/roles"
"github.com/tendermint/basecoin/stack"
"github.com/tendermint/basecoin/state"
)
// shortcut for the lazy
type ba []basecoin.Actor
func createRole(app basecoin.Handler, store state.SimpleDB,
name []byte, min uint32, sigs ...basecoin.Actor) (basecoin.Actor, error) {
tx := roles.NewCreateRoleTx(name, min, sigs)
ctx := stack.MockContext("foo", 1)
_, err := app.DeliverTx(ctx, store, tx)
return roles.NewPerm(name), err
}
func TestAssumeRole(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
// one handle to add a role, another to check permissions
disp := stack.NewDispatcher(
stack.WrapHandler(roles.NewHandler()),
stack.WrapHandler(stack.CheckHandler{}),
)
// and wrap with the roles middleware
app := stack.New(roles.NewMiddleware()).Use(disp)
// basic state for the app
ctx := stack.MockContext("role-chain", 123)
store := state.NewMemKVStore()
// potential actors
a := basecoin.Actor{App: "sig", Address: []byte("jae")}
b := basecoin.Actor{App: "sig", Address: []byte("bucky")}
c := basecoin.Actor{App: "sig", Address: []byte("ethan")}
d := basecoin.Actor{App: "tracko", Address: []byte("rigel")}
// devs is a 2-of-3 multisig
devs := data.Bytes{0, 1, 0, 1}
pdev, err := createRole(app, store, devs, 2, b, c, d)
require.Nil(err)
// deploy requires a dev role, or supreme authority
// shows how we can build larger constructs, eg. (A and B) OR C
deploy := data.Bytes("deploy")
pdeploy, err := createRole(app, store, deploy, 1, a, pdev)
require.Nil(err)
// now, let's test the roles are set properly
cases := []struct {
valid bool
// which roles we try to assume (can be multiple!)
// note: that wrapping is FILO, so tries to assume last role first
roles []data.Bytes
signers []basecoin.Actor // which people sign the tx
required []basecoin.Actor // which permission we require to succeed
}{
// basic checks to see logic works
{true, nil, nil, nil},
{true, nil, ba{b, c}, ba{b}},
{false, nil, ba{b}, ba{b, c}},
// simple role check
{false, []data.Bytes{devs}, ba{a, b}, ba{pdev}}, // not enough sigs
{false, nil, ba{b, c}, ba{pdev}}, // must explicitly request group status
{true, []data.Bytes{devs}, ba{b, c}, ba{pdev}}, // ahh... better
{true, []data.Bytes{deploy}, ba{a, b}, ba{b, pdeploy}}, // deploy also works
// multiple levels of roles - must be in correct order - assume dev, then deploy
{false, []data.Bytes{devs, deploy}, ba{c, d}, ba{pdeploy}},
{true, []data.Bytes{deploy, devs}, ba{c, d}, ba{pdev, pdeploy}},
}
for i, tc := range cases {
// set the signers, the required check
myCtx := ctx.WithPermissions(tc.signers...)
tx := stack.NewCheckTx(tc.required)
// and the roles we attempt to assume
for _, r := range tc.roles {
tx = roles.NewAssumeRoleTx(r, tx)
}
// try CheckTx and DeliverTx and make sure they both assert permissions
cres, err := app.CheckTx(myCtx, store, tx)
_, err2 := app.DeliverTx(myCtx, store, tx)
if tc.valid {
assert.Nil(err, "%d: %+v", i, err)
assert.Nil(err2, "%d: %+v", i, err2)
// make sure we charge for each role
assert.Equal(roles.CostAssume*uint64(len(tc.roles)), cres.GasAllocated)
assert.Equal(uint64(0), cres.GasPayment)
} else {
assert.NotNil(err, "%d", i)
assert.NotNil(err2, "%d", i)
}
}
}