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 }