lotus/lib/jsonrpc/rpc_test.go
2019-07-18 13:09:13 +02:00

279 lines
5.1 KiB
Go

package jsonrpc
import (
"context"
"errors"
"net/http/httptest"
"strconv"
"strings"
"sync"
"testing"
"time"
)
type SimpleServerHandler struct {
n int
}
type TestType struct {
S string
I int
}
type TestOut struct {
TestType
Ok bool
}
func (h *SimpleServerHandler) Add(in int) error {
if in == -3546 {
return errors.New("test")
}
h.n += in
return nil
}
func (h *SimpleServerHandler) AddGet(in int) int {
h.n += in
return h.n
}
func (h *SimpleServerHandler) StringMatch(t TestType, i2 int64) (out TestOut, err error) {
if strconv.FormatInt(i2, 10) == t.S {
out.Ok = true
}
if i2 != int64(t.I) {
return TestOut{}, errors.New(":(")
}
out.I = t.I
out.S = t.S
return
}
func TestRPC(t *testing.T) {
// setup server
serverHandler := &SimpleServerHandler{}
rpcServer := NewServer()
rpcServer.Register("SimpleServerHandler", serverHandler)
// httptest stuff
testServ := httptest.NewServer(rpcServer)
defer testServ.Close()
// setup client
var client struct {
Add func(int) error
AddGet func(int) int
StringMatch func(t TestType, i2 int64) (out TestOut, err error)
}
closer, err := NewClient("ws://"+testServ.Listener.Addr().String(), "SimpleServerHandler", &client)
if err != nil {
t.Fatal(err)
}
defer closer()
// Add(int) error
if err := client.Add(2); err != nil {
t.Fatal(err)
}
if serverHandler.n != 2 {
t.Error("expected 2")
}
err = client.Add(-3546)
if err == nil {
t.Fatal("expected error")
}
if err.Error() != "test" {
t.Fatal("wrong error", err)
}
// AddGet(int) int
n := client.AddGet(3)
if n != 5 {
t.Error("wrong n")
}
if serverHandler.n != 5 {
t.Error("expected 5")
}
// StringMatch
o, err := client.StringMatch(TestType{S: "0"}, 0)
if err != nil {
t.Error(err)
}
if o.S != "0" || o.I != 0 {
t.Error("wrong result")
}
_, err = client.StringMatch(TestType{S: "5"}, 5)
if err == nil || err.Error() != ":(" {
t.Error("wrong err")
}
o, err = client.StringMatch(TestType{S: "8", I: 8}, 8)
if err != nil {
t.Error(err)
}
if o.S != "8" || o.I != 8 {
t.Error("wrong result")
}
// Invalid client handlers
var noret struct {
Add func(int)
}
closer, err = NewClient("ws://"+testServ.Listener.Addr().String(), "SimpleServerHandler", &noret)
if err != nil {
t.Fatal(err)
}
// this one should actually work
noret.Add(4)
if serverHandler.n != 9 {
t.Error("expected 9")
}
closer()
var noparam struct {
Add func()
}
closer, err = NewClient("ws://"+testServ.Listener.Addr().String(), "SimpleServerHandler", &noparam)
if err != nil {
t.Fatal(err)
}
// shouldn't panic
noparam.Add()
closer()
var erronly struct {
AddGet func() (int, error)
}
closer, err = NewClient("ws://"+testServ.Listener.Addr().String(), "SimpleServerHandler", &erronly)
if err != nil {
t.Fatal(err)
}
_, err = erronly.AddGet()
if err == nil || err.Error() != "RPC error (-32602): wrong param count" {
t.Error("wrong error:", err)
}
closer()
var wrongtype struct {
Add func(string) error
}
closer, err = NewClient("ws://"+testServ.Listener.Addr().String(), "SimpleServerHandler", &wrongtype)
if err != nil {
t.Fatal(err)
}
err = wrongtype.Add("not an int")
if err == nil || !strings.Contains(err.Error(), "RPC error (-32700):") || !strings.Contains(err.Error(), "json: cannot unmarshal string into Go value of type int") {
t.Error("wrong error:", err)
}
closer()
var notfound struct {
NotThere func(string) error
}
closer, err = NewClient("ws://"+testServ.Listener.Addr().String(), "SimpleServerHandler", &notfound)
if err != nil {
t.Fatal(err)
}
err = notfound.NotThere("hello?")
if err == nil || err.Error() != "RPC error (-32601): method 'SimpleServerHandler.NotThere' not found" {
t.Error("wrong error:", err)
}
closer()
}
type CtxHandler struct {
lk sync.Mutex
cancelled bool
i int
}
func (h *CtxHandler) Test(ctx context.Context) {
h.lk.Lock()
defer h.lk.Unlock()
timeout := time.After(300 * time.Millisecond)
h.i++
select {
case <-timeout:
case <-ctx.Done():
h.cancelled = true
}
}
func TestCtx(t *testing.T) {
// setup server
serverHandler := &CtxHandler{}
rpcServer := NewServer()
rpcServer.Register("CtxHandler", serverHandler)
// httptest stuff
testServ := httptest.NewServer(rpcServer)
defer testServ.Close()
// setup client
var client struct {
Test func(ctx context.Context)
}
closer, err := NewClient("ws://"+testServ.Listener.Addr().String(), "CtxHandler", &client)
if err != nil {
t.Fatal(err)
}
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()
client.Test(ctx)
serverHandler.lk.Lock()
if !serverHandler.cancelled {
t.Error("expected cancellation on the server side")
}
serverHandler.cancelled = false
serverHandler.lk.Unlock()
closer()
var noCtxClient struct {
Test func()
}
closer, err = NewClient("ws://"+testServ.Listener.Addr().String(), "CtxHandler", &noCtxClient)
if err != nil {
t.Fatal(err)
}
noCtxClient.Test()
serverHandler.lk.Lock()
if serverHandler.cancelled || serverHandler.i != 2 {
t.Error("wrong serverHandler state")
}
serverHandler.lk.Unlock()
closer()
}