@@ -374,6 +374,81 @@ func TestMsgStoreNotExpire(t *testing.T) {
374374 assert .Len (t , c , 2 )
375375}
376376
377+ func TestLeaveChannel (t * testing.T ) {
378+ // Scenario: Have our peer receive a stateInfo message
379+ // from a peer that has left the channel, and ensure that it skips it
380+ // when returning membership.
381+ // Next, have our own peer leave the channel and ensure:
382+ // 1) It doesn't return any members of the channel when queried
383+ // 2) It doesn't send anymore pull for blocks
384+ // 3) When asked for pull for blocks, it ignores the request
385+ t .Parallel ()
386+
387+ jcm := & joinChanMsg {
388+ members2AnchorPeers : map [string ][]api.AnchorPeer {
389+ "ORG1" : {},
390+ "ORG2" : {},
391+ },
392+ }
393+
394+ cs := & cryptoService {}
395+ cs .On ("VerifyBlock" , mock .Anything ).Return (nil )
396+ adapter := new (gossipAdapterMock )
397+ adapter .On ("Gossip" , mock .Anything )
398+ adapter .On ("DeMultiplex" , mock .Anything )
399+ members := []discovery.NetworkMember {
400+ {PKIid : pkiIDInOrg1 },
401+ {PKIid : pkiIDinOrg2 },
402+ }
403+ var helloPullWG sync.WaitGroup
404+ helloPullWG .Add (1 )
405+ configureAdapter (adapter , members ... )
406+ gc := NewGossipChannel (common .PKIidType ("p0" ), orgInChannelA , cs , channelA , adapter , jcm )
407+ adapter .On ("Send" , mock .Anything , mock .Anything ).Run (func (arguments mock.Arguments ) {
408+ msg := arguments .Get (0 ).(* proto.SignedGossipMessage )
409+ if msg .IsPullMsg () {
410+ helloPullWG .Done ()
411+ assert .False (t , gc .(* gossipChannel ).hasLeftChannel ())
412+ }
413+ })
414+ gc .HandleMessage (& receivedMsg {PKIID : pkiIDInOrg1 , msg : createStateInfoMsg (1 , pkiIDInOrg1 , channelA )})
415+ gc .HandleMessage (& receivedMsg {PKIID : pkiIDinOrg2 , msg : createStateInfoMsg (1 , pkiIDinOrg2 , channelA )})
416+ // Have some peer send a block to us, so we can send some peer a digest when hello is sent to us
417+ gc .HandleMessage (& receivedMsg {msg : createDataMsg (2 , channelA ), PKIID : pkiIDInOrg1 })
418+ assert .Len (t , gc .GetPeers (), 2 )
419+ // Now, have peer in org2 "leave the channel" by publishing is an update
420+ stateInfoMsg := & receivedMsg {PKIID : pkiIDinOrg2 , msg : createStateInfoMsg (0 , pkiIDinOrg2 , channelA )}
421+ stateInfoMsg .GetGossipMessage ().GetStateInfo ().Properties .LeftChannel = true
422+ gc .HandleMessage (stateInfoMsg )
423+ assert .Len (t , gc .GetPeers (), 1 )
424+ // Ensure peer in org1 remained and peer in org2 is skipped
425+ assert .Equal (t , pkiIDInOrg1 , gc .GetPeers ()[0 ].PKIid )
426+ var digestSendTime int32
427+ var DigestSentWg sync.WaitGroup
428+ DigestSentWg .Add (1 )
429+ hello := createHelloMsg (pkiIDInOrg1 )
430+ hello .On ("Respond" , mock .Anything ).Run (func (arguments mock.Arguments ) {
431+ atomic .AddInt32 (& digestSendTime , 1 )
432+ // Ensure we only respond with digest before we leave the channel
433+ assert .Equal (t , int32 (1 ), atomic .LoadInt32 (& digestSendTime ))
434+ DigestSentWg .Done ()
435+ })
436+ // Wait until we send a hello pull message
437+ helloPullWG .Wait ()
438+ go gc .HandleMessage (hello )
439+ DigestSentWg .Wait ()
440+ // Make the peer leave the channel
441+ gc .LeaveChannel ()
442+ // Send another hello. Shouldn't respond
443+ go gc .HandleMessage (hello )
444+ // Ensure it doesn't know now any other peer
445+ assert .Len (t , gc .GetPeers (), 0 )
446+ // Sleep 3 times the pull interval.
447+ // we're not supposed to send a pull during this time.
448+ time .Sleep (conf .PullInterval * 3 )
449+
450+ }
451+
377452func TestChannelPeriodicalPublishStateInfo (t * testing.T ) {
378453 t .Parallel ()
379454 ledgerHeight := 5
0 commit comments