2019-07-03 17:39:07 +00:00
package jsonrpc
2019-06-28 13:49:34 +00:00
import (
2019-06-28 14:53:01 +00:00
"context"
2019-06-28 13:49:34 +00:00
"errors"
"net/http/httptest"
"strconv"
2019-07-18 11:09:13 +00:00
"strings"
2019-07-02 19:08:30 +00:00
"sync"
2019-06-28 13:49:34 +00:00
"testing"
2019-06-28 14:53:01 +00:00
"time"
2019-06-28 13:49:34 +00:00
)
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 { }
2019-07-08 12:46:30 +00:00
rpcServer := NewServer ( )
2019-06-29 09:19:06 +00:00
rpcServer . Register ( "SimpleServerHandler" , serverHandler )
2019-06-28 13:49:34 +00:00
// 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 )
}
2019-07-15 16:32:43 +00:00
closer , err := NewClient ( "ws://" + testServ . Listener . Addr ( ) . String ( ) , "SimpleServerHandler" , & client )
2019-07-12 17:12:51 +00:00
if err != nil {
t . Fatal ( err )
}
2019-07-03 12:30:21 +00:00
defer closer ( )
2019-06-28 13:49:34 +00:00
// Add(int) error
if err := client . Add ( 2 ) ; err != nil {
t . Fatal ( err )
}
if serverHandler . n != 2 {
t . Error ( "expected 2" )
}
2019-07-12 17:12:51 +00:00
err = client . Add ( - 3546 )
2019-06-28 13:49:34 +00:00
if err == nil {
t . Fatal ( "expected error" )
}
if err . Error ( ) != "test" {
2019-07-02 13:49:10 +00:00
t . Fatal ( "wrong error" , err )
2019-06-28 13:49:34 +00:00
}
// 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 )
}
2019-07-15 16:32:43 +00:00
closer , err = NewClient ( "ws://" + testServ . Listener . Addr ( ) . String ( ) , "SimpleServerHandler" , & noret )
2019-07-12 17:12:51 +00:00
if err != nil {
t . Fatal ( err )
}
2019-06-28 13:49:34 +00:00
// this one should actually work
noret . Add ( 4 )
if serverHandler . n != 9 {
t . Error ( "expected 9" )
}
2019-07-03 12:30:21 +00:00
closer ( )
2019-06-28 13:49:34 +00:00
var noparam struct {
Add func ( )
}
2019-07-15 16:32:43 +00:00
closer , err = NewClient ( "ws://" + testServ . Listener . Addr ( ) . String ( ) , "SimpleServerHandler" , & noparam )
2019-07-12 17:12:51 +00:00
if err != nil {
t . Fatal ( err )
}
2019-06-28 13:49:34 +00:00
// shouldn't panic
noparam . Add ( )
2019-07-03 12:30:21 +00:00
closer ( )
2019-06-28 13:49:34 +00:00
2019-06-28 14:05:10 +00:00
var erronly struct {
2019-06-28 14:53:01 +00:00
AddGet func ( ) ( int , error )
2019-06-28 14:05:10 +00:00
}
2019-07-15 16:32:43 +00:00
closer , err = NewClient ( "ws://" + testServ . Listener . Addr ( ) . String ( ) , "SimpleServerHandler" , & erronly )
2019-07-12 17:12:51 +00:00
if err != nil {
t . Fatal ( err )
}
2019-06-28 14:05:10 +00:00
2019-06-28 14:53:01 +00:00
_ , err = erronly . AddGet ( )
2019-07-02 13:49:10 +00:00
if err == nil || err . Error ( ) != "RPC error (-32602): wrong param count" {
t . Error ( "wrong error:" , err )
2019-06-28 14:05:10 +00:00
}
2019-07-03 12:30:21 +00:00
closer ( )
2019-06-28 14:05:10 +00:00
var wrongtype struct {
Add func ( string ) error
}
2019-07-15 16:32:43 +00:00
closer , err = NewClient ( "ws://" + testServ . Listener . Addr ( ) . String ( ) , "SimpleServerHandler" , & wrongtype )
2019-07-12 17:12:51 +00:00
if err != nil {
t . Fatal ( err )
}
2019-06-28 14:05:10 +00:00
err = wrongtype . Add ( "not an int" )
2019-07-18 11:09:13 +00:00
if err == nil || ! strings . Contains ( err . Error ( ) , "RPC error (-32700):" ) || ! strings . Contains ( err . Error ( ) , "json: cannot unmarshal string into Go value of type int" ) {
2019-07-02 13:49:10 +00:00
t . Error ( "wrong error:" , err )
}
2019-07-03 12:30:21 +00:00
closer ( )
2019-07-02 13:49:10 +00:00
var notfound struct {
NotThere func ( string ) error
}
2019-07-15 16:32:43 +00:00
closer , err = NewClient ( "ws://" + testServ . Listener . Addr ( ) . String ( ) , "SimpleServerHandler" , & notfound )
2019-07-12 17:12:51 +00:00
if err != nil {
t . Fatal ( err )
}
2019-07-02 13:49:10 +00:00
err = notfound . NotThere ( "hello?" )
if err == nil || err . Error ( ) != "RPC error (-32601): method 'SimpleServerHandler.NotThere' not found" {
t . Error ( "wrong error:" , err )
2019-06-28 14:05:10 +00:00
}
2019-07-03 12:30:21 +00:00
closer ( )
2019-06-28 13:49:34 +00:00
}
2019-06-28 14:53:01 +00:00
type CtxHandler struct {
2019-07-02 19:08:30 +00:00
lk sync . Mutex
2019-06-28 14:53:01 +00:00
cancelled bool
2019-07-02 19:08:30 +00:00
i int
2019-06-28 14:53:01 +00:00
}
func ( h * CtxHandler ) Test ( ctx context . Context ) {
2019-07-02 19:08:30 +00:00
h . lk . Lock ( )
defer h . lk . Unlock ( )
2019-06-28 14:53:01 +00:00
timeout := time . After ( 300 * time . Millisecond )
2019-07-02 19:08:30 +00:00
h . i ++
2019-06-28 14:53:01 +00:00
select {
case <- timeout :
case <- ctx . Done ( ) :
h . cancelled = true
}
}
func TestCtx ( t * testing . T ) {
// setup server
serverHandler := & CtxHandler { }
2019-07-08 12:46:30 +00:00
rpcServer := NewServer ( )
2019-07-02 13:20:33 +00:00
rpcServer . Register ( "CtxHandler" , serverHandler )
2019-06-28 14:53:01 +00:00
// httptest stuff
testServ := httptest . NewServer ( rpcServer )
defer testServ . Close ( )
// setup client
var client struct {
Test func ( ctx context . Context )
}
2019-07-15 16:32:43 +00:00
closer , err := NewClient ( "ws://" + testServ . Listener . Addr ( ) . String ( ) , "CtxHandler" , & client )
2019-07-12 17:12:51 +00:00
if err != nil {
t . Fatal ( err )
}
2019-06-28 14:53:01 +00:00
2019-07-02 13:20:33 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , 100 * time . Millisecond )
2019-06-28 14:53:01 +00:00
defer cancel ( )
client . Test ( ctx )
2019-07-02 19:08:30 +00:00
serverHandler . lk . Lock ( )
2019-06-28 14:53:01 +00:00
if ! serverHandler . cancelled {
t . Error ( "expected cancellation on the server side" )
}
serverHandler . cancelled = false
2019-07-02 19:08:30 +00:00
serverHandler . lk . Unlock ( )
2019-07-03 12:30:21 +00:00
closer ( )
2019-07-02 19:08:30 +00:00
2019-06-28 14:53:01 +00:00
var noCtxClient struct {
Test func ( )
}
2019-07-15 16:32:43 +00:00
closer , err = NewClient ( "ws://" + testServ . Listener . Addr ( ) . String ( ) , "CtxHandler" , & noCtxClient )
2019-07-12 17:12:51 +00:00
if err != nil {
t . Fatal ( err )
}
2019-06-28 14:53:01 +00:00
noCtxClient . Test ( )
2019-07-02 19:08:30 +00:00
serverHandler . lk . Lock ( )
if serverHandler . cancelled || serverHandler . i != 2 {
2019-06-28 14:53:01 +00:00
t . Error ( "wrong serverHandler state" )
}
2019-07-02 19:08:30 +00:00
serverHandler . lk . Unlock ( )
2019-07-03 12:30:21 +00:00
closer ( )
2019-07-01 20:00:22 +00:00
}