github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/bft/rpc/lib/client/http/client_test.go (about)

     1  package http
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"net/http"
     7  	"net/http/httptest"
     8  	"testing"
     9  	"time"
    10  
    11  	types "github.com/gnolang/gno/tm2/pkg/bft/rpc/lib/types"
    12  	"github.com/stretchr/testify/assert"
    13  	"github.com/stretchr/testify/require"
    14  )
    15  
    16  func TestClient_parseRemoteAddr(t *testing.T) {
    17  	t.Parallel()
    18  
    19  	testTable := []struct {
    20  		remoteAddr string
    21  		network    string
    22  		rest       string
    23  	}{
    24  		{
    25  			"127.0.0.1",
    26  			"tcp",
    27  			"127.0.0.1",
    28  		},
    29  		{
    30  			"https://example.com",
    31  			"https",
    32  			"example.com",
    33  		},
    34  		{
    35  			"wss://[::1]",
    36  			"wss",
    37  			"[::1]",
    38  		},
    39  	}
    40  
    41  	for _, testCase := range testTable {
    42  		testCase := testCase
    43  
    44  		t.Run(testCase.remoteAddr, func(t *testing.T) {
    45  			t.Parallel()
    46  
    47  			n, r, err := parseRemoteAddr(testCase.remoteAddr)
    48  			require.NoError(t, err)
    49  
    50  			assert.Equal(t, n, testCase.network)
    51  			assert.Equal(t, r, testCase.rest)
    52  		})
    53  	}
    54  }
    55  
    56  // Following tests check that we correctly translate http/https to tcp,
    57  // and other protocols are left intact from parseRemoteAddr()
    58  
    59  func TestClient_makeHTTPDialer(t *testing.T) {
    60  	t.Parallel()
    61  
    62  	t.Run("http", func(t *testing.T) {
    63  		t.Parallel()
    64  
    65  		_, err := makeHTTPDialer("https://.")("hello", "world")
    66  		require.Error(t, err)
    67  
    68  		assert.Contains(t, err.Error(), "dial tcp:", "should convert https to tcp")
    69  		assert.Contains(t, err.Error(), "address .:", "should have parsed the address (as incorrect)")
    70  	})
    71  
    72  	t.Run("udp", func(t *testing.T) {
    73  		t.Parallel()
    74  
    75  		_, err := makeHTTPDialer("udp://.")("hello", "world")
    76  		require.Error(t, err)
    77  
    78  		assert.Contains(t, err.Error(), "dial udp:", "udp protocol should remain the same")
    79  		assert.Contains(t, err.Error(), "address .:", "should have parsed the address (as incorrect)")
    80  	})
    81  }
    82  
    83  // createTestServer creates a test HTTP server
    84  func createTestServer(
    85  	t *testing.T,
    86  	handler http.Handler,
    87  ) *httptest.Server {
    88  	t.Helper()
    89  
    90  	s := httptest.NewServer(handler)
    91  	t.Cleanup(s.Close)
    92  
    93  	return s
    94  }
    95  
    96  func TestClient_SendRequest(t *testing.T) {
    97  	t.Parallel()
    98  
    99  	var (
   100  		request = types.RPCRequest{
   101  			JSONRPC: "2.0",
   102  			ID:      types.JSONRPCStringID("id"),
   103  		}
   104  
   105  		handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   106  			require.Equal(t, http.MethodPost, r.Method)
   107  			require.Equal(t, "application/json", r.Header.Get("content-type"))
   108  
   109  			// Parse the message
   110  			var req types.RPCRequest
   111  			require.NoError(t, json.NewDecoder(r.Body).Decode(&req))
   112  			require.Equal(t, request.ID.String(), req.ID.String())
   113  
   114  			// Send an empty response back
   115  			response := types.RPCResponse{
   116  				JSONRPC: "2.0",
   117  				ID:      req.ID,
   118  			}
   119  
   120  			// Marshal the response
   121  			marshalledResponse, err := json.Marshal(response)
   122  			require.NoError(t, err)
   123  
   124  			_, err = w.Write(marshalledResponse)
   125  			require.NoError(t, err)
   126  		})
   127  
   128  		server = createTestServer(t, handler)
   129  	)
   130  
   131  	// Create the client
   132  	c, err := NewClient(server.URL)
   133  	require.NoError(t, err)
   134  
   135  	ctx, cancelFn := context.WithTimeout(context.Background(), time.Second*5)
   136  	defer cancelFn()
   137  
   138  	// Send the request
   139  	resp, err := c.SendRequest(ctx, request)
   140  	require.NoError(t, err)
   141  
   142  	assert.Equal(t, request.ID, resp.ID)
   143  	assert.Equal(t, request.JSONRPC, resp.JSONRPC)
   144  	assert.Nil(t, resp.Result)
   145  	assert.Nil(t, resp.Error)
   146  }
   147  
   148  func TestClient_SendBatchRequest(t *testing.T) {
   149  	t.Parallel()
   150  
   151  	var (
   152  		request = types.RPCRequest{
   153  			JSONRPC: "2.0",
   154  			ID:      types.JSONRPCStringID("id"),
   155  		}
   156  
   157  		requests = types.RPCRequests{
   158  			request,
   159  			request,
   160  		}
   161  
   162  		handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   163  			require.Equal(t, http.MethodPost, r.Method)
   164  			require.Equal(t, "application/json", r.Header.Get("content-type"))
   165  
   166  			// Parse the message
   167  			var reqs types.RPCRequests
   168  			require.NoError(t, json.NewDecoder(r.Body).Decode(&reqs))
   169  			require.Len(t, reqs, len(requests))
   170  
   171  			for _, req := range reqs {
   172  				require.Equal(t, request.ID.String(), req.ID.String())
   173  			}
   174  
   175  			// Send an empty response batch back
   176  			response := types.RPCResponse{
   177  				JSONRPC: "2.0",
   178  				ID:      request.ID,
   179  			}
   180  
   181  			responses := types.RPCResponses{
   182  				response,
   183  				response,
   184  			}
   185  
   186  			// Marshal the responses
   187  			marshalledResponses, err := json.Marshal(responses)
   188  			require.NoError(t, err)
   189  
   190  			_, err = w.Write(marshalledResponses)
   191  			require.NoError(t, err)
   192  		})
   193  
   194  		server = createTestServer(t, handler)
   195  	)
   196  
   197  	// Create the client
   198  	c, err := NewClient(server.URL)
   199  	require.NoError(t, err)
   200  
   201  	ctx, cancelFn := context.WithTimeout(context.Background(), time.Second*5)
   202  	defer cancelFn()
   203  
   204  	// Send the request
   205  	resps, err := c.SendBatch(ctx, requests)
   206  	require.NoError(t, err)
   207  
   208  	require.Len(t, resps, len(requests))
   209  
   210  	for _, resp := range resps {
   211  		assert.Equal(t, request.ID, resp.ID)
   212  		assert.Equal(t, request.JSONRPC, resp.JSONRPC)
   213  		assert.Nil(t, resp.Result)
   214  		assert.Nil(t, resp.Error)
   215  	}
   216  }