github.com/ethersphere/bee/v2@v2.2.0/pkg/p2p/libp2p/libp2p_test.go (about)

     1  // Copyright 2020 The Swarm Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package libp2p_test
     6  
     7  import (
     8  	"bytes"
     9  	"context"
    10  	"crypto/ecdsa"
    11  	"sort"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/ethereum/go-ethereum/common"
    16  	"github.com/ethersphere/bee/v2/pkg/addressbook"
    17  	"github.com/ethersphere/bee/v2/pkg/crypto"
    18  	"github.com/ethersphere/bee/v2/pkg/log"
    19  	"github.com/ethersphere/bee/v2/pkg/p2p"
    20  	"github.com/ethersphere/bee/v2/pkg/p2p/libp2p"
    21  	"github.com/ethersphere/bee/v2/pkg/spinlock"
    22  	"github.com/ethersphere/bee/v2/pkg/statestore/mock"
    23  	"github.com/ethersphere/bee/v2/pkg/swarm"
    24  	"github.com/ethersphere/bee/v2/pkg/topology/lightnode"
    25  	"github.com/ethersphere/bee/v2/pkg/util/testutil"
    26  	"github.com/multiformats/go-multiaddr"
    27  )
    28  
    29  type libp2pServiceOpts struct {
    30  	Logger      log.Logger
    31  	Addressbook addressbook.Interface
    32  	PrivateKey  *ecdsa.PrivateKey
    33  	MockPeerKey *ecdsa.PrivateKey
    34  	libp2pOpts  libp2p.Options
    35  	lightNodes  *lightnode.Container
    36  	notifier    p2p.PickyNotifier
    37  }
    38  
    39  // newService constructs a new libp2p service.
    40  func newService(t *testing.T, networkID uint64, o libp2pServiceOpts) (s *libp2p.Service, overlay swarm.Address) {
    41  	t.Helper()
    42  
    43  	swarmKey, err := crypto.GenerateSecp256k1Key()
    44  	if err != nil {
    45  		t.Fatal(err)
    46  	}
    47  
    48  	nonce := common.HexToHash("0x1").Bytes()
    49  
    50  	overlay, err = crypto.NewOverlayAddress(swarmKey.PublicKey, networkID, nonce)
    51  	if err != nil {
    52  		t.Fatal(err)
    53  	}
    54  
    55  	addr := ":0"
    56  
    57  	if o.Logger == nil {
    58  		o.Logger = log.Noop
    59  	}
    60  
    61  	statestore := mock.NewStateStore()
    62  	if o.Addressbook == nil {
    63  		o.Addressbook = addressbook.New(statestore)
    64  	}
    65  
    66  	if o.PrivateKey == nil {
    67  		libp2pKey, err := crypto.GenerateSecp256k1Key()
    68  		if err != nil {
    69  			t.Fatal(err)
    70  		}
    71  
    72  		o.PrivateKey = libp2pKey
    73  	}
    74  
    75  	ctx, cancel := context.WithCancel(context.Background())
    76  	t.Cleanup(cancel)
    77  
    78  	if o.lightNodes == nil {
    79  		o.lightNodes = lightnode.NewContainer(overlay)
    80  	}
    81  	opts := o.libp2pOpts
    82  	opts.Nonce = nonce
    83  
    84  	s, err = libp2p.New(ctx, crypto.NewDefaultSigner(swarmKey), networkID, overlay, addr, o.Addressbook, statestore, o.lightNodes, o.Logger, nil, opts)
    85  	if err != nil {
    86  		t.Fatal(err)
    87  	}
    88  	testutil.CleanupCloser(t, s)
    89  
    90  	if o.notifier != nil {
    91  		s.SetPickyNotifier(o.notifier)
    92  	}
    93  
    94  	_ = s.Ready()
    95  
    96  	return s, overlay
    97  }
    98  
    99  // expectPeers validates that peers with addresses are connected.
   100  func expectPeers(t *testing.T, s *libp2p.Service, addrs ...swarm.Address) {
   101  	t.Helper()
   102  
   103  	peers := s.Peers()
   104  
   105  	if len(peers) != len(addrs) {
   106  		t.Fatalf("got peers %v, want %v", len(peers), len(addrs))
   107  	}
   108  
   109  	sort.Slice(addrs, func(i, j int) bool {
   110  		return bytes.Compare(addrs[i].Bytes(), addrs[j].Bytes()) == -1
   111  	})
   112  	sort.Slice(peers, func(i, j int) bool {
   113  		return bytes.Compare(peers[i].Address.Bytes(), peers[j].Address.Bytes()) == -1
   114  	})
   115  
   116  	for i, got := range peers {
   117  		want := addrs[i]
   118  		if !got.Address.Equal(want) {
   119  			t.Errorf("got %v peer %s, want %s", i, got.Address, want)
   120  		}
   121  	}
   122  }
   123  
   124  // expectPeersEventually validates that peers with addresses are connected with
   125  // retries. It is supposed to be used to validate asynchronous connecting on the
   126  // peer that is connected to.
   127  func expectPeersEventually(t *testing.T, s *libp2p.Service, addrs ...swarm.Address) {
   128  	t.Helper()
   129  
   130  	var peers []p2p.Peer
   131  	err := spinlock.Wait(time.Second, func() bool {
   132  		peers = s.Peers()
   133  		return len(peers) == len(addrs)
   134  
   135  	})
   136  	if err != nil {
   137  		t.Fatalf("timed out waiting for peers, got  %v, want %v", len(peers), len(addrs))
   138  	}
   139  
   140  	sort.Slice(addrs, func(i, j int) bool {
   141  		return bytes.Compare(addrs[i].Bytes(), addrs[j].Bytes()) == -1
   142  	})
   143  	sort.Slice(peers, func(i, j int) bool {
   144  		return bytes.Compare(peers[i].Address.Bytes(), peers[j].Address.Bytes()) == -1
   145  	})
   146  
   147  	for i, got := range peers {
   148  		want := addrs[i]
   149  		if !got.Address.Equal(want) {
   150  			t.Errorf("got %v peer %s, want %s", i, got.Address, want)
   151  		}
   152  	}
   153  }
   154  
   155  func serviceUnderlayAddress(t *testing.T, s *libp2p.Service) multiaddr.Multiaddr {
   156  	t.Helper()
   157  
   158  	addrs, err := s.Addresses()
   159  	if err != nil {
   160  		t.Fatal(err)
   161  	}
   162  	return addrs[0]
   163  }