github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/network/p2p/connection/peerManager_integration_test.go (about) 1 package connection_test 2 3 import ( 4 "context" 5 "testing" 6 "time" 7 8 "github.com/libp2p/go-libp2p/core/host" 9 "github.com/libp2p/go-libp2p/core/network" 10 "github.com/libp2p/go-libp2p/core/peer" 11 "github.com/libp2p/go-libp2p/core/peerstore" 12 "github.com/stretchr/testify/assert" 13 "github.com/stretchr/testify/require" 14 15 "github.com/onflow/flow-go/model/flow" 16 "github.com/onflow/flow-go/module/irrecoverable" 17 "github.com/onflow/flow-go/network/p2p" 18 "github.com/onflow/flow-go/network/p2p/connection" 19 p2ptest "github.com/onflow/flow-go/network/p2p/test" 20 "github.com/onflow/flow-go/network/p2p/translator" 21 "github.com/onflow/flow-go/network/p2p/utils" 22 "github.com/onflow/flow-go/utils/unittest" 23 ) 24 25 // TestPeerManager_Integration tests the correctness of integration between PeerManager and PeerUpdater over 26 // a fully connected topology. 27 // PeerManager should be able to connect to all peers using the connector, and must also tear down the connection to 28 // peers that are excluded from its identity provider. 29 func TestPeerManager_Integration(t *testing.T) { 30 count := 5 31 ctx, cancel := context.WithCancel(context.Background()) 32 33 signalerCtx := irrecoverable.NewMockSignalerContext(t, ctx) 34 35 // create nodes 36 idProvider := unittest.NewUpdatableIDProvider(flow.IdentityList{}) 37 nodes, identities := p2ptest.NodesFixture(t, unittest.IdentifierFixture(), "test_peer_manager", count, idProvider) 38 idProvider.SetIdentities(identities) 39 p2ptest.StartNodes(t, signalerCtx, nodes) 40 defer p2ptest.StopNodes(t, nodes, cancel) 41 42 thisNode := nodes[0] 43 topologyPeers := identities[1:] 44 45 // adds address of all other nodes into the peer store of this node, so that it can dial them. 46 info, invalid := utils.PeerInfosFromIDs(topologyPeers) 47 require.Empty(t, invalid) 48 for _, i := range info { 49 thisNode.Host().Peerstore().SetAddrs(i.ID, i.Addrs, peerstore.PermanentAddrTTL) 50 } 51 52 connector, err := connection.DefaultLibp2pBackoffConnectorFactory()(thisNode.Host()) 53 require.NoError(t, err) 54 // setup 55 peerUpdater, err := connection.NewPeerUpdater(&connection.PeerUpdaterConfig{ 56 PruneConnections: connection.PruningEnabled, 57 Logger: unittest.Logger(), 58 Host: connection.NewConnectorHost(thisNode.Host()), 59 Connector: connector, 60 }) 61 require.NoError(t, err) 62 63 idTranslator, err := translator.NewFixedTableIdentityTranslator(identities) 64 require.NoError(t, err) 65 66 peerManager := connection.NewPeerManager(unittest.Logger(), connection.DefaultPeerUpdateInterval, peerUpdater) 67 peerManager.SetPeersProvider(func() peer.IDSlice { 68 // peerManager is furnished with a full topology that connects to all nodes 69 // in the topologyPeers. 70 peers := peer.IDSlice{} 71 for _, id := range topologyPeers { 72 peerId, err := idTranslator.GetPeerID(id.NodeID) 73 require.NoError(t, err) 74 peers = append(peers, peerId) 75 } 76 77 return peers 78 }) 79 80 // initially no node should be in peer store of this node. 81 require.Empty(t, thisNode.Host().Network().Peers()) 82 peerManager.ForceUpdatePeers(ctx) 83 time.Sleep(1 * time.Second) 84 // after a forced update all other nodes must be added to the peer store of this node. 85 require.Len(t, thisNode.Host().Network().Peers(), count-1) 86 // after a forced update there must be a connection between this node and other nodes 87 connectedToAll(t, thisNode.Host(), idTranslator, topologyPeers.NodeIDs()) 88 89 // kicks one node out of the othersIds; this imitates evicting, ejecting, or unstaking a node 90 evictedId := topologyPeers[0] // evicted one 91 topologyPeers = topologyPeers[1:] // updates otherIds list 92 peerManager.ForceUpdatePeers(ctx) 93 time.Sleep(1 * time.Second) 94 // after a forced update, the evicted one should be excluded from the peer store. 95 require.Len(t, thisNode.Host().Network().Peers(), count-2) 96 // there must be a connection between this node and other nodes (except evicted one). 97 connectedToAll(t, thisNode.Host(), idTranslator, topologyPeers.NodeIDs()) 98 99 // there must be no connection between this node and evicted one 100 peerId, err := idTranslator.GetPeerID(evictedId.NodeID) 101 require.NoError(t, err) 102 assert.Equal(t, thisNode.Host().Network().Connectedness(peerId), network.NotConnected) 103 } 104 105 // connectedToAll is a test helper that fails if there is no connection between this host and at least one of the 106 // nodes in "all". 107 func connectedToAll(t *testing.T, host host.Host, translator p2p.IDTranslator, all flow.IdentifierList) { 108 for _, id := range all { 109 peerId, err := translator.GetPeerID(id) 110 require.NoError(t, err) 111 assert.Equal(t, host.Network().Connectedness(peerId), network.Connected) 112 } 113 }