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  }