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.

99 lines
3.2 KiB

7 years ago
7 years ago
7 years ago
  1. package rpcserver_test
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "io/ioutil"
  6. "net/http"
  7. "net/http/httptest"
  8. "strings"
  9. "testing"
  10. "github.com/stretchr/testify/assert"
  11. "github.com/stretchr/testify/require"
  12. "github.com/tendermint/go-amino"
  13. rs "github.com/tendermint/tendermint/rpc/lib/server"
  14. types "github.com/tendermint/tendermint/rpc/lib/types"
  15. "github.com/tendermint/tmlibs/log"
  16. )
  17. func testMux() *http.ServeMux {
  18. funcMap := map[string]*rs.RPCFunc{
  19. "c": rs.NewRPCFunc(func(s string, i int) (string, error) { return "foo", nil }, "s,i"),
  20. }
  21. cdc := amino.NewCodec()
  22. mux := http.NewServeMux()
  23. buf := new(bytes.Buffer)
  24. logger := log.NewTMLogger(buf)
  25. rs.RegisterRPCFuncs(mux, funcMap, cdc, logger)
  26. return mux
  27. }
  28. func statusOK(code int) bool { return code >= 200 && code <= 299 }
  29. // Ensure that nefarious/unintended inputs to `params`
  30. // do not crash our RPC handlers.
  31. // See Issue https://github.com/tendermint/tendermint/issues/708.
  32. func TestRPCParams(t *testing.T) {
  33. mux := testMux()
  34. tests := []struct {
  35. payload string
  36. wantErr string
  37. }{
  38. // bad
  39. {`{"jsonrpc": "2.0", "id": "0"}`, "Method not found"},
  40. {`{"jsonrpc": "2.0", "method": "y", "id": "0"}`, "Method not found"},
  41. {`{"method": "c", "id": "0", "params": a}`, "invalid character"},
  42. {`{"method": "c", "id": "0", "params": ["a"]}`, "got 1"},
  43. {`{"method": "c", "id": "0", "params": ["a", "b"]}`, "of type int"},
  44. {`{"method": "c", "id": "0", "params": [1, 1]}`, "of type string"},
  45. // good
  46. {`{"jsonrpc": "2.0", "method": "c", "id": "0", "params": null}`, ""},
  47. {`{"method": "c", "id": "0", "params": {}}`, ""},
  48. {`{"method": "c", "id": "0", "params": ["a", 10]}`, ""},
  49. }
  50. for i, tt := range tests {
  51. req, _ := http.NewRequest("POST", "http://localhost/", strings.NewReader(tt.payload))
  52. rec := httptest.NewRecorder()
  53. mux.ServeHTTP(rec, req)
  54. res := rec.Result()
  55. // Always expecting back a JSONRPCResponse
  56. assert.True(t, statusOK(res.StatusCode), "#%d: should always return 2XX", i)
  57. blob, err := ioutil.ReadAll(res.Body)
  58. if err != nil {
  59. t.Errorf("#%d: err reading body: %v", i, err)
  60. continue
  61. }
  62. recv := new(types.RPCResponse)
  63. assert.Nil(t, json.Unmarshal(blob, recv), "#%d: expecting successful parsing of an RPCResponse:\nblob: %s", i, blob)
  64. assert.NotEqual(t, recv, new(types.RPCResponse), "#%d: not expecting a blank RPCResponse", i)
  65. if tt.wantErr == "" {
  66. assert.Nil(t, recv.Error, "#%d: not expecting an error", i)
  67. } else {
  68. assert.True(t, recv.Error.Code < 0, "#%d: not expecting a positive JSONRPC code", i)
  69. // The wanted error is either in the message or the data
  70. assert.Contains(t, recv.Error.Message+recv.Error.Data, tt.wantErr, "#%d: expected substring", i)
  71. }
  72. }
  73. }
  74. func TestRPCNotification(t *testing.T) {
  75. mux := testMux()
  76. body := strings.NewReader(`{"jsonrpc": "2.0"}`)
  77. req, _ := http.NewRequest("POST", "http://localhost/", body)
  78. rec := httptest.NewRecorder()
  79. mux.ServeHTTP(rec, req)
  80. res := rec.Result()
  81. // Always expecting back a JSONRPCResponse
  82. require.True(t, statusOK(res.StatusCode), "should always return 2XX")
  83. blob, err := ioutil.ReadAll(res.Body)
  84. require.Nil(t, err, "reading from the body should not give back an error")
  85. require.Equal(t, len(blob), 0, "a notification SHOULD NOT be responded to by the server")
  86. }