@ -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") | |||||
} |
@ -1,160 +1,91 @@ | |||||
package rpctest | package rpctest | ||||
import ( | 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" | client "github.com/tendermint/go-rpc/client" | ||||
"github.com/tendermint/tendermint/config/tendermint_test" | "github.com/tendermint/tendermint/config/tendermint_test" | ||||
nm "github.com/tendermint/tendermint/node" | 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 ( | 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 { | if _, err := wsc.Start(); err != nil { | ||||
panic(err) | panic(err) | ||||
} | } | ||||
return wsc | 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 | |||||
} | } | ||||
//-------------------------------------------------------------------------------- |
@ -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) | |||||
} | |||||
*/ |