github.com/vipernet-xyz/tm@v0.34.24/p2p/conn/connection_test.go (about)

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