github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/exchange/bitswap/decision/engine_test.go (about)

     1  package decision
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"math"
     7  	"strings"
     8  	"sync"
     9  	"testing"
    10  
    11  	ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore"
    12  	dssync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore/sync"
    13  	context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
    14  	blocks "github.com/ipfs/go-ipfs/blocks"
    15  	blockstore "github.com/ipfs/go-ipfs/blocks/blockstore"
    16  	message "github.com/ipfs/go-ipfs/exchange/bitswap/message"
    17  	peer "github.com/ipfs/go-ipfs/p2p/peer"
    18  	testutil "github.com/ipfs/go-ipfs/util/testutil"
    19  )
    20  
    21  type peerAndEngine struct {
    22  	Peer   peer.ID
    23  	Engine *Engine
    24  }
    25  
    26  func newEngine(ctx context.Context, idStr string) peerAndEngine {
    27  	return peerAndEngine{
    28  		Peer: peer.ID(idStr),
    29  		//Strategy: New(true),
    30  		Engine: NewEngine(ctx,
    31  			blockstore.NewBlockstore(dssync.MutexWrap(ds.NewMapDatastore()))),
    32  	}
    33  }
    34  
    35  func TestConsistentAccounting(t *testing.T) {
    36  	ctx, cancel := context.WithCancel(context.Background())
    37  	defer cancel()
    38  	sender := newEngine(ctx, "Ernie")
    39  	receiver := newEngine(ctx, "Bert")
    40  
    41  	// Send messages from Ernie to Bert
    42  	for i := 0; i < 1000; i++ {
    43  
    44  		m := message.New(false)
    45  		content := []string{"this", "is", "message", "i"}
    46  		m.AddBlock(blocks.NewBlock([]byte(strings.Join(content, " "))))
    47  
    48  		sender.Engine.MessageSent(receiver.Peer, m)
    49  		receiver.Engine.MessageReceived(sender.Peer, m)
    50  	}
    51  
    52  	// Ensure sender records the change
    53  	if sender.Engine.numBytesSentTo(receiver.Peer) == 0 {
    54  		t.Fatal("Sent bytes were not recorded")
    55  	}
    56  
    57  	// Ensure sender and receiver have the same values
    58  	if sender.Engine.numBytesSentTo(receiver.Peer) != receiver.Engine.numBytesReceivedFrom(sender.Peer) {
    59  		t.Fatal("Inconsistent book-keeping. Strategies don't agree")
    60  	}
    61  
    62  	// Ensure sender didn't record receving anything. And that the receiver
    63  	// didn't record sending anything
    64  	if receiver.Engine.numBytesSentTo(sender.Peer) != 0 || sender.Engine.numBytesReceivedFrom(receiver.Peer) != 0 {
    65  		t.Fatal("Bert didn't send bytes to Ernie")
    66  	}
    67  }
    68  
    69  func TestPeerIsAddedToPeersWhenMessageReceivedOrSent(t *testing.T) {
    70  
    71  	ctx, cancel := context.WithCancel(context.Background())
    72  	defer cancel()
    73  	sanfrancisco := newEngine(ctx, "sf")
    74  	seattle := newEngine(ctx, "sea")
    75  
    76  	m := message.New(true)
    77  
    78  	sanfrancisco.Engine.MessageSent(seattle.Peer, m)
    79  	seattle.Engine.MessageReceived(sanfrancisco.Peer, m)
    80  
    81  	if seattle.Peer == sanfrancisco.Peer {
    82  		t.Fatal("Sanity Check: Peers have same Key!")
    83  	}
    84  
    85  	if !peerIsPartner(seattle.Peer, sanfrancisco.Engine) {
    86  		t.Fatal("Peer wasn't added as a Partner")
    87  	}
    88  
    89  	if !peerIsPartner(sanfrancisco.Peer, seattle.Engine) {
    90  		t.Fatal("Peer wasn't added as a Partner")
    91  	}
    92  }
    93  
    94  func peerIsPartner(p peer.ID, e *Engine) bool {
    95  	for _, partner := range e.Peers() {
    96  		if partner == p {
    97  			return true
    98  		}
    99  	}
   100  	return false
   101  }
   102  
   103  func TestOutboxClosedWhenEngineClosed(t *testing.T) {
   104  	t.SkipNow() // TODO implement *Engine.Close
   105  	e := NewEngine(context.Background(), blockstore.NewBlockstore(dssync.MutexWrap(ds.NewMapDatastore())))
   106  	var wg sync.WaitGroup
   107  	wg.Add(1)
   108  	go func() {
   109  		for nextEnvelope := range e.Outbox() {
   110  			<-nextEnvelope
   111  		}
   112  		wg.Done()
   113  	}()
   114  	// e.Close()
   115  	wg.Wait()
   116  	if _, ok := <-e.Outbox(); ok {
   117  		t.Fatal("channel should be closed")
   118  	}
   119  }
   120  
   121  func TestPartnerWantsThenCancels(t *testing.T) {
   122  	numRounds := 10
   123  	if testing.Short() {
   124  		numRounds = 1
   125  	}
   126  	alphabet := strings.Split("abcdefghijklmnopqrstuvwxyz", "")
   127  	vowels := strings.Split("aeiou", "")
   128  
   129  	type testCase [][]string
   130  	testcases := []testCase{
   131  		{
   132  			alphabet, vowels,
   133  		},
   134  		{
   135  			alphabet, stringsComplement(alphabet, vowels),
   136  		},
   137  	}
   138  
   139  	bs := blockstore.NewBlockstore(dssync.MutexWrap(ds.NewMapDatastore()))
   140  	for _, letter := range alphabet {
   141  		block := blocks.NewBlock([]byte(letter))
   142  		if err := bs.Put(block); err != nil {
   143  			t.Fatal(err)
   144  		}
   145  	}
   146  
   147  	for i := 0; i < numRounds; i++ {
   148  		for _, testcase := range testcases {
   149  			set := testcase[0]
   150  			cancels := testcase[1]
   151  			keeps := stringsComplement(set, cancels)
   152  
   153  			e := NewEngine(context.Background(), bs)
   154  			partner := testutil.RandPeerIDFatal(t)
   155  
   156  			partnerWants(e, set, partner)
   157  			partnerCancels(e, cancels, partner)
   158  			if err := checkHandledInOrder(t, e, keeps); err != nil {
   159  				t.Logf("run #%d of %d", i, numRounds)
   160  				t.Fatal(err)
   161  			}
   162  		}
   163  	}
   164  }
   165  
   166  func partnerWants(e *Engine, keys []string, partner peer.ID) {
   167  	add := message.New(false)
   168  	for i, letter := range keys {
   169  		block := blocks.NewBlock([]byte(letter))
   170  		add.AddEntry(block.Key(), math.MaxInt32-i)
   171  	}
   172  	e.MessageReceived(partner, add)
   173  }
   174  
   175  func partnerCancels(e *Engine, keys []string, partner peer.ID) {
   176  	cancels := message.New(false)
   177  	for _, k := range keys {
   178  		block := blocks.NewBlock([]byte(k))
   179  		cancels.Cancel(block.Key())
   180  	}
   181  	e.MessageReceived(partner, cancels)
   182  }
   183  
   184  func checkHandledInOrder(t *testing.T, e *Engine, keys []string) error {
   185  	for _, k := range keys {
   186  		next := <-e.Outbox()
   187  		envelope := <-next
   188  		received := envelope.Block
   189  		expected := blocks.NewBlock([]byte(k))
   190  		if received.Key() != expected.Key() {
   191  			return errors.New(fmt.Sprintln("received", string(received.Data), "expected", string(expected.Data)))
   192  		}
   193  	}
   194  	return nil
   195  }
   196  
   197  func stringsComplement(set, subset []string) []string {
   198  	m := make(map[string]struct{})
   199  	for _, letter := range subset {
   200  		m[letter] = struct{}{}
   201  	}
   202  	var complement []string
   203  	for _, letter := range set {
   204  		if _, exists := m[letter]; !exists {
   205  			complement = append(complement, letter)
   206  		}
   207  	}
   208  	return complement
   209  }