package rpctest
|
|
|
|
import (
|
|
"fmt"
|
|
"math/rand"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
logger "github.com/tendermint/go-logger"
|
|
wire "github.com/tendermint/go-wire"
|
|
|
|
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"
|
|
"github.com/tendermint/tendermint/proxy"
|
|
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
|
core_grpc "github.com/tendermint/tendermint/rpc/grpc"
|
|
"github.com/tendermint/tendermint/types"
|
|
)
|
|
|
|
var (
|
|
config cfg.Config
|
|
)
|
|
|
|
const tmLogLevel = "error"
|
|
|
|
// 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)
|
|
}
|
|
|
|
// 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)
|
|
// 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)
|
|
}
|
|
return config
|
|
}
|
|
|
|
// GetURIClient gets a uri client pointing to the test tendermint rpc
|
|
func GetURIClient() *client.ClientURI {
|
|
rpcAddr := GetConfig().GetString("rpc_laddr")
|
|
return client.NewClientURI(rpcAddr)
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// StartTendermint starts a test tendermint server in a go routine and returns when it is initialized
|
|
func StartTendermint(app abci.Application) *nm.Node {
|
|
node := NewTendermint(app)
|
|
node.Start()
|
|
fmt.Println("Tendermint running!")
|
|
return node
|
|
}
|
|
|
|
// 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)
|
|
return node
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------
|
|
// 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.
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------
|