Browse Source

Merge pull request #11 from tendermint/feature/refactor-tests

WSClient failing to echo bytes
pull/456/head
Ethan Buchman 8 years ago
committed by GitHub
parent
commit
052c2c1575
5 changed files with 141 additions and 150 deletions
  1. +3
    -0
      Makefile
  2. +1
    -0
      README.md
  3. +0
    -1
      client/http_client.go
  4. +24
    -2
      client/ws_client.go
  5. +113
    -147
      rpc_test.go

+ 3
- 0
Makefile View File

@ -11,5 +11,8 @@ test:
get_deps:
@echo "--> Running go get"
@go get -v -d $(PACKAGES)
@go list -f '{{join .TestImports "\n"}}' ./... | \
grep -v /vendor/ | sort | uniq | \
xargs go get -v -d
.PHONY: all test get_deps

+ 1
- 0
README.md View File

@ -125,3 +125,4 @@ IMPROVEMENTS:
- added `HTTPClient` interface, which can be used for both `ClientURI`
and `ClientJSONRPC`
- all params are now optional (Golang's default will be used if some param is missing)
- added `Call` method to `WSClient` (see method's doc for details)

+ 0
- 1
client/http_client.go View File

@ -72,7 +72,6 @@ func (c *JSONRPCClient) Call(method string, params map[string]interface{}, resul
// (handlers.go:176) on the server side
encodedParams := make(map[string]interface{})
for k, v := range params {
// log.Printf("%s: %v (%s)\n", k, v, string(wire.JSONBytes(v)))
bytes := json.RawMessage(wire.JSONBytes(v))
encodedParams[k] = &bytes
}


+ 24
- 2
client/ws_client.go View File

@ -10,6 +10,7 @@ import (
"github.com/pkg/errors"
cmn "github.com/tendermint/go-common"
types "github.com/tendermint/go-rpc/types"
wire "github.com/tendermint/go-wire"
)
const (
@ -120,7 +121,8 @@ func (wsc *WSClient) receiveEventsRoutine() {
close(wsc.ErrorsCh)
}
// subscribe to an event
// Subscribe to an event. Note the server must have a "subscribe" route
// defined.
func (wsc *WSClient) Subscribe(eventid string) error {
err := wsc.WriteJSON(types.RPCRequest{
JSONRPC: "2.0",
@ -131,7 +133,8 @@ func (wsc *WSClient) Subscribe(eventid string) error {
return err
}
// unsubscribe from an event
// Unsubscribe from an event. Note the server must have a "unsubscribe" route
// defined.
func (wsc *WSClient) Unsubscribe(eventid string) error {
err := wsc.WriteJSON(types.RPCRequest{
JSONRPC: "2.0",
@ -141,3 +144,22 @@ func (wsc *WSClient) Unsubscribe(eventid string) error {
})
return err
}
// Call asynchronously calls a given method by sending an RPCRequest to the
// server. Results will be available on ResultsCh, errors, if any, on ErrorsCh.
func (wsc *WSClient) Call(method string, params map[string]interface{}) error {
// we need this step because we attempt to decode values using `go-wire`
// (handlers.go:470) on the server side
encodedParams := make(map[string]interface{})
for k, v := range params {
bytes := json.RawMessage(wire.JSONBytes(v))
encodedParams[k] = &bytes
}
err := wsc.WriteJSON(types.RPCRequest{
JSONRPC: "2.0",
Method: method,
Params: encodedParams,
ID: "",
})
return err
}

+ 113
- 147
rpc_test.go View File

@ -3,12 +3,15 @@ package rpc
import (
"bytes"
crand "crypto/rand"
"fmt"
"math/rand"
"net/http"
"os/exec"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
client "github.com/tendermint/go-rpc/client"
server "github.com/tendermint/go-rpc/server"
types "github.com/tendermint/go-rpc/types"
@ -28,38 +31,37 @@ const (
// Define a type for results and register concrete versions
type Result interface{}
type ResultStatus struct {
type ResultEcho struct {
Value string
}
type ResultBytes struct {
type ResultEchoBytes struct {
Value []byte
}
var _ = wire.RegisterInterface(
struct{ Result }{},
wire.ConcreteType{&ResultStatus{}, 0x1},
wire.ConcreteType{&ResultBytes{}, 0x2},
wire.ConcreteType{&ResultEcho{}, 0x1},
wire.ConcreteType{&ResultEchoBytes{}, 0x2},
)
// Define some routes
var Routes = map[string]*server.RPCFunc{
"status": server.NewRPCFunc(StatusResult, "arg"),
"status_ws": server.NewWSRPCFunc(StatusWSResult, "arg"),
"bytes": server.NewRPCFunc(BytesResult, "arg"),
"echo": server.NewRPCFunc(EchoResult, "arg"),
"echo_ws": server.NewWSRPCFunc(EchoWSResult, "arg"),
"echo_bytes": server.NewRPCFunc(EchoBytesResult, "arg"),
}
// an rpc function
func StatusResult(v string) (Result, error) {
return &ResultStatus{v}, nil
func EchoResult(v string) (Result, error) {
return &ResultEcho{v}, nil
}
func StatusWSResult(wsCtx types.WSRPCContext, v string) (Result, error) {
return &ResultStatus{v}, nil
func EchoWSResult(wsCtx types.WSRPCContext, v string) (Result, error) {
return &ResultEcho{v}, nil
}
func BytesResult(v []byte) (Result, error) {
return &ResultBytes{v}, nil
func EchoBytesResult(v []byte) (Result, error) {
return &ResultEchoBytes{v}, nil
}
// launch unix and tcp servers
@ -69,7 +71,9 @@ func init() {
if err != nil {
panic(err)
}
err = cmd.Wait()
if err = cmd.Wait(); err != nil {
panic(err)
}
mux := http.NewServeMux()
server.RegisterRPCFuncs(mux, Routes)
@ -95,54 +99,49 @@ func init() {
// wait for servers to start
time.Sleep(time.Second * 2)
}
func testURI(t *testing.T, cl *client.URIClient) {
val := "acbd"
func echoViaHTTP(cl client.HTTPClient, val string) (string, error) {
params := map[string]interface{}{
"arg": val,
}
var result Result
_, err := cl.Call("status", params, &result)
if err != nil {
t.Fatal(err)
}
got := result.(*ResultStatus).Value
if got != val {
t.Fatalf("Got: %v .... Expected: %v \n", got, val)
if _, err := cl.Call("echo", params, &result); err != nil {
return "", err
}
return result.(*ResultEcho).Value, nil
}
func testJSONRPC(t *testing.T, cl *client.JSONRPCClient) {
val := "acbd"
func echoBytesViaHTTP(cl client.HTTPClient, bytes []byte) ([]byte, error) {
params := map[string]interface{}{
"arg": val,
"arg": bytes,
}
var result Result
_, err := cl.Call("status", params, &result)
if err != nil {
t.Fatal(err)
}
got := result.(*ResultStatus).Value
if got != val {
t.Fatalf("Got: %v .... Expected: %v \n", got, val)
if _, err := cl.Call("echo_bytes", params, &result); err != nil {
return []byte{}, err
}
return result.(*ResultEchoBytes).Value, nil
}
func testWS(t *testing.T, cl *client.WSClient) {
func testWithHTTPClient(t *testing.T, cl client.HTTPClient) {
val := "acbd"
got, err := echoViaHTTP(cl, val)
require.Nil(t, err)
assert.Equal(t, got, val)
val2 := randBytes(t)
got2, err := echoBytesViaHTTP(cl, val2)
require.Nil(t, err)
assert.Equal(t, got2, val2)
}
func echoViaWS(cl *client.WSClient, val string) (string, error) {
params := map[string]interface{}{
"arg": val,
}
err := cl.WriteJSON(types.RPCRequest{
JSONRPC: "2.0",
ID: "",
Method: "status",
Params: params,
})
err := cl.Call("echo", params)
if err != nil {
t.Fatal(err)
return "", err
}
select {
@ -150,127 +149,92 @@ func testWS(t *testing.T, cl *client.WSClient) {
result := new(Result)
wire.ReadJSONPtr(result, msg, &err)
if err != nil {
t.Fatal(err)
}
got := (*result).(*ResultStatus).Value
if got != val {
t.Fatalf("Got: %v .... Expected: %v \n", got, val)
return "", nil
}
return (*result).(*ResultEcho).Value, nil
case err := <-cl.ErrorsCh:
t.Fatal(err)
return "", err
}
}
//-------------
func TestURI_TCP(t *testing.T) {
cl := client.NewURIClient(tcpAddr)
testURI(t, cl)
}
func TestURI_UNIX(t *testing.T) {
cl := client.NewURIClient(unixAddr)
testURI(t, cl)
}
func echoBytesViaWS(cl *client.WSClient, bytes []byte) ([]byte, error) {
params := map[string]interface{}{
"arg": bytes,
}
err := cl.Call("echo_bytes", params)
if err != nil {
return []byte{}, err
}
func TestJSONRPC_TCP(t *testing.T) {
cl := client.NewJSONRPCClient(tcpAddr)
testJSONRPC(t, cl)
select {
case msg := <-cl.ResultsCh:
result := new(Result)
wire.ReadJSONPtr(result, msg, &err)
if err != nil {
return []byte{}, nil
}
return (*result).(*ResultEchoBytes).Value, nil
case err := <-cl.ErrorsCh:
return []byte{}, err
}
}
func TestJSONRPC_UNIX(t *testing.T) {
cl := client.NewJSONRPCClient(unixAddr)
testJSONRPC(t, cl)
func testWithWSClient(t *testing.T, cl *client.WSClient) {
val := "acbd"
got, err := echoViaWS(cl, val)
require.Nil(t, err)
assert.Equal(t, got, val)
val2 := randBytes(t)
got2, err := echoBytesViaWS(cl, val2)
require.Nil(t, err)
assert.Equal(t, got2, val2)
}
func TestWS_TCP(t *testing.T) {
cl := client.NewWSClient(tcpAddr, websocketEndpoint)
_, err := cl.Start()
if err != nil {
t.Fatal(err)
}
testWS(t, cl)
}
//-------------
func TestWS_UNIX(t *testing.T) {
cl := client.NewWSClient(unixAddr, websocketEndpoint)
_, err := cl.Start()
if err != nil {
t.Fatal(err)
func TestServersAndClientsBasic(t *testing.T) {
serverAddrs := [...]string{tcpAddr, unixAddr}
for _, addr := range serverAddrs {
cl1 := client.NewURIClient(addr)
fmt.Printf("=== testing server on %s using %v client", addr, cl1)
testWithHTTPClient(t, cl1)
cl2 := client.NewJSONRPCClient(tcpAddr)
fmt.Printf("=== testing server on %s using %v client", addr, cl2)
testWithHTTPClient(t, cl2)
cl3 := client.NewWSClient(tcpAddr, websocketEndpoint)
_, err := cl3.Start()
require.Nil(t, err)
fmt.Printf("=== testing server on %s using %v client", addr, cl3)
testWithWSClient(t, cl3)
cl3.Stop()
}
testWS(t, cl)
}
func TestHexStringArg(t *testing.T) {
cl := client.NewURIClient(tcpAddr)
// should NOT be handled as hex
val := "0xabc"
params := map[string]interface{}{
"arg": val,
}
var result Result
_, err := cl.Call("status", params, &result)
if err != nil {
t.Fatal(err)
}
got := result.(*ResultStatus).Value
if got != val {
t.Fatalf("Got: %v .... Expected: %v \n", got, val)
}
got, err := echoViaHTTP(cl, val)
require.Nil(t, err)
assert.Equal(t, got, val)
}
func TestQuotedStringArg(t *testing.T) {
cl := client.NewURIClient(tcpAddr)
// should NOT be unquoted
val := "\"abc\""
params := map[string]interface{}{
"arg": val,
}
var result Result
_, err := cl.Call("status", params, &result)
if err != nil {
t.Fatal(err)
}
got := result.(*ResultStatus).Value
if got != val {
t.Fatalf("Got: %v .... Expected: %v \n", got, val)
}
}
func randBytes(t *testing.T) []byte {
n := rand.Intn(10) + 2
buf := make([]byte, n)
_, err := crand.Read(buf)
if err != nil {
t.Fatal(err)
}
return bytes.Replace(buf, []byte("="), []byte{100}, -1)
}
func TestByteSliceViaJSONRPC(t *testing.T) {
cl := client.NewJSONRPCClient(unixAddr)
val := randBytes(t)
params := map[string]interface{}{
"arg": val,
}
var result Result
_, err := cl.Call("bytes", params, &result)
if err != nil {
t.Fatal(err)
}
got := result.(*ResultBytes).Value
if bytes.Compare(got, val) != 0 {
t.Fatalf("Got: %v .... Expected: %v \n", got, val)
}
got, err := echoViaHTTP(cl, val)
require.Nil(t, err)
assert.Equal(t, got, val)
}
func TestWSNewWSRPCFunc(t *testing.T) {
cl := client.NewWSClient(unixAddr, websocketEndpoint)
cl := client.NewWSClient(tcpAddr, websocketEndpoint)
_, err := cl.Start()
if err != nil {
t.Fatal(err)
}
require.Nil(t, err)
defer cl.Stop()
val := "acbd"
@ -280,25 +244,27 @@ func TestWSNewWSRPCFunc(t *testing.T) {
err = cl.WriteJSON(types.RPCRequest{
JSONRPC: "2.0",
ID: "",
Method: "status_ws",
Method: "echo_ws",
Params: params,
})
if err != nil {
t.Fatal(err)
}
require.Nil(t, err)
select {
case msg := <-cl.ResultsCh:
result := new(Result)
wire.ReadJSONPtr(result, msg, &err)
if err != nil {
t.Fatal(err)
}
got := (*result).(*ResultStatus).Value
if got != val {
t.Fatalf("Got: %v .... Expected: %v \n", got, val)
}
require.Nil(t, err)
got := (*result).(*ResultEcho).Value
assert.Equal(t, got, val)
case err := <-cl.ErrorsCh:
t.Fatal(err)
}
}
func randBytes(t *testing.T) []byte {
n := rand.Intn(10) + 2
buf := make([]byte, n)
_, err := crand.Read(buf)
require.Nil(t, err)
return bytes.Replace(buf, []byte("="), []byte{100}, -1)
}

Loading…
Cancel
Save