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