Add MockStatus, WaitForHeight helper

This commit is contained in:
Ethan Frey 2017-02-22 17:39:53 +01:00
parent 0905332f1d
commit 70f19e809b
5 changed files with 208 additions and 1 deletions

31
rpc/client/helpers.go Normal file
View File

@ -0,0 +1,31 @@
package client
import (
"time"
"github.com/pkg/errors"
)
// Wait for height will poll status at reasonable intervals until
// the block at the given height is available.
func WaitForHeight(c StatusClient, h int) error {
wait := 1
for wait > 0 {
s, err := c.Status()
if err != nil {
return err
}
wait = h - s.LatestBlockHeight
if wait > 10 {
return errors.Errorf("Waiting for %d block... aborting", wait)
} else if wait > 0 {
// estimate of wait time....
// wait half a second for the next block (in progress)
// plus one second for every full block
delay := time.Duration(wait-1)*time.Second + 500*time.Millisecond
time.Sleep(delay)
}
}
// guess we waited long enough
return nil
}

View File

@ -0,0 +1,75 @@
package client_test
import (
"errors"
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/rpc/client"
"github.com/tendermint/tendermint/rpc/client/mock"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
)
func TestWaitForHeight(t *testing.T) {
assert, require := assert.New(t), require.New(t)
// test with error result - immediate failure
m := &mock.StatusMock{
Call: mock.Call{
Error: errors.New("bye"),
},
}
r := mock.NewStatusRecorder(m)
// connection failure always leads to error
err := client.WaitForHeight(r, 8)
require.NotNil(err)
require.Equal("bye", err.Error())
// we called status once to check
require.Equal(1, len(r.Calls))
// now set current block height to 10
m.Call = mock.Call{
Response: &ctypes.ResultStatus{LatestBlockHeight: 10},
}
// we will not wait for more than 10 blocks
err = client.WaitForHeight(r, 40)
require.NotNil(err)
require.True(strings.Contains(err.Error(), "aborting"))
// we called status once more to check
require.Equal(2, len(r.Calls))
// waiting for the past returns immediately
err = client.WaitForHeight(r, 5)
require.Nil(err)
// we called status once more to check
require.Equal(3, len(r.Calls))
// next tick in background while we wait
go func() {
time.Sleep(500 * time.Millisecond)
m.Call.Response = &ctypes.ResultStatus{LatestBlockHeight: 15}
}()
// we wait for a few blocks
err = client.WaitForHeight(r, 12)
require.Nil(err)
// we called status once to check
require.Equal(5, len(r.Calls))
pre := r.Calls[3]
require.Nil(pre.Error)
prer, ok := pre.Response.(*ctypes.ResultStatus)
require.True(ok)
assert.Equal(10, prer.LatestBlockHeight)
post := r.Calls[4]
require.Nil(post.Error)
postr, ok := post.Response.(*ctypes.ResultStatus)
require.True(ok)
assert.Equal(15, postr.LatestBlockHeight)
}

View File

@ -1,10 +1,11 @@
package mock_test
import (
"errors"
"fmt"
"testing"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tendermint/abci/example/dummy"

55
rpc/client/mock/status.go Normal file
View File

@ -0,0 +1,55 @@
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

@ -0,0 +1,45 @@
package mock_test
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
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: []byte("block"),
LatestAppHash: []byte("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)
}