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 }