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  }