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  }