github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/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/osdi23p228/fabric/gossip/common"
    16  	"github.com/osdi23p228/fabric/gossip/protoext"
    17  	"github.com/osdi23p228/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  	comm1, _ := newCommInstance(t, naiveSec)
    65  	comm2, port2 := newCommInstance(t, naiveSec)
    66  	defer comm2.Stop()
    67  	comm3, port3 := newCommInstance(t, naiveSec)
    68  	defer comm3.Stop()
    69  	comm4, port4 := newCommInstance(t, naiveSec)
    70  	defer comm4.Stop()
    71  
    72  	acceptData := func(o interface{}) bool {
    73  		m := o.(protoext.ReceivedMessage).GetGossipMessage()
    74  		return protoext.IsDataMsg(m.GossipMessage)
    75  	}
    76  
    77  	ack := func(c <-chan protoext.ReceivedMessage) {
    78  		msg := <-c
    79  		msg.Ack(nil)
    80  	}
    81  
    82  	nack := func(c <-chan protoext.ReceivedMessage) {
    83  		msg := <-c
    84  		msg.Ack(errors.New("Failed processing message because reasons"))
    85  	}
    86  
    87  	// Have instances 2 and 3 subscribe to data messages, and ack them
    88  	inc2 := comm2.Accept(acceptData)
    89  	inc3 := comm3.Accept(acceptData)
    90  
    91  	// Collect 2 out of 2 acks - should succeed
    92  	go ack(inc2)
    93  	go ack(inc3)
    94  	res := comm1.SendWithAck(createGossipMsg(), time.Second*3, 2, remotePeer(port2), remotePeer(port3))
    95  	assert.Len(t, res, 2)
    96  	assert.Empty(t, res[0].Error())
    97  	assert.Empty(t, res[1].Error())
    98  
    99  	// Collect 2 out of 3 acks - should succeed
   100  	t1 := time.Now()
   101  	go ack(inc2)
   102  	go ack(inc3)
   103  	res = comm1.SendWithAck(createGossipMsg(), time.Second*10, 2, remotePeer(port2), remotePeer(port3), remotePeer(port4))
   104  	elapsed := time.Since(t1)
   105  	assert.Len(t, res, 2)
   106  	assert.Empty(t, res[0].Error())
   107  	assert.Empty(t, res[1].Error())
   108  	// Collection of 2 out of 3 acks should have taken much less than the timeout (10 seconds)
   109  	assert.True(t, elapsed < time.Second*5)
   110  
   111  	// Collect 2 out of 3 acks - should fail, because peer3 now have sent an error along with the ack
   112  	go ack(inc2)
   113  	go nack(inc3)
   114  	res = comm1.SendWithAck(createGossipMsg(), time.Second*10, 2, remotePeer(port2), remotePeer(port3), remotePeer(port4))
   115  	assert.Len(t, res, 3)
   116  	assert.Contains(t, []string{res[0].Error(), res[1].Error(), res[2].Error()}, "Failed processing message because reasons")
   117  	assert.Contains(t, []string{res[0].Error(), res[1].Error(), res[2].Error()}, "timed out")
   118  
   119  	// Collect 2 out of 2 acks - should fail because comm2 and comm3 now don't acknowledge messages
   120  	res = comm1.SendWithAck(createGossipMsg(), time.Second*3, 2, remotePeer(port2), remotePeer(port3))
   121  	assert.Len(t, res, 2)
   122  	assert.Contains(t, res[0].Error(), "timed out")
   123  	assert.Contains(t, res[1].Error(), "timed out")
   124  	// Drain ack messages to prepare for next salvo
   125  	<-inc2
   126  	<-inc3
   127  
   128  	// Collect 2 out of 3 acks - should fail
   129  	go ack(inc2)
   130  	go nack(inc3)
   131  	res = comm1.SendWithAck(createGossipMsg(), time.Second*3, 2, remotePeer(port2), remotePeer(port3), remotePeer(port4))
   132  	assert.Len(t, res, 3)
   133  	assert.Contains(t, []string{res[0].Error(), res[1].Error(), res[2].Error()}, "") // This is the "successful ack"
   134  	assert.Contains(t, []string{res[0].Error(), res[1].Error(), res[2].Error()}, "Failed processing message because reasons")
   135  	assert.Contains(t, []string{res[0].Error(), res[1].Error(), res[2].Error()}, "timed out")
   136  	assert.Contains(t, res.String(), "\"Failed processing message because reasons\":1")
   137  	assert.Contains(t, res.String(), "\"timed out\":1")
   138  	assert.Contains(t, res.String(), "\"successes\":1")
   139  	assert.Equal(t, 2, res.NackCount())
   140  	assert.Equal(t, 1, res.AckCount())
   141  
   142  	// Send a message to no one
   143  	res = comm1.SendWithAck(createGossipMsg(), time.Second*3, 1)
   144  	assert.Len(t, res, 0)
   145  
   146  	// Send a message while stopping
   147  	comm1.Stop()
   148  	res = comm1.SendWithAck(createGossipMsg(), time.Second*3, 1, remotePeer(port2), remotePeer(port3), remotePeer(port4))
   149  	assert.Len(t, res, 3)
   150  	assert.Contains(t, res[0].Error(), "comm is stopping")
   151  	assert.Contains(t, res[1].Error(), "comm is stopping")
   152  	assert.Contains(t, res[2].Error(), "comm is stopping")
   153  }