|
@ -3,12 +3,15 @@ package rpc |
|
|
import ( |
|
|
import ( |
|
|
"bytes" |
|
|
"bytes" |
|
|
crand "crypto/rand" |
|
|
crand "crypto/rand" |
|
|
|
|
|
"fmt" |
|
|
"math/rand" |
|
|
"math/rand" |
|
|
"net/http" |
|
|
"net/http" |
|
|
"os/exec" |
|
|
"os/exec" |
|
|
"testing" |
|
|
"testing" |
|
|
"time" |
|
|
"time" |
|
|
|
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert" |
|
|
|
|
|
"github.com/stretchr/testify/require" |
|
|
client "github.com/tendermint/go-rpc/client" |
|
|
client "github.com/tendermint/go-rpc/client" |
|
|
server "github.com/tendermint/go-rpc/server" |
|
|
server "github.com/tendermint/go-rpc/server" |
|
|
types "github.com/tendermint/go-rpc/types" |
|
|
types "github.com/tendermint/go-rpc/types" |
|
@ -28,38 +31,37 @@ const ( |
|
|
// Define a type for results and register concrete versions
|
|
|
// Define a type for results and register concrete versions
|
|
|
type Result interface{} |
|
|
type Result interface{} |
|
|
|
|
|
|
|
|
type ResultStatus struct { |
|
|
|
|
|
|
|
|
type ResultEcho struct { |
|
|
Value string |
|
|
Value string |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
type ResultBytes struct { |
|
|
|
|
|
|
|
|
type ResultEchoBytes struct { |
|
|
Value []byte |
|
|
Value []byte |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
var _ = wire.RegisterInterface( |
|
|
var _ = wire.RegisterInterface( |
|
|
struct{ Result }{}, |
|
|
struct{ Result }{}, |
|
|
wire.ConcreteType{&ResultStatus{}, 0x1}, |
|
|
|
|
|
wire.ConcreteType{&ResultBytes{}, 0x2}, |
|
|
|
|
|
|
|
|
wire.ConcreteType{&ResultEcho{}, 0x1}, |
|
|
|
|
|
wire.ConcreteType{&ResultEchoBytes{}, 0x2}, |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
// Define some routes
|
|
|
// Define some routes
|
|
|
var Routes = map[string]*server.RPCFunc{ |
|
|
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
|
|
|
// launch unix and tcp servers
|
|
@ -69,7 +71,9 @@ func init() { |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
panic(err) |
|
|
panic(err) |
|
|
} |
|
|
} |
|
|
err = cmd.Wait() |
|
|
|
|
|
|
|
|
if err = cmd.Wait(); err != nil { |
|
|
|
|
|
panic(err) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
mux := http.NewServeMux() |
|
|
mux := http.NewServeMux() |
|
|
server.RegisterRPCFuncs(mux, Routes) |
|
|
server.RegisterRPCFuncs(mux, Routes) |
|
@ -95,54 +99,49 @@ func init() { |
|
|
|
|
|
|
|
|
// wait for servers to start
|
|
|
// wait for servers to start
|
|
|
time.Sleep(time.Second * 2) |
|
|
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{}{ |
|
|
params := map[string]interface{}{ |
|
|
"arg": val, |
|
|
"arg": val, |
|
|
} |
|
|
} |
|
|
var result Result |
|
|
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{}{ |
|
|
params := map[string]interface{}{ |
|
|
"arg": val, |
|
|
|
|
|
|
|
|
"arg": bytes, |
|
|
} |
|
|
} |
|
|
var result Result |
|
|
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" |
|
|
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{}{ |
|
|
params := map[string]interface{}{ |
|
|
"arg": val, |
|
|
"arg": val, |
|
|
} |
|
|
} |
|
|
err := cl.WriteJSON(types.RPCRequest{ |
|
|
|
|
|
JSONRPC: "2.0", |
|
|
|
|
|
ID: "", |
|
|
|
|
|
Method: "status", |
|
|
|
|
|
Params: params, |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
err := cl.Call("echo", params) |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
t.Fatal(err) |
|
|
|
|
|
|
|
|
return "", err |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
select { |
|
|
select { |
|
@ -150,127 +149,92 @@ func testWS(t *testing.T, cl *client.WSClient) { |
|
|
result := new(Result) |
|
|
result := new(Result) |
|
|
wire.ReadJSONPtr(result, msg, &err) |
|
|
wire.ReadJSONPtr(result, msg, &err) |
|
|
if err != nil { |
|
|
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: |
|
|
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) { |
|
|
func TestHexStringArg(t *testing.T) { |
|
|
cl := client.NewURIClient(tcpAddr) |
|
|
cl := client.NewURIClient(tcpAddr) |
|
|
// should NOT be handled as hex
|
|
|
// should NOT be handled as hex
|
|
|
val := "0xabc" |
|
|
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) { |
|
|
func TestQuotedStringArg(t *testing.T) { |
|
|
cl := client.NewURIClient(tcpAddr) |
|
|
cl := client.NewURIClient(tcpAddr) |
|
|
// should NOT be unquoted
|
|
|
// should NOT be unquoted
|
|
|
val := "\"abc\"" |
|
|
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) { |
|
|
func TestWSNewWSRPCFunc(t *testing.T) { |
|
|
cl := client.NewWSClient(unixAddr, websocketEndpoint) |
|
|
|
|
|
|
|
|
cl := client.NewWSClient(tcpAddr, websocketEndpoint) |
|
|
_, err := cl.Start() |
|
|
_, err := cl.Start() |
|
|
if err != nil { |
|
|
|
|
|
t.Fatal(err) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
require.Nil(t, err) |
|
|
defer cl.Stop() |
|
|
defer cl.Stop() |
|
|
|
|
|
|
|
|
val := "acbd" |
|
|
val := "acbd" |
|
@ -280,25 +244,27 @@ func TestWSNewWSRPCFunc(t *testing.T) { |
|
|
err = cl.WriteJSON(types.RPCRequest{ |
|
|
err = cl.WriteJSON(types.RPCRequest{ |
|
|
JSONRPC: "2.0", |
|
|
JSONRPC: "2.0", |
|
|
ID: "", |
|
|
ID: "", |
|
|
Method: "status_ws", |
|
|
|
|
|
|
|
|
Method: "echo_ws", |
|
|
Params: params, |
|
|
Params: params, |
|
|
}) |
|
|
}) |
|
|
if err != nil { |
|
|
|
|
|
t.Fatal(err) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
require.Nil(t, err) |
|
|
|
|
|
|
|
|
select { |
|
|
select { |
|
|
case msg := <-cl.ResultsCh: |
|
|
case msg := <-cl.ResultsCh: |
|
|
result := new(Result) |
|
|
result := new(Result) |
|
|
wire.ReadJSONPtr(result, msg, &err) |
|
|
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: |
|
|
case err := <-cl.ErrorsCh: |
|
|
t.Fatal(err) |
|
|
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) |
|
|
|
|
|
} |