github.com/Hnampk/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 }