premerge2: rpc -> rpc/tendermint

This commit is contained in:
Ethan Buchman
2017-04-21 17:39:51 -04:00
parent 0017fb7ffe
commit 992b11c450
37 changed files with 0 additions and 0 deletions

View File

@ -1,195 +0,0 @@
package mock
import (
abci "github.com/tendermint/abci/types"
data "github.com/tendermint/go-data"
"github.com/tendermint/tendermint/rpc/client"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
"github.com/tendermint/tendermint/types"
)
// ABCIApp will send all abci related request to the named app,
// so you can test app behavior from a client without needing
// an entire tendermint node
type ABCIApp struct {
App abci.Application
}
func (a ABCIApp) _assertABCIClient() client.ABCIClient {
return a
}
func (a ABCIApp) ABCIInfo() (*ctypes.ResultABCIInfo, error) {
return &ctypes.ResultABCIInfo{a.App.Info()}, nil
}
func (a ABCIApp) ABCIQuery(path string, data data.Bytes, prove bool) (*ctypes.ResultABCIQuery, error) {
q := a.App.Query(abci.RequestQuery{data, path, 0, prove})
return &ctypes.ResultABCIQuery{q}, nil
}
func (a ABCIApp) BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
res := ctypes.ResultBroadcastTxCommit{}
c := a.App.CheckTx(tx)
res.CheckTx = &abci.ResponseCheckTx{c.Code, c.Data, c.Log}
if !c.IsOK() {
return &res, nil
}
d := a.App.DeliverTx(tx)
res.DeliverTx = &abci.ResponseDeliverTx{d.Code, d.Data, d.Log}
return &res, nil
}
func (a ABCIApp) BroadcastTxAsync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
c := a.App.CheckTx(tx)
// and this gets writen in a background thread...
if c.IsOK() {
go func() { a.App.DeliverTx(tx) }()
}
return &ctypes.ResultBroadcastTx{c.Code, c.Data, c.Log, tx.Hash()}, nil
}
func (a ABCIApp) BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
c := a.App.CheckTx(tx)
// and this gets writen in a background thread...
if c.IsOK() {
go func() { a.App.DeliverTx(tx) }()
}
return &ctypes.ResultBroadcastTx{c.Code, c.Data, c.Log, tx.Hash()}, nil
}
// ABCIMock will send all abci related request to the named app,
// so you can test app behavior from a client without needing
// an entire tendermint node
type ABCIMock struct {
Info Call
Query Call
BroadcastCommit Call
Broadcast Call
}
func (m ABCIMock) _assertABCIClient() client.ABCIClient {
return m
}
func (m ABCIMock) ABCIInfo() (*ctypes.ResultABCIInfo, error) {
res, err := m.Info.GetResponse(nil)
if err != nil {
return nil, err
}
return &ctypes.ResultABCIInfo{res.(abci.ResponseInfo)}, nil
}
func (m ABCIMock) ABCIQuery(path string, data data.Bytes, prove bool) (*ctypes.ResultABCIQuery, error) {
res, err := m.Query.GetResponse(QueryArgs{path, data, prove})
if err != nil {
return nil, err
}
return &ctypes.ResultABCIQuery{res.(abci.ResponseQuery)}, nil
}
func (m ABCIMock) BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
res, err := m.BroadcastCommit.GetResponse(tx)
if err != nil {
return nil, err
}
return res.(*ctypes.ResultBroadcastTxCommit), nil
}
func (m ABCIMock) BroadcastTxAsync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
res, err := m.Broadcast.GetResponse(tx)
if err != nil {
return nil, err
}
return res.(*ctypes.ResultBroadcastTx), nil
}
func (m ABCIMock) BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
res, err := m.Broadcast.GetResponse(tx)
if err != nil {
return nil, err
}
return res.(*ctypes.ResultBroadcastTx), nil
}
// ABCIRecorder can wrap another type (ABCIApp, ABCIMock, or Client)
// and record all ABCI related calls.
type ABCIRecorder struct {
Client client.ABCIClient
Calls []Call
}
func NewABCIRecorder(client client.ABCIClient) *ABCIRecorder {
return &ABCIRecorder{
Client: client,
Calls: []Call{},
}
}
func (r *ABCIRecorder) _assertABCIClient() client.ABCIClient {
return r
}
type QueryArgs struct {
Path string
Data data.Bytes
Prove bool
}
func (r *ABCIRecorder) addCall(call Call) {
r.Calls = append(r.Calls, call)
}
func (r *ABCIRecorder) ABCIInfo() (*ctypes.ResultABCIInfo, error) {
res, err := r.Client.ABCIInfo()
r.addCall(Call{
Name: "abci_info",
Response: res,
Error: err,
})
return res, err
}
func (r *ABCIRecorder) ABCIQuery(path string, data data.Bytes, prove bool) (*ctypes.ResultABCIQuery, error) {
res, err := r.Client.ABCIQuery(path, data, prove)
r.addCall(Call{
Name: "abci_query",
Args: QueryArgs{path, data, prove},
Response: res,
Error: err,
})
return res, err
}
func (r *ABCIRecorder) BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
res, err := r.Client.BroadcastTxCommit(tx)
r.addCall(Call{
Name: "broadcast_tx_commit",
Args: tx,
Response: res,
Error: err,
})
return res, err
}
func (r *ABCIRecorder) BroadcastTxAsync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
res, err := r.Client.BroadcastTxAsync(tx)
r.addCall(Call{
Name: "broadcast_tx_async",
Args: tx,
Response: res,
Error: err,
})
return res, err
}
func (r *ABCIRecorder) BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
res, err := r.Client.BroadcastTxSync(tx)
r.addCall(Call{
Name: "broadcast_tx_sync",
Args: tx,
Response: res,
Error: err,
})
return res, err
}

View File

@ -1,170 +0,0 @@
package mock_test
import (
"fmt"
"testing"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tendermint/abci/example/dummy"
abci "github.com/tendermint/abci/types"
data "github.com/tendermint/go-data"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
"github.com/tendermint/tendermint/types"
"github.com/tendermint/tendermint/rpc/client/mock"
)
func TestABCIMock(t *testing.T) {
assert, require := assert.New(t), require.New(t)
key, value := []byte("foo"), []byte("bar")
height := uint64(10)
goodTx := types.Tx{0x01, 0xff}
badTx := types.Tx{0x12, 0x21}
m := mock.ABCIMock{
Info: mock.Call{Error: errors.New("foobar")},
Query: mock.Call{Response: abci.ResponseQuery{
Key: key,
Value: value,
Height: height,
}},
// Broadcast commit depends on call
BroadcastCommit: mock.Call{
Args: goodTx,
Response: &ctypes.ResultBroadcastTxCommit{
CheckTx: &abci.ResponseCheckTx{Data: data.Bytes("stand")},
DeliverTx: &abci.ResponseDeliverTx{Data: data.Bytes("deliver")},
},
Error: errors.New("bad tx"),
},
Broadcast: mock.Call{Error: errors.New("must commit")},
}
// now, let's try to make some calls
_, err := m.ABCIInfo()
require.NotNil(err)
assert.Equal("foobar", err.Error())
// query always returns the response
query, err := m.ABCIQuery("/", nil, false)
require.Nil(err)
require.NotNil(query)
assert.Equal(key, query.Response.GetKey())
assert.Equal(value, query.Response.GetValue())
assert.Equal(height, query.Response.GetHeight())
// non-commit calls always return errors
_, err = m.BroadcastTxSync(goodTx)
require.NotNil(err)
assert.Equal("must commit", err.Error())
_, err = m.BroadcastTxAsync(goodTx)
require.NotNil(err)
assert.Equal("must commit", err.Error())
// commit depends on the input
_, err = m.BroadcastTxCommit(badTx)
require.NotNil(err)
assert.Equal("bad tx", err.Error())
bres, err := m.BroadcastTxCommit(goodTx)
require.Nil(err, "%+v", err)
assert.EqualValues(0, bres.CheckTx.Code)
assert.EqualValues("stand", bres.CheckTx.Data)
assert.EqualValues("deliver", bres.DeliverTx.Data)
}
func TestABCIRecorder(t *testing.T) {
assert, require := assert.New(t), require.New(t)
m := mock.ABCIMock{
Info: mock.Call{Response: abci.ResponseInfo{
Data: "data",
Version: "v0.9.9",
}},
Query: mock.Call{Error: errors.New("query")},
Broadcast: mock.Call{Error: errors.New("broadcast")},
BroadcastCommit: mock.Call{Error: errors.New("broadcast_commit")},
}
r := mock.NewABCIRecorder(m)
require.Equal(0, len(r.Calls))
r.ABCIInfo()
r.ABCIQuery("path", data.Bytes("data"), true)
require.Equal(2, len(r.Calls))
info := r.Calls[0]
assert.Equal("abci_info", info.Name)
assert.Nil(info.Error)
assert.Nil(info.Args)
require.NotNil(info.Response)
ir, ok := info.Response.(*ctypes.ResultABCIInfo)
require.True(ok)
assert.Equal("data", ir.Response.Data)
assert.Equal("v0.9.9", ir.Response.Version)
query := r.Calls[1]
assert.Equal("abci_query", query.Name)
assert.Nil(query.Response)
require.NotNil(query.Error)
assert.Equal("query", query.Error.Error())
require.NotNil(query.Args)
qa, ok := query.Args.(mock.QueryArgs)
require.True(ok)
assert.Equal("path", qa.Path)
assert.EqualValues("data", qa.Data)
assert.True(qa.Prove)
// now add some broadcasts
txs := []types.Tx{{1}, {2}, {3}}
r.BroadcastTxCommit(txs[0])
r.BroadcastTxSync(txs[1])
r.BroadcastTxAsync(txs[2])
require.Equal(5, len(r.Calls))
bc := r.Calls[2]
assert.Equal("broadcast_tx_commit", bc.Name)
assert.Nil(bc.Response)
require.NotNil(bc.Error)
assert.EqualValues(bc.Args, txs[0])
bs := r.Calls[3]
assert.Equal("broadcast_tx_sync", bs.Name)
assert.Nil(bs.Response)
require.NotNil(bs.Error)
assert.EqualValues(bs.Args, txs[1])
ba := r.Calls[4]
assert.Equal("broadcast_tx_async", ba.Name)
assert.Nil(ba.Response)
require.NotNil(ba.Error)
assert.EqualValues(ba.Args, txs[2])
}
func TestABCIApp(t *testing.T) {
assert, require := assert.New(t), require.New(t)
app := dummy.NewDummyApplication()
m := mock.ABCIApp{app}
// get some info
info, err := m.ABCIInfo()
require.Nil(err)
assert.Equal(`{"size":0}`, info.Response.GetData())
// add a key
key, value := "foo", "bar"
tx := fmt.Sprintf("%s=%s", key, value)
res, err := m.BroadcastTxCommit(types.Tx(tx))
require.Nil(err)
assert.True(res.CheckTx.Code.IsOK())
require.NotNil(res.DeliverTx)
assert.True(res.DeliverTx.Code.IsOK())
// check the key
qres, err := m.ABCIQuery("/key", data.Bytes(key), false)
require.Nil(err)
assert.EqualValues(value, qres.Response.Value)
}

View File

@ -1,129 +0,0 @@
/*
package mock returns a Client implementation that
accepts various (mock) implementations of the various methods.
This implementation is useful for using in tests, when you don't
need a real server, but want a high-level of control about
the server response you want to mock (eg. error handling),
or if you just want to record the calls to verify in your tests.
For real clients, you probably want the "http" package. If you
want to directly call a tendermint node in process, you can use the
"local" package.
*/
package mock
import (
"reflect"
data "github.com/tendermint/go-data"
"github.com/tendermint/tendermint/rpc/client"
"github.com/tendermint/tendermint/rpc/core"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
"github.com/tendermint/tendermint/types"
)
// Client wraps arbitrary implementations of the various interfaces.
//
// We provide a few choices to mock out each one in this package.
// Nothing hidden here, so no New function, just construct it from
// some parts, and swap them out them during the tests.
type Client struct {
client.ABCIClient
client.SignClient
client.HistoryClient
client.StatusClient
// create a mock with types.NewEventSwitch()
types.EventSwitch
}
func (c Client) _assertIsClient() client.Client {
return c
}
// Call is used by recorders to save a call and response.
// It can also be used to configure mock responses.
//
type Call struct {
Name string
Args interface{}
Response interface{}
Error error
}
// GetResponse will generate the apporiate response for us, when
// using the Call struct to configure a Mock handler.
//
// When configuring a response, if only one of Response or Error is
// set then that will always be returned. If both are set, then
// we return Response if the Args match the set args, Error otherwise.
func (c Call) GetResponse(args interface{}) (interface{}, error) {
// handle the case with no response
if c.Response == nil {
if c.Error == nil {
panic("Misconfigured call, you must set either Response or Error")
}
return nil, c.Error
}
// response without error
if c.Error == nil {
return c.Response, nil
}
// have both, we must check args....
if reflect.DeepEqual(args, c.Args) {
return c.Response, nil
}
return nil, c.Error
}
func (c Client) Status() (*ctypes.ResultStatus, error) {
return core.Status()
}
func (c Client) ABCIInfo() (*ctypes.ResultABCIInfo, error) {
return core.ABCIInfo()
}
func (c Client) ABCIQuery(path string, data data.Bytes, prove bool) (*ctypes.ResultABCIQuery, error) {
return core.ABCIQuery(path, data, prove)
}
func (c Client) BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
return core.BroadcastTxCommit(tx)
}
func (c Client) BroadcastTxAsync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
return core.BroadcastTxAsync(tx)
}
func (c Client) BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
return core.BroadcastTxSync(tx)
}
func (c Client) NetInfo() (*ctypes.ResultNetInfo, error) {
return core.NetInfo()
}
func (c Client) DialSeeds(seeds []string) (*ctypes.ResultDialSeeds, error) {
return core.UnsafeDialSeeds(seeds)
}
func (c Client) BlockchainInfo(minHeight, maxHeight int) (*ctypes.ResultBlockchainInfo, error) {
return core.BlockchainInfo(minHeight, maxHeight)
}
func (c Client) Genesis() (*ctypes.ResultGenesis, error) {
return core.Genesis()
}
func (c Client) Block(height int) (*ctypes.ResultBlock, error) {
return core.Block(height)
}
func (c Client) Commit(height int) (*ctypes.ResultCommit, error) {
return core.Commit(height)
}
func (c Client) Validators() (*ctypes.ResultValidators, error) {
return core.Validators()
}

View File

@ -1,55 +0,0 @@
package mock
import (
"github.com/tendermint/tendermint/rpc/client"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
)
// StatusMock returns the result specified by the Call
type StatusMock struct {
Call
}
func (m *StatusMock) _assertStatusClient() client.StatusClient {
return m
}
func (m *StatusMock) Status() (*ctypes.ResultStatus, error) {
res, err := m.GetResponse(nil)
if err != nil {
return nil, err
}
return res.(*ctypes.ResultStatus), nil
}
// StatusRecorder can wrap another type (StatusMock, full client)
// and record the status calls
type StatusRecorder struct {
Client client.StatusClient
Calls []Call
}
func NewStatusRecorder(client client.StatusClient) *StatusRecorder {
return &StatusRecorder{
Client: client,
Calls: []Call{},
}
}
func (r *StatusRecorder) _assertStatusClient() client.StatusClient {
return r
}
func (r *StatusRecorder) addCall(call Call) {
r.Calls = append(r.Calls, call)
}
func (r *StatusRecorder) Status() (*ctypes.ResultStatus, error) {
res, err := r.Client.Status()
r.addCall(Call{
Name: "status",
Response: res,
Error: err,
})
return res, err
}

View File

@ -1,46 +0,0 @@
package mock_test
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
data "github.com/tendermint/go-data"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
"github.com/tendermint/tendermint/rpc/client/mock"
)
func TestStatus(t *testing.T) {
assert, require := assert.New(t), require.New(t)
m := &mock.StatusMock{
Call: mock.Call{
Response: &ctypes.ResultStatus{
LatestBlockHash: data.Bytes("block"),
LatestAppHash: data.Bytes("app"),
LatestBlockHeight: 10,
}},
}
r := mock.NewStatusRecorder(m)
require.Equal(0, len(r.Calls))
// make sure response works proper
status, err := r.Status()
require.Nil(err, "%+v", err)
assert.EqualValues("block", status.LatestBlockHash)
assert.EqualValues(10, status.LatestBlockHeight)
// make sure recorder works properly
require.Equal(1, len(r.Calls))
rs := r.Calls[0]
assert.Equal("status", rs.Name)
assert.Nil(rs.Args)
assert.Nil(rs.Error)
require.NotNil(rs.Response)
st, ok := rs.Response.(*ctypes.ResultStatus)
require.True(ok)
assert.EqualValues("block", st.LatestBlockHash)
assert.EqualValues(10, st.LatestBlockHeight)
}