dht_test.go 18.6 KB
Newer Older
1 2
package dht

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
3
import (
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
4
	"bytes"
5
	"fmt"
6
	"math/rand"
7
	"sort"
8
	"sync"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
9
	"testing"
10
	"time"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
11

12 13
	pb "github.com/libp2p/go-libp2p-kad-dht/pb"

14 15 16
	ds "github.com/ipfs/go-datastore"
	dssync "github.com/ipfs/go-datastore/sync"
	u "github.com/ipfs/go-ipfs-util"
George Antoniadis's avatar
George Antoniadis committed
17
	key "github.com/ipfs/go-key"
18 19 20
	peer "github.com/ipfs/go-libp2p-peer"
	pstore "github.com/ipfs/go-libp2p-peerstore"
	ma "github.com/jbenet/go-multiaddr"
George Antoniadis's avatar
George Antoniadis committed
21 22 23 24 25
	record "github.com/libp2p/go-libp2p-record"
	routing "github.com/libp2p/go-libp2p-routing"
	netutil "github.com/libp2p/go-libp2p/p2p/test/util"
	ci "github.com/libp2p/go-testutil/ci"
	travisci "github.com/libp2p/go-testutil/ci/travis"
26
	context "golang.org/x/net/context"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
27 28
)

29
var testCaseValues = map[key.Key][]byte{}
30 31 32 33 34 35

func init() {
	testCaseValues["hello"] = []byte("world")
	for i := 0; i < 100; i++ {
		k := fmt.Sprintf("%d -- key", i)
		v := fmt.Sprintf("%d -- value", i)
36
		testCaseValues[key.Key(k)] = []byte(v)
37 38 39
	}
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
40 41
func setupDHT(ctx context.Context, t *testing.T) *IpfsDHT {
	h := netutil.GenHostSwarm(t, ctx)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
42

43
	dss := dssync.MutexWrap(ds.NewMapDatastore())
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
44
	d := NewDHT(ctx, h, dss)
45

46
	d.Validator["v"] = &record.ValidChecker{
47
		Func: func(key.Key, []byte) error {
48 49 50
			return nil
		},
		Sign: false,
Jeromy's avatar
Jeromy committed
51
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
52 53 54
	return d
}

55 56
func setupDHTS(ctx context.Context, n int, t *testing.T) ([]ma.Multiaddr, []peer.ID, []*IpfsDHT) {
	addrs := make([]ma.Multiaddr, n)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
57
	dhts := make([]*IpfsDHT, n)
58 59
	peers := make([]peer.ID, n)

60 61 62
	sanityAddrsMap := make(map[string]struct{})
	sanityPeersMap := make(map[string]struct{})

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
63
	for i := 0; i < n; i++ {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
64
		dhts[i] = setupDHT(ctx, t)
65
		peers[i] = dhts[i].self
66
		addrs[i] = dhts[i].peerstore.Addrs(dhts[i].self)[0]
67 68

		if _, lol := sanityAddrsMap[addrs[i].String()]; lol {
Jakub Sztandera's avatar
Jakub Sztandera committed
69
			t.Fatal("While setting up DHTs address got duplicated.")
70 71 72 73
		} else {
			sanityAddrsMap[addrs[i].String()] = struct{}{}
		}
		if _, lol := sanityPeersMap[peers[i].String()]; lol {
Jakub Sztandera's avatar
Jakub Sztandera committed
74
			t.Fatal("While setting up DHTs peerid got duplicated.")
75 76 77
		} else {
			sanityPeersMap[peers[i].String()] = struct{}{}
		}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
78 79 80 81 82
	}

	return addrs, peers, dhts
}

83
func connect(t *testing.T, ctx context.Context, a, b *IpfsDHT) {
84

85
	idB := b.self
86
	addrB := b.peerstore.Addrs(idB)
87 88
	if len(addrB) == 0 {
		t.Fatal("peers setup incorrectly: no local address")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
89
	}
90

Jeromy's avatar
Jeromy committed
91 92
	a.peerstore.AddAddrs(idB, addrB, pstore.TempAddrTTL)
	pi := pstore.PeerInfo{ID: idB}
Jeromy's avatar
Jeromy committed
93
	if err := a.host.Connect(ctx, pi); err != nil {
94
		t.Fatal(err)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
95
	}
96

97 98
	// loop until connection notification has been received.
	// under high load, this may not happen as immediately as we would like.
99 100 101 102 103 104 105
	for a.routingTable.Find(b.self) == "" {
		time.Sleep(time.Millisecond * 5)
	}

	for b.routingTable.Find(a.self) == "" {
		time.Sleep(time.Millisecond * 5)
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
106 107
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
108
func bootstrap(t *testing.T, ctx context.Context, dhts []*IpfsDHT) {
109

110
	ctx, cancel := context.WithCancel(ctx)
Richard Littauer's avatar
Richard Littauer committed
111
	log.Debugf("Bootstrapping DHTs...")
112 113 114 115 116 117

	// tried async. sequential fares much better. compare:
	// 100 async https://gist.github.com/jbenet/56d12f0578d5f34810b2
	// 100 sync https://gist.github.com/jbenet/6c59e7c15426e48aaedd
	// probably because results compound

118 119 120 121
	var cfg BootstrapConfig
	cfg = DefaultBootstrapConfig
	cfg.Queries = 3

122 123 124
	start := rand.Intn(len(dhts)) // randomize to decrease bias.
	for i := range dhts {
		dht := dhts[(start+i)%len(dhts)]
125
		dht.runBootstrap(ctx, cfg)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
126
	}
127
	cancel()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
128 129
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
130
func TestValueGetSet(t *testing.T) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
131 132
	// t.Skip("skipping test to debug another")

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
133
	ctx := context.Background()
134

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
135 136
	dhtA := setupDHT(ctx, t)
	dhtB := setupDHT(ctx, t)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
137

138 139
	defer dhtA.Close()
	defer dhtB.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
140 141
	defer dhtA.host.Close()
	defer dhtB.host.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
142

143
	vf := &record.ValidChecker{
144
		Func: func(key.Key, []byte) error {
145 146 147
			return nil
		},
		Sign: false,
Jeromy's avatar
Jeromy committed
148
	}
149 150 151 152
	nulsel := func(_ key.Key, bs [][]byte) (int, error) {
		return 0, nil
	}

153 154
	dhtA.Validator["v"] = vf
	dhtB.Validator["v"] = vf
155 156
	dhtA.Selector["v"] = nulsel
	dhtB.Selector["v"] = nulsel
Jeromy's avatar
Jeromy committed
157

158
	connect(t, ctx, dhtA, dhtB)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
159

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
160
	ctxT, _ := context.WithTimeout(ctx, time.Second)
161
	dhtA.PutValue(ctxT, "/v/hello", []byte("world"))
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
162

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
163
	ctxT, _ = context.WithTimeout(ctx, time.Second*2)
Jeromy's avatar
Jeromy committed
164
	val, err := dhtA.GetValue(ctxT, "/v/hello")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
165 166 167 168 169 170 171 172
	if err != nil {
		t.Fatal(err)
	}

	if string(val) != "world" {
		t.Fatalf("Expected 'world' got '%s'", string(val))
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
173
	ctxT, _ = context.WithTimeout(ctx, time.Second*2)
Jeromy's avatar
Jeromy committed
174
	val, err = dhtB.GetValue(ctxT, "/v/hello")
175 176 177 178 179 180 181
	if err != nil {
		t.Fatal(err)
	}

	if string(val) != "world" {
		t.Fatalf("Expected 'world' got '%s'", string(val))
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
182 183
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
184 185
func TestProvides(t *testing.T) {
	// t.Skip("skipping test to debug another")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
186
	ctx := context.Background()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
187

188
	_, _, dhts := setupDHTS(ctx, 4, t)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
189 190
	defer func() {
		for i := 0; i < 4; i++ {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
191
			dhts[i].Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
192
			defer dhts[i].host.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
193 194 195
		}
	}()

196 197 198
	connect(t, ctx, dhts[0], dhts[1])
	connect(t, ctx, dhts[1], dhts[2])
	connect(t, ctx, dhts[1], dhts[3])
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
199

200
	for k, v := range testCaseValues {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
201
		log.Debugf("adding local values for %s = %s", k, v)
Jeromy's avatar
Jeromy committed
202 203 204 205 206 207 208
		sk := dhts[3].peerstore.PrivKey(dhts[3].self)
		rec, err := record.MakePutRecord(sk, k, v, false)
		if err != nil {
			t.Fatal(err)
		}

		err = dhts[3].putLocal(k, rec)
209 210 211 212 213 214 215 216
		if err != nil {
			t.Fatal(err)
		}

		bits, err := dhts[3].getLocal(k)
		if err != nil {
			t.Fatal(err)
		}
217
		if !bytes.Equal(bits.GetValue(), v) {
218
			t.Fatalf("didn't store the right bits (%s, %s)", k, v)
219
		}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
220 221
	}

rht's avatar
rht committed
222
	for k := range testCaseValues {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
223
		log.Debugf("announcing provider for %s", k)
224 225 226
		if err := dhts[3].Provide(ctx, k); err != nil {
			t.Fatal(err)
		}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
227 228
	}

229 230 231 232
	// what is this timeout for? was 60ms before.
	time.Sleep(time.Millisecond * 6)

	n := 0
rht's avatar
rht committed
233
	for k := range testCaseValues {
234 235
		n = (n + 1) % 3

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
236
		log.Debugf("getting providers for %s from %d", k, n)
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
		ctxT, _ := context.WithTimeout(ctx, time.Second)
		provchan := dhts[n].FindProvidersAsync(ctxT, k, 1)

		select {
		case prov := <-provchan:
			if prov.ID == "" {
				t.Fatal("Got back nil provider")
			}
			if prov.ID != dhts[3].self {
				t.Fatal("Got back wrong provider")
			}
		case <-ctxT.Done():
			t.Fatal("Did not get a provider back.")
		}
	}
}

254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
// if minPeers or avgPeers is 0, dont test for it.
func waitForWellFormedTables(t *testing.T, dhts []*IpfsDHT, minPeers, avgPeers int, timeout time.Duration) bool {
	// test "well-formed-ness" (>= minPeers peers in every routing table)

	checkTables := func() bool {
		totalPeers := 0
		for _, dht := range dhts {
			rtlen := dht.routingTable.Size()
			totalPeers += rtlen
			if minPeers > 0 && rtlen < minPeers {
				t.Logf("routing table for %s only has %d peers (should have >%d)", dht.self, rtlen, minPeers)
				return false
			}
		}
		actualAvgPeers := totalPeers / len(dhts)
		t.Logf("avg rt size: %d", actualAvgPeers)
		if avgPeers > 0 && actualAvgPeers < avgPeers {
			t.Logf("avg rt size: %d < %d", actualAvgPeers, avgPeers)
			return false
		}
		return true
	}

	timeoutA := time.After(timeout)
	for {
		select {
		case <-timeoutA:
281
			log.Debugf("did not reach well-formed routing tables by %s", timeout)
282 283 284 285 286 287 288 289 290 291 292
			return false // failed
		case <-time.After(5 * time.Millisecond):
			if checkTables() {
				return true // succeeded
			}
		}
	}
}

func printRoutingTables(dhts []*IpfsDHT) {
	// the routing tables should be full now. let's inspect them.
293
	fmt.Printf("checking routing table of %d\n", len(dhts))
294 295 296 297 298 299 300
	for _, dht := range dhts {
		fmt.Printf("checking routing table of %s\n", dht.self)
		dht.routingTable.Print()
		fmt.Println("")
	}
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
301
func TestBootstrap(t *testing.T) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
302
	// t.Skip("skipping test to debug another")
303 304 305 306
	if testing.Short() {
		t.SkipNow()
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
307 308
	ctx := context.Background()

309
	nDHTs := 30
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
310 311 312 313
	_, _, dhts := setupDHTS(ctx, nDHTs, t)
	defer func() {
		for i := 0; i < nDHTs; i++ {
			dhts[i].Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
314
			defer dhts[i].host.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
315 316 317 318 319 320 321 322
		}
	}()

	t.Logf("connecting %d dhts in a ring", nDHTs)
	for i := 0; i < nDHTs; i++ {
		connect(t, ctx, dhts[i], dhts[(i+1)%len(dhts)])
	}

323
	<-time.After(100 * time.Millisecond)
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
	// bootstrap a few times until we get good tables.
	stop := make(chan struct{})
	go func() {
		for {
			t.Logf("bootstrapping them so they find each other", nDHTs)
			ctxT, _ := context.WithTimeout(ctx, 5*time.Second)
			bootstrap(t, ctxT, dhts)

			select {
			case <-time.After(50 * time.Millisecond):
				continue // being explicit
			case <-stop:
				return
			}
		}
	}()

341
	waitForWellFormedTables(t, dhts, 7, 10, 20*time.Second)
342
	close(stop)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
343

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
344 345
	if u.Debug {
		// the routing tables should be full now. let's inspect them.
346 347 348 349 350 351
		printRoutingTables(dhts)
	}
}

func TestPeriodicBootstrap(t *testing.T) {
	// t.Skip("skipping test to debug another")
352 353 354
	if ci.IsRunning() {
		t.Skip("skipping on CI. highly timing dependent")
	}
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
	if testing.Short() {
		t.SkipNow()
	}

	ctx := context.Background()

	nDHTs := 30
	_, _, dhts := setupDHTS(ctx, nDHTs, t)
	defer func() {
		for i := 0; i < nDHTs; i++ {
			dhts[i].Close()
			defer dhts[i].host.Close()
		}
	}()

	// signal amplifier
	amplify := func(signal chan time.Time, other []chan time.Time) {
		for t := range signal {
			for _, s := range other {
				s <- t
			}
		}
		for _, s := range other {
			close(s)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
379 380 381
		}
	}

382 383 384
	signal := make(chan time.Time)
	allSignals := []chan time.Time{}

385 386 387 388
	var cfg BootstrapConfig
	cfg = DefaultBootstrapConfig
	cfg.Queries = 5

389 390 391 392
	// kick off periodic bootstrappers with instrumented signals.
	for _, dht := range dhts {
		s := make(chan time.Time)
		allSignals = append(allSignals, s)
393
		dht.BootstrapOnSignal(cfg, s)
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408
	}
	go amplify(signal, allSignals)

	t.Logf("dhts are not connected.", nDHTs)
	for _, dht := range dhts {
		rtlen := dht.routingTable.Size()
		if rtlen > 0 {
			t.Errorf("routing table for %s should have 0 peers. has %d", dht.self, rtlen)
		}
	}

	for i := 0; i < nDHTs; i++ {
		connect(t, ctx, dhts[i], dhts[(i+1)%len(dhts)])
	}

Richard Littauer's avatar
Richard Littauer committed
409
	t.Logf("DHTs are now connected to 1-2 others.", nDHTs)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
410
	for _, dht := range dhts {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
411
		rtlen := dht.routingTable.Size()
412 413
		if rtlen > 2 {
			t.Errorf("routing table for %s should have at most 2 peers. has %d", dht.self, rtlen)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
414
		}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
415
	}
416

417 418 419 420 421 422 423 424 425
	if u.Debug {
		printRoutingTables(dhts)
	}

	t.Logf("bootstrapping them so they find each other", nDHTs)
	signal <- time.Now()

	// this is async, and we dont know when it's finished with one cycle, so keep checking
	// until the routing tables look better, or some long timeout for the failure case.
426
	waitForWellFormedTables(t, dhts, 7, 10, 20*time.Second)
427 428 429

	if u.Debug {
		printRoutingTables(dhts)
430
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
431 432
}

433 434
func TestProvidesMany(t *testing.T) {
	t.Skip("this test doesn't work")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
435
	// t.Skip("skipping test to debug another")
436 437 438 439 440 441 442
	ctx := context.Background()

	nDHTs := 40
	_, _, dhts := setupDHTS(ctx, nDHTs, t)
	defer func() {
		for i := 0; i < nDHTs; i++ {
			dhts[i].Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
443
			defer dhts[i].host.Close()
444 445 446 447 448 449 450 451
		}
	}()

	t.Logf("connecting %d dhts in a ring", nDHTs)
	for i := 0; i < nDHTs; i++ {
		connect(t, ctx, dhts[i], dhts[(i+1)%len(dhts)])
	}

452
	<-time.After(100 * time.Millisecond)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
453
	t.Logf("bootstrapping them so they find each other", nDHTs)
454
	ctxT, _ := context.WithTimeout(ctx, 20*time.Second)
455 456
	bootstrap(t, ctxT, dhts)

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
457 458 459 460 461 462 463 464
	if u.Debug {
		// the routing tables should be full now. let's inspect them.
		t.Logf("checking routing table of %d", nDHTs)
		for _, dht := range dhts {
			fmt.Printf("checking routing table of %s\n", dht.self)
			dht.routingTable.Print()
			fmt.Println("")
		}
465
	}
466

467
	var providers = map[key.Key]peer.ID{}
468

469 470 471 472
	d := 0
	for k, v := range testCaseValues {
		d = (d + 1) % len(dhts)
		dht := dhts[d]
473
		providers[k] = dht.self
474 475

		t.Logf("adding local values for %s = %s (on %s)", k, v, dht.self)
Jeromy's avatar
Jeromy committed
476 477 478 479 480 481
		rec, err := record.MakePutRecord(nil, k, v, false)
		if err != nil {
			t.Fatal(err)
		}

		err = dht.putLocal(k, rec)
482 483 484 485 486 487 488 489
		if err != nil {
			t.Fatal(err)
		}

		bits, err := dht.getLocal(k)
		if err != nil {
			t.Fatal(err)
		}
490
		if !bytes.Equal(bits.GetValue(), v) {
491
			t.Fatalf("didn't store the right bits (%s, %s)", k, v)
492 493 494 495 496 497
		}

		t.Logf("announcing provider for %s", k)
		if err := dht.Provide(ctx, k); err != nil {
			t.Fatal(err)
		}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
498 499
	}

500 501
	// what is this timeout for? was 60ms before.
	time.Sleep(time.Millisecond * 6)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
502

503 504
	errchan := make(chan error)

505
	ctxT, _ = context.WithTimeout(ctx, 5*time.Second)
506 507

	var wg sync.WaitGroup
508
	getProvider := func(dht *IpfsDHT, k key.Key) {
509
		defer wg.Done()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
510

511 512
		expected := providers[k]

513 514 515
		provchan := dht.FindProvidersAsync(ctxT, k, 1)
		select {
		case prov := <-provchan:
516 517
			actual := prov.ID
			if actual == "" {
518
				errchan <- fmt.Errorf("Got back nil provider (%s at %s)", k, dht.self)
519 520 521
			} else if actual != expected {
				errchan <- fmt.Errorf("Got back wrong provider (%s != %s) (%s at %s)",
					expected, actual, k, dht.self)
522 523 524
			}
		case <-ctxT.Done():
			errchan <- fmt.Errorf("Did not get a provider back (%s at %s)", k, dht.self)
Jeromy's avatar
Jeromy committed
525
		}
526 527
	}

rht's avatar
rht committed
528
	for k := range testCaseValues {
529 530
		// everyone should be able to find it...
		for _, dht := range dhts {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
531
			log.Debugf("getting providers for %s at %s", k, dht.self)
532 533
			wg.Add(1)
			go getProvider(dht, k)
534
		}
535 536 537 538 539 540 541 542 543 544
	}

	// we need this because of printing errors
	go func() {
		wg.Wait()
		close(errchan)
	}()

	for err := range errchan {
		t.Error(err)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
545 546 547
	}
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
548
func TestProvidesAsync(t *testing.T) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
549
	// t.Skip("skipping test to debug another")
550 551 552
	if testing.Short() {
		t.SkipNow()
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
553

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
554
	ctx := context.Background()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
555

556
	_, _, dhts := setupDHTS(ctx, 4, t)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
557 558
	defer func() {
		for i := 0; i < 4; i++ {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
559
			dhts[i].Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
560
			defer dhts[i].host.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
561 562 563
		}
	}()

564 565 566
	connect(t, ctx, dhts[0], dhts[1])
	connect(t, ctx, dhts[1], dhts[2])
	connect(t, ctx, dhts[1], dhts[3])
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
567

568
	k := key.Key("hello")
Jeromy's avatar
Jeromy committed
569 570 571 572 573 574 575 576
	val := []byte("world")
	sk := dhts[3].peerstore.PrivKey(dhts[3].self)
	rec, err := record.MakePutRecord(sk, k, val, false)
	if err != nil {
		t.Fatal(err)
	}

	err = dhts[3].putLocal(k, rec)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
577 578 579 580
	if err != nil {
		t.Fatal(err)
	}

Jeromy's avatar
Jeromy committed
581
	bits, err := dhts[3].getLocal(k)
582
	if err != nil && bytes.Equal(bits.GetValue(), val) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
583 584 585
		t.Fatal(err)
	}

586
	err = dhts[3].Provide(ctx, key.Key("hello"))
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
587 588 589 590 591 592
	if err != nil {
		t.Fatal(err)
	}

	time.Sleep(time.Millisecond * 60)

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
593
	ctxT, _ := context.WithTimeout(ctx, time.Millisecond*300)
594
	provs := dhts[0].FindProvidersAsync(ctxT, key.Key("hello"), 5)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
595
	select {
Jeromy's avatar
Jeromy committed
596 597 598 599
	case p, ok := <-provs:
		if !ok {
			t.Fatal("Provider channel was closed...")
		}
600
		if p.ID == "" {
Jeromy's avatar
Jeromy committed
601 602
			t.Fatal("Got back nil provider!")
		}
603
		if p.ID != dhts[3].self {
604
			t.Fatalf("got a provider, but not the right one. %s", p)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
605
		}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
606
	case <-ctxT.Done():
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
607 608 609 610
		t.Fatal("Didnt get back providers")
	}
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
611
func TestLayeredGet(t *testing.T) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
612
	// t.Skip("skipping test to debug another")
613 614 615
	if testing.Short() {
		t.SkipNow()
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
616

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
617
	ctx := context.Background()
618

619
	_, _, dhts := setupDHTS(ctx, 4, t)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
620 621
	defer func() {
		for i := 0; i < 4; i++ {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
622
			dhts[i].Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
623
			defer dhts[i].host.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
624 625 626
		}
	}()

627 628 629
	connect(t, ctx, dhts[0], dhts[1])
	connect(t, ctx, dhts[1], dhts[2])
	connect(t, ctx, dhts[1], dhts[3])
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
630

631
	err := dhts[3].Provide(ctx, key.Key("/v/hello"))
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
632 633 634 635
	if err != nil {
		t.Fatal(err)
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
636
	time.Sleep(time.Millisecond * 6)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
637

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
638
	t.Log("interface was changed. GetValue should not use providers.")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
639
	ctxT, _ := context.WithTimeout(ctx, time.Second)
640
	val, err := dhts[0].GetValue(ctxT, key.Key("/v/hello"))
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
641 642
	if err != routing.ErrNotFound {
		t.Error(err)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
643
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
644 645 646 647 648
	if string(val) == "world" {
		t.Error("should not get value.")
	}
	if len(val) > 0 && string(val) != "world" {
		t.Error("worse, there's a value and its not even the right one.")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
649 650 651 652
	}
}

func TestFindPeer(t *testing.T) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
653
	// t.Skip("skipping test to debug another")
654 655 656
	if testing.Short() {
		t.SkipNow()
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
657

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
658
	ctx := context.Background()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
659

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
660
	_, peers, dhts := setupDHTS(ctx, 4, t)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
661 662
	defer func() {
		for i := 0; i < 4; i++ {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
663
			dhts[i].Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
664
			dhts[i].host.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
665 666 667
		}
	}()

668 669 670
	connect(t, ctx, dhts[0], dhts[1])
	connect(t, ctx, dhts[1], dhts[2])
	connect(t, ctx, dhts[1], dhts[3])
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
671

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
672
	ctxT, _ := context.WithTimeout(ctx, time.Second)
673
	p, err := dhts[0].FindPeer(ctxT, peers[2])
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
674 675 676 677
	if err != nil {
		t.Fatal(err)
	}

678
	if p.ID == "" {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
679 680 681
		t.Fatal("Failed to find peer.")
	}

682
	if p.ID != peers[2] {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
683 684 685
		t.Fatal("Didnt find expected peer.")
	}
}
686

687
func TestFindPeersConnectedToPeer(t *testing.T) {
688 689
	t.Skip("not quite correct (see note)")

690 691 692 693 694 695 696 697 698 699
	if testing.Short() {
		t.SkipNow()
	}

	ctx := context.Background()

	_, peers, dhts := setupDHTS(ctx, 4, t)
	defer func() {
		for i := 0; i < 4; i++ {
			dhts[i].Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
700
			dhts[i].host.Close()
701 702 703 704 705
		}
	}()

	// topology:
	// 0-1, 1-2, 1-3, 2-3
706 707 708 709
	connect(t, ctx, dhts[0], dhts[1])
	connect(t, ctx, dhts[1], dhts[2])
	connect(t, ctx, dhts[1], dhts[3])
	connect(t, ctx, dhts[2], dhts[3])
710 711 712 713 714 715 716

	// fmt.Println("0 is", peers[0])
	// fmt.Println("1 is", peers[1])
	// fmt.Println("2 is", peers[2])
	// fmt.Println("3 is", peers[3])

	ctxT, _ := context.WithTimeout(ctx, time.Second)
717
	pchan, err := dhts[0].FindPeersConnectedToPeer(ctxT, peers[2])
718 719 720 721
	if err != nil {
		t.Fatal(err)
	}

722
	// shouldFind := []peer.ID{peers[1], peers[3]}
Jeromy's avatar
Jeromy committed
723
	var found []pstore.PeerInfo
724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739
	for nextp := range pchan {
		found = append(found, nextp)
	}

	// fmt.Printf("querying 0 (%s) FindPeersConnectedToPeer 2 (%s)\n", peers[0], peers[2])
	// fmt.Println("should find 1, 3", shouldFind)
	// fmt.Println("found", found)

	// testPeerListsMatch(t, shouldFind, found)

	log.Warning("TestFindPeersConnectedToPeer is not quite correct")
	if len(found) == 0 {
		t.Fatal("didn't find any peers.")
	}
}

740
func testPeerListsMatch(t *testing.T, p1, p2 []peer.ID) {
741 742 743 744 745 746 747 748 749

	if len(p1) != len(p2) {
		t.Fatal("did not find as many peers as should have", p1, p2)
	}

	ids1 := make([]string, len(p1))
	ids2 := make([]string, len(p2))

	for i, p := range p1 {
750
		ids1[i] = string(p)
751 752 753
	}

	for i, p := range p2 {
754
		ids2[i] = string(p)
755 756 757 758 759 760 761 762 763 764 765 766
	}

	sort.Sort(sort.StringSlice(ids1))
	sort.Sort(sort.StringSlice(ids2))

	for i := range ids1 {
		if ids1[i] != ids2[i] {
			t.Fatal("Didnt find expected peer", ids1[i], ids2)
		}
	}
}

767
func TestConnectCollision(t *testing.T) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
768
	// t.Skip("skipping test to debug another")
769 770 771
	if testing.Short() {
		t.SkipNow()
	}
772 773 774
	if travisci.IsRunning() {
		t.Skip("Skipping on Travis-CI.")
	}
775

776
	runTimes := 10
777

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
778
	for rtime := 0; rtime < runTimes; rtime++ {
rht's avatar
rht committed
779
		log.Info("Running Time: ", rtime)
780

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
781
		ctx := context.Background()
782

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
783 784
		dhtA := setupDHT(ctx, t)
		dhtB := setupDHT(ctx, t)
785

786 787
		addrA := dhtA.peerstore.Addrs(dhtA.self)[0]
		addrB := dhtB.peerstore.Addrs(dhtB.self)[0]
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
788

789 790
		peerA := dhtA.self
		peerB := dhtB.self
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
791

792
		errs := make(chan error)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
793
		go func() {
Jeromy's avatar
Jeromy committed
794 795
			dhtA.peerstore.AddAddr(peerB, addrB, pstore.TempAddrTTL)
			pi := pstore.PeerInfo{ID: peerB}
Jeromy's avatar
Jeromy committed
796
			err := dhtA.host.Connect(ctx, pi)
797
			errs <- err
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
798 799
		}()
		go func() {
Jeromy's avatar
Jeromy committed
800 801
			dhtB.peerstore.AddAddr(peerA, addrA, pstore.TempAddrTTL)
			pi := pstore.PeerInfo{ID: peerA}
Jeromy's avatar
Jeromy committed
802
			err := dhtB.host.Connect(ctx, pi)
803
			errs <- err
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
804 805
		}()

806
		timeout := time.After(5 * time.Second)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
807
		select {
808 809 810 811
		case e := <-errs:
			if e != nil {
				t.Fatal(e)
			}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
812 813 814 815
		case <-timeout:
			t.Fatal("Timeout received!")
		}
		select {
816 817 818 819
		case e := <-errs:
			if e != nil {
				t.Fatal(e)
			}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
820 821 822 823
		case <-timeout:
			t.Fatal("Timeout received!")
		}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
824 825
		dhtA.Close()
		dhtB.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
826 827
		dhtA.host.Close()
		dhtB.host.Close()
Jeromy's avatar
Jeromy committed
828
	}
829
}
830 831 832 833 834 835 836 837 838 839 840 841

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

	d := setupDHT(ctx, t)

	nilrec := new(pb.Message)
	if _, err := d.handlePutValue(ctx, "testpeer", nilrec); err == nil {
		t.Fatal("should have errored on nil record")
	}
}