github.com/adoriasoft/tendermint@v0.34.0-dev1.0.20200722151356-96d84601a75a/p2p/conn/connection_test.go (about)

     1  package conn
     2  
     3  import (
     4  	"net"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/fortytw2/leaktest"
     9  	"github.com/stretchr/testify/assert"
    10  	"github.com/stretchr/testify/require"
    11  
    12  	"github.com/tendermint/tendermint/libs/log"
    13  	"github.com/tendermint/tendermint/libs/protoio"
    14  	tmp2p "github.com/tendermint/tendermint/proto/tendermint/p2p"
    15  	"github.com/tendermint/tendermint/proto/tendermint/types"
    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()
    47  	defer client.Close()
    48  
    49  	clientConn := createTestMConnection(client)
    50  	err := clientConn.Start()
    51  	require.Nil(t, err)
    52  	defer clientConn.Stop() // nolint:errcheck // ignore for tests
    53  
    54  	msg := []byte("abc")
    55  	assert.True(t, clientConn.Send(0x01, msg))
    56  
    57  	msgLength := 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, msgLength)
    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()
    85  	defer client.Close()
    86  
    87  	mconn := createTestMConnection(client)
    88  	err := mconn.Start()
    89  	require.Nil(t, err)
    90  	defer mconn.Stop() // nolint:errcheck // ignore for tests
    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()
   116  	defer client.Close()
   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() // nolint:errcheck // ignore for tests
   130  
   131  	mconn2 := createTestMConnection(server)
   132  	err = mconn2.Start()
   133  	require.Nil(t, err)
   134  	defer mconn2.Stop() // nolint:errcheck // ignore for tests
   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()
   152  	defer client.Close()
   153  
   154  	mconn := createTestMConnection(client)
   155  	err := mconn.Start()
   156  	require.Nil(t, err)
   157  	defer mconn.Stop() // nolint:errcheck // ignore for tests
   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() // nolint:errcheck // ignore for tests
   181  
   182  	serverGotPing := make(chan struct{})
   183  	go func() {
   184  		// read ping
   185  		var pkt tmp2p.Packet
   186  		err := protoio.NewDelimitedReader(server, maxPingPongPacketSize).ReadMsg(&pkt)
   187  		require.NoError(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() // nolint:errcheck // ignore for tests
   220  
   221  	// sending 3 pongs in a row (abuse)
   222  	protoWriter := protoio.NewDelimitedWriter(server)
   223  
   224  	_, err = protoWriter.WriteMsg(mustWrapPacket(&tmp2p.PacketPong{}))
   225  	require.NoError(t, err)
   226  
   227  	_, err = protoWriter.WriteMsg(mustWrapPacket(&tmp2p.PacketPong{}))
   228  	require.NoError(t, err)
   229  
   230  	_, err = protoWriter.WriteMsg(mustWrapPacket(&tmp2p.PacketPong{}))
   231  	require.NoError(t, err)
   232  
   233  	serverGotPing := make(chan struct{})
   234  	go func() {
   235  		// read ping (one byte)
   236  		var packet tmp2p.Packet
   237  		err := protoio.NewDelimitedReader(server, maxPingPongPacketSize).ReadMsg(&packet)
   238  		require.NoError(t, err)
   239  		serverGotPing <- struct{}{}
   240  
   241  		// respond with pong
   242  		_, err = protoWriter.WriteMsg(mustWrapPacket(&tmp2p.PacketPong{}))
   243  		require.NoError(t, err)
   244  	}()
   245  	<-serverGotPing
   246  
   247  	pongTimerExpired := mconn.config.PongTimeout + 20*time.Millisecond
   248  	select {
   249  	case msgBytes := <-receivedCh:
   250  		t.Fatalf("Expected no data, but got %v", msgBytes)
   251  	case err := <-errorsCh:
   252  		t.Fatalf("Expected no error, but got %v", err)
   253  	case <-time.After(pongTimerExpired):
   254  		assert.True(t, mconn.IsRunning())
   255  	}
   256  }
   257  
   258  func TestMConnectionMultiplePings(t *testing.T) {
   259  	server, client := net.Pipe()
   260  	defer server.Close()
   261  	defer client.Close()
   262  
   263  	receivedCh := make(chan []byte)
   264  	errorsCh := make(chan interface{})
   265  	onReceive := func(chID byte, msgBytes []byte) {
   266  		receivedCh <- msgBytes
   267  	}
   268  	onError := func(r interface{}) {
   269  		errorsCh <- r
   270  	}
   271  	mconn := createMConnectionWithCallbacks(client, onReceive, onError)
   272  	err := mconn.Start()
   273  	require.Nil(t, err)
   274  	defer mconn.Stop() // nolint:errcheck // ignore for tests
   275  
   276  	// sending 3 pings in a row (abuse)
   277  	// see https://github.com/tendermint/tendermint/issues/1190
   278  	protoReader := protoio.NewDelimitedReader(server, maxPingPongPacketSize)
   279  	protoWriter := protoio.NewDelimitedWriter(server)
   280  	var pkt tmp2p.Packet
   281  
   282  	_, err = protoWriter.WriteMsg(mustWrapPacket(&tmp2p.PacketPing{}))
   283  	require.NoError(t, err)
   284  
   285  	err = protoReader.ReadMsg(&pkt)
   286  	require.NoError(t, err)
   287  
   288  	_, err = protoWriter.WriteMsg(mustWrapPacket(&tmp2p.PacketPing{}))
   289  	require.NoError(t, err)
   290  
   291  	err = protoReader.ReadMsg(&pkt)
   292  	require.NoError(t, err)
   293  
   294  	_, err = protoWriter.WriteMsg(mustWrapPacket(&tmp2p.PacketPing{}))
   295  	require.NoError(t, err)
   296  
   297  	err = protoReader.ReadMsg(&pkt)
   298  	require.NoError(t, err)
   299  
   300  	assert.True(t, mconn.IsRunning())
   301  }
   302  
   303  func TestMConnectionPingPongs(t *testing.T) {
   304  	// check that we are not leaking any go-routines
   305  	defer leaktest.CheckTimeout(t, 10*time.Second)()
   306  
   307  	server, client := net.Pipe()
   308  
   309  	defer server.Close()
   310  	defer client.Close()
   311  
   312  	receivedCh := make(chan []byte)
   313  	errorsCh := make(chan interface{})
   314  	onReceive := func(chID byte, msgBytes []byte) {
   315  		receivedCh <- msgBytes
   316  	}
   317  	onError := func(r interface{}) {
   318  		errorsCh <- r
   319  	}
   320  	mconn := createMConnectionWithCallbacks(client, onReceive, onError)
   321  	err := mconn.Start()
   322  	require.Nil(t, err)
   323  	defer mconn.Stop() // nolint:errcheck // ignore for tests
   324  
   325  	serverGotPing := make(chan struct{})
   326  	go func() {
   327  		protoReader := protoio.NewDelimitedReader(server, maxPingPongPacketSize)
   328  		protoWriter := protoio.NewDelimitedWriter(server)
   329  		var pkt tmp2p.PacketPing
   330  
   331  		// read ping
   332  		err = protoReader.ReadMsg(&pkt)
   333  		require.NoError(t, err)
   334  		serverGotPing <- struct{}{}
   335  
   336  		// respond with pong
   337  		_, err = protoWriter.WriteMsg(mustWrapPacket(&tmp2p.PacketPong{}))
   338  		require.NoError(t, err)
   339  
   340  		time.Sleep(mconn.config.PingInterval)
   341  
   342  		// read ping
   343  		err = protoReader.ReadMsg(&pkt)
   344  		require.NoError(t, err)
   345  		serverGotPing <- struct{}{}
   346  
   347  		// respond with pong
   348  		_, err = protoWriter.WriteMsg(mustWrapPacket(&tmp2p.PacketPong{}))
   349  		require.NoError(t, err)
   350  	}()
   351  	<-serverGotPing
   352  	<-serverGotPing
   353  
   354  	pongTimerExpired := (mconn.config.PongTimeout + 20*time.Millisecond) * 2
   355  	select {
   356  	case msgBytes := <-receivedCh:
   357  		t.Fatalf("Expected no data, but got %v", msgBytes)
   358  	case err := <-errorsCh:
   359  		t.Fatalf("Expected no error, but got %v", err)
   360  	case <-time.After(2 * pongTimerExpired):
   361  		assert.True(t, mconn.IsRunning())
   362  	}
   363  }
   364  
   365  func TestMConnectionStopsAndReturnsError(t *testing.T) {
   366  	server, client := NetPipe()
   367  	defer server.Close()
   368  	defer client.Close()
   369  
   370  	receivedCh := make(chan []byte)
   371  	errorsCh := make(chan interface{})
   372  	onReceive := func(chID byte, msgBytes []byte) {
   373  		receivedCh <- msgBytes
   374  	}
   375  	onError := func(r interface{}) {
   376  		errorsCh <- r
   377  	}
   378  	mconn := createMConnectionWithCallbacks(client, onReceive, onError)
   379  	err := mconn.Start()
   380  	require.Nil(t, err)
   381  	defer mconn.Stop() // nolint:errcheck // ignore for tests
   382  
   383  	if err := client.Close(); err != nil {
   384  		t.Error(err)
   385  	}
   386  
   387  	select {
   388  	case receivedBytes := <-receivedCh:
   389  		t.Fatalf("Expected error, got %v", receivedBytes)
   390  	case err := <-errorsCh:
   391  		assert.NotNil(t, err)
   392  		assert.False(t, mconn.IsRunning())
   393  	case <-time.After(500 * time.Millisecond):
   394  		t.Fatal("Did not receive error in 500ms")
   395  	}
   396  }
   397  
   398  func newClientAndServerConnsForReadErrors(t *testing.T, chOnErr chan struct{}) (*MConnection, *MConnection) {
   399  	server, client := NetPipe()
   400  
   401  	onReceive := func(chID byte, msgBytes []byte) {}
   402  	onError := func(r interface{}) {}
   403  
   404  	// create client conn with two channels
   405  	chDescs := []*ChannelDescriptor{
   406  		{ID: 0x01, Priority: 1, SendQueueCapacity: 1},
   407  		{ID: 0x02, Priority: 1, SendQueueCapacity: 1},
   408  	}
   409  	mconnClient := NewMConnection(client, chDescs, onReceive, onError)
   410  	mconnClient.SetLogger(log.TestingLogger().With("module", "client"))
   411  	err := mconnClient.Start()
   412  	require.Nil(t, err)
   413  
   414  	// create server conn with 1 channel
   415  	// it fires on chOnErr when there's an error
   416  	serverLogger := log.TestingLogger().With("module", "server")
   417  	onError = func(r interface{}) {
   418  		chOnErr <- struct{}{}
   419  	}
   420  	mconnServer := createMConnectionWithCallbacks(server, onReceive, onError)
   421  	mconnServer.SetLogger(serverLogger)
   422  	err = mconnServer.Start()
   423  	require.Nil(t, err)
   424  	return mconnClient, mconnServer
   425  }
   426  
   427  func expectSend(ch chan struct{}) bool {
   428  	after := time.After(time.Second * 5)
   429  	select {
   430  	case <-ch:
   431  		return true
   432  	case <-after:
   433  		return false
   434  	}
   435  }
   436  
   437  func TestMConnectionReadErrorBadEncoding(t *testing.T) {
   438  	chOnErr := make(chan struct{})
   439  	mconnClient, mconnServer := newClientAndServerConnsForReadErrors(t, chOnErr)
   440  
   441  	client := mconnClient.conn
   442  
   443  	// Write it.
   444  	_, err := client.Write([]byte{1, 2, 3, 4, 5})
   445  	require.NoError(t, err)
   446  	assert.True(t, expectSend(chOnErr), "badly encoded msgPacket")
   447  
   448  	t.Cleanup(func() {
   449  		if err := mconnClient.Stop(); err != nil {
   450  			t.Log(err)
   451  		}
   452  	})
   453  
   454  	t.Cleanup(func() {
   455  		if err := mconnServer.Stop(); err != nil {
   456  			t.Log(err)
   457  		}
   458  	})
   459  }
   460  
   461  func TestMConnectionReadErrorUnknownChannel(t *testing.T) {
   462  	chOnErr := make(chan struct{})
   463  	mconnClient, mconnServer := newClientAndServerConnsForReadErrors(t, chOnErr)
   464  
   465  	msg := []byte("Ant-Man")
   466  
   467  	// fail to send msg on channel unknown by client
   468  	assert.False(t, mconnClient.Send(0x03, msg))
   469  
   470  	// send msg on channel unknown by the server.
   471  	// should cause an error
   472  	assert.True(t, mconnClient.Send(0x02, msg))
   473  	assert.True(t, expectSend(chOnErr), "unknown channel")
   474  
   475  	t.Cleanup(func() {
   476  		if err := mconnClient.Stop(); err != nil {
   477  			t.Log(err)
   478  		}
   479  	})
   480  
   481  	t.Cleanup(func() {
   482  		if err := mconnServer.Stop(); err != nil {
   483  			t.Log(err)
   484  		}
   485  	})
   486  }
   487  
   488  func TestMConnectionReadErrorLongMessage(t *testing.T) {
   489  	chOnErr := make(chan struct{})
   490  	chOnRcv := make(chan struct{})
   491  
   492  	mconnClient, mconnServer := newClientAndServerConnsForReadErrors(t, chOnErr)
   493  	defer mconnClient.Stop() // nolint:errcheck // ignore for tests
   494  	defer mconnServer.Stop() // nolint:errcheck // ignore for tests
   495  
   496  	mconnServer.onReceive = func(chID byte, msgBytes []byte) {
   497  		chOnRcv <- struct{}{}
   498  	}
   499  
   500  	client := mconnClient.conn
   501  	protoWriter := protoio.NewDelimitedWriter(client)
   502  
   503  	// send msg thats just right
   504  	var packet = tmp2p.PacketMsg{
   505  		ChannelID: 0x01,
   506  		EOF:       true,
   507  		Data:      make([]byte, mconnClient.config.MaxPacketMsgPayloadSize),
   508  	}
   509  
   510  	_, err := protoWriter.WriteMsg(mustWrapPacket(&packet))
   511  	require.NoError(t, err)
   512  	assert.True(t, expectSend(chOnRcv), "msg just right")
   513  
   514  	// send msg thats too long
   515  	packet = tmp2p.PacketMsg{
   516  		ChannelID: 0x01,
   517  		EOF:       true,
   518  		Data:      make([]byte, mconnClient.config.MaxPacketMsgPayloadSize+100),
   519  	}
   520  
   521  	_, err = protoWriter.WriteMsg(mustWrapPacket(&packet))
   522  	require.Error(t, err)
   523  	assert.True(t, expectSend(chOnErr), "msg too long")
   524  }
   525  
   526  func TestMConnectionReadErrorUnknownMsgType(t *testing.T) {
   527  	chOnErr := make(chan struct{})
   528  	mconnClient, mconnServer := newClientAndServerConnsForReadErrors(t, chOnErr)
   529  	defer mconnClient.Stop() // nolint:errcheck // ignore for tests
   530  	defer mconnServer.Stop() // nolint:errcheck // ignore for tests
   531  
   532  	// send msg with unknown msg type
   533  	_, err := protoio.NewDelimitedWriter(mconnClient.conn).WriteMsg(&types.Header{ChainID: "x"})
   534  	require.NoError(t, err)
   535  	assert.True(t, expectSend(chOnErr), "unknown msg type")
   536  }
   537  
   538  func TestMConnectionTrySend(t *testing.T) {
   539  	server, client := NetPipe()
   540  	defer server.Close()
   541  	defer client.Close()
   542  
   543  	mconn := createTestMConnection(client)
   544  	err := mconn.Start()
   545  	require.Nil(t, err)
   546  	defer mconn.Stop() // nolint:errcheck // ignore for tests
   547  
   548  	msg := []byte("Semicolon-Woman")
   549  	resultCh := make(chan string, 2)
   550  	assert.True(t, mconn.TrySend(0x01, msg))
   551  	_, err = server.Read(make([]byte, len(msg)))
   552  	require.NoError(t, err)
   553  	assert.True(t, mconn.CanSend(0x01))
   554  	assert.True(t, mconn.TrySend(0x01, msg))
   555  	assert.False(t, mconn.CanSend(0x01))
   556  	go func() {
   557  		mconn.TrySend(0x01, msg)
   558  		resultCh <- "TrySend"
   559  	}()
   560  	assert.False(t, mconn.CanSend(0x01))
   561  	assert.False(t, mconn.TrySend(0x01, msg))
   562  	assert.Equal(t, "TrySend", <-resultCh)
   563  }