github.com/myafeier/fabric@v1.0.1-0.20170722181825-3a4b1f2bce86/core/deliverservice/client_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  	"crypto/sha256"
    21  	"errors"
    22  	"math"
    23  	"sync"
    24  	"sync/atomic"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/hyperledger/fabric/core/comm"
    29  	"github.com/hyperledger/fabric/core/deliverservice/blocksprovider"
    30  	"github.com/hyperledger/fabric/core/deliverservice/mocks"
    31  	"github.com/hyperledger/fabric/protos/common"
    32  	"github.com/hyperledger/fabric/protos/orderer"
    33  	"github.com/hyperledger/fabric/protos/utils"
    34  	"github.com/stretchr/testify/assert"
    35  	"golang.org/x/net/context"
    36  	"google.golang.org/grpc"
    37  )
    38  
    39  var connNumber = 0
    40  
    41  func newConnection() *grpc.ClientConn {
    42  	connNumber++
    43  	// The balancer is in order to check connection leaks.
    44  	// When grpc.ClientConn.Close() is called, it calls the balancer's Close()
    45  	// method which decrements the connNumber
    46  	cc, _ := grpc.Dial("", grpc.WithInsecure(), grpc.WithBalancer(&balancer{}))
    47  	return cc
    48  }
    49  
    50  type balancer struct {
    51  }
    52  
    53  func (*balancer) Start(target string, config grpc.BalancerConfig) error {
    54  	return nil
    55  }
    56  
    57  func (*balancer) Up(addr grpc.Address) (down func(error)) {
    58  	return func(error) {}
    59  }
    60  
    61  func (*balancer) Get(ctx context.Context, opts grpc.BalancerGetOptions) (addr grpc.Address, put func(), err error) {
    62  	return grpc.Address{}, func() {}, errors.New("")
    63  }
    64  
    65  func (*balancer) Notify() <-chan []grpc.Address {
    66  	return nil
    67  }
    68  
    69  func (*balancer) Close() error {
    70  	connNumber--
    71  	return nil
    72  }
    73  
    74  type blocksDelivererConsumer func(blocksprovider.BlocksDeliverer) error
    75  
    76  var blockDelivererConsumerWithRecv = func(bd blocksprovider.BlocksDeliverer) error {
    77  	_, err := bd.Recv()
    78  	return err
    79  }
    80  
    81  var blockDelivererConsumerWithSend = func(bd blocksprovider.BlocksDeliverer) error {
    82  	return bd.Send(&common.Envelope{})
    83  }
    84  
    85  type abc struct {
    86  	shouldFail bool
    87  	grpc.ClientStream
    88  }
    89  
    90  func (a *abc) Send(*common.Envelope) error {
    91  	if a.shouldFail {
    92  		return errors.New("Failed sending")
    93  	}
    94  	return nil
    95  }
    96  
    97  func (a *abc) Recv() (*orderer.DeliverResponse, error) {
    98  	if a.shouldFail {
    99  		return nil, errors.New("Failed Recv")
   100  	}
   101  	return &orderer.DeliverResponse{}, nil
   102  }
   103  
   104  type abclient struct {
   105  	shouldFail bool
   106  	stream     *abc
   107  }
   108  
   109  func (ac *abclient) Broadcast(ctx context.Context, opts ...grpc.CallOption) (orderer.AtomicBroadcast_BroadcastClient, error) {
   110  	panic("Not implemented")
   111  }
   112  
   113  func (ac *abclient) Deliver(ctx context.Context, opts ...grpc.CallOption) (orderer.AtomicBroadcast_DeliverClient, error) {
   114  	if ac.stream != nil {
   115  		return ac.stream, nil
   116  	}
   117  	if ac.shouldFail {
   118  		return nil, errors.New("Failed creating ABC")
   119  	}
   120  	return &abc{}, nil
   121  }
   122  
   123  type connProducer struct {
   124  	shouldFail      bool
   125  	connAttempts    int
   126  	connTime        time.Duration
   127  	ordererEndpoint string
   128  }
   129  
   130  func (cp *connProducer) realConnection() (*grpc.ClientConn, string, error) {
   131  	cc, err := grpc.Dial(cp.ordererEndpoint, grpc.WithInsecure())
   132  	if err != nil {
   133  		return nil, "", err
   134  	}
   135  	return cc, cp.ordererEndpoint, nil
   136  }
   137  
   138  func (cp *connProducer) NewConnection() (*grpc.ClientConn, string, error) {
   139  	time.Sleep(cp.connTime)
   140  	cp.connAttempts++
   141  	if cp.ordererEndpoint != "" {
   142  		return cp.realConnection()
   143  	}
   144  	if cp.shouldFail {
   145  		return nil, "", errors.New("Failed connecting")
   146  	}
   147  	return newConnection(), "localhost:5611", nil
   148  }
   149  
   150  // UpdateEndpoints updates the endpoints of the ConnectionProducer
   151  // to be the given endpoints
   152  func (cp *connProducer) UpdateEndpoints(endpoints []string) {
   153  	panic("Not implemented")
   154  }
   155  
   156  func TestOrderingServiceConnFailure(t *testing.T) {
   157  	testOrderingServiceConnFailure(t, blockDelivererConsumerWithRecv)
   158  	testOrderingServiceConnFailure(t, blockDelivererConsumerWithSend)
   159  	assert.Equal(t, 0, connNumber)
   160  }
   161  
   162  func testOrderingServiceConnFailure(t *testing.T, bdc blocksDelivererConsumer) {
   163  	// Scenario: Create a broadcast client and call Recv/Send.
   164  	// Connection to the ordering service should be possible only at second attempt
   165  	cp := &connProducer{shouldFail: true}
   166  	clFactory := func(*grpc.ClientConn) orderer.AtomicBroadcastClient {
   167  		return &abclient{}
   168  	}
   169  	setupInvoked := 0
   170  	setup := func(blocksprovider.BlocksDeliverer) error {
   171  		setupInvoked++
   172  		return nil
   173  	}
   174  	backoffStrategy := func(attemptNum int, elapsedTime time.Duration) (time.Duration, bool) {
   175  		// When called with the second attempt (iteration number 1),
   176  		// we should be able to connect to the ordering service.
   177  		// Set connection provider mock shouldFail flag to false
   178  		// to enable next connection attempt to succeed
   179  		if attemptNum == 1 {
   180  			cp.shouldFail = false
   181  		}
   182  
   183  		return time.Duration(0), attemptNum < 2
   184  	}
   185  	bc := NewBroadcastClient(cp, clFactory, setup, backoffStrategy)
   186  	defer bc.Close()
   187  	err := bdc(bc)
   188  	assert.NoError(t, err)
   189  	assert.Equal(t, 2, cp.connAttempts)
   190  	assert.Equal(t, 1, setupInvoked)
   191  }
   192  
   193  func TestOrderingServiceStreamFailure(t *testing.T) {
   194  	testOrderingServiceStreamFailure(t, blockDelivererConsumerWithRecv)
   195  	testOrderingServiceStreamFailure(t, blockDelivererConsumerWithSend)
   196  	assert.Equal(t, 0, connNumber)
   197  }
   198  
   199  func testOrderingServiceStreamFailure(t *testing.T, bdc blocksDelivererConsumer) {
   200  	// Scenario: Create a broadcast client and call Recv/Send.
   201  	// Connection to the ordering service should be possible at first attempt,
   202  	// but the atomic broadcast client creation fails at first attempt
   203  	abcClient := &abclient{shouldFail: true}
   204  	cp := &connProducer{}
   205  	clFactory := func(*grpc.ClientConn) orderer.AtomicBroadcastClient {
   206  		return abcClient
   207  	}
   208  	setupInvoked := 0
   209  	setup := func(blocksprovider.BlocksDeliverer) error {
   210  		setupInvoked++
   211  		return nil
   212  	}
   213  	backoffStrategy := func(attemptNum int, elapsedTime time.Duration) (time.Duration, bool) {
   214  		// When called with the second attempt (iteration number 1),
   215  		// we should be able to finally call Deliver() by the atomic broadcast client
   216  		if attemptNum == 1 {
   217  			abcClient.shouldFail = false
   218  		}
   219  		return time.Duration(0), attemptNum < 2
   220  	}
   221  	bc := NewBroadcastClient(cp, clFactory, setup, backoffStrategy)
   222  	defer bc.Close()
   223  	err := bdc(bc)
   224  	assert.NoError(t, err)
   225  	assert.Equal(t, 2, cp.connAttempts)
   226  	assert.Equal(t, 1, setupInvoked)
   227  }
   228  
   229  func TestOrderingServiceSetupFailure(t *testing.T) {
   230  	testOrderingServiceSetupFailure(t, blockDelivererConsumerWithRecv)
   231  	testOrderingServiceSetupFailure(t, blockDelivererConsumerWithSend)
   232  	assert.Equal(t, 0, connNumber)
   233  }
   234  
   235  func testOrderingServiceSetupFailure(t *testing.T, bdc blocksDelivererConsumer) {
   236  	// Scenario: Create a broadcast client and call Recv/Send.
   237  	// Connection to the ordering service should be possible,
   238  	// the atomic broadcast client creation succeeds, but invoking the setup function
   239  	// fails at the first attempt and succeeds at the second one.
   240  	cp := &connProducer{}
   241  	clFactory := func(*grpc.ClientConn) orderer.AtomicBroadcastClient {
   242  		return &abclient{}
   243  	}
   244  	setupInvoked := 0
   245  	setup := func(blocksprovider.BlocksDeliverer) error {
   246  		setupInvoked++
   247  		if setupInvoked == 1 {
   248  			return errors.New("Setup failed")
   249  		}
   250  		return nil
   251  	}
   252  	backoffStrategy := func(attemptNum int, elapsedTime time.Duration) (time.Duration, bool) {
   253  		return time.Duration(0), true
   254  	}
   255  	bc := NewBroadcastClient(cp, clFactory, setup, backoffStrategy)
   256  	defer bc.Close()
   257  	err := bdc(bc)
   258  	assert.NoError(t, err)
   259  	assert.Equal(t, 2, cp.connAttempts)
   260  	assert.Equal(t, 2, setupInvoked)
   261  }
   262  
   263  func TestOrderingServiceFirstOperationFailure(t *testing.T) {
   264  	testOrderingServiceFirstOperationFailure(t, blockDelivererConsumerWithRecv)
   265  	testOrderingServiceFirstOperationFailure(t, blockDelivererConsumerWithSend)
   266  	assert.Equal(t, 0, connNumber)
   267  }
   268  
   269  func testOrderingServiceFirstOperationFailure(t *testing.T, bdc blocksDelivererConsumer) {
   270  	// Scenario: Creation and connection to the ordering service succeeded
   271  	// but the first Recv/Send failed.
   272  	// The client should reconnect to the ordering service
   273  	cp := &connProducer{}
   274  	abStream := &abc{shouldFail: true}
   275  	abcClient := &abclient{stream: abStream}
   276  	clFactory := func(*grpc.ClientConn) orderer.AtomicBroadcastClient {
   277  		return abcClient
   278  	}
   279  
   280  	setupInvoked := 0
   281  	setup := func(blocksprovider.BlocksDeliverer) error {
   282  		// Fix stream success logic at 2nd attempt
   283  		if setupInvoked == 1 {
   284  			abStream.shouldFail = false
   285  		}
   286  		setupInvoked++
   287  		return nil
   288  	}
   289  	backoffStrategy := func(attemptNum int, elapsedTime time.Duration) (time.Duration, bool) {
   290  		return time.Duration(0), true
   291  	}
   292  	bc := NewBroadcastClient(cp, clFactory, setup, backoffStrategy)
   293  	defer bc.Close()
   294  	err := bdc(bc)
   295  	assert.NoError(t, err)
   296  	assert.Equal(t, 2, setupInvoked)
   297  	assert.Equal(t, cp.connAttempts, 2)
   298  }
   299  
   300  func TestOrderingServiceCrashAndRecover(t *testing.T) {
   301  	testOrderingServiceCrashAndRecover(t, blockDelivererConsumerWithRecv)
   302  	testOrderingServiceCrashAndRecover(t, blockDelivererConsumerWithSend)
   303  	assert.Equal(t, 0, connNumber)
   304  }
   305  
   306  func testOrderingServiceCrashAndRecover(t *testing.T, bdc blocksDelivererConsumer) {
   307  	// Scenario: The ordering service is OK at first usage of Recv/Send,
   308  	// but subsequent calls fails because of connection error.
   309  	// A reconnect is needed and only then Recv/Send should succeed
   310  	cp := &connProducer{}
   311  	abStream := &abc{}
   312  	abcClient := &abclient{stream: abStream}
   313  	clFactory := func(*grpc.ClientConn) orderer.AtomicBroadcastClient {
   314  		return abcClient
   315  	}
   316  
   317  	setupInvoked := 0
   318  	setup := func(blocksprovider.BlocksDeliverer) error {
   319  		// Fix stream success logic at 2nd attempt
   320  		if setupInvoked == 1 {
   321  			abStream.shouldFail = false
   322  		}
   323  		setupInvoked++
   324  		return nil
   325  	}
   326  	backoffStrategy := func(attemptNum int, elapsedTime time.Duration) (time.Duration, bool) {
   327  		return time.Duration(0), true
   328  	}
   329  	bc := NewBroadcastClient(cp, clFactory, setup, backoffStrategy)
   330  	defer bc.Close()
   331  	err := bdc(bc)
   332  	assert.NoError(t, err)
   333  	// Now fail the subsequent Recv/Send
   334  	abStream.shouldFail = true
   335  	err = bdc(bc)
   336  	assert.NoError(t, err)
   337  	assert.Equal(t, 2, cp.connAttempts)
   338  	assert.Equal(t, 2, setupInvoked)
   339  }
   340  
   341  func TestOrderingServicePermanentCrash(t *testing.T) {
   342  	testOrderingServicePermanentCrash(t, blockDelivererConsumerWithRecv)
   343  	testOrderingServicePermanentCrash(t, blockDelivererConsumerWithSend)
   344  	assert.Equal(t, 0, connNumber)
   345  }
   346  
   347  func testOrderingServicePermanentCrash(t *testing.T, bdc blocksDelivererConsumer) {
   348  	// Scenario: The ordering service is OK at first usage of Recv/Send,
   349  	// but subsequent calls fail because it crashes.
   350  	// The client should give up after 10 attempts in the second reconnect
   351  	cp := &connProducer{}
   352  	abStream := &abc{}
   353  	abcClient := &abclient{stream: abStream}
   354  	clFactory := func(*grpc.ClientConn) orderer.AtomicBroadcastClient {
   355  		return abcClient
   356  	}
   357  
   358  	setupInvoked := 0
   359  	setup := func(blocksprovider.BlocksDeliverer) error {
   360  		setupInvoked++
   361  		return nil
   362  	}
   363  	backoffStrategy := func(attemptNum int, elapsedTime time.Duration) (time.Duration, bool) {
   364  		return time.Duration(0), attemptNum < 10
   365  	}
   366  	bc := NewBroadcastClient(cp, clFactory, setup, backoffStrategy)
   367  	defer bc.Close()
   368  	err := bdc(bc)
   369  	assert.NoError(t, err)
   370  	// Now fail the subsequent Recv/Send
   371  	abStream.shouldFail = true
   372  	cp.shouldFail = true
   373  	err = bdc(bc)
   374  	assert.Error(t, err)
   375  	assert.Equal(t, 10, cp.connAttempts)
   376  	assert.Equal(t, 1, setupInvoked)
   377  }
   378  
   379  func TestLimitedConnAttempts(t *testing.T) {
   380  	testLimitedConnAttempts(t, blockDelivererConsumerWithRecv)
   381  	testLimitedConnAttempts(t, blockDelivererConsumerWithSend)
   382  	assert.Equal(t, 0, connNumber)
   383  }
   384  
   385  func testLimitedConnAttempts(t *testing.T, bdc blocksDelivererConsumer) {
   386  	// Scenario: The ordering service isn't available, and the backoff strategy
   387  	// specifies an upper bound of 10 connection attempts
   388  	cp := &connProducer{shouldFail: true}
   389  	clFactory := func(*grpc.ClientConn) orderer.AtomicBroadcastClient {
   390  		return &abclient{}
   391  	}
   392  	setupInvoked := 0
   393  	setup := func(blocksprovider.BlocksDeliverer) error {
   394  		setupInvoked++
   395  		return nil
   396  	}
   397  	backoffStrategy := func(attemptNum int, elapsedTime time.Duration) (time.Duration, bool) {
   398  		return time.Duration(0), attemptNum < 10
   399  	}
   400  	bc := NewBroadcastClient(cp, clFactory, setup, backoffStrategy)
   401  	defer bc.Close()
   402  	err := bdc(bc)
   403  	assert.Error(t, err)
   404  	assert.Equal(t, 10, cp.connAttempts)
   405  	assert.Equal(t, 0, setupInvoked)
   406  }
   407  
   408  func TestLimitedTotalConnTimeRcv(t *testing.T) {
   409  	testLimitedTotalConnTime(t, blockDelivererConsumerWithRecv)
   410  	assert.Equal(t, 0, connNumber)
   411  }
   412  
   413  func TestLimitedTotalConnTimeSnd(t *testing.T) {
   414  	testLimitedTotalConnTime(t, blockDelivererConsumerWithSend)
   415  	assert.Equal(t, 0, connNumber)
   416  }
   417  
   418  func testLimitedTotalConnTime(t *testing.T, bdc blocksDelivererConsumer) {
   419  	// Scenario: The ordering service isn't available, and the backoff strategy
   420  	// specifies an upper bound of 1 second
   421  	// The first attempt fails, and the second attempt doesn't take place
   422  	// becuse the creation of connection takes 1.5 seconds.
   423  	cp := &connProducer{shouldFail: true, connTime: 1500 * time.Millisecond}
   424  	clFactory := func(*grpc.ClientConn) orderer.AtomicBroadcastClient {
   425  		return &abclient{}
   426  	}
   427  	setupInvoked := 0
   428  	setup := func(blocksprovider.BlocksDeliverer) error {
   429  		setupInvoked++
   430  		return nil
   431  	}
   432  	backoffStrategy := func(attemptNum int, elapsedTime time.Duration) (time.Duration, bool) {
   433  		return 0, elapsedTime.Nanoseconds() < time.Second.Nanoseconds()
   434  	}
   435  	bc := NewBroadcastClient(cp, clFactory, setup, backoffStrategy)
   436  	defer bc.Close()
   437  	err := bdc(bc)
   438  	assert.Error(t, err)
   439  	assert.Equal(t, 1, cp.connAttempts)
   440  	assert.Equal(t, 0, setupInvoked)
   441  }
   442  
   443  func TestGreenPath(t *testing.T) {
   444  	testGreenPath(t, blockDelivererConsumerWithRecv)
   445  	testGreenPath(t, blockDelivererConsumerWithSend)
   446  	assert.Equal(t, 0, connNumber)
   447  }
   448  
   449  func testGreenPath(t *testing.T, bdc blocksDelivererConsumer) {
   450  	// Scenario: Everything succeeds
   451  	cp := &connProducer{}
   452  	abcClient := &abclient{}
   453  	clFactory := func(*grpc.ClientConn) orderer.AtomicBroadcastClient {
   454  		return abcClient
   455  	}
   456  
   457  	setupInvoked := 0
   458  	setup := func(blocksprovider.BlocksDeliverer) error {
   459  		setupInvoked++
   460  		return nil
   461  	}
   462  	backoffStrategy := func(attemptNum int, elapsedTime time.Duration) (time.Duration, bool) {
   463  		return time.Duration(0), attemptNum < 1
   464  	}
   465  	bc := NewBroadcastClient(cp, clFactory, setup, backoffStrategy)
   466  	defer bc.Close()
   467  	err := bdc(bc)
   468  	assert.NoError(t, err)
   469  	assert.Equal(t, 1, cp.connAttempts)
   470  	assert.Equal(t, 1, setupInvoked)
   471  }
   472  
   473  func TestCloseWhileRecv(t *testing.T) {
   474  	// Scenario: Recv is being called and after a while,
   475  	// the connection is closed.
   476  	// The Recv should return immediately in such a case
   477  	fakeOrderer := mocks.NewOrderer(5611, t)
   478  	time.Sleep(time.Second)
   479  	defer fakeOrderer.Shutdown()
   480  	cp := &connProducer{ordererEndpoint: "localhost:5611"}
   481  	clFactory := func(conn *grpc.ClientConn) orderer.AtomicBroadcastClient {
   482  		return orderer.NewAtomicBroadcastClient(conn)
   483  	}
   484  
   485  	setup := func(blocksprovider.BlocksDeliverer) error {
   486  		return nil
   487  	}
   488  	backoffStrategy := func(attemptNum int, elapsedTime time.Duration) (time.Duration, bool) {
   489  		return 0, true
   490  	}
   491  	bc := NewBroadcastClient(cp, clFactory, setup, backoffStrategy)
   492  	var flag int32
   493  	go func() {
   494  		for fakeOrderer.ConnCount() == 0 {
   495  			time.Sleep(time.Second)
   496  		}
   497  		atomic.StoreInt32(&flag, int32(1))
   498  		bc.Close()
   499  		bc.Close() // Try to close a second time
   500  	}()
   501  	resp, err := bc.Recv()
   502  	// Ensure we returned because bc.Close() was called and not because some other reason
   503  	assert.Equal(t, int32(1), atomic.LoadInt32(&flag), "Recv returned before bc.Close() was called")
   504  	assert.Nil(t, resp)
   505  	assert.Error(t, err)
   506  	assert.Contains(t, "Client is closing", err.Error())
   507  }
   508  
   509  func TestCloseWhileSleep(t *testing.T) {
   510  	testCloseWhileSleep(t, blockDelivererConsumerWithRecv)
   511  	testCloseWhileSleep(t, blockDelivererConsumerWithSend)
   512  	assert.Equal(t, 0, connNumber)
   513  }
   514  
   515  func testCloseWhileSleep(t *testing.T, bdc blocksDelivererConsumer) {
   516  	// Scenario: Recv/Send is being called while sleeping because
   517  	// of the backoff policy is programmed to sleep 1000000 seconds
   518  	// between retries.
   519  	// The Recv/Send should return pretty soon
   520  	cp := &connProducer{}
   521  	abcClient := &abclient{shouldFail: true}
   522  	clFactory := func(*grpc.ClientConn) orderer.AtomicBroadcastClient {
   523  		return abcClient
   524  	}
   525  
   526  	setupInvoked := 0
   527  	setup := func(blocksprovider.BlocksDeliverer) error {
   528  		setupInvoked++
   529  		return nil
   530  	}
   531  	var wg sync.WaitGroup
   532  	wg.Add(1)
   533  	backoffStrategy := func(attemptNum int, elapsedTime time.Duration) (time.Duration, bool) {
   534  		if attemptNum == 1 {
   535  			go func() {
   536  				time.Sleep(time.Second)
   537  				wg.Done()
   538  			}()
   539  		}
   540  		return time.Second * 1000000, true
   541  	}
   542  	bc := NewBroadcastClient(cp, clFactory, setup, backoffStrategy)
   543  	go func() {
   544  		wg.Wait()
   545  		bc.Close()
   546  		bc.Close() // Try to close a second time
   547  	}()
   548  	err := bdc(bc)
   549  	assert.Error(t, err)
   550  	assert.Equal(t, 1, cp.connAttempts)
   551  	assert.Equal(t, 0, setupInvoked)
   552  }
   553  
   554  type signerMock struct {
   555  }
   556  
   557  func (s *signerMock) NewSignatureHeader() (*common.SignatureHeader, error) {
   558  	return &common.SignatureHeader{}, nil
   559  }
   560  
   561  func (s *signerMock) Sign(message []byte) ([]byte, error) {
   562  	hasher := sha256.New()
   563  	hasher.Write(message)
   564  	return hasher.Sum(nil), nil
   565  }
   566  
   567  func TestProductionUsage(t *testing.T) {
   568  	defer ensureNoGoroutineLeak(t)()
   569  	// This test configures the client in a similar fashion as will be
   570  	// in production, and tests against a live gRPC server.
   571  	os := mocks.NewOrderer(5612, t)
   572  	os.SetNextExpectedSeek(5)
   573  
   574  	connFact := func(endpoint string) (*grpc.ClientConn, error) {
   575  		return grpc.Dial(endpoint, grpc.WithInsecure(), grpc.WithBlock())
   576  	}
   577  	prod := comm.NewConnectionProducer(connFact, []string{"localhost:5612"})
   578  	clFact := func(cc *grpc.ClientConn) orderer.AtomicBroadcastClient {
   579  		return orderer.NewAtomicBroadcastClient(cc)
   580  	}
   581  	onConnect := func(bd blocksprovider.BlocksDeliverer) error {
   582  		env, err := utils.CreateSignedEnvelope(common.HeaderType_CONFIG_UPDATE,
   583  			"TEST",
   584  			&signerMock{}, newTestSeekInfo(), 0, 0)
   585  		assert.NoError(t, err)
   586  		return bd.Send(env)
   587  	}
   588  	retryPol := func(attemptNum int, elapsedTime time.Duration) (time.Duration, bool) {
   589  		return time.Second * 3, attemptNum < 2
   590  	}
   591  	cl := NewBroadcastClient(prod, clFact, onConnect, retryPol)
   592  	go os.SendBlock(5)
   593  	resp, err := cl.Recv()
   594  	assert.NoError(t, err)
   595  	assert.NotNil(t, resp)
   596  	assert.Equal(t, uint64(5), resp.GetBlock().Header.Number)
   597  	os.Shutdown()
   598  	cl.Close()
   599  }
   600  
   601  func TestDisconnect(t *testing.T) {
   602  	// Scenario: spawn 2 ordering service instances
   603  	// and a client.
   604  	// Have the client try to Recv() from one of them,
   605  	// and disconnect the client until it tries connecting
   606  	// to the other instance.
   607  
   608  	defer ensureNoGoroutineLeak(t)()
   609  	os1 := mocks.NewOrderer(5613, t)
   610  	os1.SetNextExpectedSeek(5)
   611  	os2 := mocks.NewOrderer(5614, t)
   612  	os2.SetNextExpectedSeek(5)
   613  
   614  	defer os1.Shutdown()
   615  	defer os2.Shutdown()
   616  
   617  	waitForConnectionToSomeOSN := func() {
   618  		for {
   619  			if os1.ConnCount() > 0 || os2.ConnCount() > 0 {
   620  				return
   621  			}
   622  			time.Sleep(time.Millisecond * 100)
   623  		}
   624  	}
   625  
   626  	connFact := func(endpoint string) (*grpc.ClientConn, error) {
   627  		return grpc.Dial(endpoint, grpc.WithInsecure(), grpc.WithBlock())
   628  	}
   629  	prod := comm.NewConnectionProducer(connFact, []string{"localhost:5613", "localhost:5614"})
   630  	clFact := func(cc *grpc.ClientConn) orderer.AtomicBroadcastClient {
   631  		return orderer.NewAtomicBroadcastClient(cc)
   632  	}
   633  	onConnect := func(bd blocksprovider.BlocksDeliverer) error {
   634  		return nil
   635  	}
   636  	retryPol := func(attemptNum int, elapsedTime time.Duration) (time.Duration, bool) {
   637  		return time.Millisecond * 10, attemptNum < 100
   638  	}
   639  
   640  	cl := NewBroadcastClient(prod, clFact, onConnect, retryPol)
   641  	stopChan := make(chan struct{})
   642  	go func() {
   643  		cl.Recv()
   644  		stopChan <- struct{}{}
   645  	}()
   646  	waitForConnectionToSomeOSN()
   647  	cl.Disconnect()
   648  
   649  	i := 0
   650  	for (os1.ConnCount() == 0 || os2.ConnCount() == 0) && i < 100 {
   651  		t.Log("Attempt", i, "os1ConnCount()=", os1.ConnCount(), "os2ConnCount()=", os2.ConnCount())
   652  		i++
   653  		if i == 100 {
   654  			assert.Fail(t, "Didn't switch to other instance after many attempts")
   655  		}
   656  		cl.Disconnect()
   657  		time.Sleep(time.Millisecond * 500)
   658  	}
   659  	cl.Close()
   660  	select {
   661  	case <-stopChan:
   662  	case <-time.After(time.Second * 20):
   663  		assert.Fail(t, "Didn't stop within a timely manner")
   664  	}
   665  }
   666  
   667  func newTestSeekInfo() *orderer.SeekInfo {
   668  	return &orderer.SeekInfo{Start: &orderer.SeekPosition{Type: &orderer.SeekPosition_Specified{Specified: &orderer.SeekSpecified{Number: 5}}},
   669  		Stop:     &orderer.SeekPosition{Type: &orderer.SeekPosition_Specified{Specified: &orderer.SeekSpecified{Number: math.MaxUint64}}},
   670  		Behavior: orderer.SeekInfo_BLOCK_UNTIL_READY,
   671  	}
   672  }