github.com/adoriasoft/tendermint@v0.34.0-dev1.0.20200722151356-96d84601a75a/p2p/pex/pex_reactor_test.go (about)

     1  package pex
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"path/filepath"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/stretchr/testify/assert"
    12  	"github.com/stretchr/testify/require"
    13  
    14  	"github.com/tendermint/tendermint/config"
    15  	"github.com/tendermint/tendermint/libs/log"
    16  	"github.com/tendermint/tendermint/p2p"
    17  	"github.com/tendermint/tendermint/p2p/mock"
    18  	tmp2p "github.com/tendermint/tendermint/proto/tendermint/p2p"
    19  )
    20  
    21  var (
    22  	cfg *config.P2PConfig
    23  )
    24  
    25  func init() {
    26  	cfg = config.DefaultP2PConfig()
    27  	cfg.PexReactor = true
    28  	cfg.AllowDuplicateIP = true
    29  }
    30  
    31  func TestPEXReactorBasic(t *testing.T) {
    32  	r, book := createReactor(&ReactorConfig{})
    33  	defer teardownReactor(book)
    34  
    35  	assert.NotNil(t, r)
    36  	assert.NotEmpty(t, r.GetChannels())
    37  }
    38  
    39  func TestPEXReactorAddRemovePeer(t *testing.T) {
    40  	r, book := createReactor(&ReactorConfig{})
    41  	defer teardownReactor(book)
    42  
    43  	size := book.Size()
    44  	peer := p2p.CreateRandomPeer(false)
    45  
    46  	r.AddPeer(peer)
    47  	assert.Equal(t, size+1, book.Size())
    48  
    49  	r.RemovePeer(peer, "peer not available")
    50  
    51  	outboundPeer := p2p.CreateRandomPeer(true)
    52  
    53  	r.AddPeer(outboundPeer)
    54  	assert.Equal(t, size+1, book.Size(), "outbound peers should not be added to the address book")
    55  
    56  	r.RemovePeer(outboundPeer, "peer not available")
    57  }
    58  
    59  // --- FAIL: TestPEXReactorRunning (11.10s)
    60  // 				pex_reactor_test.go:411: expected all switches to be connected to at
    61  // 				least one peer (switches: 0 => {outbound: 1, inbound: 0}, 1 =>
    62  // 				{outbound: 0, inbound: 1}, 2 => {outbound: 0, inbound: 0}, )
    63  //
    64  // EXPLANATION: peers are getting rejected because in switch#addPeer we check
    65  // if any peer (who we already connected to) has the same IP. Even though local
    66  // peers have different IP addresses, they all have the same underlying remote
    67  // IP: 127.0.0.1.
    68  //
    69  func TestPEXReactorRunning(t *testing.T) {
    70  	N := 3
    71  	switches := make([]*p2p.Switch, N)
    72  
    73  	// directory to store address books
    74  	dir, err := ioutil.TempDir("", "pex_reactor")
    75  	require.Nil(t, err)
    76  	defer os.RemoveAll(dir)
    77  
    78  	books := make([]AddrBook, N)
    79  	logger := log.TestingLogger()
    80  
    81  	// create switches
    82  	for i := 0; i < N; i++ {
    83  		switches[i] = p2p.MakeSwitch(cfg, i, "testing", "123.123.123", func(i int, sw *p2p.Switch) *p2p.Switch {
    84  			books[i] = NewAddrBook(filepath.Join(dir, fmt.Sprintf("addrbook%d.json", i)), false)
    85  			books[i].SetLogger(logger.With("pex", i))
    86  			sw.SetAddrBook(books[i])
    87  
    88  			sw.SetLogger(logger.With("pex", i))
    89  
    90  			r := NewReactor(books[i], &ReactorConfig{})
    91  			r.SetLogger(logger.With("pex", i))
    92  			r.SetEnsurePeersPeriod(250 * time.Millisecond)
    93  			sw.AddReactor("pex", r)
    94  
    95  			return sw
    96  		})
    97  	}
    98  
    99  	addOtherNodeAddrToAddrBook := func(switchIndex, otherSwitchIndex int) {
   100  		addr := switches[otherSwitchIndex].NetAddress()
   101  		err := books[switchIndex].AddAddress(addr, addr)
   102  		require.NoError(t, err)
   103  	}
   104  
   105  	addOtherNodeAddrToAddrBook(0, 1)
   106  	addOtherNodeAddrToAddrBook(1, 0)
   107  	addOtherNodeAddrToAddrBook(2, 1)
   108  
   109  	for _, sw := range switches {
   110  		err := sw.Start() // start switch and reactors
   111  		require.Nil(t, err)
   112  	}
   113  
   114  	assertPeersWithTimeout(t, switches, 10*time.Millisecond, 10*time.Second, N-1)
   115  
   116  	// stop them
   117  	for _, s := range switches {
   118  		err := s.Stop()
   119  		require.NoError(t, err)
   120  	}
   121  }
   122  
   123  func TestPEXReactorReceive(t *testing.T) {
   124  	r, book := createReactor(&ReactorConfig{})
   125  	defer teardownReactor(book)
   126  
   127  	peer := p2p.CreateRandomPeer(false)
   128  
   129  	// we have to send a request to receive responses
   130  	r.RequestAddrs(peer)
   131  
   132  	size := book.Size()
   133  	msg := mustEncode(&tmp2p.PexAddrs{Addrs: []tmp2p.NetAddress{peer.SocketAddr().ToProto()}})
   134  	r.Receive(PexChannel, peer, msg)
   135  	assert.Equal(t, size+1, book.Size())
   136  
   137  	msg = mustEncode(&tmp2p.PexRequest{})
   138  	r.Receive(PexChannel, peer, msg) // should not panic.
   139  }
   140  
   141  func TestPEXReactorRequestMessageAbuse(t *testing.T) {
   142  	r, book := createReactor(&ReactorConfig{})
   143  	defer teardownReactor(book)
   144  
   145  	sw := createSwitchAndAddReactors(r)
   146  	sw.SetAddrBook(book)
   147  
   148  	peer := mock.NewPeer(nil)
   149  	peerAddr := peer.SocketAddr()
   150  	p2p.AddPeerToSwitchPeerSet(sw, peer)
   151  	assert.True(t, sw.Peers().Has(peer.ID()))
   152  	err := book.AddAddress(peerAddr, peerAddr)
   153  	require.NoError(t, err)
   154  	require.True(t, book.HasAddress(peerAddr))
   155  
   156  	id := string(peer.ID())
   157  	msg := mustEncode(&tmp2p.PexRequest{})
   158  
   159  	// first time creates the entry
   160  	r.Receive(PexChannel, peer, msg)
   161  	assert.True(t, r.lastReceivedRequests.Has(id))
   162  	assert.True(t, sw.Peers().Has(peer.ID()))
   163  
   164  	// next time sets the last time value
   165  	r.Receive(PexChannel, peer, msg)
   166  	assert.True(t, r.lastReceivedRequests.Has(id))
   167  	assert.True(t, sw.Peers().Has(peer.ID()))
   168  
   169  	// third time is too many too soon - peer is removed
   170  	r.Receive(PexChannel, peer, msg)
   171  	assert.False(t, r.lastReceivedRequests.Has(id))
   172  	assert.False(t, sw.Peers().Has(peer.ID()))
   173  	assert.True(t, book.IsBanned(peerAddr))
   174  }
   175  
   176  func TestPEXReactorAddrsMessageAbuse(t *testing.T) {
   177  	r, book := createReactor(&ReactorConfig{})
   178  	defer teardownReactor(book)
   179  
   180  	sw := createSwitchAndAddReactors(r)
   181  	sw.SetAddrBook(book)
   182  
   183  	peer := mock.NewPeer(nil)
   184  	p2p.AddPeerToSwitchPeerSet(sw, peer)
   185  	assert.True(t, sw.Peers().Has(peer.ID()))
   186  
   187  	id := string(peer.ID())
   188  
   189  	// request addrs from the peer
   190  	r.RequestAddrs(peer)
   191  	assert.True(t, r.requestsSent.Has(id))
   192  	assert.True(t, sw.Peers().Has(peer.ID()))
   193  
   194  	msg := mustEncode(&tmp2p.PexAddrs{Addrs: []tmp2p.NetAddress{peer.SocketAddr().ToProto()}})
   195  
   196  	// receive some addrs. should clear the request
   197  	r.Receive(PexChannel, peer, msg)
   198  	assert.False(t, r.requestsSent.Has(id))
   199  	assert.True(t, sw.Peers().Has(peer.ID()))
   200  
   201  	// receiving more unsolicited addrs causes a disconnect and ban
   202  	r.Receive(PexChannel, peer, msg)
   203  	assert.False(t, sw.Peers().Has(peer.ID()))
   204  	assert.True(t, book.IsBanned(peer.SocketAddr()))
   205  }
   206  
   207  func TestCheckSeeds(t *testing.T) {
   208  	// directory to store address books
   209  	dir, err := ioutil.TempDir("", "pex_reactor")
   210  	require.Nil(t, err)
   211  	defer os.RemoveAll(dir)
   212  
   213  	// 1. test creating peer with no seeds works
   214  	peerSwitch := testCreateDefaultPeer(dir, 0)
   215  	require.Nil(t, peerSwitch.Start())
   216  	peerSwitch.Stop() // nolint:errcheck // ignore for tests
   217  
   218  	// 2. create seed
   219  	seed := testCreateSeed(dir, 1, []*p2p.NetAddress{}, []*p2p.NetAddress{})
   220  
   221  	// 3. test create peer with online seed works
   222  	peerSwitch = testCreatePeerWithSeed(dir, 2, seed)
   223  	require.Nil(t, peerSwitch.Start())
   224  	peerSwitch.Stop() // nolint:errcheck // ignore for tests
   225  
   226  	// 4. test create peer with all seeds having unresolvable DNS fails
   227  	badPeerConfig := &ReactorConfig{
   228  		Seeds: []string{"ed3dfd27bfc4af18f67a49862f04cc100696e84d@bad.network.addr:26657",
   229  			"d824b13cb5d40fa1d8a614e089357c7eff31b670@anotherbad.network.addr:26657"},
   230  	}
   231  	peerSwitch = testCreatePeerWithConfig(dir, 2, badPeerConfig)
   232  	require.Error(t, peerSwitch.Start())
   233  	peerSwitch.Stop() // nolint:errcheck // ignore for tests
   234  
   235  	// 5. test create peer with one good seed address succeeds
   236  	badPeerConfig = &ReactorConfig{
   237  		Seeds: []string{"ed3dfd27bfc4af18f67a49862f04cc100696e84d@bad.network.addr:26657",
   238  			"d824b13cb5d40fa1d8a614e089357c7eff31b670@anotherbad.network.addr:26657",
   239  			seed.NetAddress().String()},
   240  	}
   241  	peerSwitch = testCreatePeerWithConfig(dir, 2, badPeerConfig)
   242  	require.Nil(t, peerSwitch.Start())
   243  	peerSwitch.Stop() // nolint:errcheck // ignore for tests
   244  }
   245  
   246  func TestPEXReactorUsesSeedsIfNeeded(t *testing.T) {
   247  	// directory to store address books
   248  	dir, err := ioutil.TempDir("", "pex_reactor")
   249  	require.Nil(t, err)
   250  	defer os.RemoveAll(dir)
   251  
   252  	// 1. create seed
   253  	seed := testCreateSeed(dir, 0, []*p2p.NetAddress{}, []*p2p.NetAddress{})
   254  	require.Nil(t, seed.Start())
   255  	defer seed.Stop() // nolint:errcheck // ignore for tests
   256  
   257  	// 2. create usual peer with only seed configured.
   258  	peer := testCreatePeerWithSeed(dir, 1, seed)
   259  	require.Nil(t, peer.Start())
   260  	defer peer.Stop() // nolint:errcheck // ignore for tests
   261  
   262  	// 3. check that the peer connects to seed immediately
   263  	assertPeersWithTimeout(t, []*p2p.Switch{peer}, 10*time.Millisecond, 3*time.Second, 1)
   264  }
   265  
   266  func TestConnectionSpeedForPeerReceivedFromSeed(t *testing.T) {
   267  	// directory to store address books
   268  	dir, err := ioutil.TempDir("", "pex_reactor")
   269  	require.Nil(t, err)
   270  	defer os.RemoveAll(dir)
   271  
   272  	// 1. create peer
   273  	peerSwitch := testCreateDefaultPeer(dir, 1)
   274  	require.Nil(t, peerSwitch.Start())
   275  	defer peerSwitch.Stop() // nolint:errcheck // ignore for tests
   276  
   277  	// 2. Create seed which knows about the peer
   278  	peerAddr := peerSwitch.NetAddress()
   279  	seed := testCreateSeed(dir, 2, []*p2p.NetAddress{peerAddr}, []*p2p.NetAddress{peerAddr})
   280  	require.Nil(t, seed.Start())
   281  	defer seed.Stop() // nolint:errcheck // ignore for tests
   282  
   283  	// 3. create another peer with only seed configured.
   284  	secondPeer := testCreatePeerWithSeed(dir, 3, seed)
   285  	require.Nil(t, secondPeer.Start())
   286  	defer secondPeer.Stop() // nolint:errcheck // ignore for tests
   287  
   288  	// 4. check that the second peer connects to seed immediately
   289  	assertPeersWithTimeout(t, []*p2p.Switch{secondPeer}, 10*time.Millisecond, 3*time.Second, 1)
   290  
   291  	// 5. check that the second peer connects to the first peer immediately
   292  	assertPeersWithTimeout(t, []*p2p.Switch{secondPeer}, 10*time.Millisecond, 1*time.Second, 2)
   293  }
   294  
   295  func TestPEXReactorSeedMode(t *testing.T) {
   296  	// directory to store address books
   297  	dir, err := ioutil.TempDir("", "pex_reactor")
   298  	require.Nil(t, err)
   299  	defer os.RemoveAll(dir)
   300  
   301  	pexRConfig := &ReactorConfig{SeedMode: true, SeedDisconnectWaitPeriod: 10 * time.Millisecond}
   302  	pexR, book := createReactor(pexRConfig)
   303  	defer teardownReactor(book)
   304  
   305  	sw := createSwitchAndAddReactors(pexR)
   306  	sw.SetAddrBook(book)
   307  	err = sw.Start()
   308  	require.NoError(t, err)
   309  	defer sw.Stop() // nolint:errcheck // ignore for tests
   310  
   311  	assert.Zero(t, sw.Peers().Size())
   312  
   313  	peerSwitch := testCreateDefaultPeer(dir, 1)
   314  	require.NoError(t, peerSwitch.Start())
   315  	defer peerSwitch.Stop() // nolint:errcheck // ignore for tests
   316  
   317  	// 1. Test crawlPeers dials the peer
   318  	pexR.crawlPeers([]*p2p.NetAddress{peerSwitch.NetAddress()})
   319  	assert.Equal(t, 1, sw.Peers().Size())
   320  	assert.True(t, sw.Peers().Has(peerSwitch.NodeInfo().ID()))
   321  
   322  	// 2. attemptDisconnects should not disconnect because of wait period
   323  	pexR.attemptDisconnects()
   324  	assert.Equal(t, 1, sw.Peers().Size())
   325  
   326  	// sleep for SeedDisconnectWaitPeriod
   327  	time.Sleep(pexRConfig.SeedDisconnectWaitPeriod + 1*time.Millisecond)
   328  
   329  	// 3. attemptDisconnects should disconnect after wait period
   330  	pexR.attemptDisconnects()
   331  	assert.Equal(t, 0, sw.Peers().Size())
   332  }
   333  
   334  func TestPEXReactorDoesNotDisconnectFromPersistentPeerInSeedMode(t *testing.T) {
   335  	// directory to store address books
   336  	dir, err := ioutil.TempDir("", "pex_reactor")
   337  	require.Nil(t, err)
   338  	defer os.RemoveAll(dir)
   339  
   340  	pexRConfig := &ReactorConfig{SeedMode: true, SeedDisconnectWaitPeriod: 1 * time.Millisecond}
   341  	pexR, book := createReactor(pexRConfig)
   342  	defer teardownReactor(book)
   343  
   344  	sw := createSwitchAndAddReactors(pexR)
   345  	sw.SetAddrBook(book)
   346  	err = sw.Start()
   347  	require.NoError(t, err)
   348  	defer sw.Stop() // nolint:errcheck // ignore for tests
   349  
   350  	assert.Zero(t, sw.Peers().Size())
   351  
   352  	peerSwitch := testCreateDefaultPeer(dir, 1)
   353  	require.NoError(t, peerSwitch.Start())
   354  	defer peerSwitch.Stop() // nolint:errcheck // ignore for tests
   355  
   356  	err = sw.AddPersistentPeers([]string{peerSwitch.NetAddress().String()})
   357  	require.NoError(t, err)
   358  
   359  	// 1. Test crawlPeers dials the peer
   360  	pexR.crawlPeers([]*p2p.NetAddress{peerSwitch.NetAddress()})
   361  	assert.Equal(t, 1, sw.Peers().Size())
   362  	assert.True(t, sw.Peers().Has(peerSwitch.NodeInfo().ID()))
   363  
   364  	// sleep for SeedDisconnectWaitPeriod
   365  	time.Sleep(pexRConfig.SeedDisconnectWaitPeriod + 1*time.Millisecond)
   366  
   367  	// 2. attemptDisconnects should not disconnect because the peer is persistent
   368  	pexR.attemptDisconnects()
   369  	assert.Equal(t, 1, sw.Peers().Size())
   370  }
   371  
   372  func TestPEXReactorDialsPeerUpToMaxAttemptsInSeedMode(t *testing.T) {
   373  	// directory to store address books
   374  	dir, err := ioutil.TempDir("", "pex_reactor")
   375  	require.Nil(t, err)
   376  	defer os.RemoveAll(dir)
   377  
   378  	pexR, book := createReactor(&ReactorConfig{SeedMode: true})
   379  	defer teardownReactor(book)
   380  
   381  	sw := createSwitchAndAddReactors(pexR)
   382  	sw.SetAddrBook(book)
   383  	// No need to start sw since crawlPeers is called manually here.
   384  
   385  	peer := mock.NewPeer(nil)
   386  	addr := peer.SocketAddr()
   387  
   388  	err = book.AddAddress(addr, addr)
   389  	require.NoError(t, err)
   390  
   391  	assert.True(t, book.HasAddress(addr))
   392  
   393  	// imitate maxAttemptsToDial reached
   394  	pexR.attemptsToDial.Store(addr.DialString(), _attemptsToDial{maxAttemptsToDial + 1, time.Now()})
   395  	pexR.crawlPeers([]*p2p.NetAddress{addr})
   396  
   397  	assert.False(t, book.HasAddress(addr))
   398  }
   399  
   400  // connect a peer to a seed, wait a bit, then stop it.
   401  // this should give it time to request addrs and for the seed
   402  // to call FlushStop, and allows us to test calling Stop concurrently
   403  // with FlushStop. Before a fix, this non-deterministically reproduced
   404  // https://github.com/tendermint/tendermint/issues/3231.
   405  func TestPEXReactorSeedModeFlushStop(t *testing.T) {
   406  	N := 2
   407  	switches := make([]*p2p.Switch, N)
   408  
   409  	// directory to store address books
   410  	dir, err := ioutil.TempDir("", "pex_reactor")
   411  	require.Nil(t, err)
   412  	defer os.RemoveAll(dir)
   413  
   414  	books := make([]AddrBook, N)
   415  	logger := log.TestingLogger()
   416  
   417  	// create switches
   418  	for i := 0; i < N; i++ {
   419  		switches[i] = p2p.MakeSwitch(cfg, i, "testing", "123.123.123", func(i int, sw *p2p.Switch) *p2p.Switch {
   420  			books[i] = NewAddrBook(filepath.Join(dir, fmt.Sprintf("addrbook%d.json", i)), false)
   421  			books[i].SetLogger(logger.With("pex", i))
   422  			sw.SetAddrBook(books[i])
   423  
   424  			sw.SetLogger(logger.With("pex", i))
   425  
   426  			config := &ReactorConfig{}
   427  			if i == 0 {
   428  				// first one is a seed node
   429  				config = &ReactorConfig{SeedMode: true}
   430  			}
   431  			r := NewReactor(books[i], config)
   432  			r.SetLogger(logger.With("pex", i))
   433  			r.SetEnsurePeersPeriod(250 * time.Millisecond)
   434  			sw.AddReactor("pex", r)
   435  
   436  			return sw
   437  		})
   438  	}
   439  
   440  	for _, sw := range switches {
   441  		err := sw.Start() // start switch and reactors
   442  		require.Nil(t, err)
   443  	}
   444  
   445  	reactor := switches[0].Reactors()["pex"].(*Reactor)
   446  	peerID := switches[1].NodeInfo().ID()
   447  
   448  	err = switches[1].DialPeerWithAddress(switches[0].NetAddress())
   449  	assert.NoError(t, err)
   450  
   451  	// sleep up to a second while waiting for the peer to send us a message.
   452  	// this isn't perfect since it's possible the peer sends us a msg and we FlushStop
   453  	// before this loop catches it. but non-deterministically it works pretty well.
   454  	for i := 0; i < 1000; i++ {
   455  		v := reactor.lastReceivedRequests.Get(string(peerID))
   456  		if v != nil {
   457  			break
   458  		}
   459  		time.Sleep(time.Millisecond)
   460  	}
   461  
   462  	// by now the FlushStop should have happened. Try stopping the peer.
   463  	// it should be safe to do this.
   464  	peers := switches[0].Peers().List()
   465  	for _, peer := range peers {
   466  		err := peer.Stop()
   467  		require.NoError(t, err)
   468  	}
   469  
   470  	// stop the switches
   471  	for _, s := range switches {
   472  		err := s.Stop()
   473  		require.NoError(t, err)
   474  	}
   475  }
   476  
   477  func TestPEXReactorDoesNotAddPrivatePeersToAddrBook(t *testing.T) {
   478  	peer := p2p.CreateRandomPeer(false)
   479  
   480  	pexR, book := createReactor(&ReactorConfig{})
   481  	book.AddPrivateIDs([]string{string(peer.NodeInfo().ID())})
   482  	defer teardownReactor(book)
   483  
   484  	// we have to send a request to receive responses
   485  	pexR.RequestAddrs(peer)
   486  
   487  	size := book.Size()
   488  	msg := mustEncode(&tmp2p.PexAddrs{Addrs: []tmp2p.NetAddress{peer.SocketAddr().ToProto()}})
   489  	pexR.Receive(PexChannel, peer, msg)
   490  	assert.Equal(t, size, book.Size())
   491  
   492  	pexR.AddPeer(peer)
   493  	assert.Equal(t, size, book.Size())
   494  }
   495  
   496  func TestPEXReactorDialPeer(t *testing.T) {
   497  	pexR, book := createReactor(&ReactorConfig{})
   498  	defer teardownReactor(book)
   499  
   500  	sw := createSwitchAndAddReactors(pexR)
   501  	sw.SetAddrBook(book)
   502  
   503  	peer := mock.NewPeer(nil)
   504  	addr := peer.SocketAddr()
   505  
   506  	assert.Equal(t, 0, pexR.AttemptsToDial(addr))
   507  
   508  	// 1st unsuccessful attempt
   509  	err := pexR.dialPeer(addr)
   510  	require.Error(t, err)
   511  
   512  	assert.Equal(t, 1, pexR.AttemptsToDial(addr))
   513  
   514  	// 2nd unsuccessful attempt
   515  	err = pexR.dialPeer(addr)
   516  	require.Error(t, err)
   517  
   518  	// must be skipped because it is too early
   519  	assert.Equal(t, 1, pexR.AttemptsToDial(addr))
   520  
   521  	if !testing.Short() {
   522  		time.Sleep(3 * time.Second)
   523  
   524  		// 3rd attempt
   525  		err = pexR.dialPeer(addr)
   526  		require.Error(t, err)
   527  
   528  		assert.Equal(t, 2, pexR.AttemptsToDial(addr))
   529  	}
   530  }
   531  
   532  func assertPeersWithTimeout(
   533  	t *testing.T,
   534  	switches []*p2p.Switch,
   535  	checkPeriod, timeout time.Duration,
   536  	nPeers int,
   537  ) {
   538  	var (
   539  		ticker    = time.NewTicker(checkPeriod)
   540  		remaining = timeout
   541  	)
   542  
   543  	for {
   544  		select {
   545  		case <-ticker.C:
   546  			// check peers are connected
   547  			allGood := true
   548  			for _, s := range switches {
   549  				outbound, inbound, _ := s.NumPeers()
   550  				if outbound+inbound < nPeers {
   551  					allGood = false
   552  					break
   553  				}
   554  			}
   555  			remaining -= checkPeriod
   556  			if remaining < 0 {
   557  				remaining = 0
   558  			}
   559  			if allGood {
   560  				return
   561  			}
   562  		case <-time.After(remaining):
   563  			numPeersStr := ""
   564  			for i, s := range switches {
   565  				outbound, inbound, _ := s.NumPeers()
   566  				numPeersStr += fmt.Sprintf("%d => {outbound: %d, inbound: %d}, ", i, outbound, inbound)
   567  			}
   568  			t.Errorf(
   569  				"expected all switches to be connected to at least %d peer(s) (switches: %s)",
   570  				nPeers, numPeersStr,
   571  			)
   572  			return
   573  		}
   574  	}
   575  }
   576  
   577  // Creates a peer with the provided config
   578  func testCreatePeerWithConfig(dir string, id int, config *ReactorConfig) *p2p.Switch {
   579  	peer := p2p.MakeSwitch(
   580  		cfg,
   581  		id,
   582  		"127.0.0.1",
   583  		"123.123.123",
   584  		func(i int, sw *p2p.Switch) *p2p.Switch {
   585  			book := NewAddrBook(filepath.Join(dir, fmt.Sprintf("addrbook%d.json", id)), false)
   586  			book.SetLogger(log.TestingLogger())
   587  			sw.SetAddrBook(book)
   588  
   589  			sw.SetLogger(log.TestingLogger())
   590  
   591  			r := NewReactor(
   592  				book,
   593  				config,
   594  			)
   595  			r.SetLogger(log.TestingLogger())
   596  			sw.AddReactor("pex", r)
   597  			return sw
   598  		},
   599  	)
   600  	return peer
   601  }
   602  
   603  // Creates a peer with the default config
   604  func testCreateDefaultPeer(dir string, id int) *p2p.Switch {
   605  	return testCreatePeerWithConfig(dir, id, &ReactorConfig{})
   606  }
   607  
   608  // Creates a seed which knows about the provided addresses / source address pairs.
   609  // Starting and stopping the seed is left to the caller
   610  func testCreateSeed(dir string, id int, knownAddrs, srcAddrs []*p2p.NetAddress) *p2p.Switch {
   611  	seed := p2p.MakeSwitch(
   612  		cfg,
   613  		id,
   614  		"127.0.0.1",
   615  		"123.123.123",
   616  		func(i int, sw *p2p.Switch) *p2p.Switch {
   617  			book := NewAddrBook(filepath.Join(dir, "addrbookSeed.json"), false)
   618  			book.SetLogger(log.TestingLogger())
   619  			for j := 0; j < len(knownAddrs); j++ {
   620  				book.AddAddress(knownAddrs[j], srcAddrs[j]) // nolint:errcheck // ignore for tests
   621  				book.MarkGood(knownAddrs[j].ID)
   622  			}
   623  			sw.SetAddrBook(book)
   624  
   625  			sw.SetLogger(log.TestingLogger())
   626  
   627  			r := NewReactor(book, &ReactorConfig{})
   628  			r.SetLogger(log.TestingLogger())
   629  			sw.AddReactor("pex", r)
   630  			return sw
   631  		},
   632  	)
   633  	return seed
   634  }
   635  
   636  // Creates a peer which knows about the provided seed.
   637  // Starting and stopping the peer is left to the caller
   638  func testCreatePeerWithSeed(dir string, id int, seed *p2p.Switch) *p2p.Switch {
   639  	conf := &ReactorConfig{
   640  		Seeds: []string{seed.NetAddress().String()},
   641  	}
   642  	return testCreatePeerWithConfig(dir, id, conf)
   643  }
   644  
   645  func createReactor(conf *ReactorConfig) (r *Reactor, book AddrBook) {
   646  	// directory to store address book
   647  	dir, err := ioutil.TempDir("", "pex_reactor")
   648  	if err != nil {
   649  		panic(err)
   650  	}
   651  	book = NewAddrBook(filepath.Join(dir, "addrbook.json"), true)
   652  	book.SetLogger(log.TestingLogger())
   653  
   654  	r = NewReactor(book, conf)
   655  	r.SetLogger(log.TestingLogger())
   656  	return
   657  }
   658  
   659  func teardownReactor(book AddrBook) {
   660  	// FIXME Shouldn't rely on .(*addrBook) assertion
   661  	err := os.RemoveAll(filepath.Dir(book.(*addrBook).FilePath()))
   662  	if err != nil {
   663  		panic(err)
   664  	}
   665  }
   666  
   667  func createSwitchAndAddReactors(reactors ...p2p.Reactor) *p2p.Switch {
   668  	sw := p2p.MakeSwitch(cfg, 0, "127.0.0.1", "123.123.123", func(i int, sw *p2p.Switch) *p2p.Switch { return sw })
   669  	sw.SetLogger(log.TestingLogger())
   670  	for _, r := range reactors {
   671  		sw.AddReactor(r.String(), r)
   672  		r.SetSwitch(sw)
   673  	}
   674  	return sw
   675  }