Add more middleware tests
This commit is contained in:
parent
82281aa3bb
commit
b9ce148e8e
|
@ -5,10 +5,12 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/tendermint/tmlibs/log"
|
||||||
|
|
||||||
"github.com/tendermint/basecoin"
|
"github.com/tendermint/basecoin"
|
||||||
"github.com/tendermint/basecoin/txs"
|
"github.com/tendermint/basecoin/txs"
|
||||||
"github.com/tendermint/basecoin/types"
|
"github.com/tendermint/basecoin/types"
|
||||||
"github.com/tendermint/tmlibs/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestChain(t *testing.T) {
|
func TestChain(t *testing.T) {
|
||||||
|
|
|
@ -35,6 +35,7 @@ var _ basecoin.Context = secureContext{}
|
||||||
func (c secureContext) WithPermissions(perms ...basecoin.Actor) basecoin.Context {
|
func (c secureContext) WithPermissions(perms ...basecoin.Actor) basecoin.Context {
|
||||||
// the guard makes sure you only set permissions for the app you are inside
|
// the guard makes sure you only set permissions for the app you are inside
|
||||||
for _, p := range perms {
|
for _, p := range perms {
|
||||||
|
// TODO: also check chainID, limit only certain middleware can set IBC?
|
||||||
if p.App != c.app {
|
if p.App != c.app {
|
||||||
err := errors.Errorf("Cannot set permission for %s from %s", c.app, p.App)
|
err := errors.Errorf("Cannot set permission for %s from %s", c.app, p.App)
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
|
@ -2,6 +2,9 @@ package stack
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
|
"github.com/tendermint/go-wire/data"
|
||||||
|
|
||||||
"github.com/tendermint/basecoin"
|
"github.com/tendermint/basecoin"
|
||||||
"github.com/tendermint/basecoin/types"
|
"github.com/tendermint/basecoin/types"
|
||||||
)
|
)
|
||||||
|
@ -10,6 +13,7 @@ const (
|
||||||
NameOK = "ok"
|
NameOK = "ok"
|
||||||
NameFail = "fail"
|
NameFail = "fail"
|
||||||
NamePanic = "panic"
|
NamePanic = "panic"
|
||||||
|
NameEcho = "echo"
|
||||||
)
|
)
|
||||||
|
|
||||||
// OKHandler just used to return okay to everything
|
// OKHandler just used to return okay to everything
|
||||||
|
@ -33,6 +37,27 @@ func (ok OKHandler) DeliverTx(ctx basecoin.Context, store types.KVStore, tx base
|
||||||
return basecoin.Result{Log: ok.Log}, nil
|
return basecoin.Result{Log: ok.Log}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EchoHandler returns success, echoing res.Data = tx bytes
|
||||||
|
type EchoHandler struct{}
|
||||||
|
|
||||||
|
var _ basecoin.Handler = EchoHandler{}
|
||||||
|
|
||||||
|
func (_ EchoHandler) Name() string {
|
||||||
|
return NameEcho
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckTx always returns an empty success tx
|
||||||
|
func (_ EchoHandler) CheckTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx) (res basecoin.Result, err error) {
|
||||||
|
data, err := data.ToWire(tx)
|
||||||
|
return basecoin.Result{Data: data}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeliverTx always returns an empty success tx
|
||||||
|
func (_ EchoHandler) DeliverTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx) (res basecoin.Result, err error) {
|
||||||
|
data, err := data.ToWire(tx)
|
||||||
|
return basecoin.Result{Data: data}, err
|
||||||
|
}
|
||||||
|
|
||||||
// FailHandler always returns an error
|
// FailHandler always returns an error
|
||||||
type FailHandler struct {
|
type FailHandler struct {
|
||||||
Err error
|
Err error
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
package stack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/tendermint/basecoin"
|
||||||
|
"github.com/tendermint/basecoin/errors"
|
||||||
|
"github.com/tendermint/basecoin/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
NameCheck = "chck"
|
||||||
|
NameGrant = "grnt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CheckMiddleware returns an error if the tx doesn't have auth of this
|
||||||
|
// Required Actor, otherwise passes along the call untouched
|
||||||
|
type CheckMiddleware struct {
|
||||||
|
Required basecoin.Actor
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ Middleware = CheckMiddleware{}
|
||||||
|
|
||||||
|
func (_ CheckMiddleware) Name() string {
|
||||||
|
return NameCheck
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p CheckMiddleware) CheckTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx, next basecoin.Checker) (res basecoin.Result, err error) {
|
||||||
|
if !ctx.HasPermission(p.Required) {
|
||||||
|
return res, errors.Unauthorized()
|
||||||
|
}
|
||||||
|
return next.CheckTx(ctx, store, tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p CheckMiddleware) DeliverTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx, next basecoin.Deliver) (res basecoin.Result, err error) {
|
||||||
|
if !ctx.HasPermission(p.Required) {
|
||||||
|
return res, errors.Unauthorized()
|
||||||
|
}
|
||||||
|
return next.DeliverTx(ctx, store, tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GrantMiddleware tries to set the permission to this Actor, which may be prohibited
|
||||||
|
type GrantMiddleware struct {
|
||||||
|
Auth basecoin.Actor
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ Middleware = GrantMiddleware{}
|
||||||
|
|
||||||
|
func (_ GrantMiddleware) Name() string {
|
||||||
|
return NameGrant
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g GrantMiddleware) CheckTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx, next basecoin.Checker) (res basecoin.Result, err error) {
|
||||||
|
ctx = ctx.WithPermissions(g.Auth)
|
||||||
|
return next.CheckTx(ctx, store, tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g GrantMiddleware) DeliverTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx, next basecoin.Deliver) (res basecoin.Result, err error) {
|
||||||
|
ctx = ctx.WithPermissions(g.Auth)
|
||||||
|
return next.DeliverTx(ctx, store, tx)
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
package stack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/tendermint/basecoin"
|
||||||
|
"github.com/tendermint/basecoin/errors"
|
||||||
|
"github.com/tendermint/basecoin/txs"
|
||||||
|
"github.com/tendermint/basecoin/types"
|
||||||
|
"github.com/tendermint/go-wire/data"
|
||||||
|
"github.com/tendermint/tmlibs/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPermissionSandbox(t *testing.T) {
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
// generic args
|
||||||
|
ctx := NewContext(log.NewNopLogger())
|
||||||
|
store := types.NewMemKVStore()
|
||||||
|
raw := txs.NewRaw([]byte{1, 2, 3, 4}).Wrap()
|
||||||
|
rawBytes, err := data.ToWire(raw)
|
||||||
|
require.Nil(err)
|
||||||
|
|
||||||
|
// test cases to make sure permissioning is solid
|
||||||
|
grantee := basecoin.Actor{App: NameGrant, Address: []byte{1}}
|
||||||
|
grantee2 := basecoin.Actor{App: NameGrant, Address: []byte{2}}
|
||||||
|
signer := basecoin.Actor{App: NameSigs, Address: []byte{1}}
|
||||||
|
cases := []struct {
|
||||||
|
grant basecoin.Actor
|
||||||
|
require basecoin.Actor
|
||||||
|
expectedRes data.Bytes
|
||||||
|
expectedErr error
|
||||||
|
}{
|
||||||
|
{grantee, grantee, rawBytes, nil},
|
||||||
|
{grantee, grantee2, nil, errors.Unauthorized()},
|
||||||
|
{grantee, signer, nil, errors.Unauthorized()},
|
||||||
|
{signer, signer, nil, errors.InternalError("panic")},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tc := range cases {
|
||||||
|
app := New(
|
||||||
|
Recovery{}, // we need this so panics turn to errors
|
||||||
|
GrantMiddleware{tc.grant},
|
||||||
|
CheckMiddleware{tc.require},
|
||||||
|
).Use(EchoHandler{})
|
||||||
|
|
||||||
|
res, err := app.CheckTx(ctx, store, raw)
|
||||||
|
checkPerm(t, i, tc.expectedRes, tc.expectedErr, res, err)
|
||||||
|
|
||||||
|
res, err = app.DeliverTx(ctx, store, raw)
|
||||||
|
checkPerm(t, i, tc.expectedRes, tc.expectedErr, res, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkPerm(t *testing.T, idx int, data []byte, expected error, res basecoin.Result, err error) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
if expected == nil {
|
||||||
|
assert.Nil(err, "%d: %+v", idx, err)
|
||||||
|
assert.EqualValues(data, res.Data)
|
||||||
|
} else {
|
||||||
|
assert.NotNil(err, "%d", idx)
|
||||||
|
// check error code!
|
||||||
|
shouldCode := errors.Wrap(expected).ErrorCode()
|
||||||
|
isCode := errors.Wrap(err).ErrorCode()
|
||||||
|
assert.Equal(shouldCode, isCode, "%d: %+v", idx, err)
|
||||||
|
}
|
||||||
|
}
|
|
@ -48,5 +48,4 @@ func TestRecovery(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue