github.com/devwanda/aphelion-staking@v0.33.9/p2p/conn/connection_test.go (about)

     1  package conn
     2  
     3  import (
     4  	"bytes"
     5  	"net"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/fortytw2/leaktest"
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  
    13  	amino "github.com/evdatsion/go-amino"
    14  
    15  	"github.com/devwanda/aphelion-staking/libs/log"
    16  )
    17  
    18  const maxPingPongPacketSize = 1024 // bytes
    19  
    20  func createTestMConnection(conn net.Conn) *MConnection {
    21  	onReceive := func(chID byte, msgBytes []byte) {
    22  	}
    23  	onError := func(r interface{}) {
    24  	}
    25  	c := createMConnectionWithCallbacks(conn, onReceive, onError)
    26  	c.SetLogger(log.TestingLogger())
    27  	return c
    28  }
    29  
    30  func createMConnectionWithCallbacks(
    31  	conn net.Conn,
    32  	onReceive func(chID byte, msgBytes []byte),
    33  	onError func(r interface{}),
    34  ) *MConnection {
    35  	cfg := DefaultMConnConfig()
    36  	cfg.PingInterval = 90 * time.Millisecond
    37  	cfg.PongTimeout = 45 * time.Millisecond
    38  	chDescs := []*ChannelDescriptor{{ID: 0x01, Priority: 1, SendQueueCapacity: 1}}
    39  	c := NewMConnectionWithConfig(conn, chDescs, onReceive, onError, cfg)
    40  	c.SetLogger(log.TestingLogger())
    41  	return c
    42  }
    43  
    44  func TestMConnectionSendFlushStop(t *testing.T) {
    45  	server, client := NetPipe()
    46  	defer server.Close() // nolint: errcheck
    47  	defer client.Close() // nolint: errcheck
    48  
    49  	clientConn := createTestMConnection(client)
    50  	err := clientConn.Start()
    51  	require.Nil(t, err)
    52  	defer clientConn.Stop()
    53  
    54  	msg := []byte("abc")
    55  	assert.True(t, clientConn.Send(0x01, msg))
    56  
    57  	aminoMsgLength := 14
    58  
    59  	// start the reader in a new routine, so we can flush
    60  	errCh := make(chan error)
    61  	go func() {
    62  		msgB := make([]byte, aminoMsgLength)
    63  		_, err := server.Read(msgB)
    64  		if err != nil {
    65  			t.Error(err)
    66  			return
    67  		}
    68  		errCh <- err
    69  	}()
    70  
    71  	// stop the conn - it should flush all conns
    72  	clientConn.FlushStop()
    73  
    74  	timer := time.NewTimer(3 * time.Second)
    75  	select {
    76  	case <-errCh:
    77  	case <-timer.C:
    78  		t.Error("timed out waiting for msgs to be read")
    79  	}
    80  }
    81  
    82  func TestMConnectionSend(t *testing.T) {
    83  	server, client := NetPipe()
    84  	defer server.Close() // nolint: errcheck
    85  	defer client.Close() // nolint: errcheck
    86  
    87  	mconn := createTestMConnection(client)
    88  	err := mconn.Start()
    89  	require.Nil(t, err)
    90  	defer mconn.Stop()
    91  
    92  	msg := []byte("Ant-Man")
    93  	assert.True(t, mconn.Send(0x01, msg))
    94  	// Note: subsequent Send/TrySend calls could pass because we are reading from
    95  	// the send queue in a separate goroutine.
    96  	_, err = server.Read(make([]byte, len(msg)))
    97  	if err != nil {
    98  		t.Error(err)
    99  	}
   100  	assert.True(t, mconn.CanSend(0x01))
   101  
   102  	msg = []byte("Spider-Man")
   103  	assert.True(t, mconn.TrySend(0x01, msg))
   104  	_, err = server.Read(make([]byte, len(msg)))
   105  	if err != nil {
   106  		t.Error(err)
   107  	}
   108  
   109  	assert.False(t, mconn.CanSend(0x05), "CanSend should return false because channel is unknown")
   110  	assert.False(t, mconn.Send(0x05, []byte("Absorbing Man")), "Send should return false because channel is unknown")
   111  }
   112  
   113  func TestMConnectionReceive(t *testing.T) {
   114  	server, client := NetPipe()
   115  	defer server.Close() // nolint: errcheck
   116  	defer client.Close() // nolint: errcheck
   117  
   118  	receivedCh := make(chan []byte)
   119  	errorsCh := make(chan interface{})
   120  	onReceive := func(chID byte, msgBytes []byte) {
   121  		receivedCh <- msgBytes
   122  	}
   123  	onError := func(r interface{}) {
   124  		errorsCh <- r
   125  	}
   126  	mconn1 := createMConnectionWithCallbacks(client, onReceive, onError)
   127  	err := mconn1.Start()
   128  	require.Nil(t, err)
   129  	defer mconn1.Stop()
   130  
   131  	mconn2 := createTestMConnection(server)
   132  	err = mconn2.Start()
   133  	require.Nil(t, err)
   134  	defer mconn2.Stop()
   135  
   136  	msg := []byte("Cyclops")
   137  	assert.True(t, mconn2.Send(0x01, msg))
   138  
   139  	select {
   140  	case receivedBytes := <-receivedCh:
   141  		assert.Equal(t, msg, receivedBytes)
   142  	case err := <-errorsCh:
   143  		t.Fatalf("Expected %s, got %+v", msg, err)
   144  	case <-time.After(500 * time.Millisecond):
   145  		t.Fatalf("Did not receive %s message in 500ms", msg)
   146  	}
   147  }
   148  
   149  func TestMConnectionStatus(t *testing.T) {
   150  	server, client := NetPipe()
   151  	defer server.Close() // nolint: errcheck
   152  	defer client.Close() // nolint: errcheck
   153  
   154  	mconn := createTestMConnection(client)
   155  	err := mconn.Start()
   156  	require.Nil(t, err)
   157  	defer mconn.Stop()
   158  
   159  	status := mconn.Status()
   160  	assert.NotNil(t, status)
   161  	assert.Zero(t, status.Channels[0].SendQueueSize)
   162  }
   163  
   164  func TestMConnectionPongTimeoutResultsInError(t *testing.T) {
   165  	server, client := net.Pipe()
   166  	defer server.Close()
   167  	defer client.Close()
   168  
   169  	receivedCh := make(chan []byte)
   170  	errorsCh := make(chan interface{})
   171  	onReceive := func(chID byte, msgBytes []byte) {
   172  		receivedCh <- msgBytes
   173  	}
   174  	onError := func(r interface{}) {
   175  		errorsCh <- r
   176  	}
   177  	mconn := createMConnectionWithCallbacks(client, onReceive, onError)
   178  	err := mconn.Start()
   179  	require.Nil(t, err)
   180  	defer mconn.Stop()
   181  
   182  	serverGotPing := make(chan struct{})
   183  	go func() {
   184  		// read ping
   185  		var pkt PacketPing
   186  		_, err = cdc.UnmarshalBinaryLengthPrefixedReader(server, &pkt, maxPingPongPacketSize)
   187  		assert.Nil(t, err)
   188  		serverGotPing <- struct{}{}
   189  	}()
   190  	<-serverGotPing
   191  
   192  	pongTimerExpired := mconn.config.PongTimeout + 20*time.Millisecond
   193  	select {
   194  	case msgBytes := <-receivedCh:
   195  		t.Fatalf("Expected error, but got %v", msgBytes)
   196  	case err := <-errorsCh:
   197  		assert.NotNil(t, err)
   198  	case <-time.After(pongTimerExpired):
   199  		t.Fatalf("Expected to receive error after %v", pongTimerExpired)
   200  	}
   201  }
   202  
   203  func TestMConnectionMultiplePongsInTheBeginning(t *testing.T) {
   204  	server, client := net.Pipe()
   205  	defer server.Close()
   206  	defer client.Close()
   207  
   208  	receivedCh := make(chan []byte)
   209  	errorsCh := make(chan interface{})
   210  	onReceive := func(chID byte, msgBytes []byte) {
   211  		receivedCh <- msgBytes
   212  	}
   213  	onError := func(r interface{}) {
   214  		errorsCh <- r
   215  	}
   216  	mconn := createMConnectionWithCallbacks(client, onReceive, onError)
   217  	err := mconn.Start()
   218  	require.Nil(t, err)
   219  	defer mconn.Stop()
   220  
   221  	// sending 3 pongs in a row (abuse)
   222  	_, err = server.Write(cdc.MustMarshalBinaryLengthPrefixed(PacketPong{}))
   223  	require.Nil(t, err)
   224  	_, err = server.Write(cdc.MustMarshalBinaryLengthPrefixed(PacketPong{}))
   225  	require.Nil(t, err)
   226  	_, err = server.Write(cdc.MustMarshalBinaryLengthPrefixed(PacketPong{}))
   227  	require.Nil(t, err)
   228  
   229  	serverGotPing := make(chan struct{})
   230  	go func() {
   231  		// read ping (one byte)
   232  		var (
   233  			packet Packet
   234  			err    error
   235  		)
   236  		_, err = cdc.UnmarshalBinaryLengthPrefixedReader(server, &packet, maxPingPongPacketSize)
   237  		require.Nil(t, err)
   238  		serverGotPing <- struct{}{}
   239  		// respond with pong
   240  		_, err = server.Write(cdc.MustMarshalBinaryLengthPrefixed(PacketPong{}))
   241  		require.Nil(t, err)
   242  	}()
   243  	<-serverGotPing
   244  
   245  	pongTimerExpired := mconn.config.PongTimeout + 20*time.Millisecond
   246  	select {
   247  	case msgBytes := <-receivedCh:
   248  		t.Fatalf("Expected no data, but got %v", msgBytes)
   249  	case err := <-errorsCh:
   250  		t.Fatalf("Expected no error, but got %v", err)
   251  	case <-time.After(pongTimerExpired):
   252  		assert.True(t, mconn.IsRunning())
   253  	}
   254  }
   255  
   256  func TestMConnectionMultiplePings(t *testing.T) {
   257  	server, client := net.Pipe()
   258  	defer server.Close()
   259  	defer client.Close()
   260  
   261  	receivedCh := make(chan []byte)
   262  	errorsCh := make(chan interface{})
   263  	onReceive := func(chID byte, msgBytes []byte) {
   264  		receivedCh <- msgBytes
   265  	}
   266  	onError := func(r interface{}) {
   267  		errorsCh <- r
   268  	}
   269  	mconn := createMConnectionWithCallbacks(client, onReceive, onError)
   270  	err := mconn.Start()
   271  	require.Nil(t, err)
   272  	defer mconn.Stop()
   273  
   274  	// sending 3 pings in a row (abuse)
   275  	// see https://github.com/devwanda/aphelion-staking/issues/1190
   276  	_, err = server.Write(cdc.MustMarshalBinaryLengthPrefixed(PacketPing{}))
   277  	require.Nil(t, err)
   278  	var pkt PacketPong
   279  	_, err = cdc.UnmarshalBinaryLengthPrefixedReader(server, &pkt, maxPingPongPacketSize)
   280  	require.Nil(t, err)
   281  	_, err = server.Write(cdc.MustMarshalBinaryLengthPrefixed(PacketPing{}))
   282  	require.Nil(t, err)
   283  	_, err = cdc.UnmarshalBinaryLengthPrefixedReader(server, &pkt, maxPingPongPacketSize)
   284  	require.Nil(t, err)
   285  	_, err = server.Write(cdc.MustMarshalBinaryLengthPrefixed(PacketPing{}))
   286  	require.Nil(t, err)
   287  	_, err = cdc.UnmarshalBinaryLengthPrefixedReader(server, &pkt, maxPingPongPacketSize)
   288  	require.Nil(t, err)
   289  
   290  	assert.True(t, mconn.IsRunning())
   291  }
   292  
   293  func TestMConnectionPingPongs(t *testing.T) {
   294  	// check that we are not leaking any go-routines
   295  	defer leaktest.CheckTimeout(t, 10*time.Second)()
   296  
   297  	server, client := net.Pipe()
   298  
   299  	defer server.Close()
   300  	defer client.Close()
   301  
   302  	receivedCh := make(chan []byte)
   303  	errorsCh := make(chan interface{})
   304  	onReceive := func(chID byte, msgBytes []byte) {
   305  		receivedCh <- msgBytes
   306  	}
   307  	onError := func(r interface{}) {
   308  		errorsCh <- r
   309  	}
   310  	mconn := createMConnectionWithCallbacks(client, onReceive, onError)
   311  	err := mconn.Start()
   312  	require.Nil(t, err)
   313  	defer mconn.Stop()
   314  
   315  	serverGotPing := make(chan struct{})
   316  	go func() {
   317  		// read ping
   318  		var pkt PacketPing
   319  		_, err = cdc.UnmarshalBinaryLengthPrefixedReader(server, &pkt, maxPingPongPacketSize)
   320  		require.Nil(t, err)
   321  		serverGotPing <- struct{}{}
   322  		// respond with pong
   323  		_, err = server.Write(cdc.MustMarshalBinaryLengthPrefixed(PacketPong{}))
   324  		require.Nil(t, err)
   325  
   326  		time.Sleep(mconn.config.PingInterval)
   327  
   328  		// read ping
   329  		_, err = cdc.UnmarshalBinaryLengthPrefixedReader(server, &pkt, maxPingPongPacketSize)
   330  		require.Nil(t, err)
   331  		// respond with pong
   332  		_, err = server.Write(cdc.MustMarshalBinaryLengthPrefixed(PacketPong{}))
   333  		require.Nil(t, err)
   334  	}()
   335  	<-serverGotPing
   336  
   337  	pongTimerExpired := (mconn.config.PongTimeout + 20*time.Millisecond) * 2
   338  	select {
   339  	case msgBytes := <-receivedCh:
   340  		t.Fatalf("Expected no data, but got %v", msgBytes)
   341  	case err := <-errorsCh:
   342  		t.Fatalf("Expected no error, but got %v", err)
   343  	case <-time.After(2 * pongTimerExpired):
   344  		assert.True(t, mconn.IsRunning())
   345  	}
   346  }
   347  
   348  func TestMConnectionStopsAndReturnsError(t *testing.T) {
   349  	server, client := NetPipe()
   350  	defer server.Close() // nolint: errcheck
   351  	defer client.Close() // nolint: errcheck
   352  
   353  	receivedCh := make(chan []byte)
   354  	errorsCh := make(chan interface{})
   355  	onReceive := func(chID byte, msgBytes []byte) {
   356  		receivedCh <- msgBytes
   357  	}
   358  	onError := func(r interface{}) {
   359  		errorsCh <- r
   360  	}
   361  	mconn := createMConnectionWithCallbacks(client, onReceive, onError)
   362  	err := mconn.Start()
   363  	require.Nil(t, err)
   364  	defer mconn.Stop()
   365  
   366  	if err := client.Close(); err != nil {
   367  		t.Error(err)
   368  	}
   369  
   370  	select {
   371  	case receivedBytes := <-receivedCh:
   372  		t.Fatalf("Expected error, got %v", receivedBytes)
   373  	case err := <-errorsCh:
   374  		assert.NotNil(t, err)
   375  		assert.False(t, mconn.IsRunning())
   376  	case <-time.After(500 * time.Millisecond):
   377  		t.Fatal("Did not receive error in 500ms")
   378  	}
   379  }
   380  
   381  func newClientAndServerConnsForReadErrors(t *testing.T, chOnErr chan struct{}) (*MConnection, *MConnection) {
   382  	server, client := NetPipe()
   383  
   384  	onReceive := func(chID byte, msgBytes []byte) {}
   385  	onError := func(r interface{}) {}
   386  
   387  	// create client conn with two channels
   388  	chDescs := []*ChannelDescriptor{
   389  		{ID: 0x01, Priority: 1, SendQueueCapacity: 1},
   390  		{ID: 0x02, Priority: 1, SendQueueCapacity: 1},
   391  	}
   392  	mconnClient := NewMConnection(client, chDescs, onReceive, onError)
   393  	mconnClient.SetLogger(log.TestingLogger().With("module", "client"))
   394  	err := mconnClient.Start()
   395  	require.Nil(t, err)
   396  
   397  	// create server conn with 1 channel
   398  	// it fires on chOnErr when there's an error
   399  	serverLogger := log.TestingLogger().With("module", "server")
   400  	onError = func(r interface{}) {
   401  		chOnErr <- struct{}{}
   402  	}
   403  	mconnServer := createMConnectionWithCallbacks(server, onReceive, onError)
   404  	mconnServer.SetLogger(serverLogger)
   405  	err = mconnServer.Start()
   406  	require.Nil(t, err)
   407  	return mconnClient, mconnServer
   408  }
   409  
   410  func expectSend(ch chan struct{}) bool {
   411  	after := time.After(time.Second * 5)
   412  	select {
   413  	case <-ch:
   414  		return true
   415  	case <-after:
   416  		return false
   417  	}
   418  }
   419  
   420  func TestMConnectionReadErrorBadEncoding(t *testing.T) {
   421  	chOnErr := make(chan struct{})
   422  	mconnClient, mconnServer := newClientAndServerConnsForReadErrors(t, chOnErr)
   423  	defer mconnClient.Stop()
   424  	defer mconnServer.Stop()
   425  
   426  	client := mconnClient.conn
   427  
   428  	// send badly encoded msgPacket
   429  	bz := cdc.MustMarshalBinaryLengthPrefixed(PacketMsg{})
   430  	bz[4] += 0x01 // Invalid prefix bytes.
   431  
   432  	// Write it.
   433  	_, err := client.Write(bz)
   434  	assert.Nil(t, err)
   435  	assert.True(t, expectSend(chOnErr), "badly encoded msgPacket")
   436  }
   437  
   438  func TestMConnectionReadErrorUnknownChannel(t *testing.T) {
   439  	chOnErr := make(chan struct{})
   440  	mconnClient, mconnServer := newClientAndServerConnsForReadErrors(t, chOnErr)
   441  	defer mconnClient.Stop()
   442  	defer mconnServer.Stop()
   443  
   444  	msg := []byte("Ant-Man")
   445  
   446  	// fail to send msg on channel unknown by client
   447  	assert.False(t, mconnClient.Send(0x03, msg))
   448  
   449  	// send msg on channel unknown by the server.
   450  	// should cause an error
   451  	assert.True(t, mconnClient.Send(0x02, msg))
   452  	assert.True(t, expectSend(chOnErr), "unknown channel")
   453  }
   454  
   455  func TestMConnectionReadErrorLongMessage(t *testing.T) {
   456  	chOnErr := make(chan struct{})
   457  	chOnRcv := make(chan struct{})
   458  
   459  	mconnClient, mconnServer := newClientAndServerConnsForReadErrors(t, chOnErr)
   460  	defer mconnClient.Stop()
   461  	defer mconnServer.Stop()
   462  
   463  	mconnServer.onReceive = func(chID byte, msgBytes []byte) {
   464  		chOnRcv <- struct{}{}
   465  	}
   466  
   467  	client := mconnClient.conn
   468  
   469  	// send msg thats just right
   470  	var err error
   471  	var buf = new(bytes.Buffer)
   472  	var packet = PacketMsg{
   473  		ChannelID: 0x01,
   474  		EOF:       1,
   475  		Bytes:     make([]byte, mconnClient.config.MaxPacketMsgPayloadSize),
   476  	}
   477  	_, err = cdc.MarshalBinaryLengthPrefixedWriter(buf, packet)
   478  	assert.Nil(t, err)
   479  	_, err = client.Write(buf.Bytes())
   480  	assert.Nil(t, err)
   481  	assert.True(t, expectSend(chOnRcv), "msg just right")
   482  
   483  	// send msg thats too long
   484  	buf = new(bytes.Buffer)
   485  	packet = PacketMsg{
   486  		ChannelID: 0x01,
   487  		EOF:       1,
   488  		Bytes:     make([]byte, mconnClient.config.MaxPacketMsgPayloadSize+100),
   489  	}
   490  	_, err = cdc.MarshalBinaryLengthPrefixedWriter(buf, packet)
   491  	assert.Nil(t, err)
   492  	_, err = client.Write(buf.Bytes())
   493  	assert.NotNil(t, err)
   494  	assert.True(t, expectSend(chOnErr), "msg too long")
   495  }
   496  
   497  func TestMConnectionReadErrorUnknownMsgType(t *testing.T) {
   498  	chOnErr := make(chan struct{})
   499  	mconnClient, mconnServer := newClientAndServerConnsForReadErrors(t, chOnErr)
   500  	defer mconnClient.Stop()
   501  	defer mconnServer.Stop()
   502  
   503  	// send msg with unknown msg type
   504  	err := amino.EncodeUvarint(mconnClient.conn, 4)
   505  	assert.Nil(t, err)
   506  	_, err = mconnClient.conn.Write([]byte{0xFF, 0xFF, 0xFF, 0xFF})
   507  	assert.Nil(t, err)
   508  	assert.True(t, expectSend(chOnErr), "unknown msg type")
   509  }
   510  
   511  func TestMConnectionTrySend(t *testing.T) {
   512  	server, client := NetPipe()
   513  	defer server.Close()
   514  	defer client.Close()
   515  
   516  	mconn := createTestMConnection(client)
   517  	err := mconn.Start()
   518  	require.Nil(t, err)
   519  	defer mconn.Stop()
   520  
   521  	msg := []byte("Semicolon-Woman")
   522  	resultCh := make(chan string, 2)
   523  	assert.True(t, mconn.TrySend(0x01, msg))
   524  	server.Read(make([]byte, len(msg)))
   525  	assert.True(t, mconn.CanSend(0x01))
   526  	assert.True(t, mconn.TrySend(0x01, msg))
   527  	assert.False(t, mconn.CanSend(0x01))
   528  	go func() {
   529  		mconn.TrySend(0x01, msg)
   530  		resultCh <- "TrySend"
   531  	}()
   532  	assert.False(t, mconn.CanSend(0x01))
   533  	assert.False(t, mconn.TrySend(0x01, msg))
   534  	assert.Equal(t, "TrySend", <-resultCh)
   535  }