github.com/zignig/go-ipfs@v0.0.0-20141111235910-c9e5fdf55a52/exchange/bitswap/bitswap_test.go (about) 1 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/go-datastore" 12 ds_sync "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore/sync" 13 blocks "github.com/jbenet/go-ipfs/blocks" 14 bstore "github.com/jbenet/go-ipfs/blockstore" 15 exchange "github.com/jbenet/go-ipfs/exchange" 16 notifications "github.com/jbenet/go-ipfs/exchange/bitswap/notifications" 17 strategy "github.com/jbenet/go-ipfs/exchange/bitswap/strategy" 18 tn "github.com/jbenet/go-ipfs/exchange/bitswap/testnet" 19 peer "github.com/jbenet/go-ipfs/peer" 20 mock "github.com/jbenet/go-ipfs/routing/mock" 21 util "github.com/jbenet/go-ipfs/util" 22 ) 23 24 func TestGetBlockTimeout(t *testing.T) { 25 26 net := tn.VirtualNetwork() 27 rs := mock.VirtualRoutingServer() 28 g := NewSessionGenerator(net, rs) 29 30 self := g.Next() 31 32 ctx, _ := context.WithTimeout(context.Background(), time.Nanosecond) 33 block := blocks.NewBlock([]byte("block")) 34 _, err := self.exchange.Block(ctx, block.Key()) 35 36 if err != context.DeadlineExceeded { 37 t.Fatal("Expected DeadlineExceeded error") 38 } 39 } 40 41 func TestProviderForKeyButNetworkCannotFind(t *testing.T) { 42 43 net := tn.VirtualNetwork() 44 rs := mock.VirtualRoutingServer() 45 g := NewSessionGenerator(net, rs) 46 47 block := blocks.NewBlock([]byte("block")) 48 rs.Announce(peer.WithIDString("testing"), block.Key()) // but not on network 49 50 solo := g.Next() 51 52 ctx, _ := context.WithTimeout(context.Background(), time.Nanosecond) 53 _, err := solo.exchange.Block(ctx, block.Key()) 54 55 if err != context.DeadlineExceeded { 56 t.Fatal("Expected DeadlineExceeded error") 57 } 58 } 59 60 // TestGetBlockAfterRequesting... 61 62 func TestGetBlockFromPeerAfterPeerAnnounces(t *testing.T) { 63 64 net := tn.VirtualNetwork() 65 rs := mock.VirtualRoutingServer() 66 block := blocks.NewBlock([]byte("block")) 67 g := NewSessionGenerator(net, rs) 68 69 hasBlock := g.Next() 70 71 if err := hasBlock.blockstore.Put(block); err != nil { 72 t.Fatal(err) 73 } 74 if err := hasBlock.exchange.HasBlock(context.Background(), *block); err != nil { 75 t.Fatal(err) 76 } 77 78 wantsBlock := g.Next() 79 80 ctx, _ := context.WithTimeout(context.Background(), time.Second) 81 received, err := wantsBlock.exchange.Block(ctx, block.Key()) 82 if err != nil { 83 t.Log(err) 84 t.Fatal("Expected to succeed") 85 } 86 87 if !bytes.Equal(block.Data, received.Data) { 88 t.Fatal("Data doesn't match") 89 } 90 } 91 92 func TestSwarm(t *testing.T) { 93 net := tn.VirtualNetwork() 94 rs := mock.VirtualRoutingServer() 95 sg := NewSessionGenerator(net, rs) 96 bg := NewBlockGenerator() 97 98 t.Log("Create a ton of instances, and just a few blocks") 99 100 numInstances := 500 101 numBlocks := 2 102 103 instances := sg.Instances(numInstances) 104 blocks := bg.Blocks(numBlocks) 105 106 t.Log("Give the blocks to the first instance") 107 108 first := instances[0] 109 for _, b := range blocks { 110 first.blockstore.Put(b) 111 first.exchange.HasBlock(context.Background(), *b) 112 rs.Announce(first.peer, b.Key()) 113 } 114 115 t.Log("Distribute!") 116 117 var wg sync.WaitGroup 118 119 for _, inst := range instances { 120 for _, b := range blocks { 121 wg.Add(1) 122 // NB: executing getOrFail concurrently puts tremendous pressure on 123 // the goroutine scheduler 124 getOrFail(inst, b, t, &wg) 125 } 126 } 127 wg.Wait() 128 129 t.Log("Verify!") 130 131 for _, inst := range instances { 132 for _, b := range blocks { 133 if _, err := inst.blockstore.Get(b.Key()); err != nil { 134 t.Fatal(err) 135 } 136 } 137 } 138 } 139 140 func getOrFail(bitswap instance, b *blocks.Block, t *testing.T, wg *sync.WaitGroup) { 141 if _, err := bitswap.blockstore.Get(b.Key()); err != nil { 142 _, err := bitswap.exchange.Block(context.Background(), b.Key()) 143 if err != nil { 144 t.Fatal(err) 145 } 146 } 147 wg.Done() 148 } 149 150 // TODO simplify this test. get to the _essence_! 151 func TestSendToWantingPeer(t *testing.T) { 152 net := tn.VirtualNetwork() 153 rs := mock.VirtualRoutingServer() 154 sg := NewSessionGenerator(net, rs) 155 bg := NewBlockGenerator() 156 157 me := sg.Next() 158 w := sg.Next() 159 o := sg.Next() 160 161 t.Logf("Session %v\n", me.peer) 162 t.Logf("Session %v\n", w.peer) 163 t.Logf("Session %v\n", o.peer) 164 165 alpha := bg.Next() 166 167 const timeout = 1 * time.Millisecond // FIXME don't depend on time 168 169 t.Logf("Peer %v attempts to get %v. NB: not available\n", w.peer, alpha.Key()) 170 ctx, _ := context.WithTimeout(context.Background(), timeout) 171 _, err := w.exchange.Block(ctx, alpha.Key()) 172 if err == nil { 173 t.Fatalf("Expected %v to NOT be available", alpha.Key()) 174 } 175 176 beta := bg.Next() 177 t.Logf("Peer %v announes availability of %v\n", w.peer, beta.Key()) 178 ctx, _ = context.WithTimeout(context.Background(), timeout) 179 if err := w.blockstore.Put(&beta); err != nil { 180 t.Fatal(err) 181 } 182 w.exchange.HasBlock(ctx, beta) 183 184 t.Logf("%v gets %v from %v and discovers it wants %v\n", me.peer, beta.Key(), w.peer, alpha.Key()) 185 ctx, _ = context.WithTimeout(context.Background(), timeout) 186 if _, err := me.exchange.Block(ctx, beta.Key()); err != nil { 187 t.Fatal(err) 188 } 189 190 t.Logf("%v announces availability of %v\n", o.peer, alpha.Key()) 191 ctx, _ = context.WithTimeout(context.Background(), timeout) 192 if err := o.blockstore.Put(&alpha); err != nil { 193 t.Fatal(err) 194 } 195 o.exchange.HasBlock(ctx, alpha) 196 197 t.Logf("%v requests %v\n", me.peer, alpha.Key()) 198 ctx, _ = context.WithTimeout(context.Background(), timeout) 199 if _, err := me.exchange.Block(ctx, alpha.Key()); err != nil { 200 t.Fatal(err) 201 } 202 203 t.Logf("%v should now have %v\n", w.peer, alpha.Key()) 204 block, err := w.blockstore.Get(alpha.Key()) 205 if err != nil { 206 t.Fatal("Should not have received an error") 207 } 208 if block.Key() != alpha.Key() { 209 t.Fatal("Expected to receive alpha from me") 210 } 211 } 212 213 func NewBlockGenerator() BlockGenerator { 214 return BlockGenerator{} 215 } 216 217 type BlockGenerator struct { 218 seq int 219 } 220 221 func (bg *BlockGenerator) Next() blocks.Block { 222 bg.seq++ 223 return *blocks.NewBlock([]byte(string(bg.seq))) 224 } 225 226 func (bg *BlockGenerator) Blocks(n int) []*blocks.Block { 227 blocks := make([]*blocks.Block, 0) 228 for i := 0; i < n; i++ { 229 b := bg.Next() 230 blocks = append(blocks, &b) 231 } 232 return blocks 233 } 234 235 func NewSessionGenerator( 236 net tn.Network, rs mock.RoutingServer) SessionGenerator { 237 return SessionGenerator{ 238 net: net, 239 rs: rs, 240 seq: 0, 241 } 242 } 243 244 type SessionGenerator struct { 245 seq int 246 net tn.Network 247 rs mock.RoutingServer 248 } 249 250 func (g *SessionGenerator) Next() instance { 251 g.seq++ 252 return session(g.net, g.rs, []byte(string(g.seq))) 253 } 254 255 func (g *SessionGenerator) Instances(n int) []instance { 256 instances := make([]instance, 0) 257 for j := 0; j < n; j++ { 258 inst := g.Next() 259 instances = append(instances, inst) 260 } 261 return instances 262 } 263 264 type instance struct { 265 peer peer.Peer 266 exchange exchange.Interface 267 blockstore bstore.Blockstore 268 } 269 270 // session creates a test bitswap session. 271 // 272 // NB: It's easy make mistakes by providing the same peer ID to two different 273 // sessions. To safeguard, use the SessionGenerator to generate sessions. It's 274 // just a much better idea. 275 func session(net tn.Network, rs mock.RoutingServer, id peer.ID) instance { 276 p := peer.WithID(id) 277 278 adapter := net.Adapter(p) 279 htc := rs.Client(p) 280 281 blockstore := bstore.NewBlockstore(ds_sync.MutexWrap(ds.NewMapDatastore())) 282 const alwaysSendToPeer = true 283 bs := &bitswap{ 284 blockstore: blockstore, 285 notifications: notifications.New(), 286 strategy: strategy.New(alwaysSendToPeer), 287 routing: htc, 288 sender: adapter, 289 wantlist: util.NewKeySet(), 290 } 291 adapter.SetDelegate(bs) 292 return instance{ 293 peer: p, 294 exchange: bs, 295 blockstore: blockstore, 296 } 297 }