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