github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/gossip/service/integration_test.go (about) 1 /* 2 Copyright hechain. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package service 8 9 import ( 10 "bytes" 11 "sync" 12 "testing" 13 "time" 14 15 "github.com/hechain20/hechain/common/flogging" 16 "github.com/hechain20/hechain/core/deliverservice" 17 "github.com/hechain20/hechain/gossip/api" 18 "github.com/hechain20/hechain/gossip/election" 19 "github.com/hechain20/hechain/gossip/util" 20 "github.com/hechain20/hechain/internal/pkg/comm" 21 "github.com/hechain20/hechain/internal/pkg/peer/blocksprovider" 22 "github.com/hechain20/hechain/internal/pkg/peer/orderers" 23 "github.com/stretchr/testify/require" 24 ) 25 26 type embeddingDeliveryService struct { 27 startOnce sync.Once 28 stopOnce sync.Once 29 deliverservice.DeliverService 30 startSignal sync.WaitGroup 31 stopSignal sync.WaitGroup 32 } 33 34 func newEmbeddingDeliveryService(ds deliverservice.DeliverService) *embeddingDeliveryService { 35 eds := &embeddingDeliveryService{ 36 DeliverService: ds, 37 } 38 eds.startSignal.Add(1) 39 eds.stopSignal.Add(1) 40 return eds 41 } 42 43 func (eds *embeddingDeliveryService) waitForDeliveryServiceActivation() { 44 eds.startSignal.Wait() 45 } 46 47 func (eds *embeddingDeliveryService) waitForDeliveryServiceTermination() { 48 eds.stopSignal.Wait() 49 } 50 51 func (eds *embeddingDeliveryService) StartDeliverForChannel(chainID string, ledgerInfo blocksprovider.LedgerInfo, finalizer func()) error { 52 eds.startOnce.Do(func() { 53 eds.startSignal.Done() 54 }) 55 return eds.DeliverService.StartDeliverForChannel(chainID, ledgerInfo, finalizer) 56 } 57 58 func (eds *embeddingDeliveryService) StopDeliverForChannel(chainID string) error { 59 eds.stopOnce.Do(func() { 60 eds.stopSignal.Done() 61 }) 62 return eds.DeliverService.StopDeliverForChannel(chainID) 63 } 64 65 func (eds *embeddingDeliveryService) Stop() { 66 eds.DeliverService.Stop() 67 } 68 69 type embeddingDeliveryServiceFactory struct { 70 DeliveryServiceFactory 71 } 72 73 func (edsf *embeddingDeliveryServiceFactory) Service(g GossipServiceAdapter, endpoints *orderers.ConnectionSource, mcs api.MessageCryptoService, isStaticLeader bool) deliverservice.DeliverService { 74 ds := edsf.DeliveryServiceFactory.Service(g, endpoints, mcs, false) 75 return newEmbeddingDeliveryService(ds) 76 } 77 78 func TestLeaderYield(t *testing.T) { 79 // Scenario: Spawn 2 peers and wait for the first one to be the leader 80 // There isn't any orderer present so the leader peer won't be able to 81 // connect to the orderer, and should relinquish its leadership after a while. 82 // Make sure the other peer declares itself as the leader soon after. 83 takeOverMaxTimeout := time.Minute 84 // It's enough to make single re-try 85 // There is no ordering service available anyway, hence connection timeout 86 // could be shorter 87 serviceConfig := &ServiceConfig{ 88 UseLeaderElection: true, 89 OrgLeader: false, 90 ElectionStartupGracePeriod: election.DefStartupGracePeriod, 91 // Since we ensuring gossip has stable membership, there is no need for 92 // leader election to wait for stabilization 93 ElectionMembershipSampleInterval: time.Millisecond * 100, 94 ElectionLeaderAliveThreshold: time.Second * 5, 95 // Test case has only two instance + making assertions only after membership view 96 // is stable, hence election duration could be shorter 97 ElectionLeaderElectionDuration: time.Millisecond * 500, 98 } 99 n := 2 100 gossips := startPeers(serviceConfig, n, 0, 1) 101 defer stopPeers(gossips) 102 channelName := "channelA" 103 peerIndexes := []int{0, 1} 104 // Add peers to the channel 105 addPeersToChannel(channelName, gossips, peerIndexes) 106 // Prime the membership view of the peers 107 waitForFullMembershipOrFailNow(t, channelName, gossips, n, time.Second*30, time.Millisecond*100) 108 109 store := newTransientStore(t) 110 defer store.tearDown() 111 112 // Helper function that creates a gossipService instance 113 newGossipService := func(i int) *GossipService { 114 gs := gossips[i].GossipService 115 gs.deliveryFactory = &embeddingDeliveryServiceFactory{&deliveryFactoryImpl{ 116 credentialSupport: comm.NewCredentialSupport(), 117 deliverServiceConfig: &deliverservice.DeliverServiceConfig{ 118 PeerTLSEnabled: false, 119 ReConnectBackoffThreshold: deliverservice.DefaultReConnectBackoffThreshold, 120 ReconnectTotalTimeThreshold: time.Second, 121 ConnectionTimeout: time.Millisecond * 100, 122 }, 123 }} 124 gs.InitializeChannel(channelName, orderers.NewConnectionSource(flogging.MustGetLogger("peer.orderers"), nil), store.Store, Support{ 125 Committer: &mockLedgerInfo{1}, 126 }) 127 return gs 128 } 129 130 // The first leader is determined by the peer with the lower PKIid (lower TCP port in this case). 131 // We set p0 to be the peer with the lower PKIid to ensure it'll be elected as leader before p1 and spare time. 132 pkiID0 := gossips[0].peerIdentity 133 pkiID1 := gossips[1].peerIdentity 134 var firstLeaderIdx, secondLeaderIdx int 135 if bytes.Compare(pkiID0, pkiID1) < 0 { 136 firstLeaderIdx = 0 137 secondLeaderIdx = 1 138 } else { 139 firstLeaderIdx = 1 140 secondLeaderIdx = 0 141 } 142 p0 := newGossipService(firstLeaderIdx) 143 p1 := newGossipService(secondLeaderIdx) 144 145 // Returns index of the leader or -1 if no leader elected 146 getLeader := func() int { 147 p0.lock.RLock() 148 p1.lock.RLock() 149 defer p0.lock.RUnlock() 150 defer p1.lock.RUnlock() 151 152 if p0.leaderElection[channelName].IsLeader() { 153 return 0 154 } 155 if p1.leaderElection[channelName].IsLeader() { 156 return 1 157 } 158 return -1 159 } 160 161 ds0 := p0.deliveryService[channelName].(*embeddingDeliveryService) 162 163 // Wait for p0 to connect to the ordering service 164 ds0.waitForDeliveryServiceActivation() 165 t.Log("p0 started its delivery service") 166 // Ensure it's a leader 167 require.Equal(t, 0, getLeader()) 168 // Wait for p0 to lose its leadership 169 ds0.waitForDeliveryServiceTermination() 170 t.Log("p0 stopped its delivery service") 171 // Ensure p0 is not a leader 172 require.NotEqual(t, 0, getLeader()) 173 // Wait for p1 to take over. It should take over before time reaches timeLimit 174 timeLimit := time.Now().Add(takeOverMaxTimeout) 175 for getLeader() != 1 && time.Now().Before(timeLimit) { 176 time.Sleep(100 * time.Millisecond) 177 } 178 if time.Now().After(timeLimit) && getLeader() != 1 { 179 util.PrintStackTrace() 180 t.Fatalf("p1 hasn't taken over leadership within %v: %d", takeOverMaxTimeout, getLeader()) 181 } 182 t.Log("p1 has taken over leadership") 183 p0.chains[channelName].Stop() 184 p1.chains[channelName].Stop() 185 p0.deliveryService[channelName].Stop() 186 p1.deliveryService[channelName].Stop() 187 }