dial_test.go 15.6 KB
Newer Older
Steven Allen's avatar
Steven Allen committed
1
package swarm_test
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
2 3

import (
Jeromy's avatar
Jeromy committed
4
	"context"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
5 6 7 8 9
	"net"
	"sync"
	"testing"
	"time"

Jeromy's avatar
Jeromy committed
10
	addrutil "github.com/libp2p/go-addr-util"
11

vyzo's avatar
vyzo committed
12
	"github.com/libp2p/go-libp2p-core/network"
13 14 15 16 17
	"github.com/libp2p/go-libp2p-core/peer"
	"github.com/libp2p/go-libp2p-core/peerstore"
	"github.com/libp2p/go-libp2p-core/transport"

	testutil "github.com/libp2p/go-libp2p-core/test"
Steven Allen's avatar
Steven Allen committed
18
	swarmt "github.com/libp2p/go-libp2p-swarm/testing"
19 20
	"github.com/libp2p/go-libp2p-testing/ci"

Jeromy's avatar
Jeromy committed
21
	ma "github.com/multiformats/go-multiaddr"
22
	manet "github.com/multiformats/go-multiaddr/net"
Steven Allen's avatar
Steven Allen committed
23 24

	. "github.com/libp2p/go-libp2p-swarm"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
25 26
)

Steven Allen's avatar
Steven Allen committed
27
func init() {
28
	transport.DialTimeout = time.Second
Steven Allen's avatar
Steven Allen committed
29 30
}

Jeromy's avatar
Jeromy committed
31 32 33 34 35 36
func closeSwarms(swarms []*Swarm) {
	for _, s := range swarms {
		s.Close()
	}
}

Steven Allen's avatar
Steven Allen committed
37
func TestBasicDialPeer(t *testing.T) {
Jeromy's avatar
Jeromy committed
38 39 40 41 42 43 44 45
	t.Parallel()
	ctx := context.Background()

	swarms := makeSwarms(ctx, t, 2)
	defer closeSwarms(swarms)
	s1 := swarms[0]
	s2 := swarms[1]

46
	s1.Peerstore().AddAddrs(s2.LocalPeer(), s2.ListenAddresses(), peerstore.PermanentAddrTTL)
Jeromy's avatar
Jeromy committed
47

Steven Allen's avatar
Steven Allen committed
48
	c, err := s1.DialPeer(ctx, s2.LocalPeer())
Jeromy's avatar
Jeromy committed
49 50 51 52
	if err != nil {
		t.Fatal(err)
	}

53
	s, err := c.NewStream(ctx)
Jeromy's avatar
Jeromy committed
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
	if err != nil {
		t.Fatal(err)
	}

	s.Close()
}

func TestDialWithNoListeners(t *testing.T) {
	t.Parallel()
	ctx := context.Background()

	s1 := makeDialOnlySwarm(ctx, t)

	swarms := makeSwarms(ctx, t, 1)
	defer closeSwarms(swarms)
	s2 := swarms[0]

71
	s1.Peerstore().AddAddrs(s2.LocalPeer(), s2.ListenAddresses(), peerstore.PermanentAddrTTL)
Jeromy's avatar
Jeromy committed
72

Steven Allen's avatar
Steven Allen committed
73
	c, err := s1.DialPeer(ctx, s2.LocalPeer())
Jeromy's avatar
Jeromy committed
74 75 76 77
	if err != nil {
		t.Fatal(err)
	}

78
	s, err := c.NewStream(ctx)
Jeromy's avatar
Jeromy committed
79 80 81 82 83 84 85
	if err != nil {
		t.Fatal(err)
	}

	s.Close()
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
func acceptAndHang(l net.Listener) {
	conns := make([]net.Conn, 0, 10)
	for {
		c, err := l.Accept()
		if err != nil {
			break
		}
		if c != nil {
			conns = append(conns, c)
		}
	}
	for _, c := range conns {
		c.Close()
	}
}

func TestSimultDials(t *testing.T) {
	// t.Skip("skipping for another test")
	t.Parallel()

	ctx := context.Background()
Steven Allen's avatar
Steven Allen committed
107
	swarms := makeSwarms(ctx, t, 2, swarmt.OptDisableReuseport)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
108 109 110 111 112 113

	// connect everyone
	{
		var wg sync.WaitGroup
		connect := func(s *Swarm, dst peer.ID, addr ma.Multiaddr) {
			// copy for other peer
Steven Allen's avatar
Steven Allen committed
114
			log.Debugf("TestSimultOpen: connecting: %s --> %s (%s)", s.LocalPeer(), dst, addr)
115
			s.Peerstore().AddAddr(dst, addr, peerstore.TempAddrTTL)
Steven Allen's avatar
Steven Allen committed
116
			if _, err := s.DialPeer(ctx, dst); err != nil {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
				t.Fatal("error swarm dialing to peer", err)
			}
			wg.Done()
		}

		ifaceAddrs0, err := swarms[0].InterfaceListenAddresses()
		if err != nil {
			t.Fatal(err)
		}
		ifaceAddrs1, err := swarms[1].InterfaceListenAddresses()
		if err != nil {
			t.Fatal(err)
		}

		log.Info("Connecting swarms simultaneously.")
		for i := 0; i < 10; i++ { // connect 10x for each.
			wg.Add(2)
Steven Allen's avatar
Steven Allen committed
134 135
			go connect(swarms[0], swarms[1].LocalPeer(), ifaceAddrs1[0])
			go connect(swarms[1], swarms[0].LocalPeer(), ifaceAddrs0[0])
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
136 137 138 139 140
		}
		wg.Wait()
	}

	// should still just have 1, at most 2 connections :)
Steven Allen's avatar
Steven Allen committed
141
	c01l := len(swarms[0].ConnsToPeer(swarms[1].LocalPeer()))
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
142 143 144
	if c01l > 2 {
		t.Error("0->1 has", c01l)
	}
Steven Allen's avatar
Steven Allen committed
145
	c10l := len(swarms[1].ConnsToPeer(swarms[0].LocalPeer()))
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
146 147 148 149 150 151 152 153 154 155 156
	if c10l > 2 {
		t.Error("1->0 has", c10l)
	}

	for _, s := range swarms {
		s.Close()
	}
}

func newSilentPeer(t *testing.T) (peer.ID, ma.Multiaddr, net.Listener) {
	dst := testutil.RandPeerIDFatal(t)
157
	lst, err := net.Listen("tcp4", "localhost:0")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
	if err != nil {
		t.Fatal(err)
	}
	addr, err := manet.FromNetAddr(lst.Addr())
	if err != nil {
		t.Fatal(err)
	}
	addrs := []ma.Multiaddr{addr}
	addrs, err = addrutil.ResolveUnspecifiedAddresses(addrs, nil)
	if err != nil {
		t.Fatal(err)
	}
	t.Log("new silent peer:", dst, addrs[0])
	return dst, addrs[0], lst
}

func TestDialWait(t *testing.T) {
	t.Parallel()

	ctx := context.Background()
	swarms := makeSwarms(ctx, t, 1)
	s1 := swarms[0]
	defer s1.Close()

	// dial to a non-existent peer.
	s2p, s2addr, s2l := newSilentPeer(t)
	go acceptAndHang(s2l)
	defer s2l.Close()
186
	s1.Peerstore().AddAddr(s2p, s2addr, peerstore.PermanentAddrTTL)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
187 188

	before := time.Now()
Steven Allen's avatar
Steven Allen committed
189
	if c, err := s1.DialPeer(ctx, s2p); err == nil {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
190 191 192 193 194
		defer c.Close()
		t.Fatal("error swarm dialing to unknown peer worked...", err)
	} else {
		t.Log("correctly got error:", err)
	}
John Steidley's avatar
John Steidley committed
195
	duration := time.Since(before)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
196

197 198
	if duration < transport.DialTimeout*DialAttempts {
		t.Error("< transport.DialTimeout * DialAttempts not being respected", duration, transport.DialTimeout*DialAttempts)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
199
	}
200 201
	if duration > 2*transport.DialTimeout*DialAttempts {
		t.Error("> 2*transport.DialTimeout * DialAttempts not being respected", duration, 2*transport.DialTimeout*DialAttempts)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
202 203
	}

Will Scott's avatar
Will Scott committed
204
	if !s1.Backoff().Backoff(s2p, s2addr) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
205 206 207 208 209 210 211
		t.Error("s2 should now be on backoff")
	}
}

func TestDialBackoff(t *testing.T) {
	// t.Skip("skipping for another test")
	if ci.IsRunning() {
212
		t.Skip("travis will never have fun with this test")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
	}

	t.Parallel()

	ctx := context.Background()
	swarms := makeSwarms(ctx, t, 2)
	s1 := swarms[0]
	s2 := swarms[1]
	defer s1.Close()
	defer s2.Close()

	s2addrs, err := s2.InterfaceListenAddresses()
	if err != nil {
		t.Fatal(err)
	}
228
	s1.Peerstore().AddAddrs(s2.LocalPeer(), s2addrs, peerstore.PermanentAddrTTL)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
229 230 231 232 233

	// dial to a non-existent peer.
	s3p, s3addr, s3l := newSilentPeer(t)
	go acceptAndHang(s3l)
	defer s3l.Close()
234
	s1.Peerstore().AddAddr(s3p, s3addr, peerstore.PermanentAddrTTL)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250

	// in this test we will:
	//   1) dial 10x to each node.
	//   2) all dials should hang
	//   3) s1->s2 should succeed.
	//   4) s1->s3 should not (and should place s3 on backoff)
	//   5) disconnect entirely
	//   6) dial 10x to each node again
	//   7) s3 dials should all return immediately (except 1)
	//   8) s2 dials should all hang, and succeed
	//   9) last s3 dial ends, unsuccessful

	dialOnlineNode := func(dst peer.ID, times int) <-chan bool {
		ch := make(chan bool)
		for i := 0; i < times; i++ {
			go func() {
Steven Allen's avatar
Steven Allen committed
251
				if _, err := s1.DialPeer(ctx, dst); err != nil {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
252 253 254 255 256 257 258 259 260 261 262 263 264 265
					t.Error("error dialing", dst, err)
					ch <- false
				} else {
					ch <- true
				}
			}()
		}
		return ch
	}

	dialOfflineNode := func(dst peer.ID, times int) <-chan bool {
		ch := make(chan bool)
		for i := 0; i < times; i++ {
			go func() {
Steven Allen's avatar
Steven Allen committed
266
				if c, err := s1.DialPeer(ctx, dst); err != nil {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
267 268 269 270 271 272 273 274 275 276 277 278 279 280
					ch <- false
				} else {
					t.Error("succeeded in dialing", dst)
					ch <- true
					c.Close()
				}
			}()
		}
		return ch
	}

	{
		// 1) dial 10x to each node.
		N := 10
Steven Allen's avatar
Steven Allen committed
281
		s2done := dialOnlineNode(s2.LocalPeer(), N)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
282 283 284
		s3done := dialOfflineNode(s3p, N)

		// when all dials should be done by:
285 286
		dialTimeout1x := time.After(transport.DialTimeout)
		dialTimeout10Ax := time.After(transport.DialTimeout * 2 * 10) // DialAttempts * 10)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340

		// 2) all dials should hang
		select {
		case <-s2done:
			t.Error("s2 should not happen immediately")
		case <-s3done:
			t.Error("s3 should not happen yet")
		case <-time.After(time.Millisecond):
			// s2 may finish very quickly, so let's get out.
		}

		// 3) s1->s2 should succeed.
		for i := 0; i < N; i++ {
			select {
			case r := <-s2done:
				if !r {
					t.Error("s2 should not fail")
				}
			case <-s3done:
				t.Error("s3 should not happen yet")
			case <-dialTimeout1x:
				t.Error("s2 took too long")
			}
		}

		select {
		case <-s2done:
			t.Error("s2 should have no more")
		case <-s3done:
			t.Error("s3 should not happen yet")
		case <-dialTimeout1x: // let it pass
		}

		// 4) s1->s3 should not (and should place s3 on backoff)
		// N-1 should finish before dialTimeout1x * 2
		for i := 0; i < N; i++ {
			select {
			case <-s2done:
				t.Error("s2 should have no more")
			case r := <-s3done:
				if r {
					t.Error("s3 should not succeed")
				}
			case <-(dialTimeout1x):
				if i < (N - 1) {
					t.Fatal("s3 took too long")
				}
				t.Log("dialTimeout1x * 1.3 hit for last peer")
			case <-dialTimeout10Ax:
				t.Fatal("s3 took too long")
			}
		}

		// check backoff state
Will Scott's avatar
Will Scott committed
341
		if s1.Backoff().Backoff(s2.LocalPeer(), s2addrs[0]) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
342 343
			t.Error("s2 should not be on backoff")
		}
Will Scott's avatar
Will Scott committed
344
		if !s1.Backoff().Backoff(s3p, s3addr) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
345 346 347 348 349
			t.Error("s3 should be on backoff")
		}

		// 5) disconnect entirely

Steven Allen's avatar
Steven Allen committed
350
		for _, c := range s1.Conns() {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
351 352
			c.Close()
		}
Steven Allen's avatar
Steven Allen committed
353
		for i := 0; i < 100 && len(s1.Conns()) > 0; i++ {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
354 355
			<-time.After(time.Millisecond)
		}
Steven Allen's avatar
Steven Allen committed
356
		if len(s1.Conns()) > 0 {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
357 358 359 360 361 362 363
			t.Fatal("s1 conns must exit")
		}
	}

	{
		// 6) dial 10x to each node again
		N := 10
Steven Allen's avatar
Steven Allen committed
364
		s2done := dialOnlineNode(s2.LocalPeer(), N)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
365 366 367
		s3done := dialOfflineNode(s3p, N)

		// when all dials should be done by:
368 369
		dialTimeout1x := time.After(transport.DialTimeout)
		dialTimeout10Ax := time.After(transport.DialTimeout * 2 * 10) // DialAttempts * 10)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410

		// 7) s3 dials should all return immediately (except 1)
		for i := 0; i < N-1; i++ {
			select {
			case <-s2done:
				t.Error("s2 should not succeed yet")
			case r := <-s3done:
				if r {
					t.Error("s3 should not succeed")
				}
			case <-dialTimeout1x:
				t.Fatal("s3 took too long")
			}
		}

		// 8) s2 dials should all hang, and succeed
		for i := 0; i < N; i++ {
			select {
			case r := <-s2done:
				if !r {
					t.Error("s2 should succeed")
				}
			// case <-s3done:
			case <-(dialTimeout1x):
				t.Fatal("s3 took too long")
			}
		}

		// 9) the last s3 should return, failed.
		select {
		case <-s2done:
			t.Error("s2 should have no more")
		case r := <-s3done:
			if r {
				t.Error("s3 should not succeed")
			}
		case <-dialTimeout10Ax:
			t.Fatal("s3 took too long")
		}

		// check backoff state (the same)
Will Scott's avatar
Will Scott committed
411
		if s1.Backoff().Backoff(s2.LocalPeer(), s2addrs[0]) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
412 413
			t.Error("s2 should not be on backoff")
		}
Will Scott's avatar
Will Scott committed
414
		if !s1.Backoff().Backoff(s3p, s3addr) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436
			t.Error("s3 should be on backoff")
		}
	}
}

func TestDialBackoffClears(t *testing.T) {
	// t.Skip("skipping for another test")
	t.Parallel()

	ctx := context.Background()
	swarms := makeSwarms(ctx, t, 2)
	s1 := swarms[0]
	s2 := swarms[1]
	defer s1.Close()
	defer s2.Close()

	// use another address first, that accept and hang on conns
	_, s2bad, s2l := newSilentPeer(t)
	go acceptAndHang(s2l)
	defer s2l.Close()

	// phase 1 -- dial to non-operational addresses
437
	s1.Peerstore().AddAddr(s2.LocalPeer(), s2bad, peerstore.PermanentAddrTTL)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
438 439

	before := time.Now()
Steven Allen's avatar
Steven Allen committed
440
	if c, err := s1.DialPeer(ctx, s2.LocalPeer()); err == nil {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
441 442 443 444 445
		t.Fatal("dialing to broken addr worked...", err)
		defer c.Close()
	} else {
		t.Log("correctly got error:", err)
	}
John Steidley's avatar
John Steidley committed
446
	duration := time.Since(before)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
447

448 449
	if duration < transport.DialTimeout*DialAttempts {
		t.Error("< transport.DialTimeout * DialAttempts not being respected", duration, transport.DialTimeout*DialAttempts)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
450
	}
451 452
	if duration > 2*transport.DialTimeout*DialAttempts {
		t.Error("> 2*transport.DialTimeout * DialAttempts not being respected", duration, 2*transport.DialTimeout*DialAttempts)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
453 454
	}

Will Scott's avatar
Will Scott committed
455
	if !s1.Backoff().Backoff(s2.LocalPeer(), s2bad) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
456 457 458 459 460 461 462 463 464 465
		t.Error("s2 should now be on backoff")
	} else {
		t.Log("correctly added to backoff")
	}

	// phase 2 -- add the working address. dial should succeed.
	ifaceAddrs1, err := swarms[1].InterfaceListenAddresses()
	if err != nil {
		t.Fatal(err)
	}
466
	s1.Peerstore().AddAddrs(s2.LocalPeer(), ifaceAddrs1, peerstore.PermanentAddrTTL)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
467

Will Scott's avatar
Will Scott committed
468 469 470
	if c, err := s1.DialPeer(ctx, s2.LocalPeer()); err == nil {
		c.Close()
		t.Log("backoffs are per address, not peer")
Jeromy's avatar
Jeromy committed
471 472
	}

Steven Allen's avatar
Steven Allen committed
473
	time.Sleep(BackoffBase)
Jeromy's avatar
Jeromy committed
474

Steven Allen's avatar
Steven Allen committed
475
	if c, err := s1.DialPeer(ctx, s2.LocalPeer()); err != nil {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
476 477 478 479 480 481
		t.Fatal(err)
	} else {
		c.Close()
		t.Log("correctly connected")
	}

Will Scott's avatar
Will Scott committed
482
	if s1.Backoff().Backoff(s2.LocalPeer(), s2bad) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
483 484 485 486 487
		t.Error("s2 should no longer be on backoff")
	} else {
		t.Log("correctly cleared backoff")
	}
}
tg's avatar
tg committed
488 489 490 491 492 493 494 495 496

func TestDialPeerFailed(t *testing.T) {
	t.Parallel()
	ctx := context.Background()

	swarms := makeSwarms(ctx, t, 2)
	defer closeSwarms(swarms)
	testedSwarm, targetSwarm := swarms[0], swarms[1]

497 498
	expectedErrorsCount := 5
	for i := 0; i < expectedErrorsCount; i++ {
tg's avatar
tg committed
499 500 501 502 503 504 505
		_, silentPeerAddress, silentPeerListener := newSilentPeer(t)
		go acceptAndHang(silentPeerListener)
		defer silentPeerListener.Close()

		testedSwarm.Peerstore().AddAddr(
			targetSwarm.LocalPeer(),
			silentPeerAddress,
506
			peerstore.PermanentAddrTTL)
tg's avatar
tg committed
507 508 509 510 511 512 513
	}

	_, err := testedSwarm.DialPeer(ctx, targetSwarm.LocalPeer())
	if err == nil {
		t.Fatal(err)
	}

514 515 516
	// dial_test.go:508: correctly get a combined error: failed to dial PEER: all dials failed
	//   * [/ip4/127.0.0.1/tcp/46485] failed to negotiate security protocol: context deadline exceeded
	//   * [/ip4/127.0.0.1/tcp/34881] failed to negotiate security protocol: context deadline exceeded
tg's avatar
tg committed
517 518
	// ...

519 520 521
	dialErr, ok := err.(*DialError)
	if !ok {
		t.Fatalf("expected *DialError, got %T", err)
tg's avatar
tg committed
522 523
	}

524 525
	if len(dialErr.DialErrors) != expectedErrorsCount {
		t.Errorf("expected %d errors, got %d", expectedErrorsCount, len(dialErr.DialErrors))
tg's avatar
tg committed
526 527
	}
}
vyzo's avatar
vyzo committed
528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551

func TestDialExistingConnection(t *testing.T) {
	ctx := context.Background()

	swarms := makeSwarms(ctx, t, 2)
	defer closeSwarms(swarms)
	s1 := swarms[0]
	s2 := swarms[1]

	s1.Peerstore().AddAddrs(s2.LocalPeer(), s2.ListenAddresses(), peerstore.PermanentAddrTTL)

	c1, err := s1.DialPeer(ctx, s2.LocalPeer())
	if err != nil {
		t.Fatal(err)
	}

	c2, err := s1.DialPeer(ctx, s2.LocalPeer())
	if err != nil {
		t.Fatal(err)
	}

	if c1 != c2 {
		t.Fatal("expecting the same connection from both dials")
	}
vyzo's avatar
vyzo committed
552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585
}

func newSilentListener(t *testing.T) ([]ma.Multiaddr, net.Listener) {
	lst, err := net.Listen("tcp4", "localhost:0")
	if err != nil {
		t.Fatal(err)
	}
	addr, err := manet.FromNetAddr(lst.Addr())
	if err != nil {
		t.Fatal(err)
	}
	addrs := []ma.Multiaddr{addr}
	addrs, err = addrutil.ResolveUnspecifiedAddresses(addrs, nil)
	if err != nil {
		t.Fatal(err)
	}
	return addrs, lst

}

func TestDialSimultaneousJoin(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	swarms := makeSwarms(ctx, t, 2)
	s1 := swarms[0]
	s2 := swarms[1]
	defer s1.Close()
	defer s2.Close()

	s2silentAddrs, s2silentListener := newSilentListener(t)
	go acceptAndHang(s2silentListener)

	connch := make(chan network.Conn, 512)
Cory Schwartz's avatar
Cory Schwartz committed
586
	errs := make(chan error, 2)
vyzo's avatar
vyzo committed
587 588 589 590 591 592 593

	// start a dial to s2 through the silent addr
	go func() {
		s1.Peerstore().AddAddrs(s2.LocalPeer(), s2silentAddrs, peerstore.PermanentAddrTTL)

		c, err := s1.DialPeer(ctx, s2.LocalPeer())
		if err != nil {
Cory Schwartz's avatar
Cory Schwartz committed
594 595 596
			errs <- err
			connch <- nil
			return
vyzo's avatar
vyzo committed
597 598 599 600 601
		}

		t.Logf("first dial succedded; conn: %+v", c)

		connch <- c
Cory Schwartz's avatar
Cory Schwartz committed
602
		errs <- nil
vyzo's avatar
vyzo committed
603 604 605 606 607 608 609 610 611
	}()

	// wait a bit for the dial to take hold
	time.Sleep(100 * time.Millisecond)

	// start a second dial to s2 that uses the real s2 addrs
	go func() {
		s2addrs, err := s2.InterfaceListenAddresses()
		if err != nil {
Cory Schwartz's avatar
Cory Schwartz committed
612 613
			errs <- err
			return
vyzo's avatar
vyzo committed
614 615 616 617 618
		}
		s1.Peerstore().AddAddrs(s2.LocalPeer(), s2addrs[:1], peerstore.PermanentAddrTTL)

		c, err := s1.DialPeer(ctx, s2.LocalPeer())
		if err != nil {
Cory Schwartz's avatar
Cory Schwartz committed
619 620 621
			errs <- err
			connch <- nil
			return
vyzo's avatar
vyzo committed
622
		}
vyzo's avatar
vyzo committed
623

vyzo's avatar
vyzo committed
624 625 626
		t.Logf("second dial succedded; conn: %+v", c)

		connch <- c
Cory Schwartz's avatar
Cory Schwartz committed
627
		errs <- nil
vyzo's avatar
vyzo committed
628 629 630 631 632 633 634 635 636
	}()

	// wait for the second dial to finish
	c2 := <-connch

	// start a third dial to s2, this should get the existing connection from the successful dial
	go func() {
		c, err := s1.DialPeer(ctx, s2.LocalPeer())
		if err != nil {
Cory Schwartz's avatar
Cory Schwartz committed
637 638 639
			errs <- err
			connch <- nil
			return
vyzo's avatar
vyzo committed
640 641 642 643 644
		}

		t.Logf("third dial succedded; conn: %+v", c)

		connch <- c
Cory Schwartz's avatar
Cory Schwartz committed
645
		errs <- nil
vyzo's avatar
vyzo committed
646 647 648 649
	}()

	c3 := <-connch

Cory Schwartz's avatar
Cory Schwartz committed
650 651 652 653 654 655 656 657
	// raise any errors from the two
	for i := 0; i < 3; i++ {
		err := <-errs
		if err != nil {
			t.Fatal(err)
		}
	}

vyzo's avatar
vyzo committed
658 659 660 661 662 663 664 665 666 667 668 669 670 671
	if c2 != c3 {
		t.Fatal("expected c2 and c3 to be the same")
	}

	// next, the first dial to s2, using the silent addr should timeout; at this point the dial
	// will error but the last chance check will see the existing connection and return it
	select {
	case c1 := <-connch:
		if c1 != c2 {
			t.Fatal("expected c1 and c2 to be the same")
		}
	case <-time.After(2 * transport.DialTimeout):
		t.Fatal("no connection from first dial")
	}
vyzo's avatar
vyzo committed
672
}
vyzo's avatar
vyzo committed
673

vyzo's avatar
vyzo committed
674
func TestDialSelf2(t *testing.T) {
vyzo's avatar
vyzo committed
675 676 677 678 679 680 681 682 683 684 685 686
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	swarms := makeSwarms(ctx, t, 2)
	s1 := swarms[0]
	defer s1.Close()

	_, err := s1.DialPeer(ctx, s1.LocalPeer())
	if err != ErrDialToSelf {
		t.Fatal("expected error from self dial")
	}
}