dht_test.go 17.5 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
	ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore"
13
	dssync "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore/sync"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
14
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
15
	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
16

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
17
	peer "github.com/jbenet/go-ipfs/p2p/peer"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
18
	netutil "github.com/jbenet/go-ipfs/p2p/test/util"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
19
	routing "github.com/jbenet/go-ipfs/routing"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
20
	u "github.com/jbenet/go-ipfs/util"
21

22
	ci "github.com/jbenet/go-ipfs/util/testutil/ci"
23
	travisci "github.com/jbenet/go-ipfs/util/testutil/ci/travis"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
24 25
)

26 27 28 29 30 31 32 33 34 35 36
var testCaseValues = map[u.Key][]byte{}

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

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

40
	dss := dssync.MutexWrap(ds.NewMapDatastore())
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
41
	d := NewDHT(ctx, h, dss)
42

43
	d.Validator["v"] = func(u.Key, []byte) error {
Jeromy's avatar
Jeromy committed
44 45
		return nil
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
46 47 48
	return d
}

49 50
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
51
	dhts := make([]*IpfsDHT, n)
52 53
	peers := make([]peer.ID, n)

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
54
	for i := 0; i < n; i++ {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
55
		dhts[i] = setupDHT(ctx, t)
56
		peers[i] = dhts[i].self
57
		addrs[i] = dhts[i].peerstore.Addrs(dhts[i].self)[0]
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
58 59 60 61 62
	}

	return addrs, peers, dhts
}

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

65
	idB := b.self
66
	addrB := b.peerstore.Addrs(idB)
67 68
	if len(addrB) == 0 {
		t.Fatal("peers setup incorrectly: no local address")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
69
	}
70

71
	a.peerstore.AddAddrs(idB, addrB, peer.TempAddrTTL)
72 73
	if err := a.Connect(ctx, idB); err != nil {
		t.Fatal(err)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
74 75 76
	}
}

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

79
	ctx, cancel := context.WithCancel(ctx)
80 81 82 83 84 85 86
	log.Debugf("bootstrapping dhts...")

	// 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

87 88 89 90
	var cfg BootstrapConfig
	cfg = DefaultBootstrapConfig
	cfg.Queries = 3

91 92 93
	start := rand.Intn(len(dhts)) // randomize to decrease bias.
	for i := range dhts {
		dht := dhts[(start+i)%len(dhts)]
94
		dht.runBootstrap(ctx, cfg)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
95
	}
96
	cancel()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
97 98
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
99
func TestPing(t *testing.T) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
100
	// t.Skip("skipping test to debug another")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
101
	ctx := context.Background()
102

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
103 104
	dhtA := setupDHT(ctx, t)
	dhtB := setupDHT(ctx, t)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
105

106 107
	peerA := dhtA.self
	peerB := dhtB.self
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
108

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
109 110
	defer dhtA.Close()
	defer dhtB.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
111 112
	defer dhtA.host.Close()
	defer dhtB.host.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
113

114
	connect(t, ctx, dhtA, dhtB)
115

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
116
	//Test that we can ping the node
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
117
	ctxT, _ := context.WithTimeout(ctx, 100*time.Millisecond)
Jeromy's avatar
Jeromy committed
118
	if _, err := dhtA.Ping(ctxT, peerB); err != nil {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
119 120
		t.Fatal(err)
	}
121

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
122
	ctxT, _ = context.WithTimeout(ctx, 100*time.Millisecond)
Jeromy's avatar
Jeromy committed
123
	if _, err := dhtB.Ping(ctxT, peerA); err != nil {
124 125
		t.Fatal(err)
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
126 127 128
}

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

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

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

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

Jeromy's avatar
Jeromy committed
141 142 143
	vf := func(u.Key, []byte) error {
		return nil
	}
144 145
	dhtA.Validator["v"] = vf
	dhtB.Validator["v"] = vf
Jeromy's avatar
Jeromy committed
146

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

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

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
152
	ctxT, _ = context.WithTimeout(ctx, time.Second*2)
Jeromy's avatar
Jeromy committed
153
	val, err := dhtA.GetValue(ctxT, "/v/hello")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
154 155 156 157 158 159 160 161
	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
162
	ctxT, _ = context.WithTimeout(ctx, time.Second*2)
Jeromy's avatar
Jeromy committed
163
	val, err = dhtB.GetValue(ctxT, "/v/hello")
164 165 166 167 168 169 170
	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
171 172
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
173 174
func TestProvides(t *testing.T) {
	// t.Skip("skipping test to debug another")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
175
	ctx := context.Background()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
176

177
	_, _, dhts := setupDHTS(ctx, 4, t)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
178 179
	defer func() {
		for i := 0; i < 4; i++ {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
180
			dhts[i].Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
181
			defer dhts[i].host.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
182 183 184
		}
	}()

185 186 187
	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
188

189
	for k, v := range testCaseValues {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
190
		log.Debugf("adding local values for %s = %s", k, v)
191 192 193 194 195 196 197 198 199 200 201 202
		err := dhts[3].putLocal(k, v)
		if err != nil {
			t.Fatal(err)
		}

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

205
	for k, _ := range testCaseValues {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
206
		log.Debugf("announcing provider for %s", k)
207 208 209
		if err := dhts[3].Provide(ctx, k); err != nil {
			t.Fatal(err)
		}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
210 211
	}

212 213 214 215 216 217 218
	// what is this timeout for? was 60ms before.
	time.Sleep(time.Millisecond * 6)

	n := 0
	for k, _ := range testCaseValues {
		n = (n + 1) % 3

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
219
		log.Debugf("getting providers for %s from %d", k, n)
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
		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.")
		}
	}
}

237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
// 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:
264
			log.Debugf("did not reach well-formed routing tables by %s", timeout)
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
			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.
	fmt.Println("checking routing table of %d", len(dhts))
	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
284
func TestBootstrap(t *testing.T) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
285
	// t.Skip("skipping test to debug another")
286 287 288 289
	if testing.Short() {
		t.SkipNow()
	}

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

292
	nDHTs := 30
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
293 294 295 296
	_, _, 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
297
			defer dhts[i].host.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
298 299 300 301 302 303 304 305
		}
	}()

	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)])
	}

306
	<-time.After(100 * time.Millisecond)
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
	// 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
			}
		}
	}()

324
	waitForWellFormedTables(t, dhts, 7, 10, 20*time.Second)
325
	close(stop)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
326

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
327 328
	if u.Debug {
		// the routing tables should be full now. let's inspect them.
329 330 331 332 333 334
		printRoutingTables(dhts)
	}
}

func TestPeriodicBootstrap(t *testing.T) {
	// t.Skip("skipping test to debug another")
335 336 337
	if ci.IsRunning() {
		t.Skip("skipping on CI. highly timing dependent")
	}
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
	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
362 363 364
		}
	}

365 366 367
	signal := make(chan time.Time)
	allSignals := []chan time.Time{}

368 369 370 371
	var cfg BootstrapConfig
	cfg = DefaultBootstrapConfig
	cfg.Queries = 5

372 373 374 375
	// kick off periodic bootstrappers with instrumented signals.
	for _, dht := range dhts {
		s := make(chan time.Time)
		allSignals = append(allSignals, s)
376
		dht.BootstrapOnSignal(cfg, s)
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392
	}
	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)])
	}

	t.Logf("dhts are now connected to 1-2 others.", nDHTs)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
393
	for _, dht := range dhts {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
394
		rtlen := dht.routingTable.Size()
395 396
		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
397
		}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
398
	}
399

400 401 402 403 404 405 406 407 408
	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.
409
	waitForWellFormedTables(t, dhts, 7, 10, 20*time.Second)
410 411 412

	if u.Debug {
		printRoutingTables(dhts)
413
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
414 415
}

416 417
func TestProvidesMany(t *testing.T) {
	t.Skip("this test doesn't work")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
418
	// t.Skip("skipping test to debug another")
419 420 421 422 423 424 425
	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
426
			defer dhts[i].host.Close()
427 428 429 430 431 432 433 434
		}
	}()

	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)])
	}

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

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
440 441 442 443 444 445 446 447
	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("")
		}
448
	}
449

450 451
	var providers = map[u.Key]peer.ID{}

452 453 454 455
	d := 0
	for k, v := range testCaseValues {
		d = (d + 1) % len(dhts)
		dht := dhts[d]
456
		providers[k] = dht.self
457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475

		t.Logf("adding local values for %s = %s (on %s)", k, v, dht.self)
		err := dht.putLocal(k, v)
		if err != nil {
			t.Fatal(err)
		}

		bits, err := dht.getLocal(k)
		if err != nil {
			t.Fatal(err)
		}
		if !bytes.Equal(bits, v) {
			t.Fatal("didn't store the right bits (%s, %s)", k, v)
		}

		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
476 477
	}

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

481 482
	errchan := make(chan error)

483
	ctxT, _ = context.WithTimeout(ctx, 5*time.Second)
484 485 486 487

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

489 490
		expected := providers[k]

491 492 493
		provchan := dht.FindProvidersAsync(ctxT, k, 1)
		select {
		case prov := <-provchan:
494 495
			actual := prov.ID
			if actual == "" {
496
				errchan <- fmt.Errorf("Got back nil provider (%s at %s)", k, dht.self)
497 498 499
			} else if actual != expected {
				errchan <- fmt.Errorf("Got back wrong provider (%s != %s) (%s at %s)",
					expected, actual, k, dht.self)
500 501 502
			}
		case <-ctxT.Done():
			errchan <- fmt.Errorf("Did not get a provider back (%s at %s)", k, dht.self)
Jeromy's avatar
Jeromy committed
503
		}
504 505 506 507 508
	}

	for k, _ := range testCaseValues {
		// everyone should be able to find it...
		for _, dht := range dhts {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
509
			log.Debugf("getting providers for %s at %s", k, dht.self)
510 511
			wg.Add(1)
			go getProvider(dht, k)
512
		}
513 514 515 516 517 518 519 520 521 522
	}

	// 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
523 524 525
	}
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
526
func TestProvidesAsync(t *testing.T) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
527
	// t.Skip("skipping test to debug another")
528 529 530
	if testing.Short() {
		t.SkipNow()
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
531

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

534
	_, _, dhts := setupDHTS(ctx, 4, t)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
535 536
	defer func() {
		for i := 0; i < 4; i++ {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
537
			dhts[i].Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
538
			defer dhts[i].host.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
539 540 541
		}
	}()

542 543 544
	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
545

546
	err := dhts[3].putLocal(u.Key("hello"), []byte("world"))
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
547 548 549 550 551 552 553 554 555
	if err != nil {
		t.Fatal(err)
	}

	bits, err := dhts[3].getLocal(u.Key("hello"))
	if err != nil && bytes.Equal(bits, []byte("world")) {
		t.Fatal(err)
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
556
	err = dhts[3].Provide(ctx, u.Key("hello"))
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
557 558 559 560 561 562
	if err != nil {
		t.Fatal(err)
	}

	time.Sleep(time.Millisecond * 60)

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
563 564
	ctxT, _ := context.WithTimeout(ctx, time.Millisecond*300)
	provs := dhts[0].FindProvidersAsync(ctxT, u.Key("hello"), 5)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
565
	select {
Jeromy's avatar
Jeromy committed
566 567 568 569
	case p, ok := <-provs:
		if !ok {
			t.Fatal("Provider channel was closed...")
		}
570
		if p.ID == "" {
Jeromy's avatar
Jeromy committed
571 572
			t.Fatal("Got back nil provider!")
		}
573
		if p.ID != dhts[3].self {
574
			t.Fatalf("got a provider, but not the right one. %s", p)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
575
		}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
576
	case <-ctxT.Done():
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
577 578 579 580
		t.Fatal("Didnt get back providers")
	}
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
581
func TestLayeredGet(t *testing.T) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
582
	// t.Skip("skipping test to debug another")
583 584 585
	if testing.Short() {
		t.SkipNow()
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
586

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

589
	_, _, dhts := setupDHTS(ctx, 4, t)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
590 591
	defer func() {
		for i := 0; i < 4; i++ {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
592
			dhts[i].Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
593
			defer dhts[i].host.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
594 595 596
		}
	}()

597 598 599
	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
600

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
601
	err := dhts[3].Provide(ctx, u.Key("/v/hello"))
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
602 603 604 605
	if err != nil {
		t.Fatal(err)
	}

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

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
608
	t.Log("interface was changed. GetValue should not use providers.")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
609
	ctxT, _ := context.WithTimeout(ctx, time.Second)
Jeromy's avatar
Jeromy committed
610
	val, err := dhts[0].GetValue(ctxT, u.Key("/v/hello"))
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
611 612
	if err != routing.ErrNotFound {
		t.Error(err)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
613
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
614 615 616 617 618
	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
619 620 621 622
	}
}

func TestFindPeer(t *testing.T) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
623
	// t.Skip("skipping test to debug another")
624 625 626
	if testing.Short() {
		t.SkipNow()
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
627

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

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
630
	_, peers, dhts := setupDHTS(ctx, 4, t)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
631 632
	defer func() {
		for i := 0; i < 4; i++ {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
633
			dhts[i].Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
634
			dhts[i].host.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
635 636 637
		}
	}()

638 639 640
	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
641

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
642
	ctxT, _ := context.WithTimeout(ctx, time.Second)
643
	p, err := dhts[0].FindPeer(ctxT, peers[2])
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
644 645 646 647
	if err != nil {
		t.Fatal(err)
	}

648
	if p.ID == "" {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
649 650 651
		t.Fatal("Failed to find peer.")
	}

652
	if p.ID != peers[2] {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
653 654 655
		t.Fatal("Didnt find expected peer.")
	}
}
656

657
func TestFindPeersConnectedToPeer(t *testing.T) {
658 659
	t.Skip("not quite correct (see note)")

660 661 662 663 664 665 666 667 668 669
	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
670
			dhts[i].host.Close()
671 672 673 674 675
		}
	}()

	// topology:
	// 0-1, 1-2, 1-3, 2-3
676 677 678 679
	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])
680 681 682 683 684 685 686

	// 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)
687
	pchan, err := dhts[0].FindPeersConnectedToPeer(ctxT, peers[2])
688 689 690 691
	if err != nil {
		t.Fatal(err)
	}

692 693
	// shouldFind := []peer.ID{peers[1], peers[3]}
	found := []peer.PeerInfo{}
694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709
	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.")
	}
}

710
func testPeerListsMatch(t *testing.T, p1, p2 []peer.ID) {
711 712 713 714 715 716 717 718 719

	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 {
720
		ids1[i] = string(p)
721 722 723
	}

	for i, p := range p2 {
724
		ids2[i] = string(p)
725 726 727 728 729 730 731 732 733 734 735 736
	}

	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)
		}
	}
}

737
func TestConnectCollision(t *testing.T) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
738
	// t.Skip("skipping test to debug another")
739 740 741
	if testing.Short() {
		t.SkipNow()
	}
742 743 744
	if travisci.IsRunning() {
		t.Skip("Skipping on Travis-CI.")
	}
745

746
	runTimes := 10
747

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
748 749
	for rtime := 0; rtime < runTimes; rtime++ {
		log.Notice("Running Time: ", rtime)
750

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

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
753 754
		dhtA := setupDHT(ctx, t)
		dhtB := setupDHT(ctx, t)
755

756 757
		addrA := dhtA.peerstore.Addrs(dhtA.self)[0]
		addrB := dhtB.peerstore.Addrs(dhtB.self)[0]
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
758

759 760
		peerA := dhtA.self
		peerB := dhtB.self
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
761

762
		errs := make(chan error)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
763
		go func() {
764
			dhtA.peerstore.AddAddr(peerB, addrB, peer.TempAddrTTL)
765
			err := dhtA.Connect(ctx, peerB)
766
			errs <- err
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
767 768
		}()
		go func() {
769
			dhtB.peerstore.AddAddr(peerA, addrA, peer.TempAddrTTL)
770
			err := dhtB.Connect(ctx, peerA)
771
			errs <- err
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
772 773
		}()

774
		timeout := time.After(5 * time.Second)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
775
		select {
776 777 778 779
		case e := <-errs:
			if e != nil {
				t.Fatal(e)
			}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
780 781 782 783
		case <-timeout:
			t.Fatal("Timeout received!")
		}
		select {
784 785 786 787
		case e := <-errs:
			if e != nil {
				t.Fatal(e)
			}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
788 789 790 791
		case <-timeout:
			t.Fatal("Timeout received!")
		}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
792 793
		dhtA.Close()
		dhtB.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
794 795
		dhtA.host.Close()
		dhtB.host.Close()
Jeromy's avatar
Jeromy committed
796
	}
797
}