You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

298 lines
6.5 KiB

8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
  1. package rpc
  2. import (
  3. "bytes"
  4. crand "crypto/rand"
  5. "fmt"
  6. "math/rand"
  7. "net/http"
  8. "os/exec"
  9. "testing"
  10. "time"
  11. "github.com/stretchr/testify/assert"
  12. "github.com/stretchr/testify/require"
  13. wire "github.com/tendermint/go-wire"
  14. client "github.com/tendermint/tendermint/rpc/client"
  15. server "github.com/tendermint/tendermint/rpc/server"
  16. types "github.com/tendermint/tendermint/rpc/types"
  17. )
  18. // Client and Server should work over tcp or unix sockets
  19. const (
  20. tcpAddr = "tcp://0.0.0.0:46657"
  21. unixSocket = "/tmp/rpc.sock"
  22. unixAddr = "unix:///tmp/rpc.sock"
  23. websocketEndpoint = "/websocket/endpoint"
  24. )
  25. // Define a type for results and register concrete versions
  26. type Result interface{}
  27. type ResultEcho struct {
  28. Value string
  29. }
  30. type ResultEchoBytes struct {
  31. Value []byte
  32. }
  33. var _ = wire.RegisterInterface(
  34. struct{ Result }{},
  35. wire.ConcreteType{&ResultEcho{}, 0x1},
  36. wire.ConcreteType{&ResultEchoBytes{}, 0x2},
  37. )
  38. // Define some routes
  39. var Routes = map[string]*server.RPCFunc{
  40. "echo": server.NewRPCFunc(EchoResult, "arg"),
  41. "echo_ws": server.NewWSRPCFunc(EchoWSResult, "arg"),
  42. "echo_bytes": server.NewRPCFunc(EchoBytesResult, "arg"),
  43. }
  44. func EchoResult(v string) (Result, error) {
  45. return &ResultEcho{v}, nil
  46. }
  47. func EchoWSResult(wsCtx types.WSRPCContext, v string) (Result, error) {
  48. return &ResultEcho{v}, nil
  49. }
  50. func EchoBytesResult(v []byte) (Result, error) {
  51. return &ResultEchoBytes{v}, nil
  52. }
  53. // launch unix and tcp servers
  54. func init() {
  55. cmd := exec.Command("rm", "-f", unixSocket)
  56. err := cmd.Start()
  57. if err != nil {
  58. panic(err)
  59. }
  60. if err = cmd.Wait(); err != nil {
  61. panic(err)
  62. }
  63. mux := http.NewServeMux()
  64. server.RegisterRPCFuncs(mux, Routes)
  65. wm := server.NewWebsocketManager(Routes, nil)
  66. mux.HandleFunc(websocketEndpoint, wm.WebsocketHandler)
  67. go func() {
  68. _, err := server.StartHTTPServer(tcpAddr, mux)
  69. if err != nil {
  70. panic(err)
  71. }
  72. }()
  73. mux2 := http.NewServeMux()
  74. server.RegisterRPCFuncs(mux2, Routes)
  75. wm = server.NewWebsocketManager(Routes, nil)
  76. mux2.HandleFunc(websocketEndpoint, wm.WebsocketHandler)
  77. go func() {
  78. _, err := server.StartHTTPServer(unixAddr, mux2)
  79. if err != nil {
  80. panic(err)
  81. }
  82. }()
  83. // wait for servers to start
  84. time.Sleep(time.Second * 2)
  85. }
  86. func echoViaHTTP(cl client.HTTPClient, val string) (string, error) {
  87. params := map[string]interface{}{
  88. "arg": val,
  89. }
  90. var result Result
  91. if _, err := cl.Call("echo", params, &result); err != nil {
  92. return "", err
  93. }
  94. return result.(*ResultEcho).Value, nil
  95. }
  96. func echoBytesViaHTTP(cl client.HTTPClient, bytes []byte) ([]byte, error) {
  97. params := map[string]interface{}{
  98. "arg": bytes,
  99. }
  100. var result Result
  101. if _, err := cl.Call("echo_bytes", params, &result); err != nil {
  102. return []byte{}, err
  103. }
  104. return result.(*ResultEchoBytes).Value, nil
  105. }
  106. func testWithHTTPClient(t *testing.T, cl client.HTTPClient) {
  107. val := "acbd"
  108. got, err := echoViaHTTP(cl, val)
  109. require.Nil(t, err)
  110. assert.Equal(t, got, val)
  111. val2 := randBytes(t)
  112. got2, err := echoBytesViaHTTP(cl, val2)
  113. require.Nil(t, err)
  114. assert.Equal(t, got2, val2)
  115. }
  116. func echoViaWS(cl *client.WSClient, val string) (string, error) {
  117. params := map[string]interface{}{
  118. "arg": val,
  119. }
  120. err := cl.Call("echo", params)
  121. if err != nil {
  122. return "", err
  123. }
  124. select {
  125. case msg := <-cl.ResultsCh:
  126. result := new(Result)
  127. wire.ReadJSONPtr(result, msg, &err)
  128. if err != nil {
  129. return "", nil
  130. }
  131. return (*result).(*ResultEcho).Value, nil
  132. case err := <-cl.ErrorsCh:
  133. return "", err
  134. }
  135. }
  136. func echoBytesViaWS(cl *client.WSClient, bytes []byte) ([]byte, error) {
  137. params := map[string]interface{}{
  138. "arg": bytes,
  139. }
  140. err := cl.Call("echo_bytes", params)
  141. if err != nil {
  142. return []byte{}, err
  143. }
  144. select {
  145. case msg := <-cl.ResultsCh:
  146. result := new(Result)
  147. wire.ReadJSONPtr(result, msg, &err)
  148. if err != nil {
  149. return []byte{}, nil
  150. }
  151. return (*result).(*ResultEchoBytes).Value, nil
  152. case err := <-cl.ErrorsCh:
  153. return []byte{}, err
  154. }
  155. }
  156. func testWithWSClient(t *testing.T, cl *client.WSClient) {
  157. val := "acbd"
  158. got, err := echoViaWS(cl, val)
  159. require.Nil(t, err)
  160. assert.Equal(t, got, val)
  161. val2 := randBytes(t)
  162. got2, err := echoBytesViaWS(cl, val2)
  163. require.Nil(t, err)
  164. assert.Equal(t, got2, val2)
  165. }
  166. //-------------
  167. func TestServersAndClientsBasic(t *testing.T) {
  168. serverAddrs := [...]string{tcpAddr, unixAddr}
  169. for _, addr := range serverAddrs {
  170. cl1 := client.NewURIClient(addr)
  171. fmt.Printf("=== testing server on %s using %v client", addr, cl1)
  172. testWithHTTPClient(t, cl1)
  173. cl2 := client.NewJSONRPCClient(tcpAddr)
  174. fmt.Printf("=== testing server on %s using %v client", addr, cl2)
  175. testWithHTTPClient(t, cl2)
  176. cl3 := client.NewWSClient(tcpAddr, websocketEndpoint)
  177. _, err := cl3.Start()
  178. require.Nil(t, err)
  179. fmt.Printf("=== testing server on %s using %v client", addr, cl3)
  180. testWithWSClient(t, cl3)
  181. cl3.Stop()
  182. }
  183. }
  184. func TestHexStringArg(t *testing.T) {
  185. cl := client.NewURIClient(tcpAddr)
  186. // should NOT be handled as hex
  187. val := "0xabc"
  188. got, err := echoViaHTTP(cl, val)
  189. require.Nil(t, err)
  190. assert.Equal(t, got, val)
  191. }
  192. func TestQuotedStringArg(t *testing.T) {
  193. cl := client.NewURIClient(tcpAddr)
  194. // should NOT be unquoted
  195. val := "\"abc\""
  196. got, err := echoViaHTTP(cl, val)
  197. require.Nil(t, err)
  198. assert.Equal(t, got, val)
  199. }
  200. func TestWSNewWSRPCFunc(t *testing.T) {
  201. cl := client.NewWSClient(tcpAddr, websocketEndpoint)
  202. _, err := cl.Start()
  203. require.Nil(t, err)
  204. defer cl.Stop()
  205. val := "acbd"
  206. params := map[string]interface{}{
  207. "arg": val,
  208. }
  209. err = cl.WriteJSON(types.RPCRequest{
  210. JSONRPC: "2.0",
  211. ID: "",
  212. Method: "echo_ws",
  213. Params: params,
  214. })
  215. require.Nil(t, err)
  216. select {
  217. case msg := <-cl.ResultsCh:
  218. result := new(Result)
  219. wire.ReadJSONPtr(result, msg, &err)
  220. require.Nil(t, err)
  221. got := (*result).(*ResultEcho).Value
  222. assert.Equal(t, got, val)
  223. case err := <-cl.ErrorsCh:
  224. t.Fatal(err)
  225. }
  226. }
  227. func TestWSHandlesArrayParams(t *testing.T) {
  228. cl := client.NewWSClient(tcpAddr, websocketEndpoint)
  229. _, err := cl.Start()
  230. require.Nil(t, err)
  231. defer cl.Stop()
  232. val := "acbd"
  233. params := []interface{}{val}
  234. err = cl.WriteJSON(types.RPCRequest{
  235. JSONRPC: "2.0",
  236. ID: "",
  237. Method: "echo_ws",
  238. Params: params,
  239. })
  240. require.Nil(t, err)
  241. select {
  242. case msg := <-cl.ResultsCh:
  243. result := new(Result)
  244. wire.ReadJSONPtr(result, msg, &err)
  245. require.Nil(t, err)
  246. got := (*result).(*ResultEcho).Value
  247. assert.Equal(t, got, val)
  248. case err := <-cl.ErrorsCh:
  249. t.Fatalf("%+v", err)
  250. }
  251. }
  252. func randBytes(t *testing.T) []byte {
  253. n := rand.Intn(10) + 2
  254. buf := make([]byte, n)
  255. _, err := crand.Read(buf)
  256. require.Nil(t, err)
  257. return bytes.Replace(buf, []byte("="), []byte{100}, -1)
  258. }