github.com/koko1123/flow-go-1@v0.29.6/network/p2p/p2pnode/libp2pNode_test.go (about)

     1  package p2pnode_test
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"testing"
     7  	"time"
     8  
     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/koko1123/flow-go-1/model/flow"
    16  	"github.com/koko1123/flow-go-1/module/irrecoverable"
    17  	"github.com/koko1123/flow-go-1/module/mock"
    18  	"github.com/koko1123/flow-go-1/network/channels"
    19  	"github.com/koko1123/flow-go-1/network/internal/p2pfixtures"
    20  	"github.com/koko1123/flow-go-1/network/internal/p2putils"
    21  	"github.com/koko1123/flow-go-1/network/internal/testutils"
    22  	p2ptest "github.com/koko1123/flow-go-1/network/p2p/test"
    23  	"github.com/koko1123/flow-go-1/network/p2p/utils"
    24  	validator "github.com/koko1123/flow-go-1/network/validator/pubsub"
    25  	"github.com/koko1123/flow-go-1/utils/unittest"
    26  )
    27  
    28  // TestMultiAddress evaluates correct translations from
    29  // dns and ip4 to libp2p multi-address
    30  func TestMultiAddress(t *testing.T) {
    31  	key := p2pfixtures.NetworkingKeyFixtures(t)
    32  
    33  	tt := []struct {
    34  		identity     *flow.Identity
    35  		multiaddress string
    36  	}{
    37  		{ // ip4 test case
    38  			identity:     unittest.IdentityFixture(unittest.WithNetworkingKey(key.PublicKey()), unittest.WithAddress("172.16.254.1:72")),
    39  			multiaddress: "/ip4/172.16.254.1/tcp/72",
    40  		},
    41  		{ // dns test case
    42  			identity:     unittest.IdentityFixture(unittest.WithNetworkingKey(key.PublicKey()), unittest.WithAddress("consensus:2222")),
    43  			multiaddress: "/dns4/consensus/tcp/2222",
    44  		},
    45  		{ // dns test case
    46  			identity:     unittest.IdentityFixture(unittest.WithNetworkingKey(key.PublicKey()), unittest.WithAddress("flow.com:3333")),
    47  			multiaddress: "/dns4/flow.com/tcp/3333",
    48  		},
    49  	}
    50  
    51  	for _, tc := range tt {
    52  		ip, port, _, err := p2putils.NetworkingInfo(*tc.identity)
    53  		require.NoError(t, err)
    54  
    55  		actualAddress := utils.MultiAddressStr(ip, port)
    56  		assert.Equal(t, tc.multiaddress, actualAddress, "incorrect multi-address translation")
    57  	}
    58  
    59  }
    60  
    61  // TestSingleNodeLifeCycle evaluates correct lifecycle translation from start to stop the node
    62  func TestSingleNodeLifeCycle(t *testing.T) {
    63  	ctx, cancel := context.WithCancel(context.Background())
    64  	signalerCtx := irrecoverable.NewMockSignalerContext(t, ctx)
    65  
    66  	node, _ := p2ptest.NodeFixture(
    67  		t,
    68  		unittest.IdentifierFixture(),
    69  		"test_single_node_life_cycle",
    70  	)
    71  
    72  	node.Start(signalerCtx)
    73  	unittest.RequireComponentsReadyBefore(t, 100*time.Millisecond, node)
    74  
    75  	cancel()
    76  	unittest.RequireComponentsDoneBefore(t, 100*time.Millisecond, node)
    77  }
    78  
    79  // TestGetPeerInfo evaluates the deterministic translation between the nodes address and
    80  // their libp2p info. It generates an address, and checks whether repeated translations
    81  // yields the same info or not.
    82  func TestGetPeerInfo(t *testing.T) {
    83  	for i := 0; i < 10; i++ {
    84  		key := p2pfixtures.NetworkingKeyFixtures(t)
    85  
    86  		// creates node-i identity
    87  		identity := unittest.IdentityFixture(unittest.WithNetworkingKey(key.PublicKey()), unittest.WithAddress("1.1.1.1:0"))
    88  
    89  		// translates node-i address into info
    90  		info, err := utils.PeerAddressInfo(*identity)
    91  		require.NoError(t, err)
    92  
    93  		// repeats the translation for node-i
    94  		for j := 0; j < 10; j++ {
    95  			rinfo, err := utils.PeerAddressInfo(*identity)
    96  			require.NoError(t, err)
    97  			assert.Equal(t, rinfo.String(), info.String(), "inconsistent id generated")
    98  		}
    99  	}
   100  }
   101  
   102  // TestAddPeers checks if nodes can be added as peers to a given node
   103  func TestAddPeers(t *testing.T) {
   104  	count := 3
   105  	ctx, cancel := context.WithCancel(context.Background())
   106  	signalerCtx := irrecoverable.NewMockSignalerContext(t, ctx)
   107  
   108  	// create nodes
   109  	nodes, identities := p2ptest.NodesFixture(t, unittest.IdentifierFixture(), "test_add_peers", count)
   110  	p2ptest.StartNodes(t, signalerCtx, nodes, 100*time.Millisecond)
   111  	defer p2ptest.StopNodes(t, nodes, cancel, 100*time.Millisecond)
   112  
   113  	// add the remaining nodes to the first node as its set of peers
   114  	for _, identity := range identities[1:] {
   115  		peerInfo, err := utils.PeerAddressInfo(*identity)
   116  		require.NoError(t, err)
   117  		require.NoError(t, nodes[0].AddPeer(ctx, peerInfo))
   118  	}
   119  
   120  	// Checks if both of the other nodes have been added as peers to the first node
   121  	assert.Len(t, nodes[0].Host().Network().Peers(), count-1)
   122  }
   123  
   124  // TestRemovePeers checks if nodes can be removed as peers from a given node
   125  func TestRemovePeers(t *testing.T) {
   126  	count := 3
   127  	ctx, cancel := context.WithCancel(context.Background())
   128  	signalerCtx := irrecoverable.NewMockSignalerContext(t, ctx)
   129  
   130  	// create nodes
   131  	nodes, identities := p2ptest.NodesFixture(t, unittest.IdentifierFixture(), "test_remove_peers", count)
   132  	peerInfos, errs := utils.PeerInfosFromIDs(identities)
   133  	assert.Len(t, errs, 0)
   134  
   135  	p2ptest.StartNodes(t, signalerCtx, nodes, 100*time.Millisecond)
   136  	defer p2ptest.StopNodes(t, nodes, cancel, 100*time.Millisecond)
   137  
   138  	// add nodes two and three to the first node as its peers
   139  	for _, pInfo := range peerInfos[1:] {
   140  		require.NoError(t, nodes[0].AddPeer(ctx, pInfo))
   141  	}
   142  
   143  	// check if all other nodes have been added as peers to the first node
   144  	assert.Len(t, nodes[0].Host().Network().Peers(), count-1)
   145  
   146  	// disconnect from each peer and assert that the connection no longer exists
   147  	for _, pInfo := range peerInfos[1:] {
   148  		require.NoError(t, nodes[0].RemovePeer(pInfo.ID))
   149  		assert.Equal(t, network.NotConnected, nodes[0].Host().Network().Connectedness(pInfo.ID))
   150  	}
   151  }
   152  
   153  func TestConnGater(t *testing.T) {
   154  	ctx, cancel := context.WithCancel(context.Background())
   155  	signalerCtx := irrecoverable.NewMockSignalerContext(t, ctx)
   156  
   157  	sporkID := unittest.IdentifierFixture()
   158  
   159  	node1Peers := unittest.NewProtectedMap[peer.ID, struct{}]()
   160  	node1, identity1 := p2ptest.NodeFixture(
   161  		t,
   162  		sporkID,
   163  		t.Name(),
   164  		p2ptest.WithConnectionGater(testutils.NewConnectionGater(func(pid peer.ID) error {
   165  			if !node1Peers.Has(pid) {
   166  				return fmt.Errorf("peer id not found: %s", pid.String())
   167  			}
   168  			return nil
   169  		})))
   170  
   171  	p2ptest.StartNode(t, signalerCtx, node1, 100*time.Millisecond)
   172  	defer p2ptest.StopNode(t, node1, cancel, 100*time.Millisecond)
   173  
   174  	node1Info, err := utils.PeerAddressInfo(identity1)
   175  	assert.NoError(t, err)
   176  
   177  	node2Peers := unittest.NewProtectedMap[peer.ID, struct{}]()
   178  	node2, identity2 := p2ptest.NodeFixture(
   179  		t,
   180  		sporkID, t.Name(),
   181  		p2ptest.WithConnectionGater(testutils.NewConnectionGater(func(pid peer.ID) error {
   182  			if !node2Peers.Has(pid) {
   183  				return fmt.Errorf("id not found: %s", pid.String())
   184  			}
   185  			return nil
   186  		})))
   187  	p2ptest.StartNode(t, signalerCtx, node2, 100*time.Millisecond)
   188  	defer p2ptest.StopNode(t, node2, cancel, 100*time.Millisecond)
   189  
   190  	node2Info, err := utils.PeerAddressInfo(identity2)
   191  	assert.NoError(t, err)
   192  
   193  	node1.Host().Peerstore().AddAddrs(node2Info.ID, node2Info.Addrs, peerstore.PermanentAddrTTL)
   194  	node2.Host().Peerstore().AddAddrs(node1Info.ID, node1Info.Addrs, peerstore.PermanentAddrTTL)
   195  
   196  	_, err = node1.CreateStream(ctx, node2Info.ID)
   197  	assert.Error(t, err, "connection should not be possible")
   198  
   199  	_, err = node2.CreateStream(ctx, node1Info.ID)
   200  	assert.Error(t, err, "connection should not be possible")
   201  
   202  	node1Peers.Add(node2Info.ID, struct{}{})
   203  	_, err = node1.CreateStream(ctx, node2Info.ID)
   204  	assert.Error(t, err, "connection should not be possible")
   205  
   206  	node2Peers.Add(node1Info.ID, struct{}{})
   207  	_, err = node1.CreateStream(ctx, node2Info.ID)
   208  	assert.NoError(t, err, "connection should not be blocked")
   209  }
   210  
   211  // TestNode_HasSubscription checks that when a node subscribes to a topic HasSubscription should return true.
   212  func TestNode_HasSubscription(t *testing.T) {
   213  	ctx, cancel := context.WithCancel(context.Background())
   214  	signalerCtx := irrecoverable.NewMockSignalerContext(t, ctx)
   215  
   216  	sporkID := unittest.IdentifierFixture()
   217  	node, _ := p2ptest.NodeFixture(t, sporkID, "test_has_subscription")
   218  
   219  	p2ptest.StartNode(t, signalerCtx, node, 100*time.Millisecond)
   220  	defer p2ptest.StopNode(t, node, cancel, 100*time.Millisecond)
   221  
   222  	logger := unittest.Logger()
   223  	met := mock.NewNetworkMetrics(t)
   224  
   225  	topicValidator := validator.TopicValidator(logger, unittest.NetworkCodec(), unittest.NetworkSlashingViolationsConsumer(logger, met), func(id peer.ID) error {
   226  		return nil
   227  	})
   228  
   229  	// create test topic
   230  	topic := channels.TopicFromChannel(channels.TestNetworkChannel, unittest.IdentifierFixture())
   231  	_, err := node.Subscribe(topic, topicValidator)
   232  	require.NoError(t, err)
   233  
   234  	require.True(t, node.HasSubscription(topic))
   235  
   236  	// create topic with no subscription
   237  	topic = channels.TopicFromChannel(channels.ConsensusCommittee, unittest.IdentifierFixture())
   238  	require.False(t, node.HasSubscription(topic))
   239  }