Browse Source

collision merge of light-client code

pull/418/head
Ethan Frey 7 years ago
parent
commit
d971416d12
7 changed files with 577 additions and 149 deletions
  1. +178
    -0
      rpc/client/client.go
  2. +19
    -20
      rpc/test/client_test.go
  3. +1
    -1
      rpc/test/grpc_test.go
  4. +59
    -128
      rpc/test/helpers.go
  5. +157
    -0
      rpc/test/helpers_old.go
  6. +33
    -0
      rpc/test/main_test.go
  7. +130
    -0
      rpc/test/rpc_test.go

+ 178
- 0
rpc/client/client.go View File

@ -0,0 +1,178 @@
package rpcclient
import (
"encoding/json"
"github.com/pkg/errors"
"github.com/tendermint/go-rpc/client"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
"github.com/tendermint/tendermint/types"
)
type HTTPClient struct {
remote string
endpoint string
rpc *rpcclient.ClientJSONRPC
ws *rpcclient.WSClient
}
func New(remote, wsEndpoint string) *HTTPClient {
return &HTTPClient{
rpc: rpcclient.NewClientJSONRPC(remote),
remote: remote,
endpoint: wsEndpoint,
}
}
func (c *HTTPClient) Status() (*ctypes.ResultStatus, error) {
tmResult := new(ctypes.TMResult)
_, err := c.rpc.Call("status", []interface{}{}, tmResult)
if err != nil {
return nil, errors.Wrap(err, "Status")
}
// note: panics if rpc doesn't match. okay???
return (*tmResult).(*ctypes.ResultStatus), nil
}
func (c *HTTPClient) ABCIInfo() (*ctypes.ResultABCIInfo, error) {
tmResult := new(ctypes.TMResult)
_, err := c.rpc.Call("abci_info", []interface{}{}, tmResult)
if err != nil {
return nil, errors.Wrap(err, "ABCIInfo")
}
return (*tmResult).(*ctypes.ResultABCIInfo), nil
}
func (c *HTTPClient) ABCIQuery(path string, data []byte, prove bool) (*ctypes.ResultABCIQuery, error) {
tmResult := new(ctypes.TMResult)
_, err := c.rpc.Call("abci_query", []interface{}{path, data, prove}, tmResult)
if err != nil {
return nil, errors.Wrap(err, "ABCIQuery")
}
return (*tmResult).(*ctypes.ResultABCIQuery), nil
}
func (c *HTTPClient) BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
return c.broadcastTX("broadcast_tx_commit", tx)
}
func (c *HTTPClient) BroadcastTxAsync(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
return c.broadcastTX("broadcast_tx_async", tx)
}
func (c *HTTPClient) BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
return c.broadcastTX("broadcast_tx_sync", tx)
}
func (c *HTTPClient) broadcastTX(route string, tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
tmResult := new(ctypes.TMResult)
_, err := c.rpc.Call(route, []interface{}{tx}, tmResult)
if err != nil {
return nil, errors.Wrap(err, route)
}
return (*tmResult).(*ctypes.ResultBroadcastTxCommit), nil
}
func (c *HTTPClient) NetInfo() (*ctypes.ResultNetInfo, error) {
tmResult := new(ctypes.TMResult)
_, err := c.rpc.Call("net_info", nil, tmResult)
if err != nil {
return nil, errors.Wrap(err, "NetInfo")
}
return (*tmResult).(*ctypes.ResultNetInfo), nil
}
func (c *HTTPClient) DialSeeds(seeds []string) (*ctypes.ResultDialSeeds, error) {
tmResult := new(ctypes.TMResult)
// TODO: is this the correct way to marshall seeds?
_, err := c.rpc.Call("dial_seeds", []interface{}{seeds}, tmResult)
if err != nil {
return nil, errors.Wrap(err, "DialSeeds")
}
return (*tmResult).(*ctypes.ResultDialSeeds), nil
}
func (c *HTTPClient) BlockchainInfo(minHeight, maxHeight int) (*ctypes.ResultBlockchainInfo, error) {
tmResult := new(ctypes.TMResult)
_, err := c.rpc.Call("blockchain", []interface{}{minHeight, maxHeight}, tmResult)
if err != nil {
return nil, errors.Wrap(err, "BlockchainInfo")
}
return (*tmResult).(*ctypes.ResultBlockchainInfo), nil
}
func (c *HTTPClient) Genesis() (*ctypes.ResultGenesis, error) {
tmResult := new(ctypes.TMResult)
_, err := c.rpc.Call("genesis", nil, tmResult)
if err != nil {
return nil, errors.Wrap(err, "Genesis")
}
return (*tmResult).(*ctypes.ResultGenesis), nil
}
func (c *HTTPClient) Block(height int) (*ctypes.ResultBlock, error) {
tmResult := new(ctypes.TMResult)
_, err := c.rpc.Call("block", []interface{}{height}, tmResult)
if err != nil {
return nil, errors.Wrap(err, "Block")
}
return (*tmResult).(*ctypes.ResultBlock), nil
}
func (c *HTTPClient) Commit(height int) (*ctypes.ResultCommit, error) {
tmResult := new(ctypes.TMResult)
_, err := c.rpc.Call("commit", []interface{}{height}, tmResult)
if err != nil {
return nil, errors.Wrap(err, "Commit")
}
return (*tmResult).(*ctypes.ResultCommit), nil
}
func (c *HTTPClient) Validators() (*ctypes.ResultValidators, error) {
tmResult := new(ctypes.TMResult)
_, err := c.rpc.Call("validators", nil, tmResult)
if err != nil {
return nil, errors.Wrap(err, "Validators")
}
return (*tmResult).(*ctypes.ResultValidators), nil
}
/** websocket event stuff here... **/
// StartWebsocket starts up a websocket and a listener goroutine
// if already started, do nothing
func (c *HTTPClient) StartWebsocket() error {
var err error
if c.ws == nil {
ws := rpcclient.NewWSClient(c.remote, c.endpoint)
_, err = ws.Start()
if err == nil {
c.ws = ws
}
}
return errors.Wrap(err, "StartWebsocket")
}
// StopWebsocket stops the websocket connection
func (c *HTTPClient) StopWebsocket() {
if c.ws != nil {
c.ws.Stop()
c.ws = nil
}
}
// GetEventChannels returns the results and error channel from the websocket
func (c *HTTPClient) GetEventChannels() (chan json.RawMessage, chan error) {
if c.ws == nil {
return nil, nil
}
return c.ws.ResultsCh, c.ws.ErrorsCh
}
func (c *HTTPClient) Subscribe(event string) error {
return errors.Wrap(c.ws.Subscribe(event), "Subscribe")
}
func (c *HTTPClient) Unsubscribe(event string) error {
return errors.Wrap(c.ws.Unsubscribe(event), "Unsubscribe")
}

+ 19
- 20
rpc/test/client_test.go View File

@ -24,7 +24,7 @@ import (
func TestURIStatus(t *testing.T) {
tmResult := new(ctypes.TMResult)
_, err := clientURI.Call("status", map[string]interface{}{}, tmResult)
_, err := GetURIClient().Call("status", map[string]interface{}{}, tmResult)
if err != nil {
panic(err)
}
@ -33,7 +33,7 @@ func TestURIStatus(t *testing.T) {
func TestJSONStatus(t *testing.T) {
tmResult := new(ctypes.TMResult)
_, err := clientJSON.Call("status", []interface{}{}, tmResult)
_, err := GetJSONClient().Call("status", []interface{}{}, tmResult)
if err != nil {
panic(err)
}
@ -41,6 +41,8 @@ func TestJSONStatus(t *testing.T) {
}
func testStatus(t *testing.T, statusI interface{}) {
chainID := GetConfig().GetString("chain_id")
tmRes := statusI.(*ctypes.TMResult)
status := (*tmRes).(*ctypes.ResultStatus)
if status.NodeInfo.Network != chainID {
@ -68,7 +70,7 @@ func TestURIBroadcastTxSync(t *testing.T) {
defer config.Set("block_size", -1)
tmResult := new(ctypes.TMResult)
tx := randBytes()
_, err := clientURI.Call("broadcast_tx_sync", map[string]interface{}{"tx": tx}, tmResult)
_, err := GetURIClient().Call("broadcast_tx_sync", map[string]interface{}{"tx": tx}, tmResult)
if err != nil {
panic(err)
}
@ -80,7 +82,7 @@ func TestJSONBroadcastTxSync(t *testing.T) {
defer config.Set("block_size", -1)
tmResult := new(ctypes.TMResult)
tx := randBytes()
_, err := clientJSON.Call("broadcast_tx_sync", []interface{}{tx}, tmResult)
_, err := GetJSONClient().Call("broadcast_tx_sync", []interface{}{tx}, tmResult)
if err != nil {
panic(err)
}
@ -118,13 +120,10 @@ func testTxKV() ([]byte, []byte, []byte) {
func sendTx() ([]byte, []byte) {
tmResult := new(ctypes.TMResult)
k, v, tx := testTxKV()
_, err := clientJSON.Call("broadcast_tx_commit", []interface{}{tx}, tmResult)
_, err := GetJSONClient().Call("broadcast_tx_commit", []interface{}{tx}, tmResult)
if err != nil {
panic(err)
}
fmt.Println("SENT TX", tx)
fmt.Printf("SENT TX %X\n", tx)
fmt.Printf("k %X; v %X", k, v)
return k, v
}
@ -132,7 +131,7 @@ func TestURIABCIQuery(t *testing.T) {
k, v := sendTx()
time.Sleep(time.Second)
tmResult := new(ctypes.TMResult)
_, err := clientURI.Call("abci_query", map[string]interface{}{"path": "", "data": k, "prove": false}, tmResult)
_, err := GetURIClient().Call("abci_query", map[string]interface{}{"path": "", "data": k, "prove": false}, tmResult)
if err != nil {
panic(err)
}
@ -142,7 +141,7 @@ func TestURIABCIQuery(t *testing.T) {
func TestJSONABCIQuery(t *testing.T) {
k, v := sendTx()
tmResult := new(ctypes.TMResult)
_, err := clientJSON.Call("abci_query", []interface{}{"", k, false}, tmResult)
_, err := GetJSONClient().Call("abci_query", []interface{}{"", k, false}, tmResult)
if err != nil {
panic(err)
}
@ -168,7 +167,7 @@ func testABCIQuery(t *testing.T, statusI interface{}, value []byte) {
func TestURIBroadcastTxCommit(t *testing.T) {
tmResult := new(ctypes.TMResult)
tx := randBytes()
_, err := clientURI.Call("broadcast_tx_commit", map[string]interface{}{"tx": tx}, tmResult)
_, err := GetURIClient().Call("broadcast_tx_commit", map[string]interface{}{"tx": tx}, tmResult)
if err != nil {
panic(err)
}
@ -178,7 +177,7 @@ func TestURIBroadcastTxCommit(t *testing.T) {
func TestJSONBroadcastTxCommit(t *testing.T) {
tmResult := new(ctypes.TMResult)
tx := randBytes()
_, err := clientJSON.Call("broadcast_tx_commit", []interface{}{tx}, tmResult)
_, err := GetJSONClient().Call("broadcast_tx_commit", []interface{}{tx}, tmResult)
if err != nil {
panic(err)
}
@ -211,13 +210,13 @@ var wsTyp = "JSONRPC"
// make a simple connection to the server
func TestWSConnect(t *testing.T) {
wsc := newWSClient(t)
wsc := GetWSClient()
wsc.Stop()
}
// receive a new block message
func TestWSNewBlock(t *testing.T) {
wsc := newWSClient(t)
wsc := GetWSClient()
eid := types.EventStringNewBlock()
subscribe(t, wsc, eid)
defer func() {
@ -225,7 +224,7 @@ func TestWSNewBlock(t *testing.T) {
wsc.Stop()
}()
waitForEvent(t, wsc, eid, true, func() {}, func(eid string, b interface{}) error {
fmt.Println("Check:", b)
// fmt.Println("Check:", b)
return nil
})
}
@ -235,7 +234,7 @@ func TestWSBlockchainGrowth(t *testing.T) {
if testing.Short() {
t.Skip("skipping test in short mode.")
}
wsc := newWSClient(t)
wsc := GetWSClient()
eid := types.EventStringNewBlock()
subscribe(t, wsc, eid)
defer func() {
@ -263,7 +262,7 @@ func TestWSBlockchainGrowth(t *testing.T) {
}
func TestWSTxEvent(t *testing.T) {
wsc := newWSClient(t)
wsc := GetWSClient()
tx := randBytes()
// listen for the tx I am about to submit
@ -276,7 +275,7 @@ func TestWSTxEvent(t *testing.T) {
// send an tx
tmResult := new(ctypes.TMResult)
_, err := clientJSON.Call("broadcast_tx_sync", []interface{}{tx}, tmResult)
_, err := GetJSONClient().Call("broadcast_tx_sync", []interface{}{tx}, tmResult)
if err != nil {
t.Fatal("Error submitting event")
}
@ -341,7 +340,7 @@ var testCasesUnsafeSetConfig = [][]string{
func TestURIUnsafeSetConfig(t *testing.T) {
for _, testCase := range testCasesUnsafeSetConfig {
tmResult := new(ctypes.TMResult)
_, err := clientURI.Call("unsafe_set_config", map[string]interface{}{
_, err := GetURIClient().Call("unsafe_set_config", map[string]interface{}{
"type": testCase[0],
"key": testCase[1],
"value": testCase[2],
@ -356,7 +355,7 @@ func TestURIUnsafeSetConfig(t *testing.T) {
func TestJSONUnsafeSetConfig(t *testing.T) {
for _, testCase := range testCasesUnsafeSetConfig {
tmResult := new(ctypes.TMResult)
_, err := clientJSON.Call("unsafe_set_config", []interface{}{testCase[0], testCase[1], testCase[2]}, tmResult)
_, err := GetJSONClient().Call("unsafe_set_config", []interface{}{testCase[0], testCase[1], testCase[2]}, tmResult)
if err != nil {
panic(err)
}


+ 1
- 1
rpc/test/grpc_test.go View File

@ -11,7 +11,7 @@ import (
//-------------------------------------------
func TestBroadcastTx(t *testing.T) {
res, err := clientGRPC.BroadcastTx(context.Background(), &core_grpc.RequestBroadcastTx{[]byte("this is a tx")})
res, err := GetGRPCClient().BroadcastTx(context.Background(), &core_grpc.RequestBroadcastTx{[]byte("this is a tx")})
if err != nil {
t.Fatal(err)
}


+ 59
- 128
rpc/test/helpers.go View File

@ -1,160 +1,91 @@
package rpctest
import (
"testing"
"time"
"fmt"
. "github.com/tendermint/go-common"
cfg "github.com/tendermint/go-config"
"github.com/tendermint/go-wire"
logger "github.com/tendermint/go-logger"
abci "github.com/tendermint/abci/types"
cfg "github.com/tendermint/go-config"
client "github.com/tendermint/go-rpc/client"
"github.com/tendermint/tendermint/config/tendermint_test"
nm "github.com/tendermint/tendermint/node"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
"github.com/tendermint/tendermint/rpc/grpc"
"github.com/tendermint/tendermint/proxy"
rpcclient "github.com/tendermint/tendermint/rpc/client"
core_grpc "github.com/tendermint/tendermint/rpc/grpc"
"github.com/tendermint/tendermint/types"
)
// global variables for use across all tests
var (
config cfg.Config
node *nm.Node
chainID string
rpcAddr string
requestAddr string
websocketAddr string
websocketEndpoint string
grpcAddr string
clientURI *client.ClientURI
clientJSON *client.ClientJSONRPC
clientGRPC core_grpc.BroadcastAPIClient
config cfg.Config
node *nm.Node
)
// initialize config and create new node
func init() {
config = tendermint_test.ResetConfig("rpc_test_client_test")
chainID = config.GetString("chain_id")
rpcAddr = config.GetString("rpc_laddr")
grpcAddr = config.GetString("grpc_laddr")
requestAddr = rpcAddr
websocketAddr = rpcAddr
websocketEndpoint = "/websocket"
clientURI = client.NewClientURI(requestAddr)
clientJSON = client.NewClientJSONRPC(requestAddr)
clientGRPC = core_grpc.StartGRPCClient(grpcAddr)
// TODO: change consensus/state.go timeouts to be shorter
const tmLogLevel = "error"
// start a node
ready := make(chan struct{})
go newNode(ready)
<-ready
// GetConfig returns a config for the test cases as a singleton
func GetConfig() cfg.Config {
if config == nil {
config = tendermint_test.ResetConfig("rpc_test_client_test")
// Shut up the logging
logger.SetLogLevel(tmLogLevel)
}
return config
}
// create a new node and sleep forever
func newNode(ready chan struct{}) {
// Create & start node
node = nm.NewNodeDefault(config)
node.Start()
time.Sleep(time.Second)
// GetClient gets a rpc client pointing to the test tendermint rpc
func GetClient() *rpcclient.HTTPClient {
rpcAddr := GetConfig().GetString("rpc_laddr")
return rpcclient.New(rpcAddr, "/websocket")
}
ready <- struct{}{}
// GetURIClient gets a uri client pointing to the test tendermint rpc
func GetURIClient() *client.ClientURI {
rpcAddr := GetConfig().GetString("rpc_laddr")
return client.NewClientURI(rpcAddr)
}
// Sleep forever
ch := make(chan struct{})
<-ch
// GetJSONClient gets a http/json client pointing to the test tendermint rpc
func GetJSONClient() *client.ClientJSONRPC {
rpcAddr := GetConfig().GetString("rpc_laddr")
return client.NewClientJSONRPC(rpcAddr)
}
//--------------------------------------------------------------------------------
// Utilities for testing the websocket service
func GetGRPCClient() core_grpc.BroadcastAPIClient {
grpcAddr := config.GetString("grpc_laddr")
return core_grpc.StartGRPCClient(grpcAddr)
}
// create a new connection
func newWSClient(t *testing.T) *client.WSClient {
wsc := client.NewWSClient(websocketAddr, websocketEndpoint)
func GetWSClient() *client.WSClient {
rpcAddr := GetConfig().GetString("rpc_laddr")
wsc := client.NewWSClient(rpcAddr, "/websocket")
if _, err := wsc.Start(); err != nil {
panic(err)
}
return wsc
}
// subscribe to an event
func subscribe(t *testing.T, wsc *client.WSClient, eventid string) {
if err := wsc.Subscribe(eventid); err != nil {
panic(err)
}
}
// StartTendermint starts a test tendermint server in a go routine and returns when it is initialized
// TODO: can one pass an Application in????
func StartTendermint(app abci.Application) *nm.Node {
// start a node
fmt.Println("Starting Tendermint...")
// unsubscribe from an event
func unsubscribe(t *testing.T, wsc *client.WSClient, eventid string) {
if err := wsc.Unsubscribe(eventid); err != nil {
panic(err)
}
node = NewTendermint(app)
fmt.Println("Tendermint running!")
return node
}
// wait for an event; do things that might trigger events, and check them when they are received
// the check function takes an event id and the byte slice read off the ws
func waitForEvent(t *testing.T, wsc *client.WSClient, eventid string, dieOnTimeout bool, f func(), check func(string, interface{}) error) {
// go routine to wait for webscoket msg
goodCh := make(chan interface{})
errCh := make(chan error)
// Read message
go func() {
var err error
LOOP:
for {
select {
case r := <-wsc.ResultsCh:
result := new(ctypes.TMResult)
wire.ReadJSONPtr(result, r, &err)
if err != nil {
errCh <- err
break LOOP
}
event, ok := (*result).(*ctypes.ResultEvent)
if ok && event.Name == eventid {
goodCh <- event.Data
break LOOP
}
case err := <-wsc.ErrorsCh:
errCh <- err
break LOOP
case <-wsc.Quit:
break LOOP
}
}
}()
// do stuff (transactions)
f()
// wait for an event or timeout
timeout := time.NewTimer(10 * time.Second)
select {
case <-timeout.C:
if dieOnTimeout {
wsc.Stop()
panic(Fmt("%s event was not received in time", eventid))
}
// else that's great, we didn't hear the event
// and we shouldn't have
case eventData := <-goodCh:
if dieOnTimeout {
// message was received and expected
// run the check
if err := check(eventid, eventData); err != nil {
panic(err) // Show the stack trace.
}
} else {
wsc.Stop()
panic(Fmt("%s event was not expected", eventid))
}
case err := <-errCh:
panic(err) // Show the stack trace.
// NewTendermint creates a new tendermint server and sleeps forever
func NewTendermint(app abci.Application) *nm.Node {
// Create & start node
config := GetConfig()
privValidatorFile := config.GetString("priv_validator_file")
privValidator := types.LoadOrGenPrivValidator(privValidatorFile)
papp := proxy.NewLocalClientCreator(app)
node := nm.NewNode(config, privValidator, papp)
}
// node.Start now does everything including the RPC server
node.Start()
return node
}
//--------------------------------------------------------------------------------

+ 157
- 0
rpc/test/helpers_old.go View File

@ -0,0 +1,157 @@
package rpctest
import (
"testing"
"time"
. "github.com/tendermint/go-common"
"github.com/tendermint/go-wire"
client "github.com/tendermint/go-rpc/client"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
)
/*
// global variables for use across all tests
var (
config cfg.Config
node *nm.Node
chainID string
rpcAddr string
requestAddr string
websocketAddr string
websocketEndpoint string
grpcAddr string
clientURI *client.ClientURI
clientJSON *client.ClientJSONRPC
clientGRPC core_grpc.BroadcastAPIClient
)
// initialize config and create new node
func init() {
config = tendermint_test.ResetConfig("rpc_test_client_test")
chainID = config.GetString("chain_id")
rpcAddr = config.GetString("rpc_laddr")
grpcAddr = config.GetString("grpc_laddr")
requestAddr = rpcAddr
websocketAddr = rpcAddr
websocketEndpoint = "/websocket"
clientURI = client.NewClientURI(requestAddr)
clientJSON = client.NewClientJSONRPC(requestAddr)
clientGRPC = core_grpc.StartGRPCClient(grpcAddr)
// TODO: change consensus/state.go timeouts to be shorter
// start a node
ready := make(chan struct{})
go newNode(ready)
<-ready
}
// create a new node and sleep forever
func newNode(ready chan struct{}) {
// Create & start node
node = nm.NewNodeDefault(config)
node.Start()
time.Sleep(time.Second)
ready <- struct{}{}
// Sleep forever
ch := make(chan struct{})
<-ch
}
//--------------------------------------------------------------------------------
// Utilities for testing the websocket service
// create a new connection
func newWSClient(t *testing.T) *client.WSClient {
wsc := client.NewWSClient(websocketAddr, websocketEndpoint)
if _, err := wsc.Start(); err != nil {
panic(err)
}
return wsc
}
*/
// subscribe to an event
func subscribe(t *testing.T, wsc *client.WSClient, eventid string) {
if err := wsc.Subscribe(eventid); err != nil {
panic(err)
}
}
// unsubscribe from an event
func unsubscribe(t *testing.T, wsc *client.WSClient, eventid string) {
if err := wsc.Unsubscribe(eventid); err != nil {
panic(err)
}
}
// wait for an event; do things that might trigger events, and check them when they are received
// the check function takes an event id and the byte slice read off the ws
func waitForEvent(t *testing.T, wsc *client.WSClient, eventid string, dieOnTimeout bool, f func(), check func(string, interface{}) error) {
// go routine to wait for webscoket msg
goodCh := make(chan interface{})
errCh := make(chan error)
// Read message
go func() {
var err error
LOOP:
for {
select {
case r := <-wsc.ResultsCh:
result := new(ctypes.TMResult)
wire.ReadJSONPtr(result, r, &err)
if err != nil {
errCh <- err
break LOOP
}
event, ok := (*result).(*ctypes.ResultEvent)
if ok && event.Name == eventid {
goodCh <- event.Data
break LOOP
}
case err := <-wsc.ErrorsCh:
errCh <- err
break LOOP
case <-wsc.Quit:
break LOOP
}
}
}()
// do stuff (transactions)
f()
// wait for an event or timeout
timeout := time.NewTimer(10 * time.Second)
select {
case <-timeout.C:
if dieOnTimeout {
wsc.Stop()
panic(Fmt("%s event was not received in time", eventid))
}
// else that's great, we didn't hear the event
// and we shouldn't have
case eventData := <-goodCh:
if dieOnTimeout {
// message was received and expected
// run the check
if err := check(eventid, eventData); err != nil {
panic(err) // Show the stack trace.
}
} else {
wsc.Stop()
panic(Fmt("%s event was not expected", eventid))
}
case err := <-errCh:
panic(err) // Show the stack trace.
}
}
//--------------------------------------------------------------------------------

+ 33
- 0
rpc/test/main_test.go View File

@ -0,0 +1,33 @@
/*
package tests contain integration tests and helper functions for testing
the RPC interface
In particular, it allows us to spin up a tendermint node in process, with
a live RPC server, which we can use to verify our rpc calls. It provides
all data structures, enabling us to do more complex tests (like node_test.go)
that introspect the blocks themselves to validate signatures and the like.
It currently only spins up one node, it would be interesting to expand it
to multiple nodes to see the real effects of validating partially signed
blocks.
*/
package rpctest
import (
"os"
"testing"
"github.com/tendermint/abci/example/dummy"
)
func TestMain(m *testing.M) {
// start a tendermint node (and merkleeyes) in the background to test against
app := dummy.NewDummyApplication()
node := StartTendermint(app)
code := m.Run()
// and shut down proper at the end
node.Stop()
node.Wait()
os.Exit(code)
}

+ 130
- 0
rpc/test/rpc_test.go View File

@ -0,0 +1,130 @@
package rpctest
import (
"testing"
"github.com/stretchr/testify/assert"
// "github.com/stretchr/testify/require"
// merkle "github.com/tendermint/go-merkle"
// "github.com/tendermint/tendermint/types"
)
// Make sure status is correct (we connect properly)
func TestStatus(t *testing.T) {
c := GetClient()
status, err := c.Status()
if assert.Nil(t, err) {
assert.Equal(t, GetConfig().GetString("chain_id"), status.NodeInfo.Network)
}
}
/*
// Make some app checks
func TestAppCalls(t *testing.T) {
assert, require := assert.New(t), require.New(t)
c := GetClient()
_, err := c.Block(1)
assert.NotNil(err) // no block yet
k, v, tx := TestTxKV()
_, err = c.BroadcastTxCommit(tx)
require.Nil(err)
// wait before querying
time.Sleep(time.Second * 2)
qres, err := c.ABCIQuery("/key", k, false)
if assert.Nil(err) && assert.True(qres.Response.Code.IsOK()) {
data := qres.Response
// assert.Equal(k, data.GetKey()) // only returned for proofs
assert.Equal(v, data.GetValue())
}
// and we can even check the block is added
block, err := c.Block(3)
assert.Nil(err) // now it's good :)
appHash := block.BlockMeta.Header.AppHash
assert.True(len(appHash) > 0)
// and get the corresponding commit with the same apphash
commit, err := c.Commit(3)
assert.Nil(err) // now it's good :)
cappHash := commit.Header.AppHash
assert.Equal(appHash, cappHash)
assert.NotNil(commit.Commit)
// compare the commits (note Commit(2) has commit from Block(3))
commit2, err := c.Commit(2)
assert.Nil(err) // now it's good :)
assert.Equal(block.Block.LastCommit, commit2.Commit)
// and we got a proof that works!
pres, err := c.ABCIQuery("/key", k, true)
if assert.Nil(err) && assert.True(pres.Response.Code.IsOK()) {
proof, err := merkle.ReadProof(pres.Response.GetProof())
if assert.Nil(err) {
key := pres.Response.GetKey()
value := pres.Response.GetValue()
assert.Equal(appHash, proof.RootHash)
valid := proof.Verify(key, value, appHash)
assert.True(valid)
}
}
}
// run most calls just to make sure no syntax errors
func TestNoErrors(t *testing.T) {
assert := assert.New(t)
c := GetClient()
_, err := c.NetInfo()
assert.Nil(err)
_, err = c.BlockchainInfo(0, 4)
assert.Nil(err)
// TODO: check with a valid height
_, err = c.Block(1000)
assert.NotNil(err)
// maybe this is an error???
// _, err = c.DialSeeds([]string{"one", "two"})
// assert.Nil(err)
gen, err := c.Genesis()
if assert.Nil(err) {
assert.Equal(GetConfig().GetString("chain_id"), gen.Genesis.ChainID)
}
}
func TestSubscriptions(t *testing.T) {
assert, require := assert.New(t), require.New(t)
c := GetClient()
err := c.StartWebsocket()
require.Nil(err)
defer c.StopWebsocket()
// subscribe to a transaction event
_, _, tx := TestTxKV()
// this causes a panic in tendermint core!!!
eventType := types.EventStringTx(types.Tx(tx))
c.Subscribe(eventType)
read := 0
// set up a listener
r, e := c.GetEventChannels()
go func() {
// read one event in the background
select {
case <-r:
// TODO: actually parse this or something
read += 1
case err := <-e:
panic(err)
}
}()
// make sure nothing has happened yet.
assert.Equal(0, read)
// send a tx and wait for it to propogate
_, err = c.BroadcastTxCommit(tx)
assert.Nil(err, string(tx))
// wait before querying
time.Sleep(time.Second)
// now make sure the event arrived
assert.Equal(1, read)
}
*/

Loading…
Cancel
Save