diff --git a/rpc/client/event_test.go b/rpc/client/event_test.go new file mode 100644 index 000000000..912949e0d --- /dev/null +++ b/rpc/client/event_test.go @@ -0,0 +1,58 @@ +package client_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + events "github.com/tendermint/go-events" + "github.com/tendermint/tendermint/types" +) + +func TestEvents(t *testing.T) { + require := require.New(t) + for i, c := range GetClients() { + // test if this client implements event switch as well. + evsw, ok := c.(types.EventSwitch) + // TODO: assert this for all clients when it is suported + // if !assert.True(ok, "%d: %v", i, c) { + // continue + // } + if !ok { + continue + } + + // start for this test it if it wasn't already running + if !evsw.IsRunning() { + // if so, then we start it, listen, and stop it. + st, err := evsw.Start() + require.Nil(err, "%d: %+v", i, err) + require.True(st, "%d", i) + // defer evsw.Stop() + } + + // let's wait for the next header... + listener := "fooz" + event, timeout := make(chan events.EventData, 1), make(chan bool, 1) + // start timeout count-down + go func() { + time.Sleep(1 * time.Second) + timeout <- true + }() + + // register for the next header event + evsw.AddListenerForEvent(listener, types.EventStringNewBlockHeader(), func(data events.EventData) { + event <- data + }) + // make sure to unregister after the test is over + defer evsw.RemoveListener(listener) + + select { + case <-timeout: + require.True(false, "%d: a timeout waiting for event", i) + case evt := <-event: + _, ok := evt.(types.EventDataNewBlockHeader) + require.True(ok, "%d: %#v", i, evt) + } + } +} diff --git a/rpc/client/interface.go b/rpc/client/interface.go index 5dffe30bc..50f065114 100644 --- a/rpc/client/interface.go +++ b/rpc/client/interface.go @@ -46,16 +46,6 @@ type SignClient interface { Validators() (*ctypes.ResultValidators, error) } -// NetworkClient is general info about the network state. May not -// be needed usually. -// -// Not included in the Client interface, but generally implemented -// by concrete implementations. -type NetworkClient interface { - NetInfo() (*ctypes.ResultNetInfo, error) - DumpConsensusState() (*ctypes.ResultDumpConsensusState, error) -} - // HistoryClient shows us data from genesis to now in large chunks. type HistoryClient interface { Genesis() (*ctypes.ResultGenesis, error) @@ -67,12 +57,22 @@ type StatusClient interface { Status() (*ctypes.ResultStatus, error) } +// Client wraps most important rpc calls a client would make +// if you want to listen for events, test if it also +// implements events.EventSwitch type Client interface { ABCIClient SignClient HistoryClient StatusClient - // Note: doesn't include NetworkClient, is it important?? +} - // TODO: add some sort of generic subscription mechanism... +// NetworkClient is general info about the network state. May not +// be needed usually. +// +// Not included in the Client interface, but generally implemented +// by concrete implementations. +type NetworkClient interface { + NetInfo() (*ctypes.ResultNetInfo, error) + DumpConsensusState() (*ctypes.ResultDumpConsensusState, error) } diff --git a/rpc/client/localclient.go b/rpc/client/localclient.go index fc533f15f..0a83db05d 100644 --- a/rpc/client/localclient.go +++ b/rpc/client/localclient.go @@ -23,6 +23,7 @@ powerful control during testing, you probably want the "client/mock" package. */ type Local struct { node *nm.Node + types.EventSwitch } // NewLocal configures a client that calls the Node directly. @@ -34,7 +35,8 @@ type Local struct { func NewLocal(node *nm.Node) Local { node.ConfigureRPC() return Local{ - node: node, + node: node, + EventSwitch: node.EventSwitch(), } }