bitswap_test.go 6.4 KB
Newer Older
1
package bitswap
Brian Tiger Chow's avatar
Brian Tiger Chow committed
2 3

import (
4
	"bytes"
5
	"sync"
Brian Tiger Chow's avatar
Brian Tiger Chow committed
6 7 8 9
	"testing"
	"time"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
10
	blocks "github.com/jbenet/go-ipfs/blocks"
11
	blocksutil "github.com/jbenet/go-ipfs/blocks/blocksutil"
12
	tn "github.com/jbenet/go-ipfs/exchange/bitswap/testnet"
Brian Tiger Chow's avatar
Brian Tiger Chow committed
13
	mockrouting "github.com/jbenet/go-ipfs/routing/mock"
14
	delay "github.com/jbenet/go-ipfs/util/delay"
15
	testutil "github.com/jbenet/go-ipfs/util/testutil"
Brian Tiger Chow's avatar
Brian Tiger Chow committed
16 17
)

Brian Tiger Chow's avatar
Brian Tiger Chow committed
18 19
// FIXME the tests are really sensitive to the network delay. fix them to work
// well under varying conditions
20 21
const kNetworkDelay = 0 * time.Millisecond

22 23 24
func TestClose(t *testing.T) {
	// TODO
	t.Skip("TODO Bitswap's Close implementation is a WIP")
25
	vnet := tn.VirtualNetwork(delay.Fixed(kNetworkDelay))
Brian Tiger Chow's avatar
Brian Tiger Chow committed
26
	rout := mockrouting.NewServer()
27
	sesgen := NewSessionGenerator(vnet, rout)
28
	bgen := blocksutil.NewBlockGenerator()
29 30 31 32

	block := bgen.Next()
	bitswap := sesgen.Next()

33 34
	bitswap.Exchange.Close()
	bitswap.Exchange.GetBlock(context.Background(), block.Key())
35 36
}

Brian Tiger Chow's avatar
Brian Tiger Chow committed
37 38
func TestGetBlockTimeout(t *testing.T) {

39
	net := tn.VirtualNetwork(delay.Fixed(kNetworkDelay))
Brian Tiger Chow's avatar
Brian Tiger Chow committed
40
	rs := mockrouting.NewServer()
41
	g := NewSessionGenerator(net, rs)
42

43
	self := g.Next()
44

Brian Tiger Chow's avatar
Brian Tiger Chow committed
45
	ctx, _ := context.WithTimeout(context.Background(), time.Nanosecond)
46
	block := blocks.NewBlock([]byte("block"))
47
	_, err := self.Exchange.GetBlock(ctx, block.Key())
Brian Tiger Chow's avatar
Brian Tiger Chow committed
48 49 50 51 52 53 54 55

	if err != context.DeadlineExceeded {
		t.Fatal("Expected DeadlineExceeded error")
	}
}

func TestProviderForKeyButNetworkCannotFind(t *testing.T) {

56
	net := tn.VirtualNetwork(delay.Fixed(kNetworkDelay))
Brian Tiger Chow's avatar
Brian Tiger Chow committed
57
	rs := mockrouting.NewServer()
58
	g := NewSessionGenerator(net, rs)
Brian Tiger Chow's avatar
Brian Tiger Chow committed
59

60
	block := blocks.NewBlock([]byte("block"))
Brian Tiger Chow's avatar
Brian Tiger Chow committed
61
	rs.Client(testutil.NewPeerWithIDString("testing")).Provide(context.Background(), block.Key()) // but not on network
Brian Tiger Chow's avatar
Brian Tiger Chow committed
62

63
	solo := g.Next()
Brian Tiger Chow's avatar
Brian Tiger Chow committed
64 65

	ctx, _ := context.WithTimeout(context.Background(), time.Nanosecond)
66
	_, err := solo.Exchange.GetBlock(ctx, block.Key())
Brian Tiger Chow's avatar
Brian Tiger Chow committed
67

Brian Tiger Chow's avatar
Brian Tiger Chow committed
68 69 70 71 72
	if err != context.DeadlineExceeded {
		t.Fatal("Expected DeadlineExceeded error")
	}
}

Brian Tiger Chow's avatar
Brian Tiger Chow committed
73 74 75 76
// TestGetBlockAfterRequesting...

func TestGetBlockFromPeerAfterPeerAnnounces(t *testing.T) {

77
	net := tn.VirtualNetwork(delay.Fixed(kNetworkDelay))
Brian Tiger Chow's avatar
Brian Tiger Chow committed
78
	rs := mockrouting.NewServer()
79
	block := blocks.NewBlock([]byte("block"))
80
	g := NewSessionGenerator(net, rs)
Brian Tiger Chow's avatar
Brian Tiger Chow committed
81

82
	hasBlock := g.Next()
Brian Tiger Chow's avatar
Brian Tiger Chow committed
83

84
	if err := hasBlock.Blockstore().Put(block); err != nil {
85 86
		t.Fatal(err)
	}
87
	if err := hasBlock.Exchange.HasBlock(context.Background(), block); err != nil {
88 89
		t.Fatal(err)
	}
Brian Tiger Chow's avatar
Brian Tiger Chow committed
90

91
	wantsBlock := g.Next()
Brian Tiger Chow's avatar
Brian Tiger Chow committed
92 93

	ctx, _ := context.WithTimeout(context.Background(), time.Second)
94
	received, err := wantsBlock.Exchange.GetBlock(ctx, block.Key())
Brian Tiger Chow's avatar
Brian Tiger Chow committed
95 96 97 98
	if err != nil {
		t.Log(err)
		t.Fatal("Expected to succeed")
	}
99 100 101 102

	if !bytes.Equal(block.Data, received.Data) {
		t.Fatal("Data doesn't match")
	}
Brian Tiger Chow's avatar
Brian Tiger Chow committed
103 104
}

105
func TestLargeSwarm(t *testing.T) {
106 107 108
	if testing.Short() {
		t.SkipNow()
	}
109
	t.Parallel()
110
	numInstances := 5
111
	numBlocks := 2
112 113
	PerformDistributionTest(t, numInstances, numBlocks)
}
114

115 116 117
func TestLargeFile(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
118
	}
119 120 121 122
	t.Parallel()
	numInstances := 10
	numBlocks := 100
	PerformDistributionTest(t, numInstances, numBlocks)
123 124
}

125
func PerformDistributionTest(t *testing.T, numInstances, numBlocks int) {
126 127 128
	if testing.Short() {
		t.SkipNow()
	}
129
	net := tn.VirtualNetwork(delay.Fixed(kNetworkDelay))
Brian Tiger Chow's avatar
Brian Tiger Chow committed
130
	rs := mockrouting.NewServer()
131
	sg := NewSessionGenerator(net, rs)
132
	bg := blocksutil.NewBlockGenerator()
133 134 135 136 137 138 139 140 141 142

	t.Log("Test a few nodes trying to get one file with a lot of blocks")

	instances := sg.Instances(numInstances)
	blocks := bg.Blocks(numBlocks)

	t.Log("Give the blocks to the first instance")

	first := instances[0]
	for _, b := range blocks {
143
		first.Blockstore().Put(b)
144
		first.Exchange.HasBlock(context.Background(), b)
Brian Tiger Chow's avatar
Brian Tiger Chow committed
145
		rs.Client(first.Peer).Provide(context.Background(), b.Key())
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
	}

	t.Log("Distribute!")

	var wg sync.WaitGroup

	for _, inst := range instances {
		for _, b := range blocks {
			wg.Add(1)
			// NB: executing getOrFail concurrently puts tremendous pressure on
			// the goroutine scheduler
			getOrFail(inst, b, t, &wg)
		}
	}
	wg.Wait()

	t.Log("Verify!")

	for _, inst := range instances {
		for _, b := range blocks {
166
			if _, err := inst.Blockstore().Get(b.Key()); err != nil {
167 168 169 170 171 172
				t.Fatal(err)
			}
		}
	}
}

173
func getOrFail(bitswap Instance, b *blocks.Block, t *testing.T, wg *sync.WaitGroup) {
174
	if _, err := bitswap.Blockstore().Get(b.Key()); err != nil {
175
		_, err := bitswap.Exchange.GetBlock(context.Background(), b.Key())
176 177 178 179 180 181 182
		if err != nil {
			t.Fatal(err)
		}
	}
	wg.Done()
}

183
// TODO simplify this test. get to the _essence_!
184
func TestSendToWantingPeer(t *testing.T) {
Brian Tiger Chow's avatar
Brian Tiger Chow committed
185 186 187 188
	if testing.Short() {
		t.SkipNow()
	}

189
	net := tn.VirtualNetwork(delay.Fixed(kNetworkDelay))
Brian Tiger Chow's avatar
Brian Tiger Chow committed
190
	rs := mockrouting.NewServer()
191
	sg := NewSessionGenerator(net, rs)
192
	bg := blocksutil.NewBlockGenerator()
193 194 195 196 197

	me := sg.Next()
	w := sg.Next()
	o := sg.Next()

198 199 200
	t.Logf("Session %v\n", me.Peer)
	t.Logf("Session %v\n", w.Peer)
	t.Logf("Session %v\n", o.Peer)
201

202 203
	alpha := bg.Next()

Brian Tiger Chow's avatar
Brian Tiger Chow committed
204
	const timeout = 100 * time.Millisecond // FIXME don't depend on time
205

206
	t.Logf("Peer %v attempts to get %v. NB: not available\n", w.Peer, alpha.Key())
207
	ctx, _ := context.WithTimeout(context.Background(), timeout)
208
	_, err := w.Exchange.GetBlock(ctx, alpha.Key())
209
	if err == nil {
210
		t.Fatalf("Expected %v to NOT be available", alpha.Key())
211 212 213
	}

	beta := bg.Next()
214
	t.Logf("Peer %v announes availability  of %v\n", w.Peer, beta.Key())
215
	ctx, _ = context.WithTimeout(context.Background(), timeout)
216
	if err := w.Blockstore().Put(beta); err != nil {
217 218
		t.Fatal(err)
	}
219
	w.Exchange.HasBlock(ctx, beta)
220

221
	t.Logf("%v gets %v from %v and discovers it wants %v\n", me.Peer, beta.Key(), w.Peer, alpha.Key())
222
	ctx, _ = context.WithTimeout(context.Background(), timeout)
223
	if _, err := me.Exchange.GetBlock(ctx, beta.Key()); err != nil {
224 225
		t.Fatal(err)
	}
226

227
	t.Logf("%v announces availability of %v\n", o.Peer, alpha.Key())
228
	ctx, _ = context.WithTimeout(context.Background(), timeout)
229
	if err := o.Blockstore().Put(alpha); err != nil {
230 231
		t.Fatal(err)
	}
232
	o.Exchange.HasBlock(ctx, alpha)
233

234
	t.Logf("%v requests %v\n", me.Peer, alpha.Key())
235
	ctx, _ = context.WithTimeout(context.Background(), timeout)
236
	if _, err := me.Exchange.GetBlock(ctx, alpha.Key()); err != nil {
237 238
		t.Fatal(err)
	}
239

240
	t.Logf("%v should now have %v\n", w.Peer, alpha.Key())
241
	block, err := w.Blockstore().Get(alpha.Key())
242
	if err != nil {
243
		t.Fatalf("Should not have received an error: %s", err)
244 245
	}
	if block.Key() != alpha.Key() {
246
		t.Fatal("Expected to receive alpha from me")
247
	}
248
}