github.com/noirx94/tendermintmp@v0.0.1/rpc/jsonrpc/server/http_server_test.go (about)

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