notify_test.go 3.06 KB
Newer Older
Steven Allen's avatar
Steven Allen committed
1 2 3 4
package dht

import (
	"context"
5
	"fmt"
Steven Allen's avatar
Steven Allen committed
6
	"testing"
7 8
	"time"

9
	tu "github.com/libp2p/go-libp2p-testing/etc"
Aarsh Shah's avatar
Aarsh Shah committed
10 11

	"github.com/stretchr/testify/require"
Steven Allen's avatar
Steven Allen committed
12 13
)

Aarsh Shah's avatar
Aarsh Shah committed
14 15 16 17 18 19
// TODO Debug test failures due to timing issue on windows
// Both tests are timing dependent as can be seen in the 2 seconds timed context that we use in "tu.WaitFor".
// While both tests work fine on OSX and complete in under a second,
// they repeatedly fail to complete in the stipulated time on Windows.
// However, increasing the timeout makes them pass on Windows.

Steven Allen's avatar
Steven Allen committed
20 21 22 23
func TestNotifieeMultipleConn(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

Aarsh Shah's avatar
Aarsh Shah committed
24 25
	d1 := setupDHT(ctx, t, false, RoutingTableCheckInterval(50*time.Millisecond))
	d2 := setupDHT(ctx, t, false, RoutingTableCheckInterval(50*time.Millisecond))
Steven Allen's avatar
Steven Allen committed
26

27 28 29 30 31 32 33 34
	nn1, err := newSubscriberNotifiee(d1)
	if err != nil {
		t.Fatal(err)
	}
	nn2, err := newSubscriberNotifiee(d2)
	if err != nil {
		t.Fatal(err)
	}
Steven Allen's avatar
Steven Allen committed
35 36 37 38 39 40 41 42 43 44 45 46

	connect(t, ctx, d1, d2)
	c12 := d1.host.Network().ConnsToPeer(d2.self)[0]
	c21 := d2.host.Network().ConnsToPeer(d1.self)[0]

	// Pretend to reestablish/re-kill connection
	nn1.Connected(d1.host.Network(), c12)
	nn2.Connected(d2.host.Network(), c21)

	if !checkRoutingTable(d1, d2) {
		t.Fatal("no routes")
	}
Aarsh Shah's avatar
Aarsh Shah committed
47 48

	// we are still connected, so the disconnect notification should be a No-op
Steven Allen's avatar
Steven Allen committed
49 50 51 52 53 54 55
	nn1.Disconnected(d1.host.Network(), c12)
	nn2.Disconnected(d2.host.Network(), c21)

	if !checkRoutingTable(d1, d2) {
		t.Fatal("no routes")
	}

Aarsh Shah's avatar
Aarsh Shah committed
56 57
	// the connection close should now mark the peer as missing in the RT for both peers
	// because of the disconnect notification
Steven Allen's avatar
Steven Allen committed
58 59 60 61 62 63 64
	for _, conn := range d1.host.Network().ConnsToPeer(d2.self) {
		conn.Close()
	}
	for _, conn := range d2.host.Network().ConnsToPeer(d1.self) {
		conn.Close()
	}

Aarsh Shah's avatar
Aarsh Shah committed
65 66 67 68 69 70 71 72 73
	// close both the hosts so all connection attempts to them by RT Peer validation fail
	d1.host.Close()
	d2.host.Close()

	// wait context will ensure that the RT cleanup completes
	waitCtx, cancel := context.WithTimeout(ctx, 2*time.Second)
	defer cancel()

	require.NoError(t, tu.WaitFor(waitCtx, func() error {
74 75 76 77
		if checkRoutingTable(d1, d2) {
			return fmt.Errorf("should not have routes")
		}
		return nil
Aarsh Shah's avatar
Aarsh Shah committed
78
	}))
Steven Allen's avatar
Steven Allen committed
79 80 81
}

func TestNotifieeFuzz(t *testing.T) {
82
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
Steven Allen's avatar
Steven Allen committed
83 84
	defer cancel()

Aarsh Shah's avatar
Aarsh Shah committed
85 86
	d1 := setupDHT(ctx, t, false, RoutingTableCheckInterval(50*time.Millisecond))
	d2 := setupDHT(ctx, t, false, RoutingTableCheckInterval(50*time.Millisecond))
Steven Allen's avatar
Steven Allen committed
87

Matt Joiner's avatar
Matt Joiner committed
88
	for i := 0; i < 10; i++ {
Steven Allen's avatar
Steven Allen committed
89 90 91 92 93
		connectNoSync(t, ctx, d1, d2)
		for _, conn := range d1.host.Network().ConnsToPeer(d2.self) {
			conn.Close()
		}
	}
Aarsh Shah's avatar
Aarsh Shah committed
94 95 96 97 98

	// close both hosts so peer validation reconnect fails
	d1.host.Close()
	d2.host.Close()
	require.NoError(t, tu.WaitFor(ctx, func() error {
99 100 101 102
		if checkRoutingTable(d1, d2) {
			return fmt.Errorf("should not have routes")
		}
		return nil
Aarsh Shah's avatar
Aarsh Shah committed
103
	}))
Steven Allen's avatar
Steven Allen committed
104 105 106 107 108 109 110
}

func checkRoutingTable(a, b *IpfsDHT) bool {
	// loop until connection notification has been received.
	// under high load, this may not happen as immediately as we would like.
	return a.routingTable.Find(b.self) != "" && b.routingTable.Find(a.self) != ""
}