dht_test.go 9.78 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
	"sort"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
6
	"testing"
7
	"time"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
8 9 10

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"

11
	ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore"
12
	dssync "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore/sync"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
13 14
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"

15
	// ci "github.com/jbenet/go-ipfs/crypto"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
16 17 18
	inet "github.com/jbenet/go-ipfs/net"
	peer "github.com/jbenet/go-ipfs/peer"
	u "github.com/jbenet/go-ipfs/util"
19
	testutil "github.com/jbenet/go-ipfs/util/testutil"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
20 21
)

22
func setupDHT(ctx context.Context, t *testing.T, addr ma.Multiaddr) *IpfsDHT {
23

24 25 26 27 28 29
	sk, pk, err := testutil.RandKeyPair(512)
	if err != nil {
		t.Fatal(err)
	}

	p, err := peer.IDFromPublicKey(pk)
30 31 32 33
	if err != nil {
		t.Fatal(err)
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
34
	peerstore := peer.NewPeerstore()
35 36 37
	peerstore.AddPrivKey(p, sk)
	peerstore.AddPubKey(p, pk)
	peerstore.AddAddress(p, addr)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
38

39
	n, err := inet.NewNetwork(ctx, []ma.Multiaddr{addr}, p, peerstore)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
40 41 42 43
	if err != nil {
		t.Fatal(err)
	}

44 45
	dss := dssync.MutexWrap(ds.NewMapDatastore())
	d := NewDHT(ctx, p, n, dss)
46

Jeromy's avatar
Jeromy committed
47 48 49
	d.Validators["v"] = func(u.Key, []byte) error {
		return nil
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
50 51 52
	return d
}

53 54
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
55
	dhts := make([]*IpfsDHT, n)
56 57
	peers := make([]peer.ID, n)

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
58
	for i := 0; i < n; i++ {
59 60 61
		addrs[i] = testutil.RandLocalTCPAddress()
		dhts[i] = setupDHT(ctx, t, addrs[i])
		peers[i] = dhts[i].self
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
62 63 64 65 66
	}

	return addrs, peers, dhts
}

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

69 70 71 72
	idB := b.self
	addrB := b.peerstore.Addresses(idB)
	if len(addrB) == 0 {
		t.Fatal("peers setup incorrectly: no local address")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
73
	}
74 75 76 77

	a.peerstore.AddAddresses(idB, addrB)
	if err := a.Connect(ctx, idB); err != nil {
		t.Fatal(err)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
78 79 80 81
	}
}

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

85 86
	addrA := testutil.RandLocalTCPAddress()
	addrB := testutil.RandLocalTCPAddress()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
87

88 89
	dhtA := setupDHT(ctx, t, addrA)
	dhtB := setupDHT(ctx, t, addrB)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
90

91 92
	peerA := dhtA.self
	peerB := dhtB.self
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
93

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
94 95
	defer dhtA.Close()
	defer dhtB.Close()
96 97
	defer dhtA.network.Close()
	defer dhtB.network.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
98

99
	connect(t, ctx, dhtA, dhtB)
100

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
101
	//Test that we can ping the node
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
102
	ctxT, _ := context.WithTimeout(ctx, 100*time.Millisecond)
103
	if err := dhtA.Ping(ctxT, peerB); err != nil {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
104 105
		t.Fatal(err)
	}
106

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
107
	ctxT, _ = context.WithTimeout(ctx, 100*time.Millisecond)
108
	if err := dhtB.Ping(ctxT, peerA); err != nil {
109 110
		t.Fatal(err)
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
111 112 113
}

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

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

118 119
	addrA := testutil.RandLocalTCPAddress()
	addrB := testutil.RandLocalTCPAddress()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
120

121 122
	dhtA := setupDHT(ctx, t, addrA)
	dhtB := setupDHT(ctx, t, addrB)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
123

124 125 126 127
	defer dhtA.Close()
	defer dhtB.Close()
	defer dhtA.network.Close()
	defer dhtB.network.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
128

Jeromy's avatar
Jeromy committed
129 130 131 132 133 134
	vf := func(u.Key, []byte) error {
		return nil
	}
	dhtA.Validators["v"] = vf
	dhtB.Validators["v"] = vf

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

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

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
140
	ctxT, _ = context.WithTimeout(ctx, time.Second*2)
Jeromy's avatar
Jeromy committed
141
	val, err := dhtA.GetValue(ctxT, "/v/hello")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
142 143 144 145 146 147 148 149
	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
150
	ctxT, _ = context.WithTimeout(ctx, time.Second*2)
Jeromy's avatar
Jeromy committed
151
	val, err = dhtB.GetValue(ctxT, "/v/hello")
152 153 154 155 156 157 158
	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
159 160
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
161 162
func TestProvides(t *testing.T) {
	// t.Skip("skipping test to debug another")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
163
	ctx := context.Background()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
164

165
	_, _, dhts := setupDHTS(ctx, 4, t)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
166 167
	defer func() {
		for i := 0; i < 4; i++ {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
168
			dhts[i].Close()
169
			defer dhts[i].network.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
170 171 172
		}
	}()

173 174 175
	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
176

177
	err := dhts[3].putLocal(u.Key("hello"), []byte("world"))
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
178 179 180 181 182 183 184 185 186
	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
187
	err = dhts[3].Provide(ctx, u.Key("hello"))
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
188 189 190 191
	if err != nil {
		t.Fatal(err)
	}

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

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
195
	ctxT, _ := context.WithTimeout(ctx, time.Second)
Jeromy's avatar
Jeromy committed
196
	provchan := dhts[0].FindProvidersAsync(ctxT, u.Key("hello"), 1)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
197

Jeromy's avatar
Jeromy committed
198 199
	select {
	case prov := <-provchan:
200
		if prov.ID == "" {
Jeromy's avatar
Jeromy committed
201 202
			t.Fatal("Got back nil provider")
		}
203 204 205 206
		if prov.ID != dhts[3].self {
			t.Fatal("Got back nil provider")
		}
	case <-ctxT.Done():
Jeromy's avatar
Jeromy committed
207
		t.Fatal("Did not get a provider back.")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
208 209 210
	}
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
211
func TestProvidesAsync(t *testing.T) {
212 213 214
	if testing.Short() {
		t.SkipNow()
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
215

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

218
	_, _, dhts := setupDHTS(ctx, 4, t)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
219 220
	defer func() {
		for i := 0; i < 4; i++ {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
221
			dhts[i].Close()
222
			defer dhts[i].network.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
223 224 225
		}
	}()

226 227 228
	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
229

230
	err := dhts[3].putLocal(u.Key("hello"), []byte("world"))
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
231 232 233 234 235 236 237 238 239
	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
240
	err = dhts[3].Provide(ctx, u.Key("hello"))
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
241 242 243 244 245 246
	if err != nil {
		t.Fatal(err)
	}

	time.Sleep(time.Millisecond * 60)

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
247 248
	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
249
	select {
Jeromy's avatar
Jeromy committed
250 251 252 253
	case p, ok := <-provs:
		if !ok {
			t.Fatal("Provider channel was closed...")
		}
254
		if p.ID == "" {
Jeromy's avatar
Jeromy committed
255 256
			t.Fatal("Got back nil provider!")
		}
257
		if p.ID != dhts[3].self {
258
			t.Fatalf("got a provider, but not the right one. %s", p)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
259
		}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
260
	case <-ctxT.Done():
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
261 262 263 264
		t.Fatal("Didnt get back providers")
	}
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
265
func TestLayeredGet(t *testing.T) {
266 267 268
	if testing.Short() {
		t.SkipNow()
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
269

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

272
	_, _, dhts := setupDHTS(ctx, 4, t)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
273 274
	defer func() {
		for i := 0; i < 4; i++ {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
275
			dhts[i].Close()
276
			defer dhts[i].network.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
277 278 279
		}
	}()

280 281 282
	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
283

284
	err := dhts[3].putLocal(u.Key("/v/hello"), []byte("world"))
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
285 286 287 288
	if err != nil {
		t.Fatal(err)
	}

Jeromy's avatar
Jeromy committed
289
	err = dhts[3].Provide(ctx, u.Key("/v/hello"))
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
290 291 292 293 294 295
	if err != nil {
		t.Fatal(err)
	}

	time.Sleep(time.Millisecond * 60)

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
296
	ctxT, _ := context.WithTimeout(ctx, time.Second)
Jeromy's avatar
Jeromy committed
297
	val, err := dhts[0].GetValue(ctxT, u.Key("/v/hello"))
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
298 299 300 301 302 303 304 305 306 307 308
	if err != nil {
		t.Fatal(err)
	}

	if string(val) != "world" {
		t.Fatal("Got incorrect value.")
	}

}

func TestFindPeer(t *testing.T) {
309 310 311
	if testing.Short() {
		t.SkipNow()
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
312

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

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
315
	_, peers, dhts := setupDHTS(ctx, 4, t)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
316 317
	defer func() {
		for i := 0; i < 4; i++ {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
318
			dhts[i].Close()
319
			dhts[i].network.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
320 321 322
		}
	}()

323 324 325
	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
326

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
327
	ctxT, _ := context.WithTimeout(ctx, time.Second)
328
	p, err := dhts[0].FindPeer(ctxT, peers[2])
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
329 330 331 332
	if err != nil {
		t.Fatal(err)
	}

333
	if p.ID == "" {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
334 335 336
		t.Fatal("Failed to find peer.")
	}

337
	if p.ID != peers[2] {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
338 339 340
		t.Fatal("Didnt find expected peer.")
	}
}
341

342
func TestFindPeersConnectedToPeer(t *testing.T) {
343 344
	t.Skip("not quite correct (see note)")

345 346 347 348 349 350 351 352 353 354
	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()
355
			dhts[i].network.Close()
356 357 358 359 360
		}
	}()

	// topology:
	// 0-1, 1-2, 1-3, 2-3
361 362 363 364
	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])
365 366 367 368 369 370 371

	// 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)
372
	pchan, err := dhts[0].FindPeersConnectedToPeer(ctxT, peers[2])
373 374 375 376
	if err != nil {
		t.Fatal(err)
	}

377 378
	// shouldFind := []peer.ID{peers[1], peers[3]}
	found := []peer.PeerInfo{}
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
	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.")
	}
}

395
func testPeerListsMatch(t *testing.T, p1, p2 []peer.ID) {
396 397 398 399 400 401 402 403 404

	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 {
405
		ids1[i] = string(p)
406 407 408
	}

	for i, p := range p2 {
409
		ids2[i] = string(p)
410 411 412 413 414 415 416 417 418 419 420 421
	}

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

422
func TestConnectCollision(t *testing.T) {
423 424 425
	if testing.Short() {
		t.SkipNow()
	}
426

427
	runTimes := 10
428

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

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

434 435
		addrA := testutil.RandLocalTCPAddress()
		addrB := testutil.RandLocalTCPAddress()
436

437 438
		dhtA := setupDHT(ctx, t, addrA)
		dhtB := setupDHT(ctx, t, addrB)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
439

440 441
		peerA := dhtA.self
		peerB := dhtB.self
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
442

443
		errs := make(chan error)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
444
		go func() {
445
			dhtA.peerstore.AddAddress(peerB, addrB)
446
			err := dhtA.Connect(ctx, peerB)
447
			errs <- err
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
448 449
		}()
		go func() {
450
			dhtB.peerstore.AddAddress(peerA, addrA)
451
			err := dhtB.Connect(ctx, peerA)
452
			errs <- err
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
453 454 455 456
		}()

		timeout := time.After(time.Second)
		select {
457 458 459 460
		case e := <-errs:
			if e != nil {
				t.Fatal(e)
			}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
461 462 463 464
		case <-timeout:
			t.Fatal("Timeout received!")
		}
		select {
465 466 467 468
		case e := <-errs:
			if e != nil {
				t.Fatal(e)
			}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
469 470 471 472
		case <-timeout:
			t.Fatal("Timeout received!")
		}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
473 474
		dhtA.Close()
		dhtB.Close()
475 476
		dhtA.network.Close()
		dhtB.network.Close()
Jeromy's avatar
Jeromy committed
477
	}
478
}