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