github.com/okex/exchain@v1.8.0/libs/tendermint/rpc/jsonrpc/jsonrpc_test.go (about) 1 package jsonrpc 2 3 import ( 4 "bytes" 5 "context" 6 crand "crypto/rand" 7 "encoding/json" 8 "fmt" 9 "net/http" 10 "os" 11 "os/exec" 12 "testing" 13 "time" 14 15 "github.com/go-kit/kit/log/term" 16 "github.com/stretchr/testify/assert" 17 "github.com/stretchr/testify/require" 18 19 amino "github.com/tendermint/go-amino" 20 21 tmbytes "github.com/okex/exchain/libs/tendermint/libs/bytes" 22 "github.com/okex/exchain/libs/tendermint/libs/log" 23 tmrand "github.com/okex/exchain/libs/tendermint/libs/rand" 24 25 client "github.com/okex/exchain/libs/tendermint/rpc/jsonrpc/client" 26 server "github.com/okex/exchain/libs/tendermint/rpc/jsonrpc/server" 27 types "github.com/okex/exchain/libs/tendermint/rpc/jsonrpc/types" 28 ) 29 30 // Client and Server should work over tcp or unix sockets 31 const ( 32 tcpAddr = "tcp://127.0.0.1:47768" 33 34 unixSocket = "/tmp/rpc_test.sock" 35 unixAddr = "unix://" + unixSocket 36 37 websocketEndpoint = "/websocket/endpoint" 38 39 testVal = "acbd" 40 ) 41 42 type ResultEcho struct { 43 Value string `json:"value"` 44 } 45 46 type ResultEchoInt struct { 47 Value int `json:"value"` 48 } 49 50 type ResultEchoBytes struct { 51 Value []byte `json:"value"` 52 } 53 54 type ResultEchoDataBytes struct { 55 Value tmbytes.HexBytes `json:"value"` 56 } 57 58 // Define some routes 59 var Routes = map[string]*server.RPCFunc{ 60 "echo": server.NewRPCFunc(EchoResult, "arg"), 61 "echo_ws": server.NewWSRPCFunc(EchoWSResult, "arg"), 62 "echo_bytes": server.NewRPCFunc(EchoBytesResult, "arg"), 63 "echo_data_bytes": server.NewRPCFunc(EchoDataBytesResult, "arg"), 64 "echo_int": server.NewRPCFunc(EchoIntResult, "arg"), 65 } 66 67 // Amino codec required to encode/decode everything above. 68 var RoutesCdc = amino.NewCodec() 69 70 func EchoResult(ctx *types.Context, v string) (*ResultEcho, error) { 71 return &ResultEcho{v}, nil 72 } 73 74 func EchoWSResult(ctx *types.Context, v string) (*ResultEcho, error) { 75 return &ResultEcho{v}, nil 76 } 77 78 func EchoIntResult(ctx *types.Context, v int) (*ResultEchoInt, error) { 79 return &ResultEchoInt{v}, nil 80 } 81 82 func EchoBytesResult(ctx *types.Context, v []byte) (*ResultEchoBytes, error) { 83 return &ResultEchoBytes{v}, nil 84 } 85 86 func EchoDataBytesResult(ctx *types.Context, v tmbytes.HexBytes) (*ResultEchoDataBytes, error) { 87 return &ResultEchoDataBytes{v}, nil 88 } 89 90 func TestMain(m *testing.M) { 91 setup() 92 code := m.Run() 93 os.Exit(code) 94 } 95 96 var colorFn = func(keyvals ...interface{}) term.FgBgColor { 97 for i := 0; i < len(keyvals)-1; i += 2 { 98 if keyvals[i] == "socket" { 99 if keyvals[i+1] == "tcp" { 100 return term.FgBgColor{Fg: term.DarkBlue} 101 } else if keyvals[i+1] == "unix" { 102 return term.FgBgColor{Fg: term.DarkCyan} 103 } 104 } 105 } 106 return term.FgBgColor{} 107 } 108 109 // launch unix and tcp servers 110 func setup() { 111 logger := log.NewTMLoggerWithColorFn(log.NewSyncWriter(os.Stdout), colorFn) 112 113 cmd := exec.Command("rm", "-f", unixSocket) 114 err := cmd.Start() 115 if err != nil { 116 panic(err) 117 } 118 if err = cmd.Wait(); err != nil { 119 panic(err) 120 } 121 122 tcpLogger := logger.With("socket", "tcp") 123 mux := http.NewServeMux() 124 server.RegisterRPCFuncs(mux, Routes, RoutesCdc, tcpLogger) 125 wm := server.NewWebsocketManager(Routes, RoutesCdc, server.ReadWait(5*time.Second), server.PingPeriod(1*time.Second)) 126 wm.SetLogger(tcpLogger) 127 mux.HandleFunc(websocketEndpoint, wm.WebsocketHandler) 128 config := server.DefaultConfig() 129 listener1, err := server.Listen(tcpAddr, config) 130 if err != nil { 131 panic(err) 132 } 133 go server.Serve(listener1, mux, tcpLogger, config) 134 135 unixLogger := logger.With("socket", "unix") 136 mux2 := http.NewServeMux() 137 server.RegisterRPCFuncs(mux2, Routes, RoutesCdc, unixLogger) 138 wm = server.NewWebsocketManager(Routes, RoutesCdc) 139 wm.SetLogger(unixLogger) 140 mux2.HandleFunc(websocketEndpoint, wm.WebsocketHandler) 141 listener2, err := server.Listen(unixAddr, config) 142 if err != nil { 143 panic(err) 144 } 145 go server.Serve(listener2, mux2, unixLogger, config) 146 147 // wait for servers to start 148 time.Sleep(time.Second * 2) 149 } 150 151 func echoViaHTTP(cl client.Caller, val string) (string, error) { 152 params := map[string]interface{}{ 153 "arg": val, 154 } 155 result := new(ResultEcho) 156 if _, err := cl.Call("echo", params, result); err != nil { 157 return "", err 158 } 159 return result.Value, nil 160 } 161 162 func echoIntViaHTTP(cl client.Caller, val int) (int, error) { 163 params := map[string]interface{}{ 164 "arg": val, 165 } 166 result := new(ResultEchoInt) 167 if _, err := cl.Call("echo_int", params, result); err != nil { 168 return 0, err 169 } 170 return result.Value, nil 171 } 172 173 func echoBytesViaHTTP(cl client.Caller, bytes []byte) ([]byte, error) { 174 params := map[string]interface{}{ 175 "arg": bytes, 176 } 177 result := new(ResultEchoBytes) 178 if _, err := cl.Call("echo_bytes", params, result); err != nil { 179 return []byte{}, err 180 } 181 return result.Value, nil 182 } 183 184 func echoDataBytesViaHTTP(cl client.Caller, bytes tmbytes.HexBytes) (tmbytes.HexBytes, error) { 185 params := map[string]interface{}{ 186 "arg": bytes, 187 } 188 result := new(ResultEchoDataBytes) 189 if _, err := cl.Call("echo_data_bytes", params, result); err != nil { 190 return []byte{}, err 191 } 192 return result.Value, nil 193 } 194 195 func testWithHTTPClient(t *testing.T, cl client.HTTPClient) { 196 val := testVal 197 got, err := echoViaHTTP(cl, val) 198 require.Nil(t, err) 199 assert.Equal(t, got, val) 200 201 val2 := randBytes(t) 202 got2, err := echoBytesViaHTTP(cl, val2) 203 require.Nil(t, err) 204 assert.Equal(t, got2, val2) 205 206 val3 := tmbytes.HexBytes(randBytes(t)) 207 got3, err := echoDataBytesViaHTTP(cl, val3) 208 require.Nil(t, err) 209 assert.Equal(t, got3, val3) 210 211 val4 := tmrand.Intn(10000) 212 got4, err := echoIntViaHTTP(cl, val4) 213 require.Nil(t, err) 214 assert.Equal(t, got4, val4) 215 } 216 217 func echoViaWS(cl *client.WSClient, val string) (string, error) { 218 params := map[string]interface{}{ 219 "arg": val, 220 } 221 err := cl.Call(context.Background(), "echo", params) 222 if err != nil { 223 return "", err 224 } 225 226 msg := <-cl.ResponsesCh 227 if msg.Error != nil { 228 return "", err 229 230 } 231 result := new(ResultEcho) 232 err = json.Unmarshal(msg.Result, result) 233 if err != nil { 234 return "", nil 235 } 236 return result.Value, nil 237 } 238 239 func echoBytesViaWS(cl *client.WSClient, bytes []byte) ([]byte, error) { 240 params := map[string]interface{}{ 241 "arg": bytes, 242 } 243 err := cl.Call(context.Background(), "echo_bytes", params) 244 if err != nil { 245 return []byte{}, err 246 } 247 248 msg := <-cl.ResponsesCh 249 if msg.Error != nil { 250 return []byte{}, msg.Error 251 252 } 253 result := new(ResultEchoBytes) 254 err = json.Unmarshal(msg.Result, result) 255 if err != nil { 256 return []byte{}, nil 257 } 258 return result.Value, nil 259 } 260 261 func testWithWSClient(t *testing.T, cl *client.WSClient) { 262 val := testVal 263 got, err := echoViaWS(cl, val) 264 require.Nil(t, err) 265 assert.Equal(t, got, val) 266 267 val2 := randBytes(t) 268 got2, err := echoBytesViaWS(cl, val2) 269 require.Nil(t, err) 270 assert.Equal(t, got2, val2) 271 } 272 273 //------------- 274 275 func TestServersAndClientsBasic(t *testing.T) { 276 serverAddrs := [...]string{tcpAddr} //unixAddr 277 for _, addr := range serverAddrs { 278 cl1, err := client.NewURI(addr) 279 require.Nil(t, err) 280 fmt.Printf("=== testing server on %s using URI client", addr) 281 testWithHTTPClient(t, cl1) 282 283 cl2, err := client.New(addr) 284 require.Nil(t, err) 285 fmt.Printf("=== testing server on %s using JSONRPC client", addr) 286 testWithHTTPClient(t, cl2) 287 288 cl3, err := client.NewWS(addr, websocketEndpoint) 289 require.Nil(t, err) 290 cl3.SetLogger(log.TestingLogger()) 291 err = cl3.Start() 292 require.Nil(t, err) 293 fmt.Printf("=== testing server on %s using WS client", addr) 294 testWithWSClient(t, cl3) 295 cl3.Stop() 296 } 297 } 298 299 func TestHexStringArg(t *testing.T) { 300 cl, err := client.NewURI(tcpAddr) 301 require.Nil(t, err) 302 // should NOT be handled as hex 303 val := "0xabc" 304 got, err := echoViaHTTP(cl, val) 305 require.Nil(t, err) 306 assert.Equal(t, got, val) 307 } 308 309 func TestQuotedStringArg(t *testing.T) { 310 cl, err := client.NewURI(tcpAddr) 311 require.Nil(t, err) 312 // should NOT be unquoted 313 val := "\"abc\"" 314 got, err := echoViaHTTP(cl, val) 315 require.Nil(t, err) 316 assert.Equal(t, got, val) 317 } 318 319 func TestWSNewWSRPCFunc(t *testing.T) { 320 cl, err := client.NewWS(tcpAddr, websocketEndpoint) 321 require.Nil(t, err) 322 cl.SetLogger(log.TestingLogger()) 323 err = cl.Start() 324 require.Nil(t, err) 325 defer cl.Stop() 326 327 val := testVal 328 params := map[string]interface{}{ 329 "arg": val, 330 } 331 err = cl.Call(context.Background(), "echo_ws", params) 332 require.Nil(t, err) 333 334 msg := <-cl.ResponsesCh 335 if msg.Error != nil { 336 t.Fatal(err) 337 } 338 result := new(ResultEcho) 339 err = json.Unmarshal(msg.Result, result) 340 require.Nil(t, err) 341 got := result.Value 342 assert.Equal(t, got, val) 343 } 344 345 func TestWSHandlesArrayParams(t *testing.T) { 346 cl, err := client.NewWS(tcpAddr, websocketEndpoint) 347 require.Nil(t, err) 348 cl.SetLogger(log.TestingLogger()) 349 err = cl.Start() 350 require.Nil(t, err) 351 defer cl.Stop() 352 353 val := testVal 354 params := []interface{}{val} 355 err = cl.CallWithArrayParams(context.Background(), "echo_ws", params) 356 require.Nil(t, err) 357 358 msg := <-cl.ResponsesCh 359 if msg.Error != nil { 360 t.Fatalf("%+v", err) 361 } 362 result := new(ResultEcho) 363 err = json.Unmarshal(msg.Result, result) 364 require.Nil(t, err) 365 got := result.Value 366 assert.Equal(t, got, val) 367 } 368 369 // TestWSClientPingPong checks that a client & server exchange pings 370 // & pongs so connection stays alive. 371 func TestWSClientPingPong(t *testing.T) { 372 cl, err := client.NewWS(tcpAddr, websocketEndpoint) 373 require.Nil(t, err) 374 cl.SetLogger(log.TestingLogger()) 375 err = cl.Start() 376 require.Nil(t, err) 377 defer cl.Stop() 378 379 time.Sleep(6 * time.Second) 380 } 381 382 func randBytes(t *testing.T) []byte { 383 n := tmrand.Intn(10) + 2 384 buf := make([]byte, n) 385 _, err := crand.Read(buf) 386 require.Nil(t, err) 387 return bytes.Replace(buf, []byte("="), []byte{100}, -1) 388 }