github.com/darrenli6/fabric-sdk-example@v0.0.0-20220109053535-94b13b56df8c/core/deliverservice/deliveryclient_test.go (about)

     1  /*
     2  Copyright IBM Corp. 2017 All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8                   http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package deliverclient
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"fmt"
    23  	"runtime"
    24  	"sync"
    25  	"sync/atomic"
    26  	"testing"
    27  	"time"
    28  
    29  	"github.com/hyperledger/fabric/core/deliverservice/blocksprovider"
    30  	"github.com/hyperledger/fabric/core/deliverservice/mocks"
    31  	"github.com/hyperledger/fabric/gossip/api"
    32  	"github.com/hyperledger/fabric/gossip/common"
    33  	"github.com/hyperledger/fabric/msp/mgmt/testtools"
    34  	"github.com/hyperledger/fabric/protos/orderer"
    35  	"github.com/stretchr/testify/assert"
    36  	"google.golang.org/grpc"
    37  )
    38  
    39  func init() {
    40  	msptesttools.LoadMSPSetupForTesting()
    41  }
    42  
    43  const (
    44  	goRoutineTestWaitTimeout = time.Second * 15
    45  )
    46  
    47  var (
    48  	lock = sync.Mutex{}
    49  )
    50  
    51  type mockBlocksDelivererFactory struct {
    52  	mockCreate func() (blocksprovider.BlocksDeliverer, error)
    53  }
    54  
    55  func (mock *mockBlocksDelivererFactory) Create() (blocksprovider.BlocksDeliverer, error) {
    56  	return mock.mockCreate()
    57  }
    58  
    59  type mockMCS struct {
    60  }
    61  
    62  func (*mockMCS) GetPKIidOfCert(peerIdentity api.PeerIdentityType) common.PKIidType {
    63  	return common.PKIidType("pkiID")
    64  }
    65  
    66  func (*mockMCS) VerifyBlock(chainID common.ChainID, seqNum uint64, signedBlock []byte) error {
    67  	return nil
    68  }
    69  
    70  func (*mockMCS) Sign(msg []byte) ([]byte, error) {
    71  	return msg, nil
    72  }
    73  
    74  func (*mockMCS) Verify(peerIdentity api.PeerIdentityType, signature, message []byte) error {
    75  	return nil
    76  }
    77  
    78  func (*mockMCS) VerifyByChannel(chainID common.ChainID, peerIdentity api.PeerIdentityType, signature, message []byte) error {
    79  	return nil
    80  }
    81  
    82  func (*mockMCS) ValidateIdentity(peerIdentity api.PeerIdentityType) error {
    83  	return nil
    84  }
    85  
    86  func TestNewDeliverService(t *testing.T) {
    87  	defer ensureNoGoroutineLeak(t)()
    88  	gossipServiceAdapter := &mocks.MockGossipServiceAdapter{GossipBlockDisseminations: make(chan uint64, 1)}
    89  	factory := &struct{ mockBlocksDelivererFactory }{}
    90  
    91  	blocksDeliverer := &mocks.MockBlocksDeliverer{}
    92  	blocksDeliverer.MockRecv = mocks.MockRecv
    93  
    94  	factory.mockCreate = func() (blocksprovider.BlocksDeliverer, error) {
    95  		return blocksDeliverer, nil
    96  	}
    97  	abcf := func(*grpc.ClientConn) orderer.AtomicBroadcastClient {
    98  		return &mocks.MockAtomicBroadcastClient{blocksDeliverer}
    99  	}
   100  
   101  	connFactory := func(_ string) func(string) (*grpc.ClientConn, error) {
   102  		return func(endpoint string) (*grpc.ClientConn, error) {
   103  			lock.Lock()
   104  			defer lock.Unlock()
   105  			return newConnection(), nil
   106  		}
   107  	}
   108  	service, err := NewDeliverService(&Config{
   109  		Endpoints:   []string{"a"},
   110  		Gossip:      gossipServiceAdapter,
   111  		CryptoSvc:   &mockMCS{},
   112  		ABCFactory:  abcf,
   113  		ConnFactory: connFactory,
   114  	})
   115  	assert.NoError(t, err)
   116  	assert.NoError(t, service.StartDeliverForChannel("TEST_CHAINID", &mocks.MockLedgerInfo{0}, func() {}))
   117  
   118  	// Lets start deliver twice
   119  	assert.Error(t, service.StartDeliverForChannel("TEST_CHAINID", &mocks.MockLedgerInfo{0}, func() {}), "can't start delivery")
   120  	// Lets stop deliver that not started
   121  	assert.Error(t, service.StopDeliverForChannel("TEST_CHAINID2"), "can't stop delivery")
   122  
   123  	// Let it try to simulate a few recv -> gossip rounds
   124  	time.Sleep(time.Second)
   125  	assert.NoError(t, service.StopDeliverForChannel("TEST_CHAINID"))
   126  	time.Sleep(time.Duration(10) * time.Millisecond)
   127  	// Make sure to stop all blocks providers
   128  	service.Stop()
   129  	time.Sleep(time.Duration(500) * time.Millisecond)
   130  	assert.Equal(t, 0, connNumber)
   131  	assertBlockDissemination(0, gossipServiceAdapter.GossipBlockDisseminations, t)
   132  	assert.Equal(t, atomic.LoadInt32(&blocksDeliverer.RecvCnt), atomic.LoadInt32(&gossipServiceAdapter.AddPayloadsCnt))
   133  	assert.Error(t, service.StartDeliverForChannel("TEST_CHAINID", &mocks.MockLedgerInfo{0}, func() {}), "Delivery service is stopping")
   134  	assert.Error(t, service.StopDeliverForChannel("TEST_CHAINID"), "Delivery service is stopping")
   135  }
   136  
   137  func TestDeliverServiceRestart(t *testing.T) {
   138  	defer ensureNoGoroutineLeak(t)()
   139  	// Scenario: bring up ordering service instance, then shut it down, and then resurrect it.
   140  	// Client is expected to reconnect to it, and to ask for a block sequence that is the next block
   141  	// after the last block it got from the previous incarnation of the ordering service.
   142  
   143  	os := mocks.NewOrderer(5611, t)
   144  
   145  	time.Sleep(time.Second)
   146  	gossipServiceAdapter := &mocks.MockGossipServiceAdapter{GossipBlockDisseminations: make(chan uint64)}
   147  
   148  	service, err := NewDeliverService(&Config{
   149  		Endpoints:   []string{"localhost:5611"},
   150  		Gossip:      gossipServiceAdapter,
   151  		CryptoSvc:   &mockMCS{},
   152  		ABCFactory:  DefaultABCFactory,
   153  		ConnFactory: DefaultConnectionFactory,
   154  	})
   155  	assert.NoError(t, err)
   156  
   157  	li := &mocks.MockLedgerInfo{Height: uint64(100)}
   158  	os.SetNextExpectedSeek(uint64(100))
   159  
   160  	err = service.StartDeliverForChannel("TEST_CHAINID", li, func() {})
   161  	assert.NoError(t, err, "can't start delivery")
   162  	// Check that delivery client requests blocks in order
   163  	go os.SendBlock(uint64(100))
   164  	assertBlockDissemination(100, gossipServiceAdapter.GossipBlockDisseminations, t)
   165  	go os.SendBlock(uint64(101))
   166  	assertBlockDissemination(101, gossipServiceAdapter.GossipBlockDisseminations, t)
   167  	go os.SendBlock(uint64(102))
   168  	assertBlockDissemination(102, gossipServiceAdapter.GossipBlockDisseminations, t)
   169  	os.Shutdown()
   170  	time.Sleep(time.Second * 3)
   171  	os = mocks.NewOrderer(5611, t)
   172  	li.Height = 103
   173  	os.SetNextExpectedSeek(uint64(103))
   174  	go os.SendBlock(uint64(103))
   175  	assertBlockDissemination(103, gossipServiceAdapter.GossipBlockDisseminations, t)
   176  	service.Stop()
   177  	os.Shutdown()
   178  }
   179  
   180  func TestDeliverServiceFailover(t *testing.T) {
   181  	defer ensureNoGoroutineLeak(t)()
   182  	// Scenario: bring up 2 ordering service instances,
   183  	// and shut down the instance that the client has connected to.
   184  	// Client is expected to connect to the other instance, and to ask for a block sequence that is the next block
   185  	// after the last block it got from the ordering service that was shut down.
   186  	// Then, shut down the other node, and bring back the first (that was shut down first).
   187  
   188  	os1 := mocks.NewOrderer(5612, t)
   189  	os2 := mocks.NewOrderer(5613, t)
   190  
   191  	time.Sleep(time.Second)
   192  	gossipServiceAdapter := &mocks.MockGossipServiceAdapter{GossipBlockDisseminations: make(chan uint64)}
   193  
   194  	service, err := NewDeliverService(&Config{
   195  		Endpoints:   []string{"localhost:5612", "localhost:5613"},
   196  		Gossip:      gossipServiceAdapter,
   197  		CryptoSvc:   &mockMCS{},
   198  		ABCFactory:  DefaultABCFactory,
   199  		ConnFactory: DefaultConnectionFactory,
   200  	})
   201  	assert.NoError(t, err)
   202  	li := &mocks.MockLedgerInfo{Height: uint64(100)}
   203  	os1.SetNextExpectedSeek(uint64(100))
   204  	os2.SetNextExpectedSeek(uint64(100))
   205  
   206  	err = service.StartDeliverForChannel("TEST_CHAINID", li, func() {})
   207  	assert.NoError(t, err, "can't start delivery")
   208  	// We need to discover to which instance the client connected to
   209  	go os1.SendBlock(uint64(100))
   210  	instance2fail := os1
   211  	reincarnatedNodePort := 5612
   212  	instance2failSecond := os2
   213  	select {
   214  	case seq := <-gossipServiceAdapter.GossipBlockDisseminations:
   215  		assert.Equal(t, uint64(100), seq)
   216  	case <-time.After(time.Second * 2):
   217  		// Shutdown first instance and replace it, in order to make an instance
   218  		// with an empty sending channel
   219  		os1.Shutdown()
   220  		time.Sleep(time.Second)
   221  		os1 = mocks.NewOrderer(5612, t)
   222  		instance2fail = os2
   223  		instance2failSecond = os1
   224  		reincarnatedNodePort = 5613
   225  		// Ensure we really are connected to the second instance,
   226  		// by making it send a block
   227  		go os2.SendBlock(uint64(100))
   228  		assertBlockDissemination(100, gossipServiceAdapter.GossipBlockDisseminations, t)
   229  	}
   230  
   231  	atomic.StoreUint64(&li.Height, uint64(101))
   232  	os1.SetNextExpectedSeek(uint64(101))
   233  	os2.SetNextExpectedSeek(uint64(101))
   234  	// Fail the orderer node the client is connected to
   235  	instance2fail.Shutdown()
   236  	time.Sleep(time.Second)
   237  	// Ensure the client asks blocks from the other ordering service node
   238  	go instance2failSecond.SendBlock(uint64(101))
   239  	assertBlockDissemination(101, gossipServiceAdapter.GossipBlockDisseminations, t)
   240  	atomic.StoreUint64(&li.Height, uint64(102))
   241  	// Now shut down the 2nd node
   242  	instance2failSecond.Shutdown()
   243  	time.Sleep(time.Second * 1)
   244  	// Bring up the first one
   245  	os := mocks.NewOrderer(reincarnatedNodePort, t)
   246  	os.SetNextExpectedSeek(102)
   247  	go os.SendBlock(uint64(102))
   248  	assertBlockDissemination(102, gossipServiceAdapter.GossipBlockDisseminations, t)
   249  	os.Shutdown()
   250  	service.Stop()
   251  }
   252  
   253  func TestDeliverServiceServiceUnavailable(t *testing.T) {
   254  	orgMaxRetryDelay := blocksprovider.MaxRetryDelay
   255  	blocksprovider.MaxRetryDelay = time.Millisecond * 200
   256  	defer func() { blocksprovider.MaxRetryDelay = orgMaxRetryDelay }()
   257  	defer ensureNoGoroutineLeak(t)()
   258  	// Scenario: bring up 2 ordering service instances,
   259  	// Make the instance the client connects to fail after a delivery of a block and send SERVICE_UNAVAILABLE
   260  	// whenever subsequent seeks are sent to it.
   261  	// The client is expected to connect to the other instance, and to ask for a block sequence that is the next block
   262  	// after the last block it got from the first ordering service node.
   263  
   264  	os1 := mocks.NewOrderer(5615, t)
   265  	os2 := mocks.NewOrderer(5616, t)
   266  
   267  	gossipServiceAdapter := &mocks.MockGossipServiceAdapter{GossipBlockDisseminations: make(chan uint64)}
   268  
   269  	service, err := NewDeliverService(&Config{
   270  		Endpoints:   []string{"localhost:5615", "localhost:5616"},
   271  		Gossip:      gossipServiceAdapter,
   272  		CryptoSvc:   &mockMCS{},
   273  		ABCFactory:  DefaultABCFactory,
   274  		ConnFactory: DefaultConnectionFactory,
   275  	})
   276  	assert.NoError(t, err)
   277  	li := &mocks.MockLedgerInfo{Height: 100}
   278  	os1.SetNextExpectedSeek(li.Height)
   279  	os2.SetNextExpectedSeek(li.Height)
   280  
   281  	err = service.StartDeliverForChannel("TEST_CHAINID", li, func() {})
   282  	assert.NoError(t, err, "can't start delivery")
   283  
   284  	waitForConnectionToSomeOSN := func() (*mocks.Orderer, *mocks.Orderer) {
   285  		for {
   286  			if os1.ConnCount() > 0 {
   287  				return os1, os2
   288  			}
   289  			if os2.ConnCount() > 0 {
   290  				return os2, os1
   291  			}
   292  			time.Sleep(time.Millisecond * 100)
   293  		}
   294  	}
   295  
   296  	activeInstance, backupInstance := waitForConnectionToSomeOSN()
   297  	assert.NotNil(t, activeInstance)
   298  	assert.NotNil(t, backupInstance)
   299  	// Check that delivery client get connected to active
   300  	assert.Equal(t, activeInstance.ConnCount(), 1)
   301  	// and not connected to backup instances
   302  	assert.Equal(t, backupInstance.ConnCount(), 0)
   303  
   304  	// Send first block
   305  	go activeInstance.SendBlock(li.Height)
   306  
   307  	assertBlockDissemination(li.Height, gossipServiceAdapter.GossipBlockDisseminations, t)
   308  	li.Height++
   309  
   310  	// Backup instance should expect a seek of 101 since we got 100
   311  	backupInstance.SetNextExpectedSeek(li.Height)
   312  	// Have backup instance prepare to send a block
   313  	backupInstance.SendBlock(li.Height)
   314  
   315  	// Fail instance delivery client connected to
   316  	activeInstance.Fail()
   317  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
   318  	defer cancel()
   319  
   320  	wg := sync.WaitGroup{}
   321  	wg.Add(1)
   322  
   323  	go func(ctx context.Context) {
   324  		defer wg.Done()
   325  		for {
   326  			select {
   327  			case <-time.After(time.Millisecond * 100):
   328  				if backupInstance.ConnCount() > 0 {
   329  					return
   330  				}
   331  			case <-ctx.Done():
   332  				return
   333  			}
   334  		}
   335  	}(ctx)
   336  
   337  	wg.Wait()
   338  	assert.NoError(t, ctx.Err(), "Delivery client has not failed over to alive ordering service")
   339  	// Check that delivery client was indeed connected
   340  	assert.Equal(t, backupInstance.ConnCount(), 1)
   341  	// Ensure the client asks blocks from the other ordering service node
   342  	assertBlockDissemination(li.Height, gossipServiceAdapter.GossipBlockDisseminations, t)
   343  
   344  	// Cleanup
   345  	os1.Shutdown()
   346  	os2.Shutdown()
   347  	service.Stop()
   348  }
   349  
   350  func TestDeliverServiceShutdown(t *testing.T) {
   351  	defer ensureNoGoroutineLeak(t)()
   352  	// Scenario: Launch an ordering service node and let the client pull some blocks.
   353  	// Then, shut down the client, and check that it is no longer fetching blocks.
   354  	os := mocks.NewOrderer(5614, t)
   355  
   356  	time.Sleep(time.Second)
   357  	gossipServiceAdapter := &mocks.MockGossipServiceAdapter{GossipBlockDisseminations: make(chan uint64)}
   358  
   359  	service, err := NewDeliverService(&Config{
   360  		Endpoints:   []string{"localhost:5614"},
   361  		Gossip:      gossipServiceAdapter,
   362  		CryptoSvc:   &mockMCS{},
   363  		ABCFactory:  DefaultABCFactory,
   364  		ConnFactory: DefaultConnectionFactory,
   365  	})
   366  	assert.NoError(t, err)
   367  
   368  	li := &mocks.MockLedgerInfo{Height: uint64(100)}
   369  	os.SetNextExpectedSeek(uint64(100))
   370  	err = service.StartDeliverForChannel("TEST_CHAINID", li, func() {})
   371  	assert.NoError(t, err, "can't start delivery")
   372  
   373  	// Check that delivery service requests blocks in order
   374  	go os.SendBlock(uint64(100))
   375  	assertBlockDissemination(100, gossipServiceAdapter.GossipBlockDisseminations, t)
   376  	go os.SendBlock(uint64(101))
   377  	assertBlockDissemination(101, gossipServiceAdapter.GossipBlockDisseminations, t)
   378  	atomic.StoreUint64(&li.Height, uint64(102))
   379  	os.SetNextExpectedSeek(uint64(102))
   380  	// Now stop the delivery service and make sure we don't disseminate a block
   381  	service.Stop()
   382  	go os.SendBlock(uint64(102))
   383  	select {
   384  	case <-gossipServiceAdapter.GossipBlockDisseminations:
   385  		assert.Fail(t, "Disseminated a block after shutting down the delivery service")
   386  	case <-time.After(time.Second * 2):
   387  	}
   388  	os.Shutdown()
   389  	time.Sleep(time.Second)
   390  }
   391  
   392  func TestDeliverServiceShutdownRespawn(t *testing.T) {
   393  	// Scenario: Launch an ordering service node and let the client pull some blocks.
   394  	// Then, wait a few seconds, and don't send any blocks.
   395  	// Afterwards - start a new instance and shut down the old instance.
   396  	SetReconnectTotalTimeThreshold(time.Second)
   397  	defer func() {
   398  		SetReconnectTotalTimeThreshold(time.Second * 60 * 5)
   399  	}()
   400  	defer ensureNoGoroutineLeak(t)()
   401  
   402  	osn1 := mocks.NewOrderer(5614, t)
   403  
   404  	time.Sleep(time.Second)
   405  	gossipServiceAdapter := &mocks.MockGossipServiceAdapter{GossipBlockDisseminations: make(chan uint64)}
   406  
   407  	service, err := NewDeliverService(&Config{
   408  		Endpoints:   []string{"localhost:5614", "localhost:5615"},
   409  		Gossip:      gossipServiceAdapter,
   410  		CryptoSvc:   &mockMCS{},
   411  		ABCFactory:  DefaultABCFactory,
   412  		ConnFactory: DefaultConnectionFactory,
   413  	})
   414  	assert.NoError(t, err)
   415  
   416  	li := &mocks.MockLedgerInfo{Height: uint64(100)}
   417  	osn1.SetNextExpectedSeek(uint64(100))
   418  	err = service.StartDeliverForChannel("TEST_CHAINID", li, func() {})
   419  	assert.NoError(t, err, "can't start delivery")
   420  
   421  	// Check that delivery service requests blocks in order
   422  	go osn1.SendBlock(uint64(100))
   423  	assertBlockDissemination(100, gossipServiceAdapter.GossipBlockDisseminations, t)
   424  	go osn1.SendBlock(uint64(101))
   425  	assertBlockDissemination(101, gossipServiceAdapter.GossipBlockDisseminations, t)
   426  	atomic.StoreUint64(&li.Height, uint64(102))
   427  	// Now wait for a few seconds
   428  	time.Sleep(time.Second * 2)
   429  	// Now start the new instance
   430  	osn2 := mocks.NewOrderer(5615, t)
   431  	// Now stop the old instance
   432  	osn1.Shutdown()
   433  	// Send a block from osn2
   434  	osn2.SetNextExpectedSeek(uint64(102))
   435  	go osn2.SendBlock(uint64(102))
   436  	// Ensure it is received
   437  	assertBlockDissemination(102, gossipServiceAdapter.GossipBlockDisseminations, t)
   438  	service.Stop()
   439  	osn2.Shutdown()
   440  }
   441  
   442  func TestDeliverServiceBadConfig(t *testing.T) {
   443  	// Empty endpoints
   444  	service, err := NewDeliverService(&Config{
   445  		Endpoints:   []string{},
   446  		Gossip:      &mocks.MockGossipServiceAdapter{},
   447  		CryptoSvc:   &mockMCS{},
   448  		ABCFactory:  DefaultABCFactory,
   449  		ConnFactory: DefaultConnectionFactory,
   450  	})
   451  	assert.Error(t, err)
   452  	assert.Nil(t, service)
   453  
   454  	// Nil gossip adapter
   455  	service, err = NewDeliverService(&Config{
   456  		Endpoints:   []string{"a"},
   457  		Gossip:      nil,
   458  		CryptoSvc:   &mockMCS{},
   459  		ABCFactory:  DefaultABCFactory,
   460  		ConnFactory: DefaultConnectionFactory,
   461  	})
   462  	assert.Error(t, err)
   463  	assert.Nil(t, service)
   464  
   465  	// Nil crypto service
   466  	service, err = NewDeliverService(&Config{
   467  		Endpoints:   []string{"a"},
   468  		Gossip:      &mocks.MockGossipServiceAdapter{},
   469  		CryptoSvc:   nil,
   470  		ABCFactory:  DefaultABCFactory,
   471  		ConnFactory: DefaultConnectionFactory,
   472  	})
   473  	assert.Error(t, err)
   474  	assert.Nil(t, service)
   475  
   476  	// Nil ABCFactory
   477  	service, err = NewDeliverService(&Config{
   478  		Endpoints:   []string{"a"},
   479  		Gossip:      &mocks.MockGossipServiceAdapter{},
   480  		CryptoSvc:   &mockMCS{},
   481  		ABCFactory:  nil,
   482  		ConnFactory: DefaultConnectionFactory,
   483  	})
   484  	assert.Error(t, err)
   485  	assert.Nil(t, service)
   486  
   487  	// Nil connFactory
   488  	service, err = NewDeliverService(&Config{
   489  		Endpoints:  []string{"a"},
   490  		Gossip:     &mocks.MockGossipServiceAdapter{},
   491  		CryptoSvc:  &mockMCS{},
   492  		ABCFactory: DefaultABCFactory,
   493  	})
   494  	assert.Error(t, err)
   495  	assert.Nil(t, service)
   496  }
   497  
   498  func TestRetryPolicyOverflow(t *testing.T) {
   499  	connFactory := func(channelID string) func(endpoint string) (*grpc.ClientConn, error) {
   500  		return func(_ string) (*grpc.ClientConn, error) {
   501  			return nil, errors.New("")
   502  		}
   503  	}
   504  	client := (&deliverServiceImpl{conf: &Config{ConnFactory: connFactory}}).newClient("TEST", &mocks.MockLedgerInfo{Height: uint64(100)})
   505  	assert.NotNil(t, client.shouldRetry)
   506  	for i := 0; i < 100; i++ {
   507  		retryTime, _ := client.shouldRetry(i, time.Second)
   508  		assert.True(t, retryTime <= time.Hour && retryTime > 0)
   509  	}
   510  }
   511  
   512  func assertBlockDissemination(expectedSeq uint64, ch chan uint64, t *testing.T) {
   513  	select {
   514  	case seq := <-ch:
   515  		assert.Equal(t, expectedSeq, seq)
   516  	case <-time.After(time.Second * 5):
   517  		assert.FailNow(t, fmt.Sprintf("Didn't gossip a new block with seq num %d within a timely manner", expectedSeq))
   518  		t.Fatal()
   519  	}
   520  }
   521  
   522  func ensureNoGoroutineLeak(t *testing.T) func() {
   523  	goroutineCountAtStart := runtime.NumGoroutine()
   524  	return func() {
   525  		start := time.Now()
   526  		timeLimit := start.Add(goRoutineTestWaitTimeout)
   527  		for time.Now().Before(timeLimit) {
   528  			time.Sleep(time.Millisecond * 500)
   529  			if goroutineCountAtStart >= runtime.NumGoroutine() {
   530  				return
   531  			}
   532  		}
   533  		assert.Fail(t, "Some goroutine(s) didn't finish: %s", getStackTrace())
   534  	}
   535  }
   536  
   537  func getStackTrace() string {
   538  	buf := make([]byte, 1<<16)
   539  	runtime.Stack(buf, true)
   540  	return string(buf)
   541  }