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.

189 lines
5.2 KiB

p2p: file descriptor leaks (#3150) * close peer's connection to avoid fd leak Fixes #2967 * rename peer#Addr to RemoteAddr * fix test * fixes after Ethan's review * bring back the check * changelog entry * write a test for switch#acceptRoutine * increase timeouts? :( * remove extra assertNPeersWithTimeout * simplify test * assert number of peers (just to be safe) * Cleanup in OnStop * run tests with verbose flag on CircleCI * spawn a reading routine to prevent connection from closing * get port from the listener random port is faster, but often results in ``` panic: listen tcp 127.0.0.1:44068: bind: address already in use [recovered] panic: listen tcp 127.0.0.1:44068: bind: address already in use goroutine 79 [running]: testing.tRunner.func1(0xc0001bd600) /usr/local/go/src/testing/testing.go:792 +0x387 panic(0x974d20, 0xc0001b0500) /usr/local/go/src/runtime/panic.go:513 +0x1b9 github.com/tendermint/tendermint/p2p.MakeSwitch(0xc0000f42a0, 0x0, 0x9fb9cc, 0x9, 0x9fc346, 0xb, 0xb42128, 0x0, 0x0, 0x0, ...) /home/vagrant/go/src/github.com/tendermint/tendermint/p2p/test_util.go:182 +0xa28 github.com/tendermint/tendermint/p2p.MakeConnectedSwitches(0xc0000f42a0, 0x2, 0xb42128, 0xb41eb8, 0x4f1205, 0xc0001bed80, 0x4f16ed) /home/vagrant/go/src/github.com/tendermint/tendermint/p2p/test_util.go:75 +0xf9 github.com/tendermint/tendermint/p2p.MakeSwitchPair(0xbb8d20, 0xc0001bd600, 0xb42128, 0x2f7, 0x4f16c0) /home/vagrant/go/src/github.com/tendermint/tendermint/p2p/switch_test.go:94 +0x4c github.com/tendermint/tendermint/p2p.TestSwitches(0xc0001bd600) /home/vagrant/go/src/github.com/tendermint/tendermint/p2p/switch_test.go:117 +0x58 testing.tRunner(0xc0001bd600, 0xb42038) /usr/local/go/src/testing/testing.go:827 +0xbf created by testing.(*T).Run /usr/local/go/src/testing/testing.go:878 +0x353 exit status 2 FAIL github.com/tendermint/tendermint/p2p 0.350s ```
6 years ago
  1. package p2p
  2. import (
  3. "net"
  4. "sync"
  5. "testing"
  6. "github.com/stretchr/testify/assert"
  7. "github.com/tendermint/tendermint/libs/service"
  8. )
  9. // mockPeer for testing the PeerSet
  10. type mockPeer struct {
  11. service.BaseService
  12. ip net.IP
  13. id ID
  14. }
  15. func (mp *mockPeer) FlushStop() { mp.Stop() } //nolint:errcheck // ignore error
  16. func (mp *mockPeer) TrySend(chID byte, msgBytes []byte) bool { return true }
  17. func (mp *mockPeer) Send(chID byte, msgBytes []byte) bool { return true }
  18. func (mp *mockPeer) NodeInfo() NodeInfo { return DefaultNodeInfo{} }
  19. func (mp *mockPeer) Status() ConnectionStatus { return ConnectionStatus{} }
  20. func (mp *mockPeer) ID() ID { return mp.id }
  21. func (mp *mockPeer) IsOutbound() bool { return false }
  22. func (mp *mockPeer) IsPersistent() bool { return true }
  23. func (mp *mockPeer) Get(s string) interface{} { return s }
  24. func (mp *mockPeer) Set(string, interface{}) {}
  25. func (mp *mockPeer) RemoteIP() net.IP { return mp.ip }
  26. func (mp *mockPeer) SocketAddr() *NetAddress { return nil }
  27. func (mp *mockPeer) RemoteAddr() net.Addr { return &net.TCPAddr{IP: mp.ip, Port: 8800} }
  28. func (mp *mockPeer) CloseConn() error { return nil }
  29. // Returns a mock peer
  30. func newMockPeer(ip net.IP) *mockPeer {
  31. if ip == nil {
  32. ip = net.IP{127, 0, 0, 1}
  33. }
  34. nodeKey := GenNodeKey()
  35. return &mockPeer{
  36. ip: ip,
  37. id: nodeKey.ID,
  38. }
  39. }
  40. func TestPeerSetAddRemoveOne(t *testing.T) {
  41. t.Parallel()
  42. peerSet := NewPeerSet()
  43. var peerList []Peer
  44. for i := 0; i < 5; i++ {
  45. p := newMockPeer(net.IP{127, 0, 0, byte(i)})
  46. if err := peerSet.Add(p); err != nil {
  47. t.Error(err)
  48. }
  49. peerList = append(peerList, p)
  50. }
  51. n := len(peerList)
  52. // 1. Test removing from the front
  53. for i, peerAtFront := range peerList {
  54. removed := peerSet.Remove(peerAtFront)
  55. assert.True(t, removed)
  56. wantSize := n - i - 1
  57. for j := 0; j < 2; j++ {
  58. assert.Equal(t, false, peerSet.Has(peerAtFront.ID()), "#%d Run #%d: failed to remove peer", i, j)
  59. assert.Equal(t, wantSize, peerSet.Size(), "#%d Run #%d: failed to remove peer and decrement size", i, j)
  60. // Test the route of removing the now non-existent element
  61. removed := peerSet.Remove(peerAtFront)
  62. assert.False(t, removed)
  63. }
  64. }
  65. // 2. Next we are testing removing the peer at the end
  66. // a) Replenish the peerSet
  67. for _, peer := range peerList {
  68. if err := peerSet.Add(peer); err != nil {
  69. t.Error(err)
  70. }
  71. }
  72. // b) In reverse, remove each element
  73. for i := n - 1; i >= 0; i-- {
  74. peerAtEnd := peerList[i]
  75. removed := peerSet.Remove(peerAtEnd)
  76. assert.True(t, removed)
  77. assert.Equal(t, false, peerSet.Has(peerAtEnd.ID()), "#%d: failed to remove item at end", i)
  78. assert.Equal(t, i, peerSet.Size(), "#%d: differing sizes after peerSet.Remove(atEndPeer)", i)
  79. }
  80. }
  81. func TestPeerSetAddRemoveMany(t *testing.T) {
  82. t.Parallel()
  83. peerSet := NewPeerSet()
  84. peers := []Peer{}
  85. N := 100
  86. for i := 0; i < N; i++ {
  87. peer := newMockPeer(net.IP{127, 0, 0, byte(i)})
  88. if err := peerSet.Add(peer); err != nil {
  89. t.Errorf("failed to add new peer")
  90. }
  91. if peerSet.Size() != i+1 {
  92. t.Errorf("failed to add new peer and increment size")
  93. }
  94. peers = append(peers, peer)
  95. }
  96. for i, peer := range peers {
  97. removed := peerSet.Remove(peer)
  98. assert.True(t, removed)
  99. if peerSet.Has(peer.ID()) {
  100. t.Errorf("failed to remove peer")
  101. }
  102. if peerSet.Size() != len(peers)-i-1 {
  103. t.Errorf("failed to remove peer and decrement size")
  104. }
  105. }
  106. }
  107. func TestPeerSetAddDuplicate(t *testing.T) {
  108. t.Parallel()
  109. peerSet := NewPeerSet()
  110. peer := newMockPeer(nil)
  111. n := 20
  112. errsChan := make(chan error)
  113. // Add the same asynchronously to test the
  114. // concurrent guarantees of our APIs, and
  115. // our expectation in the end is that only
  116. // one addition succeeded, but the rest are
  117. // instances of ErrSwitchDuplicatePeer.
  118. for i := 0; i < n; i++ {
  119. go func() {
  120. errsChan <- peerSet.Add(peer)
  121. }()
  122. }
  123. // Now collect and tally the results
  124. errsTally := make(map[string]int)
  125. for i := 0; i < n; i++ {
  126. err := <-errsChan
  127. switch err.(type) {
  128. case ErrSwitchDuplicatePeerID:
  129. errsTally["duplicateID"]++
  130. default:
  131. errsTally["other"]++
  132. }
  133. }
  134. // Our next procedure is to ensure that only one addition
  135. // succeeded and that the rest are each ErrSwitchDuplicatePeer.
  136. wantErrCount, gotErrCount := n-1, errsTally["duplicateID"]
  137. assert.Equal(t, wantErrCount, gotErrCount, "invalid ErrSwitchDuplicatePeer count")
  138. wantNilErrCount, gotNilErrCount := 1, errsTally["other"]
  139. assert.Equal(t, wantNilErrCount, gotNilErrCount, "invalid nil errCount")
  140. }
  141. func TestPeerSetGet(t *testing.T) {
  142. t.Parallel()
  143. var (
  144. peerSet = NewPeerSet()
  145. peer = newMockPeer(nil)
  146. )
  147. assert.Nil(t, peerSet.Get(peer.ID()), "expecting a nil lookup, before .Add")
  148. if err := peerSet.Add(peer); err != nil {
  149. t.Fatalf("Failed to add new peer: %v", err)
  150. }
  151. var wg sync.WaitGroup
  152. for i := 0; i < 10; i++ {
  153. // Add them asynchronously to test the
  154. // concurrent guarantees of our APIs.
  155. wg.Add(1)
  156. go func(i int) {
  157. defer wg.Done()
  158. have, want := peerSet.Get(peer.ID()), peer
  159. assert.Equal(t, have, want, "%d: have %v, want %v", i, have, want)
  160. }(i)
  161. }
  162. wg.Wait()
  163. }