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.

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