You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

206 lines
4.8 KiB

  1. package p2p_test
  2. import (
  3. "sync"
  4. "testing"
  5. "github.com/gogo/protobuf/proto"
  6. "github.com/stretchr/testify/mock"
  7. "github.com/stretchr/testify/require"
  8. "github.com/tendermint/tendermint/config"
  9. "github.com/tendermint/tendermint/libs/log"
  10. "github.com/tendermint/tendermint/p2p"
  11. p2pmocks "github.com/tendermint/tendermint/p2p/mocks"
  12. ssproto "github.com/tendermint/tendermint/proto/tendermint/statesync"
  13. )
  14. var (
  15. channelID1 = byte(0x01)
  16. channelID2 = byte(0x02)
  17. p2pCfg = config.DefaultP2PConfig()
  18. testChannelShims = map[p2p.ChannelID]*p2p.ChannelDescriptorShim{
  19. p2p.ChannelID(channelID1): {
  20. MsgType: new(ssproto.Message),
  21. Descriptor: &p2p.ChannelDescriptor{
  22. ID: channelID1,
  23. Priority: 3,
  24. SendQueueCapacity: 10,
  25. RecvMessageCapacity: int(4e6),
  26. },
  27. },
  28. p2p.ChannelID(channelID2): {
  29. MsgType: new(ssproto.Message),
  30. Descriptor: &p2p.ChannelDescriptor{
  31. ID: channelID2,
  32. Priority: 1,
  33. SendQueueCapacity: 4,
  34. RecvMessageCapacity: int(16e6),
  35. },
  36. },
  37. }
  38. )
  39. type reactorShimTestSuite struct {
  40. shim *p2p.ReactorShim
  41. sw *p2p.Switch
  42. }
  43. func setup(t *testing.T, peers []p2p.Peer) *reactorShimTestSuite {
  44. t.Helper()
  45. rts := &reactorShimTestSuite{
  46. shim: p2p.NewReactorShim(log.TestingLogger(), "TestShim", testChannelShims),
  47. }
  48. rts.sw = p2p.MakeSwitch(p2pCfg, 1, "testing", "123.123.123", func(_ int, sw *p2p.Switch) *p2p.Switch {
  49. for _, peer := range peers {
  50. p2p.AddPeerToSwitchPeerSet(sw, peer)
  51. }
  52. sw.AddReactor(rts.shim.Name, rts.shim)
  53. return sw
  54. }, log.TestingLogger())
  55. // start the reactor shim
  56. require.NoError(t, rts.shim.Start())
  57. t.Cleanup(func() {
  58. require.NoError(t, rts.shim.Stop())
  59. for _, chs := range rts.shim.Channels {
  60. chs.Channel.Close()
  61. }
  62. })
  63. return rts
  64. }
  65. func simplePeer(t *testing.T, id string) (*p2pmocks.Peer, p2p.NodeID) {
  66. t.Helper()
  67. peerID := p2p.NodeID(id)
  68. peer := &p2pmocks.Peer{}
  69. peer.On("ID").Return(peerID)
  70. return peer, peerID
  71. }
  72. func TestReactorShim_GetChannel(t *testing.T) {
  73. rts := setup(t, nil)
  74. p2pCh := rts.shim.GetChannel(p2p.ChannelID(channelID1))
  75. require.NotNil(t, p2pCh)
  76. require.Equal(t, p2pCh.ID, p2p.ChannelID(channelID1))
  77. p2pCh = rts.shim.GetChannel(p2p.ChannelID(byte(0x03)))
  78. require.Nil(t, p2pCh)
  79. }
  80. func TestReactorShim_GetChannels(t *testing.T) {
  81. rts := setup(t, nil)
  82. p2pChs := rts.shim.GetChannels()
  83. require.Len(t, p2pChs, 2)
  84. require.Equal(t, p2p.ChannelID(p2pChs[0].ID), p2p.ChannelID(channelID1))
  85. require.Equal(t, p2p.ChannelID(p2pChs[1].ID), p2p.ChannelID(channelID2))
  86. }
  87. func TestReactorShim_AddPeer(t *testing.T) {
  88. peerA, peerIDA := simplePeer(t, "aa")
  89. rts := setup(t, []p2p.Peer{peerA})
  90. var wg sync.WaitGroup
  91. wg.Add(1)
  92. var peerUpdate p2p.PeerUpdate
  93. go func() {
  94. peerUpdate = <-rts.shim.PeerUpdates.Updates()
  95. wg.Done()
  96. }()
  97. rts.shim.AddPeer(peerA)
  98. wg.Wait()
  99. require.Equal(t, peerIDA, peerUpdate.NodeID)
  100. require.Equal(t, p2p.PeerStatusUp, peerUpdate.Status)
  101. }
  102. func TestReactorShim_RemovePeer(t *testing.T) {
  103. peerA, peerIDA := simplePeer(t, "aa")
  104. rts := setup(t, []p2p.Peer{peerA})
  105. var wg sync.WaitGroup
  106. wg.Add(1)
  107. var peerUpdate p2p.PeerUpdate
  108. go func() {
  109. peerUpdate = <-rts.shim.PeerUpdates.Updates()
  110. wg.Done()
  111. }()
  112. rts.shim.RemovePeer(peerA, "test reason")
  113. wg.Wait()
  114. require.Equal(t, peerIDA, peerUpdate.NodeID)
  115. require.Equal(t, p2p.PeerStatusDown, peerUpdate.Status)
  116. }
  117. func TestReactorShim_Receive(t *testing.T) {
  118. peerA, peerIDA := simplePeer(t, "aa")
  119. rts := setup(t, []p2p.Peer{peerA})
  120. msg := &ssproto.Message{
  121. Sum: &ssproto.Message_ChunkRequest{
  122. ChunkRequest: &ssproto.ChunkRequest{Height: 1, Format: 1, Index: 1},
  123. },
  124. }
  125. bz, err := proto.Marshal(msg)
  126. require.NoError(t, err)
  127. var wg sync.WaitGroup
  128. var response *ssproto.Message
  129. peerA.On("Send", channelID1, mock.Anything).Run(func(args mock.Arguments) {
  130. m := &ssproto.Message{}
  131. require.NoError(t, proto.Unmarshal(args[1].([]byte), m))
  132. response = m
  133. wg.Done()
  134. }).Return(true)
  135. p2pCh := rts.shim.Channels[p2p.ChannelID(channelID1)]
  136. wg.Add(2)
  137. // Simulate receiving the envelope in some real reactor and replying back with
  138. // the same envelope and then closing the Channel.
  139. go func() {
  140. e := <-p2pCh.Channel.In
  141. require.Equal(t, peerIDA, e.From)
  142. require.NotNil(t, e.Message)
  143. p2pCh.Channel.Out <- p2p.Envelope{To: e.From, Message: e.Message}
  144. p2pCh.Channel.Close()
  145. wg.Done()
  146. }()
  147. rts.shim.Receive(channelID1, peerA, bz)
  148. // wait until the mock peer called Send and we (fake) proxied the envelope
  149. wg.Wait()
  150. require.NotNil(t, response)
  151. m, err := response.Unwrap()
  152. require.NoError(t, err)
  153. require.Equal(t, msg.GetChunkRequest(), m)
  154. // Since p2pCh was closed in the simulated reactor above, calling Receive
  155. // should not block.
  156. rts.shim.Receive(channelID1, peerA, bz)
  157. require.Empty(t, p2pCh.Channel.In)
  158. peerA.AssertExpectations(t)
  159. }