@cryptotaxi247 / kubo / commits / b7b046582

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,