mirror of
https://github.com/tendermint/tendermint.git
synced 2026-08-31 21:27:04 +00:00
collision merge of light-client code
This commit is contained in:
@@ -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
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
+63
-132
@@ -1,160 +1,91 @@
|
||||
package rpctest
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
"fmt"
|
||||
|
||||
. "github.com/tendermint/go-common"
|
||||
logger "github.com/tendermint/go-logger"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
cfg "github.com/tendermint/go-config"
|
||||
"github.com/tendermint/go-wire"
|
||||
|
||||
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"
|
||||
const tmLogLevel = "error"
|
||||
|
||||
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
|
||||
// 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)
|
||||
|
||||
ready <- struct{}{}
|
||||
|
||||
// Sleep forever
|
||||
ch := make(chan struct{})
|
||||
<-ch
|
||||
// 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")
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// Utilities for testing the websocket service
|
||||
// GetURIClient gets a uri client pointing to the test tendermint rpc
|
||||
func GetURIClient() *client.ClientURI {
|
||||
rpcAddr := GetConfig().GetString("rpc_laddr")
|
||||
return client.NewClientURI(rpcAddr)
|
||||
}
|
||||
|
||||
// create a new connection
|
||||
func newWSClient(t *testing.T) *client.WSClient {
|
||||
wsc := client.NewWSClient(websocketAddr, websocketEndpoint)
|
||||
// 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)
|
||||
}
|
||||
|
||||
func GetGRPCClient() core_grpc.BroadcastAPIClient {
|
||||
grpcAddr := config.GetString("grpc_laddr")
|
||||
return core_grpc.StartGRPCClient(grpcAddr)
|
||||
}
|
||||
|
||||
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...")
|
||||
|
||||
node = NewTendermint(app)
|
||||
fmt.Println("Tendermint running!")
|
||||
return node
|
||||
}
|
||||
|
||||
// unsubscribe from an event
|
||||
func unsubscribe(t *testing.T, wsc *client.WSClient, eventid string) {
|
||||
if err := wsc.Unsubscribe(eventid); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
@@ -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.
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
*/
|
||||
Reference in New Issue
Block a user