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.

190 lines
5.3 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/crypto/ed25519"
  8. cmn "github.com/tendermint/tendermint/libs/common"
  9. )
  10. // mockPeer for testing the PeerSet
  11. type mockPeer struct {
  12. cmn.BaseService
  13. ip net.IP
  14. id ID
  15. }
  16. func (mp *mockPeer) FlushStop() { mp.Stop() }
  17. func (mp *mockPeer) TrySend(chID byte, msgBytes []byte) bool { return true }
  18. func (mp *mockPeer) Send(chID byte, msgBytes []byte) bool { return true }
  19. func (mp *mockPeer) NodeInfo() NodeInfo { return DefaultNodeInfo{} }
  20. func (mp *mockPeer) Status() ConnectionStatus { return ConnectionStatus{} }
  21. func (mp *mockPeer) ID() ID { return mp.id }
  22. func (mp *mockPeer) IsOutbound() bool { return false }
  23. func (mp *mockPeer) IsPersistent() bool { return true }
  24. func (mp *mockPeer) Get(s string) interface{} { return s }
  25. func (mp *mockPeer) Set(string, interface{}) {}
  26. func (mp *mockPeer) RemoteIP() net.IP { return mp.ip }
  27. func (mp *mockPeer) SocketAddr() *NetAddress { return nil }
  28. func (mp *mockPeer) RemoteAddr() net.Addr { return &net.TCPAddr{IP: mp.ip, Port: 8800} }
  29. func (mp *mockPeer) CloseConn() error { return nil }
  30. // Returns a mock peer
  31. func newMockPeer(ip net.IP) *mockPeer {
  32. if ip == nil {
  33. ip = net.IP{127, 0, 0, 1}
  34. }
  35. nodeKey := NodeKey{PrivKey: ed25519.GenPrivKey()}
  36. return &mockPeer{
  37. ip: ip,
  38. id: nodeKey.ID(),
  39. }
  40. }
  41. func TestPeerSetAddRemoveOne(t *testing.T) {
  42. t.Parallel()
  43. peerSet := NewPeerSet()
  44. var peerList []Peer
  45. for i := 0; i < 5; i++ {
  46. p := newMockPeer(net.IP{127, 0, 0, byte(i)})
  47. if err := peerSet.Add(p); err != nil {
  48. t.Error(err)
  49. }
  50. peerList = append(peerList, p)
  51. }
  52. n := len(peerList)
  53. // 1. Test removing from the front
  54. for i, peerAtFront := range peerList {
  55. removed := peerSet.Remove(peerAtFront)
  56. assert.True(t, removed)
  57. wantSize := n - i - 1
  58. for j := 0; j < 2; j++ {
  59. assert.Equal(t, false, peerSet.Has(peerAtFront.ID()), "#%d Run #%d: failed to remove peer", i, j)
  60. assert.Equal(t, wantSize, peerSet.Size(), "#%d Run #%d: failed to remove peer and decrement size", i, j)
  61. // Test the route of removing the now non-existent element
  62. removed := peerSet.Remove(peerAtFront)
  63. assert.False(t, removed)
  64. }
  65. }
  66. // 2. Next we are testing removing the peer at the end
  67. // a) Replenish the peerSet
  68. for _, peer := range peerList {
  69. if err := peerSet.Add(peer); err != nil {
  70. t.Error(err)
  71. }
  72. }
  73. // b) In reverse, remove each element
  74. for i := n - 1; i >= 0; i-- {
  75. peerAtEnd := peerList[i]
  76. removed := peerSet.Remove(peerAtEnd)
  77. assert.True(t, removed)
  78. assert.Equal(t, false, peerSet.Has(peerAtEnd.ID()), "#%d: failed to remove item at end", i)
  79. assert.Equal(t, i, peerSet.Size(), "#%d: differing sizes after peerSet.Remove(atEndPeer)", i)
  80. }
  81. }
  82. func TestPeerSetAddRemoveMany(t *testing.T) {
  83. t.Parallel()
  84. peerSet := NewPeerSet()
  85. peers := []Peer{}
  86. N := 100
  87. for i := 0; i < N; i++ {
  88. peer := newMockPeer(net.IP{127, 0, 0, byte(i)})
  89. if err := peerSet.Add(peer); err != nil {
  90. t.Errorf("failed to add new peer")
  91. }
  92. if peerSet.Size() != i+1 {
  93. t.Errorf("failed to add new peer and increment size")
  94. }
  95. peers = append(peers, peer)
  96. }
  97. for i, peer := range peers {
  98. removed := peerSet.Remove(peer)
  99. assert.True(t, removed)
  100. if peerSet.Has(peer.ID()) {
  101. t.Errorf("failed to remove peer")
  102. }
  103. if peerSet.Size() != len(peers)-i-1 {
  104. t.Errorf("failed to remove peer and decrement size")
  105. }
  106. }
  107. }
  108. func TestPeerSetAddDuplicate(t *testing.T) {
  109. t.Parallel()
  110. peerSet := NewPeerSet()
  111. peer := newMockPeer(nil)
  112. n := 20
  113. errsChan := make(chan error)
  114. // Add the same asynchronously to test the
  115. // concurrent guarantees of our APIs, and
  116. // our expectation in the end is that only
  117. // one addition succeeded, but the rest are
  118. // instances of ErrSwitchDuplicatePeer.
  119. for i := 0; i < n; i++ {
  120. go func() {
  121. errsChan <- peerSet.Add(peer)
  122. }()
  123. }
  124. // Now collect and tally the results
  125. errsTally := make(map[string]int)
  126. for i := 0; i < n; i++ {
  127. err := <-errsChan
  128. switch err.(type) {
  129. case ErrSwitchDuplicatePeerID:
  130. errsTally["duplicateID"]++
  131. default:
  132. errsTally["other"]++
  133. }
  134. }
  135. // Our next procedure is to ensure that only one addition
  136. // succeeded and that the rest are each ErrSwitchDuplicatePeer.
  137. wantErrCount, gotErrCount := n-1, errsTally["duplicateID"]
  138. assert.Equal(t, wantErrCount, gotErrCount, "invalid ErrSwitchDuplicatePeer count")
  139. wantNilErrCount, gotNilErrCount := 1, errsTally["other"]
  140. assert.Equal(t, wantNilErrCount, gotNilErrCount, "invalid nil errCount")
  141. }
  142. func TestPeerSetGet(t *testing.T) {
  143. t.Parallel()
  144. var (
  145. peerSet = NewPeerSet()
  146. peer = newMockPeer(nil)
  147. )
  148. assert.Nil(t, peerSet.Get(peer.ID()), "expecting a nil lookup, before .Add")
  149. if err := peerSet.Add(peer); err != nil {
  150. t.Fatalf("Failed to add new peer: %v", err)
  151. }
  152. var wg sync.WaitGroup
  153. for i := 0; i < 10; i++ {
  154. // Add them asynchronously to test the
  155. // concurrent guarantees of our APIs.
  156. wg.Add(1)
  157. go func(i int) {
  158. defer wg.Done()
  159. have, want := peerSet.Get(peer.ID()), peer
  160. assert.Equal(t, have, want, "%d: have %v, want %v", i, have, want)
  161. }(i)
  162. }
  163. wg.Wait()
  164. }