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