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  }