test(bitswap) test with swarm of ~500 instances
test(bitswap) run synchronously to aid the scheduler
Brian Tiger Chow committed
Sep 19, 2014 at 17:32 UTC
b7b046582bd5ba689ad679eef67b53674ece918f
1 file changed
+98
-4
exchange/bitswap/bitswap_test.go
+98
-4
@@ -2,12 +2,14 @@ package bitswap
2
3
import (
4
"bytes"
5
+ "sync"
6
"testing"
7
"time"
8
9
context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
10
11
ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/datastore.go"
12
+ "github.com/jbenet/go-ipfs/blocks"
13
bstore "github.com/jbenet/go-ipfs/blockstore"
14
exchange "github.com/jbenet/go-ipfs/exchange"
15
notifications "github.com/jbenet/go-ipfs/exchange/bitswap/notifications"
@@ -85,6 +87,64 @@ func TestGetBlockFromPeerAfterPeerAnnounces(t *testing.T) {
87
}
88
}
89
90
+func TestSwarm(t *testing.T) {
91
+ net := tn.VirtualNetwork()
92
+ rs := tn.VirtualRoutingServer()
93
+ sg := NewSessionGenerator(net, rs)
94
+ bg := NewBlockGenerator(t)
95
+
96
+ t.Log("Create a ton of instances, and just a few blocks")
97
+
98
+ numInstances := 500
99
+ numBlocks := 2
100
+
101
+ instances := sg.Instances(numInstances)
102
+ blocks := bg.Blocks(numBlocks)
103
+
104
+ t.Log("Give the blocks to the first instance")
105
+
106
+ first := instances[0]
107
+ for _, b := range blocks {
108
+ first.blockstore.Put(*b)
109
+ first.exchange.HasBlock(context.Background(), *b)
110
+ rs.Announce(first.peer, b.Key())
111
+ }
112
+
113
+ t.Log("Distribute!")
114
+
115
+ var wg sync.WaitGroup
116
+
117
+ for _, inst := range instances {
118
+ for _, b := range blocks {
119
+ wg.Add(1)
120
+ // NB: executing getOrFail concurrently puts tremendous pressure on
121
+ // the goroutine scheduler
122
+ getOrFail(inst, b, t, &wg)
123
+ }
124
+ }
125
+ wg.Wait()
126
+
127
+ t.Log("Verify!")
128
+
129
+ for _, inst := range instances {
130
+ for _, b := range blocks {
131
+ if _, err := inst.blockstore.Get(b.Key()); err != nil {
132
+ t.Fatal(err)
133
+ }
134
+ }
135
+ }
136
+}
137
+
138
+func getOrFail(bitswap instance, b *blocks.Block, t *testing.T, wg *sync.WaitGroup) {
139
+ if _, err := bitswap.blockstore.Get(b.Key()); err != nil {
140
+ _, err := bitswap.exchange.Block(context.Background(), b.Key())
141
+ if err != nil {
142
+ t.Fatal(err)
143
+ }
144
+ }
145
+ wg.Done()
146
+}
147
+
148
func TestSendToWantingPeer(t *testing.T) {
149
t.Log("I get a file from peer |w|. In this message, I receive |w|'s wants")
150
t.Log("Peer |w| tells me it wants file |f|, but I don't have it")
@@ -92,6 +152,31 @@ func TestSendToWantingPeer(t *testing.T) {
152
t.Log("After receiving |f| from |o|, I send it to the wanting peer |w|")
153
}
154
155
+func NewBlockGenerator(t *testing.T) BlockGenerator {
156
+ return BlockGenerator{
157
+ T: t,
158
+ }
159
+}
160
+
161
+type BlockGenerator struct {
162
+ *testing.T // b/c block generation can fail
163
+ seq int
164
+}
165
+
166
+func (bg *BlockGenerator) Next() blocks.Block {
167
+ bg.seq++
168
+ return testutil.NewBlockOrFail(bg.T, string(bg.seq))
169
+}
170
+
171
+func (bg *BlockGenerator) Blocks(n int) []*blocks.Block {
172
+ blocks := make([]*blocks.Block, 0)
173
+ for i := 0; i < n; i++ {
174
+ b := bg.Next()
175
+ blocks = append(blocks, &b)
176
+ }
177
+ return blocks
178
+}
179
+
180
func NewSessionGenerator(
181
net tn.Network, rs tn.RoutingServer) SessionGenerator {
182
return SessionGenerator{
@@ -107,12 +192,21 @@ type SessionGenerator struct {
192
rs tn.RoutingServer
193
}
194
110
-func (g *SessionGenerator) Next() testnetBitSwap {
195
+func (g *SessionGenerator) Next() instance {
196
g.seq++
197
return session(g.net, g.rs, []byte(string(g.seq)))
198
}
199
115
-type testnetBitSwap struct {
200
+func (g *SessionGenerator) Instances(n int) []instance {
201
+ instances := make([]instance, 0)
202
+ for j := 0; j < n; j++ {
203
+ inst := g.Next()
204
+ instances = append(instances, inst)
205
+ }
206
+ return instances
207
+}
208
+
209
+type instance struct {
210
peer *peer.Peer
211
exchange exchange.Interface
212
blockstore bstore.Blockstore
@@ -123,7 +217,7 @@ type testnetBitSwap struct {
217
// NB: It's easy make mistakes by providing the same peer ID to two different
218
// sessions. To safeguard, use the SessionGenerator to generate sessions. It's
219
// just a much better idea.
126
-func session(net tn.Network, rs tn.RoutingServer, id peer.ID) testnetBitSwap {
220
+func session(net tn.Network, rs tn.RoutingServer, id peer.ID) instance {
221
p := &peer.Peer{ID: id}
222
223
adapter := net.Adapter(p)
@@ -138,7 +232,7 @@ func session(net tn.Network, rs tn.RoutingServer, id peer.ID) testnetBitSwap {
232
sender: adapter,
233
}
234
adapter.SetDelegate(bs)
141
- return testnetBitSwap{
235
+ return instance{
236
peer: p,
237
exchange: bs,
238
blockstore: blockstore,