github.com/adoriasoft/tendermint@v0.34.0-dev1.0.20200722151356-96d84601a75a/rpc/jsonrpc/server/http_server_test.go (about) 1 package server 2 3 import ( 4 "crypto/tls" 5 "errors" 6 "fmt" 7 "io" 8 "io/ioutil" 9 "net" 10 "net/http" 11 "net/http/httptest" 12 "sync" 13 "sync/atomic" 14 "testing" 15 "time" 16 17 "github.com/stretchr/testify/assert" 18 "github.com/stretchr/testify/require" 19 20 "github.com/tendermint/tendermint/libs/log" 21 types "github.com/tendermint/tendermint/rpc/jsonrpc/types" 22 ) 23 24 type sampleResult struct { 25 Value string `json:"value"` 26 } 27 28 func TestMaxOpenConnections(t *testing.T) { 29 const max = 5 // max simultaneous connections 30 31 // Start the server. 32 var open int32 33 mux := http.NewServeMux() 34 mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 35 if n := atomic.AddInt32(&open, 1); n > int32(max) { 36 t.Errorf("%d open connections, want <= %d", n, max) 37 } 38 defer atomic.AddInt32(&open, -1) 39 time.Sleep(10 * time.Millisecond) 40 fmt.Fprint(w, "some body") 41 }) 42 config := DefaultConfig() 43 config.MaxOpenConnections = max 44 l, err := Listen("tcp://127.0.0.1:0", config) 45 require.NoError(t, err) 46 defer l.Close() 47 go Serve(l, mux, log.TestingLogger(), config) //nolint:errcheck // ignore for tests 48 49 // Make N GET calls to the server. 50 attempts := max * 2 51 var wg sync.WaitGroup 52 var failed int32 53 for i := 0; i < attempts; i++ { 54 wg.Add(1) 55 go func() { 56 defer wg.Done() 57 c := http.Client{Timeout: 3 * time.Second} 58 r, err := c.Get("http://" + l.Addr().String()) 59 if err != nil { 60 t.Log(err) 61 atomic.AddInt32(&failed, 1) 62 return 63 } 64 defer r.Body.Close() 65 _, err = io.Copy(ioutil.Discard, r.Body) 66 require.NoError(t, err) 67 }() 68 } 69 wg.Wait() 70 71 // We expect some Gets to fail as the server's accept queue is filled, 72 // but most should succeed. 73 if int(failed) >= attempts/2 { 74 t.Errorf("%d requests failed within %d attempts", failed, attempts) 75 } 76 } 77 78 func TestServeTLS(t *testing.T) { 79 ln, err := net.Listen("tcp", "localhost:0") 80 require.NoError(t, err) 81 defer ln.Close() 82 83 mux := http.NewServeMux() 84 mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 85 fmt.Fprint(w, "some body") 86 }) 87 88 go ServeTLS(ln, mux, "test.crt", "test.key", log.TestingLogger(), DefaultConfig()) 89 90 tr := &http.Transport{ 91 TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // nolint: gosec 92 } 93 c := &http.Client{Transport: tr} 94 res, err := c.Get("https://" + ln.Addr().String()) 95 require.NoError(t, err) 96 defer res.Body.Close() 97 assert.Equal(t, http.StatusOK, res.StatusCode) 98 99 body, err := ioutil.ReadAll(res.Body) 100 require.NoError(t, err) 101 assert.Equal(t, []byte("some body"), body) 102 } 103 104 func TestWriteRPCResponseHTTP(t *testing.T) { 105 id := types.JSONRPCIntID(-1) 106 107 // one argument 108 w := httptest.NewRecorder() 109 WriteRPCResponseHTTP(w, types.NewRPCSuccessResponse(id, &sampleResult{"hello"})) 110 resp := w.Result() 111 body, err := ioutil.ReadAll(resp.Body) 112 _ = resp.Body.Close() 113 require.NoError(t, err) 114 assert.Equal(t, 200, resp.StatusCode) 115 assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) 116 assert.Equal(t, `{ 117 "jsonrpc": "2.0", 118 "id": -1, 119 "result": { 120 "value": "hello" 121 } 122 }`, string(body)) 123 124 // multiple arguments 125 w = httptest.NewRecorder() 126 WriteRPCResponseHTTP(w, 127 types.NewRPCSuccessResponse(id, &sampleResult{"hello"}), 128 types.NewRPCSuccessResponse(id, &sampleResult{"world"})) 129 resp = w.Result() 130 body, err = ioutil.ReadAll(resp.Body) 131 _ = resp.Body.Close() 132 require.NoError(t, err) 133 134 assert.Equal(t, 200, resp.StatusCode) 135 assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) 136 assert.Equal(t, `[ 137 { 138 "jsonrpc": "2.0", 139 "id": -1, 140 "result": { 141 "value": "hello" 142 } 143 }, 144 { 145 "jsonrpc": "2.0", 146 "id": -1, 147 "result": { 148 "value": "world" 149 } 150 } 151 ]`, string(body)) 152 } 153 154 func TestWriteRPCResponseHTTPError(t *testing.T) { 155 w := httptest.NewRecorder() 156 WriteRPCResponseHTTPError(w, 157 http.StatusInternalServerError, 158 types.RPCInternalError(types.JSONRPCIntID(-1), errors.New("foo"))) 159 resp := w.Result() 160 body, err := ioutil.ReadAll(resp.Body) 161 _ = resp.Body.Close() 162 require.NoError(t, err) 163 assert.Equal(t, http.StatusInternalServerError, resp.StatusCode) 164 assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) 165 assert.Equal(t, `{ 166 "jsonrpc": "2.0", 167 "id": -1, 168 "error": { 169 "code": -32603, 170 "message": "Internal error", 171 "data": "foo" 172 } 173 }`, string(body)) 174 }