github.com/number571/tendermint@v0.34.11-gost/rpc/jsonrpc/jsonrpc_test.go (about)

     1  package jsonrpc
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	crand "crypto/rand"
     7  	"encoding/json"
     8  	"fmt"
     9  	mrand "math/rand"
    10  	"net/http"
    11  	"os"
    12  	"os/exec"
    13  	"testing"
    14  	"time"
    15  
    16  	"github.com/stretchr/testify/assert"
    17  	"github.com/stretchr/testify/require"
    18  
    19  	tmbytes "github.com/number571/tendermint/libs/bytes"
    20  	"github.com/number571/tendermint/libs/log"
    21  	client "github.com/number571/tendermint/rpc/jsonrpc/client"
    22  	server "github.com/number571/tendermint/rpc/jsonrpc/server"
    23  	types "github.com/number571/tendermint/rpc/jsonrpc/types"
    24  )
    25  
    26  // Client and Server should work over tcp or unix sockets
    27  const (
    28  	tcpAddr = "tcp://127.0.0.1:47768"
    29  
    30  	unixSocket = "/tmp/rpc_test.sock"
    31  	unixAddr   = "unix://" + unixSocket
    32  
    33  	websocketEndpoint = "/websocket/endpoint"
    34  
    35  	testVal = "acbd"
    36  )
    37  
    38  var (
    39  	ctx = context.Background()
    40  )
    41  
    42  type ResultEcho struct {
    43  	Value string `json:"value"`
    44  }
    45  
    46  type ResultEchoInt struct {
    47  	Value int `json:"value"`
    48  }
    49  
    50  type ResultEchoBytes struct {
    51  	Value []byte `json:"value"`
    52  }
    53  
    54  type ResultEchoDataBytes struct {
    55  	Value tmbytes.HexBytes `json:"value"`
    56  }
    57  
    58  // Define some routes
    59  var Routes = map[string]*server.RPCFunc{
    60  	"echo":            server.NewRPCFunc(EchoResult, "arg", false),
    61  	"echo_ws":         server.NewWSRPCFunc(EchoWSResult, "arg"),
    62  	"echo_bytes":      server.NewRPCFunc(EchoBytesResult, "arg", false),
    63  	"echo_data_bytes": server.NewRPCFunc(EchoDataBytesResult, "arg", false),
    64  	"echo_int":        server.NewRPCFunc(EchoIntResult, "arg", false),
    65  }
    66  
    67  func EchoResult(ctx *types.Context, v string) (*ResultEcho, error) {
    68  	return &ResultEcho{v}, nil
    69  }
    70  
    71  func EchoWSResult(ctx *types.Context, v string) (*ResultEcho, error) {
    72  	return &ResultEcho{v}, nil
    73  }
    74  
    75  func EchoIntResult(ctx *types.Context, v int) (*ResultEchoInt, error) {
    76  	return &ResultEchoInt{v}, nil
    77  }
    78  
    79  func EchoBytesResult(ctx *types.Context, v []byte) (*ResultEchoBytes, error) {
    80  	return &ResultEchoBytes{v}, nil
    81  }
    82  
    83  func EchoDataBytesResult(ctx *types.Context, v tmbytes.HexBytes) (*ResultEchoDataBytes, error) {
    84  	return &ResultEchoDataBytes{v}, nil
    85  }
    86  
    87  func TestMain(m *testing.M) {
    88  	setup()
    89  	code := m.Run()
    90  	os.Exit(code)
    91  }
    92  
    93  // launch unix and tcp servers
    94  func setup() {
    95  	logger := log.MustNewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo, false)
    96  
    97  	cmd := exec.Command("rm", "-f", unixSocket)
    98  	err := cmd.Start()
    99  	if err != nil {
   100  		panic(err)
   101  	}
   102  	if err = cmd.Wait(); err != nil {
   103  		panic(err)
   104  	}
   105  
   106  	tcpLogger := logger.With("socket", "tcp")
   107  	mux := http.NewServeMux()
   108  	server.RegisterRPCFuncs(mux, Routes, tcpLogger)
   109  	wm := server.NewWebsocketManager(Routes, server.ReadWait(5*time.Second), server.PingPeriod(1*time.Second))
   110  	wm.SetLogger(tcpLogger)
   111  	mux.HandleFunc(websocketEndpoint, wm.WebsocketHandler)
   112  	config := server.DefaultConfig()
   113  	listener1, err := server.Listen(tcpAddr, config)
   114  	if err != nil {
   115  		panic(err)
   116  	}
   117  	go func() {
   118  		if err := server.Serve(listener1, mux, tcpLogger, config); err != nil {
   119  			panic(err)
   120  		}
   121  	}()
   122  
   123  	unixLogger := logger.With("socket", "unix")
   124  	mux2 := http.NewServeMux()
   125  	server.RegisterRPCFuncs(mux2, Routes, unixLogger)
   126  	wm = server.NewWebsocketManager(Routes)
   127  	wm.SetLogger(unixLogger)
   128  	mux2.HandleFunc(websocketEndpoint, wm.WebsocketHandler)
   129  	listener2, err := server.Listen(unixAddr, config)
   130  	if err != nil {
   131  		panic(err)
   132  	}
   133  	go func() {
   134  		if err := server.Serve(listener2, mux2, unixLogger, config); err != nil {
   135  			panic(err)
   136  		}
   137  	}()
   138  
   139  	// wait for servers to start
   140  	time.Sleep(time.Second * 2)
   141  }
   142  
   143  func echoViaHTTP(cl client.Caller, val string) (string, error) {
   144  	params := map[string]interface{}{
   145  		"arg": val,
   146  	}
   147  	result := new(ResultEcho)
   148  	if _, err := cl.Call(ctx, "echo", params, result); err != nil {
   149  		return "", err
   150  	}
   151  	return result.Value, nil
   152  }
   153  
   154  func echoIntViaHTTP(cl client.Caller, val int) (int, error) {
   155  	params := map[string]interface{}{
   156  		"arg": val,
   157  	}
   158  	result := new(ResultEchoInt)
   159  	if _, err := cl.Call(ctx, "echo_int", params, result); err != nil {
   160  		return 0, err
   161  	}
   162  	return result.Value, nil
   163  }
   164  
   165  func echoBytesViaHTTP(cl client.Caller, bytes []byte) ([]byte, error) {
   166  	params := map[string]interface{}{
   167  		"arg": bytes,
   168  	}
   169  	result := new(ResultEchoBytes)
   170  	if _, err := cl.Call(ctx, "echo_bytes", params, result); err != nil {
   171  		return []byte{}, err
   172  	}
   173  	return result.Value, nil
   174  }
   175  
   176  func echoDataBytesViaHTTP(cl client.Caller, bytes tmbytes.HexBytes) (tmbytes.HexBytes, error) {
   177  	params := map[string]interface{}{
   178  		"arg": bytes,
   179  	}
   180  	result := new(ResultEchoDataBytes)
   181  	if _, err := cl.Call(ctx, "echo_data_bytes", params, result); err != nil {
   182  		return []byte{}, err
   183  	}
   184  	return result.Value, nil
   185  }
   186  
   187  func testWithHTTPClient(t *testing.T, cl client.HTTPClient) {
   188  	val := testVal
   189  	got, err := echoViaHTTP(cl, val)
   190  	require.Nil(t, err)
   191  	assert.Equal(t, got, val)
   192  
   193  	val2 := randBytes(t)
   194  	got2, err := echoBytesViaHTTP(cl, val2)
   195  	require.Nil(t, err)
   196  	assert.Equal(t, got2, val2)
   197  
   198  	val3 := tmbytes.HexBytes(randBytes(t))
   199  	got3, err := echoDataBytesViaHTTP(cl, val3)
   200  	require.Nil(t, err)
   201  	assert.Equal(t, got3, val3)
   202  
   203  	val4 := mrand.Intn(10000)
   204  	got4, err := echoIntViaHTTP(cl, val4)
   205  	require.Nil(t, err)
   206  	assert.Equal(t, got4, val4)
   207  }
   208  
   209  func echoViaWS(cl *client.WSClient, val string) (string, error) {
   210  	params := map[string]interface{}{
   211  		"arg": val,
   212  	}
   213  	err := cl.Call(context.Background(), "echo", params)
   214  	if err != nil {
   215  		return "", err
   216  	}
   217  
   218  	msg := <-cl.ResponsesCh
   219  	if msg.Error != nil {
   220  		return "", err
   221  
   222  	}
   223  	result := new(ResultEcho)
   224  	err = json.Unmarshal(msg.Result, result)
   225  	if err != nil {
   226  		return "", nil
   227  	}
   228  	return result.Value, nil
   229  }
   230  
   231  func echoBytesViaWS(cl *client.WSClient, bytes []byte) ([]byte, error) {
   232  	params := map[string]interface{}{
   233  		"arg": bytes,
   234  	}
   235  	err := cl.Call(context.Background(), "echo_bytes", params)
   236  	if err != nil {
   237  		return []byte{}, err
   238  	}
   239  
   240  	msg := <-cl.ResponsesCh
   241  	if msg.Error != nil {
   242  		return []byte{}, msg.Error
   243  
   244  	}
   245  	result := new(ResultEchoBytes)
   246  	err = json.Unmarshal(msg.Result, result)
   247  	if err != nil {
   248  		return []byte{}, nil
   249  	}
   250  	return result.Value, nil
   251  }
   252  
   253  func testWithWSClient(t *testing.T, cl *client.WSClient) {
   254  	val := testVal
   255  	got, err := echoViaWS(cl, val)
   256  	require.Nil(t, err)
   257  	assert.Equal(t, got, val)
   258  
   259  	val2 := randBytes(t)
   260  	got2, err := echoBytesViaWS(cl, val2)
   261  	require.Nil(t, err)
   262  	assert.Equal(t, got2, val2)
   263  }
   264  
   265  //-------------
   266  
   267  func TestServersAndClientsBasic(t *testing.T) {
   268  	serverAddrs := [...]string{tcpAddr, unixAddr}
   269  	for _, addr := range serverAddrs {
   270  		cl1, err := client.NewURI(addr)
   271  		require.Nil(t, err)
   272  		fmt.Printf("=== testing server on %s using URI client", addr)
   273  		testWithHTTPClient(t, cl1)
   274  
   275  		cl2, err := client.New(addr)
   276  		require.Nil(t, err)
   277  		fmt.Printf("=== testing server on %s using JSONRPC client", addr)
   278  		testWithHTTPClient(t, cl2)
   279  
   280  		cl3, err := client.NewWS(addr, websocketEndpoint)
   281  		require.Nil(t, err)
   282  		cl3.SetLogger(log.TestingLogger())
   283  		err = cl3.Start()
   284  		require.Nil(t, err)
   285  		fmt.Printf("=== testing server on %s using WS client", addr)
   286  		testWithWSClient(t, cl3)
   287  		err = cl3.Stop()
   288  		require.NoError(t, err)
   289  	}
   290  }
   291  
   292  func TestHexStringArg(t *testing.T) {
   293  	cl, err := client.NewURI(tcpAddr)
   294  	require.Nil(t, err)
   295  	// should NOT be handled as hex
   296  	val := "0xabc"
   297  	got, err := echoViaHTTP(cl, val)
   298  	require.Nil(t, err)
   299  	assert.Equal(t, got, val)
   300  }
   301  
   302  func TestQuotedStringArg(t *testing.T) {
   303  	cl, err := client.NewURI(tcpAddr)
   304  	require.Nil(t, err)
   305  	// should NOT be unquoted
   306  	val := "\"abc\""
   307  	got, err := echoViaHTTP(cl, val)
   308  	require.Nil(t, err)
   309  	assert.Equal(t, got, val)
   310  }
   311  
   312  func TestWSNewWSRPCFunc(t *testing.T) {
   313  	cl, err := client.NewWS(tcpAddr, websocketEndpoint)
   314  	require.Nil(t, err)
   315  	cl.SetLogger(log.TestingLogger())
   316  	err = cl.Start()
   317  	require.Nil(t, err)
   318  	t.Cleanup(func() {
   319  		if err := cl.Stop(); err != nil {
   320  			t.Error(err)
   321  		}
   322  	})
   323  
   324  	val := testVal
   325  	params := map[string]interface{}{
   326  		"arg": val,
   327  	}
   328  	err = cl.Call(context.Background(), "echo_ws", params)
   329  	require.Nil(t, err)
   330  
   331  	msg := <-cl.ResponsesCh
   332  	if msg.Error != nil {
   333  		t.Fatal(err)
   334  	}
   335  	result := new(ResultEcho)
   336  	err = json.Unmarshal(msg.Result, result)
   337  	require.Nil(t, err)
   338  	got := result.Value
   339  	assert.Equal(t, got, val)
   340  }
   341  
   342  func TestWSHandlesArrayParams(t *testing.T) {
   343  	cl, err := client.NewWS(tcpAddr, websocketEndpoint)
   344  	require.Nil(t, err)
   345  	cl.SetLogger(log.TestingLogger())
   346  	err = cl.Start()
   347  	require.Nil(t, err)
   348  	t.Cleanup(func() {
   349  		if err := cl.Stop(); err != nil {
   350  			t.Error(err)
   351  		}
   352  	})
   353  
   354  	val := testVal
   355  	params := []interface{}{val}
   356  	err = cl.CallWithArrayParams(context.Background(), "echo_ws", params)
   357  	require.Nil(t, err)
   358  
   359  	msg := <-cl.ResponsesCh
   360  	if msg.Error != nil {
   361  		t.Fatalf("%+v", err)
   362  	}
   363  	result := new(ResultEcho)
   364  	err = json.Unmarshal(msg.Result, result)
   365  	require.Nil(t, err)
   366  	got := result.Value
   367  	assert.Equal(t, got, val)
   368  }
   369  
   370  // TestWSClientPingPong checks that a client & server exchange pings
   371  // & pongs so connection stays alive.
   372  func TestWSClientPingPong(t *testing.T) {
   373  	cl, err := client.NewWS(tcpAddr, websocketEndpoint)
   374  	require.Nil(t, err)
   375  	cl.SetLogger(log.TestingLogger())
   376  	err = cl.Start()
   377  	require.Nil(t, err)
   378  	t.Cleanup(func() {
   379  		if err := cl.Stop(); err != nil {
   380  			t.Error(err)
   381  		}
   382  	})
   383  
   384  	time.Sleep(6 * time.Second)
   385  }
   386  
   387  func randBytes(t *testing.T) []byte {
   388  	n := mrand.Intn(10) + 2
   389  	buf := make([]byte, n)
   390  	_, err := crand.Read(buf)
   391  	require.Nil(t, err)
   392  	return bytes.ReplaceAll(buf, []byte("="), []byte{100})
   393  }