func TestSendMessageAsyncButWaitForResponse(t *testing.T) { net := VirtualNetwork() idOfResponder := []byte("responder") waiter := net.Adapter(peer.WithIDString("waiter")) responder := net.Adapter(peer.WithID(idOfResponder)) var wg sync.WaitGroup wg.Add(1) expectedStr := "received async" responder.SetDelegate(lambda(func( ctx context.Context, fromWaiter peer.Peer, msgFromWaiter bsmsg.BitSwapMessage) ( peer.Peer, bsmsg.BitSwapMessage) { msgToWaiter := bsmsg.New() msgToWaiter.AddBlock(*blocks.NewBlock([]byte(expectedStr))) return fromWaiter, msgToWaiter })) waiter.SetDelegate(lambda(func( ctx context.Context, fromResponder peer.Peer, msgFromResponder bsmsg.BitSwapMessage) ( peer.Peer, bsmsg.BitSwapMessage) { // TODO assert that this came from the correct peer and that the message contents are as expected ok := false for _, b := range msgFromResponder.Blocks() { if string(b.Data) == expectedStr { wg.Done() ok = true } } if !ok { t.Fatal("Message not received from the responder") } return nil, nil })) messageSentAsync := bsmsg.New() messageSentAsync.AddBlock(*blocks.NewBlock([]byte("data"))) errSending := waiter.SendMessage( context.Background(), peer.WithID(idOfResponder), messageSentAsync) if errSending != nil { t.Fatal(errSending) } wg.Wait() // until waiter delegate function is executed }
func TestConsistentAccounting(t *testing.T) { sender := newPeerAndStrategist("Ernie") receiver := newPeerAndStrategist("Bert") // Send messages from Ernie to Bert for i := 0; i < 1000; i++ { m := message.New() content := []string{"this", "is", "message", "i"} m.AddBlock(*blocks.NewBlock([]byte(strings.Join(content, " ")))) sender.MessageSent(receiver.Peer, m) receiver.MessageReceived(sender.Peer, m) } // Ensure sender records the change if sender.NumBytesSentTo(receiver.Peer) == 0 { t.Fatal("Sent bytes were not recorded") } // Ensure sender and receiver have the same values if sender.NumBytesSentTo(receiver.Peer) != receiver.NumBytesReceivedFrom(sender.Peer) { t.Fatal("Inconsistent book-keeping. Strategies don't agree") } // Ensure sender didn't record receving anything. And that the receiver // didn't record sending anything if receiver.NumBytesSentTo(sender.Peer) != 0 || sender.NumBytesReceivedFrom(receiver.Peer) != 0 { t.Fatal("Bert didn't send bytes to Ernie") } }
func TestSendRequestToCooperativePeer(t *testing.T) { net := VirtualNetwork() idOfRecipient := []byte("recipient") t.Log("Get two network adapters") initiator := net.Adapter(peer.WithIDString("initiator")) recipient := net.Adapter(peer.WithID(idOfRecipient)) expectedStr := "response from recipient" recipient.SetDelegate(lambda(func( ctx context.Context, from peer.Peer, incoming bsmsg.BitSwapMessage) ( peer.Peer, bsmsg.BitSwapMessage) { t.Log("Recipient received a message from the network") // TODO test contents of incoming message m := bsmsg.New() m.AddBlock(*blocks.NewBlock([]byte(expectedStr))) return from, m })) t.Log("Build a message and send a synchronous request to recipient") message := bsmsg.New() message.AddBlock(*blocks.NewBlock([]byte("data"))) response, err := initiator.SendRequest( context.Background(), peer.WithID(idOfRecipient), message) if err != nil { t.Fatal(err) } t.Log("Check the contents of the response from recipient") for _, blockFromRecipient := range response.Blocks() { if string(blockFromRecipient.Data) == expectedStr { return } } t.Fatal("Should have returned after finding expected block data") }
// GetBlock attempts to retrieve a particular block from peers within the // deadline enforced by the context // // TODO ensure only one active request per key func (bs *bitswap) Block(parent context.Context, k u.Key) (*blocks.Block, error) { log.Debugf("Get Block %v", k) now := time.Now() defer func() { log.Debugf("GetBlock took %f secs", time.Now().Sub(now).Seconds()) }() ctx, cancelFunc := context.WithCancel(parent) defer cancelFunc() bs.wantlist.Add(k) promise := bs.notifications.Subscribe(ctx, k) const maxProviders = 20 peersToQuery := bs.routing.FindProvidersAsync(ctx, k, maxProviders) go func() { message := bsmsg.New() for _, wanted := range bs.wantlist.Keys() { message.AddWanted(wanted) } for peerToQuery := range peersToQuery { log.Debugf("bitswap got peersToQuery: %s", peerToQuery) go func(p peer.Peer) { log.Debugf("bitswap dialing peer: %s", p) err := bs.sender.DialPeer(ctx, p) if err != nil { log.Errorf("Error sender.DialPeer(%s)", p) return } response, err := bs.sender.SendRequest(ctx, p, message) if err != nil { log.Errorf("Error sender.SendRequest(%s) = %s", p, err) return } // FIXME ensure accounting is handled correctly when // communication fails. May require slightly different API to // get better guarantees. May need shared sequence numbers. bs.strategy.MessageSent(p, message) if response == nil { return } bs.ReceiveMessage(ctx, p, response) }(peerToQuery) } }() select { case block := <-promise: bs.wantlist.Remove(k) return &block, nil case <-parent.Done(): return nil, parent.Err() } }
// TODO(brian): handle errors func (bs *bitswap) ReceiveMessage(ctx context.Context, p peer.Peer, incoming bsmsg.BitSwapMessage) ( peer.Peer, bsmsg.BitSwapMessage) { log.Debugf("ReceiveMessage from %v", p.Key()) log.Debugf("Message wantlist: %v", incoming.Wantlist()) if p == nil { log.Error("Received message from nil peer!") // TODO propagate the error upward return nil, nil } if incoming == nil { log.Error("Got nil bitswap message!") // TODO propagate the error upward return nil, nil } // Record message bytes in ledger // TODO: this is bad, and could be easily abused. // Should only track *useful* messages in ledger bs.strategy.MessageReceived(p, incoming) // FIRST for _, block := range incoming.Blocks() { // TODO verify blocks? if err := bs.blockstore.Put(&block); err != nil { continue // FIXME(brian): err ignored } bs.notifications.Publish(block) err := bs.HasBlock(ctx, block) if err != nil { log.Warningf("HasBlock errored: %s", err) } } message := bsmsg.New() for _, wanted := range bs.wantlist.Keys() { message.AddWanted(wanted) } for _, key := range incoming.Wantlist() { // TODO: might be better to check if we have the block before checking // if we should send it to someone if bs.strategy.ShouldSendBlockToPeer(key, p) { if block, errBlockNotFound := bs.blockstore.Get(key); errBlockNotFound != nil { continue } else { message.AddBlock(*block) } } } defer bs.strategy.MessageSent(p, message) log.Debug("Returning message.") return p, message }
func TestBlockRecordedAsWantedAfterMessageReceived(t *testing.T) { beggar := newPeerAndStrategist("can't be chooser") chooser := newPeerAndStrategist("chooses JIF") block := blocks.NewBlock([]byte("data wanted by beggar")) messageFromBeggarToChooser := message.New() messageFromBeggarToChooser.AddWanted(block.Key()) chooser.MessageReceived(beggar.Peer, messageFromBeggarToChooser) // for this test, doesn't matter if you record that beggar sent if !chooser.BlockIsWantedByPeer(block.Key(), beggar.Peer) { t.Fatal("chooser failed to record that beggar wants block") } }
func (bs *bitswap) sendToPeersThatWant(ctx context.Context, block blocks.Block) { log.Debugf("Sending %v to peers that want it", block.Key()) for _, p := range bs.strategy.Peers() { if bs.strategy.BlockIsWantedByPeer(block.Key(), p) { log.Debugf("%v wants %v", p, block.Key()) if bs.strategy.ShouldSendBlockToPeer(block.Key(), p) { message := bsmsg.New() message.AddBlock(block) for _, wanted := range bs.wantlist.Keys() { message.AddWanted(wanted) } bs.send(ctx, p, message) } } } }
func TestPeerIsAddedToPeersWhenMessageReceivedOrSent(t *testing.T) { sanfrancisco := newPeerAndStrategist("sf") seattle := newPeerAndStrategist("sea") m := message.New() sanfrancisco.MessageSent(seattle.Peer, m) seattle.MessageReceived(sanfrancisco.Peer, m) if seattle.Peer.Key() == sanfrancisco.Peer.Key() { t.Fatal("Sanity Check: Peers have same Key!") } if !peerIsPartner(seattle.Peer, sanfrancisco.Strategy) { t.Fatal("Peer wasn't added as a Partner") } if !peerIsPartner(sanfrancisco.Peer, seattle.Strategy) { t.Fatal("Peer wasn't added as a Partner") } }