tendermint/rpc/test/helpers.go

195 lines
5.0 KiB
Go
Raw Normal View History

2016-01-10 13:33:52 -08:00
package rpctest
import (
2017-02-21 10:36:18 -08:00
"fmt"
"math/rand"
"os"
"path/filepath"
"strings"
"testing"
"time"
2016-01-10 13:33:52 -08:00
"github.com/stretchr/testify/require"
2017-02-21 10:36:18 -08:00
logger "github.com/tendermint/go-logger"
wire "github.com/tendermint/go-wire"
2016-01-10 13:33:52 -08:00
2017-02-21 10:36:18 -08:00
abci "github.com/tendermint/abci/types"
cfg "github.com/tendermint/go-config"
2016-01-12 13:54:27 -08:00
client "github.com/tendermint/go-rpc/client"
2016-05-08 15:00:58 -07:00
"github.com/tendermint/tendermint/config/tendermint_test"
2016-01-10 13:33:52 -08:00
nm "github.com/tendermint/tendermint/node"
2017-02-21 10:36:18 -08:00
"github.com/tendermint/tendermint/proxy"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
2017-02-21 10:36:18 -08:00
core_grpc "github.com/tendermint/tendermint/rpc/grpc"
"github.com/tendermint/tendermint/types"
2016-01-10 13:33:52 -08:00
)
var (
2017-02-21 10:36:18 -08:00
config cfg.Config
node *nm.Node
2016-01-10 13:33:52 -08:00
)
2017-02-21 10:36:18 -08:00
const tmLogLevel = "error"
2016-01-12 13:54:27 -08:00
// f**ing long, but unique for each test
func makePathname() string {
// get path
p, err := os.Getwd()
if err != nil {
panic(err)
}
fmt.Println(p)
sep := string(filepath.Separator)
return strings.Replace(p, sep, "_", -1)
}
func randPort() int {
// returns between base and base + spread
base, spread := 20000, 20000
return base + rand.Intn(spread)
}
func makeAddrs() (string, string, string) {
start := randPort()
return fmt.Sprintf("tcp://0.0.0.0:%d", start),
fmt.Sprintf("tcp://0.0.0.0:%d", start+1),
fmt.Sprintf("tcp://0.0.0.0:%d", start+2)
}
2017-02-21 10:36:18 -08:00
// GetConfig returns a config for the test cases as a singleton
func GetConfig() cfg.Config {
if config == nil {
pathname := makePathname()
config = tendermint_test.ResetConfig(pathname)
2017-02-21 10:36:18 -08:00
// Shut up the logging
logger.SetLogLevel(tmLogLevel)
// and we use random ports to run in parallel
tm, rpc, grpc := makeAddrs()
config.Set("node_laddr", tm)
config.Set("rpc_laddr", rpc)
config.Set("grpc_laddr", grpc)
2017-02-21 10:36:18 -08:00
}
return config
2016-01-12 13:54:27 -08:00
}
2017-02-22 05:41:10 -08:00
func GetNode() *nm.Node {
return node
}
2017-02-21 10:36:18 -08:00
// GetURIClient gets a uri client pointing to the test tendermint rpc
func GetURIClient() *client.ClientURI {
rpcAddr := GetConfig().GetString("rpc_laddr")
return client.NewClientURI(rpcAddr)
}
2016-01-10 13:33:52 -08:00
2017-02-21 10:36:18 -08:00
// 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)
2016-01-10 13:33:52 -08:00
}
2017-02-21 10:36:18 -08:00
func GetGRPCClient() core_grpc.BroadcastAPIClient {
grpcAddr := config.GetString("grpc_laddr")
return core_grpc.StartGRPCClient(grpcAddr)
}
2016-01-10 13:33:52 -08:00
2017-02-21 10:36:18 -08:00
func GetWSClient() *client.WSClient {
rpcAddr := GetConfig().GetString("rpc_laddr")
wsc := client.NewWSClient(rpcAddr, "/websocket")
2016-01-13 18:20:25 -08:00
if _, err := wsc.Start(); err != nil {
panic(err)
2016-01-10 13:33:52 -08:00
}
2016-01-13 18:20:25 -08:00
return wsc
2016-01-10 13:33:52 -08:00
}
2017-02-21 10:36:18 -08:00
// 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...")
2016-01-10 13:33:52 -08:00
2017-02-21 10:36:18 -08:00
node = NewTendermint(app)
fmt.Println("Tendermint running!")
return node
2016-01-10 13:33:52 -08:00
}
2017-02-21 10:36:18 -08:00
// 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)
2016-01-10 13:33:52 -08:00
2017-02-21 10:36:18 -08:00
// node.Start now does everything including the RPC server
node.Start()
return node
2016-01-10 13:33:52 -08:00
}
//--------------------------------------------------------------------------------
// Utilities for testing the websocket service
// 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()
require.True(t, false, "%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
require.Nil(t, check(eventid, eventData))
} else {
wsc.Stop()
require.True(t, false, "%s event was not expected", eventid)
}
case err := <-errCh:
panic(err) // Show the stack trace.
}
}
//--------------------------------------------------------------------------------