peerwantmanager_test.go 12.4 KB
Newer Older
dirkmc's avatar
dirkmc committed
1 2 3 4 5
package peermanager

import (
	"testing"

6
	"github.com/ipfs/go-bitswap/internal/testutil"
dirkmc's avatar
dirkmc committed
7
	cid "github.com/ipfs/go-cid"
8
	peer "github.com/libp2p/go-libp2p-core/peer"
dirkmc's avatar
dirkmc committed
9 10 11 12 13 14 15 16 17 18 19 20 21
)

type gauge struct {
	count int
}

func (g *gauge) Inc() {
	g.count++
}
func (g *gauge) Dec() {
	g.count--
}

22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
type mockPQ struct {
	bcst    []cid.Cid
	wbs     []cid.Cid
	whs     []cid.Cid
	cancels []cid.Cid
}

func (mpq *mockPQ) clear() {
	mpq.bcst = nil
	mpq.wbs = nil
	mpq.whs = nil
	mpq.cancels = nil
}

func (mpq *mockPQ) Startup()  {}
func (mpq *mockPQ) Shutdown() {}

func (mpq *mockPQ) AddBroadcastWantHaves(whs []cid.Cid) {
	mpq.bcst = append(mpq.bcst, whs...)
}
func (mpq *mockPQ) AddWants(wbs []cid.Cid, whs []cid.Cid) {
	mpq.wbs = append(mpq.wbs, wbs...)
	mpq.whs = append(mpq.whs, whs...)
}
func (mpq *mockPQ) AddCancels(cs []cid.Cid) {
	mpq.cancels = append(mpq.cancels, cs...)
}
func (mpq *mockPQ) ResponseReceived(ks []cid.Cid) {
}

func clearSent(pqs map[peer.ID]PeerQueue) {
	for _, pqi := range pqs {
		pqi.(*mockPQ).clear()
	}
}

dirkmc's avatar
dirkmc committed
58
func TestEmpty(t *testing.T) {
dirkmc's avatar
dirkmc committed
59
	pwm := newPeerWantManager(&gauge{}, &gauge{})
dirkmc's avatar
dirkmc committed
60

61
	if len(pwm.getWantBlocks()) > 0 {
dirkmc's avatar
dirkmc committed
62 63
		t.Fatal("Expected GetWantBlocks() to have length 0")
	}
64
	if len(pwm.getWantHaves()) > 0 {
dirkmc's avatar
dirkmc committed
65 66 67 68
		t.Fatal("Expected GetWantHaves() to have length 0")
	}
}

69
func TestPWMBroadcastWantHaves(t *testing.T) {
dirkmc's avatar
dirkmc committed
70
	pwm := newPeerWantManager(&gauge{}, &gauge{})
dirkmc's avatar
dirkmc committed
71 72 73 74 75 76

	peers := testutil.GeneratePeers(3)
	cids := testutil.GenerateCids(2)
	cids2 := testutil.GenerateCids(2)
	cids3 := testutil.GenerateCids(2)

77 78 79 80 81 82 83 84
	peerQueues := make(map[peer.ID]PeerQueue)
	for _, p := range peers[:2] {
		pq := &mockPQ{}
		peerQueues[p] = pq
		pwm.addPeer(pq, p)
		if len(pq.bcst) > 0 {
			t.Errorf("expected no broadcast wants")
		}
85
	}
dirkmc's avatar
dirkmc committed
86 87

	// Broadcast 2 cids to 2 peers
88 89 90 91 92 93 94
	pwm.broadcastWantHaves(cids)
	for _, pqi := range peerQueues {
		pq := pqi.(*mockPQ)
		if len(pq.bcst) != 2 {
			t.Fatal("Expected 2 want-haves")
		}
		if !testutil.MatchKeysIgnoreOrder(pq.bcst, cids) {
dirkmc's avatar
dirkmc committed
95 96 97 98 99
			t.Fatal("Expected all cids to be broadcast")
		}
	}

	// Broadcasting same cids should have no effect
100 101 102 103 104 105 106
	clearSent(peerQueues)
	pwm.broadcastWantHaves(cids)
	for _, pqi := range peerQueues {
		pq := pqi.(*mockPQ)
		if len(pq.bcst) != 0 {
			t.Fatal("Expected 0 want-haves")
		}
dirkmc's avatar
dirkmc committed
107 108 109
	}

	// Broadcast 2 other cids
110 111 112 113 114 115 116 117
	clearSent(peerQueues)
	pwm.broadcastWantHaves(cids2)
	for _, pqi := range peerQueues {
		pq := pqi.(*mockPQ)
		if len(pq.bcst) != 2 {
			t.Fatal("Expected 2 want-haves")
		}
		if !testutil.MatchKeysIgnoreOrder(pq.bcst, cids2) {
dirkmc's avatar
dirkmc committed
118 119 120 121 122
			t.Fatal("Expected all new cids to be broadcast")
		}
	}

	// Broadcast mix of old and new cids
123 124 125 126 127 128 129 130 131
	clearSent(peerQueues)
	pwm.broadcastWantHaves(append(cids, cids3...))
	for _, pqi := range peerQueues {
		pq := pqi.(*mockPQ)
		if len(pq.bcst) != 2 {
			t.Fatal("Expected 2 want-haves")
		}
		// Only new cids should be broadcast
		if !testutil.MatchKeysIgnoreOrder(pq.bcst, cids3) {
dirkmc's avatar
dirkmc committed
132 133 134 135 136
			t.Fatal("Expected all new cids to be broadcast")
		}
	}

	// Sending want-block for a cid should prevent broadcast to that peer
137
	clearSent(peerQueues)
dirkmc's avatar
dirkmc committed
138 139
	cids4 := testutil.GenerateCids(4)
	wantBlocks := []cid.Cid{cids4[0], cids4[2]}
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
	p0 := peers[0]
	p1 := peers[1]
	pwm.sendWants(p0, wantBlocks, []cid.Cid{})

	pwm.broadcastWantHaves(cids4)
	pq0 := peerQueues[p0].(*mockPQ)
	if len(pq0.bcst) != 2 { // only broadcast 2 / 4 want-haves
		t.Fatal("Expected 2 want-haves")
	}
	if !testutil.MatchKeysIgnoreOrder(pq0.bcst, []cid.Cid{cids4[1], cids4[3]}) {
		t.Fatalf("Expected unsent cids to be broadcast")
	}
	pq1 := peerQueues[p1].(*mockPQ)
	if len(pq1.bcst) != 4 { // broadcast all 4 want-haves
		t.Fatal("Expected 4 want-haves")
	}
	if !testutil.MatchKeysIgnoreOrder(pq1.bcst, cids4) {
		t.Fatal("Expected all cids to be broadcast")
dirkmc's avatar
dirkmc committed
158 159
	}

160 161 162 163 164
	allCids := cids
	allCids = append(allCids, cids2...)
	allCids = append(allCids, cids3...)
	allCids = append(allCids, cids4...)

dirkmc's avatar
dirkmc committed
165
	// Add another peer
166 167 168 169 170
	peer2 := peers[2]
	pq2 := &mockPQ{}
	peerQueues[peer2] = pq2
	pwm.addPeer(pq2, peer2)
	if !testutil.MatchKeysIgnoreOrder(pq2.bcst, allCids) {
171
		t.Fatalf("Expected all cids to be broadcast.")
dirkmc's avatar
dirkmc committed
172
	}
173

174 175 176
	clearSent(peerQueues)
	pwm.broadcastWantHaves(allCids)
	if len(pq2.bcst) != 0 {
177
		t.Errorf("did not expect to have CIDs to broadcast")
dirkmc's avatar
dirkmc committed
178 179 180
	}
}

181
func TestPWMSendWants(t *testing.T) {
dirkmc's avatar
dirkmc committed
182
	pwm := newPeerWantManager(&gauge{}, &gauge{})
dirkmc's avatar
dirkmc committed
183 184 185 186 187 188 189

	peers := testutil.GeneratePeers(2)
	p0 := peers[0]
	p1 := peers[1]
	cids := testutil.GenerateCids(2)
	cids2 := testutil.GenerateCids(2)

190 191 192 193 194 195 196 197
	peerQueues := make(map[peer.ID]PeerQueue)
	for _, p := range peers[:2] {
		pq := &mockPQ{}
		peerQueues[p] = pq
		pwm.addPeer(pq, p)
	}
	pq0 := peerQueues[p0].(*mockPQ)
	pq1 := peerQueues[p1].(*mockPQ)
dirkmc's avatar
dirkmc committed
198 199

	// Send 2 want-blocks and 2 want-haves to p0
200 201 202
	clearSent(peerQueues)
	pwm.sendWants(p0, cids, cids2)
	if !testutil.MatchKeysIgnoreOrder(pq0.wbs, cids) {
dirkmc's avatar
dirkmc committed
203 204
		t.Fatal("Expected 2 want-blocks")
	}
205
	if !testutil.MatchKeysIgnoreOrder(pq0.whs, cids2) {
dirkmc's avatar
dirkmc committed
206 207 208 209 210 211
		t.Fatal("Expected 2 want-haves")
	}

	// Send to p0
	// - 1 old want-block and 2 new want-blocks
	// - 1 old want-have  and 2 new want-haves
212
	clearSent(peerQueues)
dirkmc's avatar
dirkmc committed
213 214
	cids3 := testutil.GenerateCids(2)
	cids4 := testutil.GenerateCids(2)
215 216
	pwm.sendWants(p0, append(cids3, cids[0]), append(cids4, cids2[0]))
	if !testutil.MatchKeysIgnoreOrder(pq0.wbs, cids3) {
dirkmc's avatar
dirkmc committed
217 218
		t.Fatal("Expected 2 want-blocks")
	}
219
	if !testutil.MatchKeysIgnoreOrder(pq0.whs, cids4) {
dirkmc's avatar
dirkmc committed
220 221 222 223
		t.Fatal("Expected 2 want-haves")
	}

	// Send to p0 as want-blocks: 1 new want-block, 1 old want-have
224
	clearSent(peerQueues)
dirkmc's avatar
dirkmc committed
225 226
	cids5 := testutil.GenerateCids(1)
	newWantBlockOldWantHave := append(cids5, cids2[0])
227
	pwm.sendWants(p0, newWantBlockOldWantHave, []cid.Cid{})
dirkmc's avatar
dirkmc committed
228 229
	// If a want was sent as a want-have, it should be ok to now send it as a
	// want-block
230
	if !testutil.MatchKeysIgnoreOrder(pq0.wbs, newWantBlockOldWantHave) {
dirkmc's avatar
dirkmc committed
231 232
		t.Fatal("Expected 2 want-blocks")
	}
233
	if len(pq0.whs) != 0 {
dirkmc's avatar
dirkmc committed
234 235 236 237
		t.Fatal("Expected 0 want-haves")
	}

	// Send to p0 as want-haves: 1 new want-have, 1 old want-block
238
	clearSent(peerQueues)
dirkmc's avatar
dirkmc committed
239 240
	cids6 := testutil.GenerateCids(1)
	newWantHaveOldWantBlock := append(cids6, cids[0])
241
	pwm.sendWants(p0, []cid.Cid{}, newWantHaveOldWantBlock)
dirkmc's avatar
dirkmc committed
242 243
	// If a want was previously sent as a want-block, it should not be
	// possible to now send it as a want-have
244
	if !testutil.MatchKeysIgnoreOrder(pq0.whs, cids6) {
dirkmc's avatar
dirkmc committed
245 246
		t.Fatal("Expected 1 want-have")
	}
247
	if len(pq0.wbs) != 0 {
dirkmc's avatar
dirkmc committed
248 249 250 251
		t.Fatal("Expected 0 want-blocks")
	}

	// Send 2 want-blocks and 2 want-haves to p1
252 253
	pwm.sendWants(p1, cids, cids2)
	if !testutil.MatchKeysIgnoreOrder(pq1.wbs, cids) {
dirkmc's avatar
dirkmc committed
254 255
		t.Fatal("Expected 2 want-blocks")
	}
256
	if !testutil.MatchKeysIgnoreOrder(pq1.whs, cids2) {
dirkmc's avatar
dirkmc committed
257 258 259 260
		t.Fatal("Expected 2 want-haves")
	}
}

261
func TestPWMSendCancels(t *testing.T) {
dirkmc's avatar
dirkmc committed
262
	pwm := newPeerWantManager(&gauge{}, &gauge{})
dirkmc's avatar
dirkmc committed
263 264 265 266 267 268 269 270 271 272 273

	peers := testutil.GeneratePeers(2)
	p0 := peers[0]
	p1 := peers[1]
	wb1 := testutil.GenerateCids(2)
	wh1 := testutil.GenerateCids(2)
	wb2 := testutil.GenerateCids(2)
	wh2 := testutil.GenerateCids(2)
	allwb := append(wb1, wb2...)
	allwh := append(wh1, wh2...)

274 275 276 277 278 279 280 281
	peerQueues := make(map[peer.ID]PeerQueue)
	for _, p := range peers[:2] {
		pq := &mockPQ{}
		peerQueues[p] = pq
		pwm.addPeer(pq, p)
	}
	pq0 := peerQueues[p0].(*mockPQ)
	pq1 := peerQueues[p1].(*mockPQ)
dirkmc's avatar
dirkmc committed
282 283

	// Send 2 want-blocks and 2 want-haves to p0
284
	pwm.sendWants(p0, wb1, wh1)
dirkmc's avatar
dirkmc committed
285 286
	// Send 3 want-blocks and 3 want-haves to p1
	// (1 overlapping want-block / want-have with p0)
287
	pwm.sendWants(p1, append(wb2, wb1[1]), append(wh2, wh1[1]))
dirkmc's avatar
dirkmc committed
288

289
	if !testutil.MatchKeysIgnoreOrder(pwm.getWantBlocks(), allwb) {
dirkmc's avatar
dirkmc committed
290 291
		t.Fatal("Expected 4 cids to be wanted")
	}
292
	if !testutil.MatchKeysIgnoreOrder(pwm.getWantHaves(), allwh) {
dirkmc's avatar
dirkmc committed
293 294 295 296
		t.Fatal("Expected 4 cids to be wanted")
	}

	// Cancel 1 want-block and 1 want-have that were sent to p0
297 298
	clearSent(peerQueues)
	pwm.sendCancels([]cid.Cid{wb1[0], wh1[0]})
dirkmc's avatar
dirkmc committed
299
	// Should cancel the want-block and want-have
300 301
	if len(pq1.cancels) != 0 {
		t.Fatal("Expected no cancels sent to p1")
dirkmc's avatar
dirkmc committed
302
	}
303
	if !testutil.MatchKeysIgnoreOrder(pq0.cancels, []cid.Cid{wb1[0], wh1[0]}) {
dirkmc's avatar
dirkmc committed
304 305
		t.Fatal("Expected 2 cids to be cancelled")
	}
306
	if !testutil.MatchKeysIgnoreOrder(pwm.getWantBlocks(), append(wb2, wb1[1])) {
dirkmc's avatar
dirkmc committed
307 308
		t.Fatal("Expected 3 want-blocks")
	}
309
	if !testutil.MatchKeysIgnoreOrder(pwm.getWantHaves(), append(wh2, wh1[1])) {
dirkmc's avatar
dirkmc committed
310 311 312 313
		t.Fatal("Expected 3 want-haves")
	}

	// Cancel everything
314
	clearSent(peerQueues)
dirkmc's avatar
dirkmc committed
315
	allCids := append(allwb, allwh...)
316 317 318
	pwm.sendCancels(allCids)
	// Should cancel the remaining want-blocks and want-haves for p0
	if !testutil.MatchKeysIgnoreOrder(pq0.cancels, []cid.Cid{wb1[1], wh1[1]}) {
dirkmc's avatar
dirkmc committed
319 320
		t.Fatal("Expected un-cancelled cids to be cancelled")
	}
321 322 323 324 325 326 327 328

	// Should cancel the remaining want-blocks and want-haves for p1
	remainingP1 := append(wb2, wh2...)
	remainingP1 = append(remainingP1, wb1[1], wh1[1])
	if len(pq1.cancels) != len(remainingP1) {
		t.Fatal("mismatch", len(pq1.cancels), len(remainingP1))
	}
	if !testutil.MatchKeysIgnoreOrder(pq1.cancels, remainingP1) {
dirkmc's avatar
dirkmc committed
329 330
		t.Fatal("Expected un-cancelled cids to be cancelled")
	}
331
	if len(pwm.getWantBlocks()) != 0 {
dirkmc's avatar
dirkmc committed
332 333
		t.Fatal("Expected 0 want-blocks")
	}
334
	if len(pwm.getWantHaves()) != 0 {
dirkmc's avatar
dirkmc committed
335 336 337 338 339 340
		t.Fatal("Expected 0 want-haves")
	}
}

func TestStats(t *testing.T) {
	g := &gauge{}
dirkmc's avatar
dirkmc committed
341 342
	wbg := &gauge{}
	pwm := newPeerWantManager(g, wbg)
dirkmc's avatar
dirkmc committed
343 344 345

	peers := testutil.GeneratePeers(2)
	p0 := peers[0]
dirkmc's avatar
dirkmc committed
346
	p1 := peers[1]
dirkmc's avatar
dirkmc committed
347 348 349
	cids := testutil.GenerateCids(2)
	cids2 := testutil.GenerateCids(2)

350 351 352 353
	peerQueues := make(map[peer.ID]PeerQueue)
	pq := &mockPQ{}
	peerQueues[p0] = pq
	pwm.addPeer(pq, p0)
dirkmc's avatar
dirkmc committed
354 355

	// Send 2 want-blocks and 2 want-haves to p0
356
	pwm.sendWants(p0, cids, cids2)
dirkmc's avatar
dirkmc committed
357

dirkmc's avatar
dirkmc committed
358 359 360 361
	if g.count != 4 {
		t.Fatal("Expected 4 wants")
	}
	if wbg.count != 2 {
dirkmc's avatar
dirkmc committed
362 363 364 365 366
		t.Fatal("Expected 2 want-blocks")
	}

	// Send 1 old want-block and 2 new want-blocks to p0
	cids3 := testutil.GenerateCids(2)
367
	pwm.sendWants(p0, append(cids3, cids[0]), []cid.Cid{})
dirkmc's avatar
dirkmc committed
368

dirkmc's avatar
dirkmc committed
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392
	if g.count != 6 {
		t.Fatal("Expected 6 wants")
	}
	if wbg.count != 4 {
		t.Fatal("Expected 4 want-blocks")
	}

	// Broadcast 1 old want-have and 2 new want-haves
	cids4 := testutil.GenerateCids(2)
	pwm.broadcastWantHaves(append(cids4, cids2[0]))
	if g.count != 8 {
		t.Fatal("Expected 8 wants")
	}
	if wbg.count != 4 {
		t.Fatal("Expected 4 want-blocks")
	}

	// Add a second peer
	pwm.addPeer(pq, p1)

	if g.count != 8 {
		t.Fatal("Expected 8 wants")
	}
	if wbg.count != 4 {
dirkmc's avatar
dirkmc committed
393 394 395 396 397
		t.Fatal("Expected 4 want-blocks")
	}

	// Cancel 1 want-block that was sent to p0
	// and 1 want-block that was not sent
dirkmc's avatar
dirkmc committed
398 399
	cids5 := testutil.GenerateCids(1)
	pwm.sendCancels(append(cids5, cids[0]))
dirkmc's avatar
dirkmc committed
400

dirkmc's avatar
dirkmc committed
401 402 403 404 405
	if g.count != 7 {
		t.Fatal("Expected 7 wants")
	}
	if wbg.count != 3 {
		t.Fatal("Expected 3 want-blocks")
dirkmc's avatar
dirkmc committed
406
	}
407

dirkmc's avatar
dirkmc committed
408
	// Remove first peer
409 410
	pwm.removePeer(p0)

dirkmc's avatar
dirkmc committed
411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436
	// Should still have 3 broadcast wants
	if g.count != 3 {
		t.Fatal("Expected 3 wants")
	}
	if wbg.count != 0 {
		t.Fatal("Expected all want-blocks to be removed")
	}

	// Remove second peer
	pwm.removePeer(p1)

	// Should still have 3 broadcast wants
	if g.count != 3 {
		t.Fatal("Expected 3 wants")
	}
	if wbg.count != 0 {
		t.Fatal("Expected 0 want-blocks")
	}

	// Cancel one remaining broadcast want-have
	pwm.sendCancels(cids2[:1])
	if g.count != 2 {
		t.Fatal("Expected 2 wants")
	}
	if wbg.count != 0 {
		t.Fatal("Expected 0 want-blocks")
437
	}
dirkmc's avatar
dirkmc committed
438
}
Dirk McCormick's avatar
Dirk McCormick committed
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516

func TestStatsOverlappingWantBlockWantHave(t *testing.T) {
	g := &gauge{}
	wbg := &gauge{}
	pwm := newPeerWantManager(g, wbg)

	peers := testutil.GeneratePeers(2)
	p0 := peers[0]
	p1 := peers[1]
	cids := testutil.GenerateCids(2)
	cids2 := testutil.GenerateCids(2)

	pwm.addPeer(&mockPQ{}, p0)
	pwm.addPeer(&mockPQ{}, p1)

	// Send 2 want-blocks and 2 want-haves to p0
	pwm.sendWants(p0, cids, cids2)

	// Send opposite:
	// 2 want-haves and 2 want-blocks to p1
	pwm.sendWants(p1, cids2, cids)

	if g.count != 4 {
		t.Fatal("Expected 4 wants")
	}
	if wbg.count != 4 {
		t.Fatal("Expected 4 want-blocks")
	}

	// Cancel 1 of each group of cids
	pwm.sendCancels([]cid.Cid{cids[0], cids2[0]})

	if g.count != 2 {
		t.Fatal("Expected 2 wants")
	}
	if wbg.count != 2 {
		t.Fatal("Expected 2 want-blocks")
	}
}

func TestStatsRemovePeerOverlappingWantBlockWantHave(t *testing.T) {
	g := &gauge{}
	wbg := &gauge{}
	pwm := newPeerWantManager(g, wbg)

	peers := testutil.GeneratePeers(2)
	p0 := peers[0]
	p1 := peers[1]
	cids := testutil.GenerateCids(2)
	cids2 := testutil.GenerateCids(2)

	pwm.addPeer(&mockPQ{}, p0)
	pwm.addPeer(&mockPQ{}, p1)

	// Send 2 want-blocks and 2 want-haves to p0
	pwm.sendWants(p0, cids, cids2)

	// Send opposite:
	// 2 want-haves and 2 want-blocks to p1
	pwm.sendWants(p1, cids2, cids)

	if g.count != 4 {
		t.Fatal("Expected 4 wants")
	}
	if wbg.count != 4 {
		t.Fatal("Expected 4 want-blocks")
	}

	// Remove p0
	pwm.removePeer(p0)

	if g.count != 4 {
		t.Fatal("Expected 4 wants")
	}
	if wbg.count != 2 {
		t.Fatal("Expected 2 want-blocks")
	}
}