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  }