github.com/defanghe/fabric@v2.1.1+incompatible/gossip/comm/ack_test.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package comm
     8  
     9  import (
    10  	"errors"
    11  	"testing"
    12  	"time"
    13  
    14  	proto "github.com/hyperledger/fabric-protos-go/gossip"
    15  	"github.com/hyperledger/fabric/gossip/common"
    16  	"github.com/hyperledger/fabric/gossip/protoext"
    17  	"github.com/hyperledger/fabric/gossip/util"
    18  	"github.com/stretchr/testify/assert"
    19  )
    20  
    21  func TestInterceptAcks(t *testing.T) {
    22  	pubsub := util.NewPubSub()
    23  	pkiID := common.PKIidType("pkiID")
    24  	msgs := make(chan *protoext.SignedGossipMessage, 1)
    25  	handlerFunc := func(message *protoext.SignedGossipMessage) {
    26  		msgs <- message
    27  	}
    28  	wrappedHandler := interceptAcks(handlerFunc, pkiID, pubsub)
    29  	ack := &protoext.SignedGossipMessage{
    30  		GossipMessage: &proto.GossipMessage{
    31  			Nonce: 1,
    32  			Content: &proto.GossipMessage_Ack{
    33  				Ack: &proto.Acknowledgement{},
    34  			},
    35  		},
    36  	}
    37  	sub := pubsub.Subscribe(topicForAck(1, pkiID), time.Second)
    38  	wrappedHandler(ack)
    39  	// Ensure ack was consumed and not passed onwards to the wrapped hander
    40  	assert.Len(t, msgs, 0)
    41  	_, err := sub.Listen()
    42  	// Ensure ack was published
    43  	assert.NoError(t, err)
    44  
    45  	// Test none acks are just forwarded
    46  	notAck := &protoext.SignedGossipMessage{
    47  		GossipMessage: &proto.GossipMessage{
    48  			Nonce: 2,
    49  			Content: &proto.GossipMessage_DataMsg{
    50  				DataMsg: &proto.DataMessage{},
    51  			},
    52  		},
    53  	}
    54  	sub = pubsub.Subscribe(topicForAck(2, pkiID), time.Second)
    55  	wrappedHandler(notAck)
    56  	// Ensure message was passed to the wrapped handler
    57  	assert.Len(t, msgs, 1)
    58  	_, err = sub.Listen()
    59  	// Ensure ack was not published
    60  	assert.Error(t, err)
    61  }
    62  
    63  func TestAck(t *testing.T) {
    64  	t.Parallel()
    65  
    66  	comm1, _ := newCommInstance(t, naiveSec)
    67  	comm2, port2 := newCommInstance(t, naiveSec)
    68  	defer comm2.Stop()
    69  	comm3, port3 := newCommInstance(t, naiveSec)
    70  	defer comm3.Stop()
    71  	comm4, port4 := newCommInstance(t, naiveSec)
    72  	defer comm4.Stop()
    73  
    74  	acceptData := func(o interface{}) bool {
    75  		m := o.(protoext.ReceivedMessage).GetGossipMessage()
    76  		return protoext.IsDataMsg(m.GossipMessage)
    77  	}
    78  
    79  	ack := func(c <-chan protoext.ReceivedMessage) {
    80  		msg := <-c
    81  		msg.Ack(nil)
    82  	}
    83  
    84  	nack := func(c <-chan protoext.ReceivedMessage) {
    85  		msg := <-c
    86  		msg.Ack(errors.New("Failed processing message because reasons"))
    87  	}
    88  
    89  	// Have instances 2 and 3 subscribe to data messages, and ack them
    90  	inc2 := comm2.Accept(acceptData)
    91  	inc3 := comm3.Accept(acceptData)
    92  
    93  	// Collect 2 out of 2 acks - should succeed
    94  	go ack(inc2)
    95  	go ack(inc3)
    96  	res := comm1.SendWithAck(createGossipMsg(), time.Second*3, 2, remotePeer(port2), remotePeer(port3))
    97  	assert.Len(t, res, 2)
    98  	assert.Empty(t, res[0].Error())
    99  	assert.Empty(t, res[1].Error())
   100  
   101  	// Collect 2 out of 3 acks - should succeed
   102  	t1 := time.Now()
   103  	go ack(inc2)
   104  	go ack(inc3)
   105  	res = comm1.SendWithAck(createGossipMsg(), time.Second*10, 2, remotePeer(port2), remotePeer(port3), remotePeer(port4))
   106  	elapsed := time.Since(t1)
   107  	assert.Len(t, res, 2)
   108  	assert.Empty(t, res[0].Error())
   109  	assert.Empty(t, res[1].Error())
   110  	// Collection of 2 out of 3 acks should have taken much less than the timeout (10 seconds)
   111  	assert.True(t, elapsed < time.Second*5)
   112  
   113  	// Collect 2 out of 3 acks - should fail, because peer3 now have sent an error along with the ack
   114  	go ack(inc2)
   115  	go nack(inc3)
   116  	res = comm1.SendWithAck(createGossipMsg(), time.Second*10, 2, remotePeer(port2), remotePeer(port3), remotePeer(port4))
   117  	assert.Len(t, res, 3)
   118  	assert.Contains(t, []string{res[0].Error(), res[1].Error(), res[2].Error()}, "Failed processing message because reasons")
   119  	assert.Contains(t, []string{res[0].Error(), res[1].Error(), res[2].Error()}, "timed out")
   120  
   121  	// Collect 2 out of 2 acks - should fail because comm2 and comm3 now don't acknowledge messages
   122  	res = comm1.SendWithAck(createGossipMsg(), time.Second*3, 2, remotePeer(port2), remotePeer(port3))
   123  	assert.Len(t, res, 2)
   124  	assert.Contains(t, res[0].Error(), "timed out")
   125  	assert.Contains(t, res[1].Error(), "timed out")
   126  	// Drain ack messages to prepare for next salvo
   127  	<-inc2
   128  	<-inc3
   129  
   130  	// Collect 2 out of 3 acks - should fail
   131  	go ack(inc2)
   132  	go nack(inc3)
   133  	res = comm1.SendWithAck(createGossipMsg(), time.Second*3, 2, remotePeer(port2), remotePeer(port3), remotePeer(port4))
   134  	assert.Len(t, res, 3)
   135  	assert.Contains(t, []string{res[0].Error(), res[1].Error(), res[2].Error()}, "") // This is the "successful ack"
   136  	assert.Contains(t, []string{res[0].Error(), res[1].Error(), res[2].Error()}, "Failed processing message because reasons")
   137  	assert.Contains(t, []string{res[0].Error(), res[1].Error(), res[2].Error()}, "timed out")
   138  	assert.Contains(t, res.String(), "\"Failed processing message because reasons\":1")
   139  	assert.Contains(t, res.String(), "\"timed out\":1")
   140  	assert.Contains(t, res.String(), "\"successes\":1")
   141  	assert.Equal(t, 2, res.NackCount())
   142  	assert.Equal(t, 1, res.AckCount())
   143  
   144  	// Send a message to no one
   145  	res = comm1.SendWithAck(createGossipMsg(), time.Second*3, 1)
   146  	assert.Len(t, res, 0)
   147  
   148  	// Send a message while stopping
   149  	comm1.Stop()
   150  	res = comm1.SendWithAck(createGossipMsg(), time.Second*3, 1, remotePeer(port2), remotePeer(port3), remotePeer(port4))
   151  	assert.Len(t, res, 3)
   152  	assert.Contains(t, res[0].Error(), "comm is stopping")
   153  	assert.Contains(t, res[1].Error(), "comm is stopping")
   154  	assert.Contains(t, res[2].Error(), "comm is stopping")
   155  }