github.com/tenywen/fabric@v1.0.0-beta.0.20170620030522-a5b1ed380643/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  	"errors"
    21  	"runtime"
    22  	"sync"
    23  	"sync/atomic"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/hyperledger/fabric/core/deliverservice/blocksprovider"
    28  	"github.com/hyperledger/fabric/core/deliverservice/mocks"
    29  	"github.com/hyperledger/fabric/gossip/api"
    30  	"github.com/hyperledger/fabric/gossip/common"
    31  	"github.com/hyperledger/fabric/msp/mgmt/testtools"
    32  	"github.com/hyperledger/fabric/protos/orderer"
    33  	"github.com/stretchr/testify/assert"
    34  	"google.golang.org/grpc"
    35  )
    36  
    37  func init() {
    38  	msptesttools.LoadMSPSetupForTesting()
    39  }
    40  
    41  const (
    42  	goRoutineTestWaitTimeout = time.Second * 15
    43  )
    44  
    45  var (
    46  	lock = sync.Mutex{}
    47  )
    48  
    49  type mockBlocksDelivererFactory struct {
    50  	mockCreate func() (blocksprovider.BlocksDeliverer, error)
    51  }
    52  
    53  func (mock *mockBlocksDelivererFactory) Create() (blocksprovider.BlocksDeliverer, error) {
    54  	return mock.mockCreate()
    55  }
    56  
    57  type mockMCS struct {
    58  }
    59  
    60  func (*mockMCS) GetPKIidOfCert(peerIdentity api.PeerIdentityType) common.PKIidType {
    61  	return common.PKIidType("pkiID")
    62  }
    63  
    64  func (*mockMCS) VerifyBlock(chainID common.ChainID, seqNum uint64, signedBlock []byte) error {
    65  	return nil
    66  }
    67  
    68  func (*mockMCS) Sign(msg []byte) ([]byte, error) {
    69  	return msg, nil
    70  }
    71  
    72  func (*mockMCS) Verify(peerIdentity api.PeerIdentityType, signature, message []byte) error {
    73  	return nil
    74  }
    75  
    76  func (*mockMCS) VerifyByChannel(chainID common.ChainID, peerIdentity api.PeerIdentityType, signature, message []byte) error {
    77  	return nil
    78  }
    79  
    80  func (*mockMCS) ValidateIdentity(peerIdentity api.PeerIdentityType) error {
    81  	return nil
    82  }
    83  
    84  func TestNewDeliverService(t *testing.T) {
    85  	defer ensureNoGoroutineLeak(t)()
    86  	gossipServiceAdapter := &mocks.MockGossipServiceAdapter{GossipBlockDisseminations: make(chan uint64, 1)}
    87  	factory := &struct{ mockBlocksDelivererFactory }{}
    88  
    89  	blocksDeliverer := &mocks.MockBlocksDeliverer{}
    90  	blocksDeliverer.MockRecv = mocks.MockRecv
    91  
    92  	factory.mockCreate = func() (blocksprovider.BlocksDeliverer, error) {
    93  		return blocksDeliverer, nil
    94  	}
    95  	abcf := func(*grpc.ClientConn) orderer.AtomicBroadcastClient {
    96  		return &mocks.MockAtomicBroadcastClient{blocksDeliverer}
    97  	}
    98  
    99  	connFactory := func(_ string) func(string) (*grpc.ClientConn, error) {
   100  		return func(endpoint string) (*grpc.ClientConn, error) {
   101  			lock.Lock()
   102  			defer lock.Unlock()
   103  			return newConnection(), nil
   104  		}
   105  	}
   106  	service, err := NewDeliverService(&Config{
   107  		Endpoints:   []string{"a"},
   108  		Gossip:      gossipServiceAdapter,
   109  		CryptoSvc:   &mockMCS{},
   110  		ABCFactory:  abcf,
   111  		ConnFactory: connFactory,
   112  	})
   113  	assert.NoError(t, err)
   114  	assert.NoError(t, service.StartDeliverForChannel("TEST_CHAINID", &mocks.MockLedgerInfo{0}))
   115  
   116  	// Lets start deliver twice
   117  	assert.Error(t, service.StartDeliverForChannel("TEST_CHAINID", &mocks.MockLedgerInfo{0}), "can't start delivery")
   118  	// Lets stop deliver that not started
   119  	assert.Error(t, service.StopDeliverForChannel("TEST_CHAINID2"), "can't stop delivery")
   120  
   121  	// Let it try to simulate a few recv -> gossip rounds
   122  	time.Sleep(time.Second)
   123  	assert.NoError(t, service.StopDeliverForChannel("TEST_CHAINID"))
   124  	time.Sleep(time.Duration(10) * time.Millisecond)
   125  	// Make sure to stop all blocks providers
   126  	service.Stop()
   127  	time.Sleep(time.Duration(500) * time.Millisecond)
   128  	assert.Equal(t, 0, connNumber)
   129  	assertBlockDissemination(0, gossipServiceAdapter.GossipBlockDisseminations, t)
   130  	assert.Equal(t, atomic.LoadInt32(&blocksDeliverer.RecvCnt), atomic.LoadInt32(&gossipServiceAdapter.AddPayloadsCnt))
   131  	assert.Error(t, service.StartDeliverForChannel("TEST_CHAINID", &mocks.MockLedgerInfo{0}), "Delivery service is stopping")
   132  	assert.Error(t, service.StopDeliverForChannel("TEST_CHAINID"), "Delivery service is stopping")
   133  }
   134  
   135  func TestDeliverServiceRestart(t *testing.T) {
   136  	defer ensureNoGoroutineLeak(t)()
   137  	// Scenario: bring up ordering service instance, then shut it down, and then resurrect it.
   138  	// Client is expected to reconnect to it, and to ask for a block sequence that is the next block
   139  	// after the last block it got from the previous incarnation of the ordering service.
   140  
   141  	os := mocks.NewOrderer(5611, t)
   142  
   143  	time.Sleep(time.Second)
   144  	gossipServiceAdapter := &mocks.MockGossipServiceAdapter{GossipBlockDisseminations: make(chan uint64)}
   145  
   146  	service, err := NewDeliverService(&Config{
   147  		Endpoints:   []string{"localhost:5611"},
   148  		Gossip:      gossipServiceAdapter,
   149  		CryptoSvc:   &mockMCS{},
   150  		ABCFactory:  DefaultABCFactory,
   151  		ConnFactory: DefaultConnectionFactory,
   152  	})
   153  	assert.NoError(t, err)
   154  
   155  	li := &mocks.MockLedgerInfo{Height: uint64(100)}
   156  	os.SetNextExpectedSeek(uint64(100))
   157  
   158  	err = service.StartDeliverForChannel("TEST_CHAINID", li)
   159  	assert.NoError(t, err, "can't start delivery")
   160  	// Check that delivery client requests blocks in order
   161  	go os.SendBlock(uint64(100))
   162  	assertBlockDissemination(100, gossipServiceAdapter.GossipBlockDisseminations, t)
   163  	go os.SendBlock(uint64(101))
   164  	assertBlockDissemination(101, gossipServiceAdapter.GossipBlockDisseminations, t)
   165  	go os.SendBlock(uint64(102))
   166  	assertBlockDissemination(102, gossipServiceAdapter.GossipBlockDisseminations, t)
   167  	os.Shutdown()
   168  	time.Sleep(time.Second * 3)
   169  	os = mocks.NewOrderer(5611, t)
   170  	li.Height = 103
   171  	os.SetNextExpectedSeek(uint64(103))
   172  	go os.SendBlock(uint64(103))
   173  	assertBlockDissemination(103, gossipServiceAdapter.GossipBlockDisseminations, t)
   174  	service.Stop()
   175  	os.Shutdown()
   176  }
   177  
   178  func TestDeliverServiceFailover(t *testing.T) {
   179  	defer ensureNoGoroutineLeak(t)()
   180  	// Scenario: bring up 2 ordering service instances,
   181  	// and shut down the instance that the client has connected to.
   182  	// Client is expected to connect to the other instance, and to ask for a block sequence that is the next block
   183  	// after the last block it got from the ordering service that was shut down.
   184  	// Then, shut down the other node, and bring back the first (that was shut down first).
   185  
   186  	os1 := mocks.NewOrderer(5612, t)
   187  	os2 := mocks.NewOrderer(5613, t)
   188  
   189  	time.Sleep(time.Second)
   190  	gossipServiceAdapter := &mocks.MockGossipServiceAdapter{GossipBlockDisseminations: make(chan uint64)}
   191  
   192  	service, err := NewDeliverService(&Config{
   193  		Endpoints:   []string{"localhost:5612", "localhost:5613"},
   194  		Gossip:      gossipServiceAdapter,
   195  		CryptoSvc:   &mockMCS{},
   196  		ABCFactory:  DefaultABCFactory,
   197  		ConnFactory: DefaultConnectionFactory,
   198  	})
   199  	assert.NoError(t, err)
   200  	li := &mocks.MockLedgerInfo{Height: uint64(100)}
   201  	os1.SetNextExpectedSeek(uint64(100))
   202  	os2.SetNextExpectedSeek(uint64(100))
   203  
   204  	err = service.StartDeliverForChannel("TEST_CHAINID", li)
   205  	assert.NoError(t, err, "can't start delivery")
   206  	// We need to discover to which instance the client connected to
   207  	go os1.SendBlock(uint64(100))
   208  	instance2fail := os1
   209  	reincarnatedNodePort := 5612
   210  	instance2failSecond := os2
   211  	select {
   212  	case seq := <-gossipServiceAdapter.GossipBlockDisseminations:
   213  		assert.Equal(t, uint64(100), seq)
   214  	case <-time.After(time.Second * 2):
   215  		// Shutdown first instance and replace it, in order to make an instance
   216  		// with an empty sending channel
   217  		os1.Shutdown()
   218  		time.Sleep(time.Second)
   219  		os1 = mocks.NewOrderer(5612, t)
   220  		instance2fail = os2
   221  		instance2failSecond = os1
   222  		reincarnatedNodePort = 5613
   223  		// Ensure we really are connected to the second instance,
   224  		// by making it send a block
   225  		go os2.SendBlock(uint64(100))
   226  		assertBlockDissemination(100, gossipServiceAdapter.GossipBlockDisseminations, t)
   227  	}
   228  
   229  	atomic.StoreUint64(&li.Height, uint64(101))
   230  	os1.SetNextExpectedSeek(uint64(101))
   231  	os2.SetNextExpectedSeek(uint64(101))
   232  	// Fail the orderer node the client is connected to
   233  	instance2fail.Shutdown()
   234  	time.Sleep(time.Second)
   235  	// Ensure the client asks blocks from the other ordering service node
   236  	go instance2failSecond.SendBlock(uint64(101))
   237  	assertBlockDissemination(101, gossipServiceAdapter.GossipBlockDisseminations, t)
   238  	atomic.StoreUint64(&li.Height, uint64(102))
   239  	// Now shut down the 2nd node
   240  	instance2failSecond.Shutdown()
   241  	time.Sleep(time.Second * 1)
   242  	// Bring up the first one
   243  	os := mocks.NewOrderer(reincarnatedNodePort, t)
   244  	os.SetNextExpectedSeek(102)
   245  	go os.SendBlock(uint64(102))
   246  	assertBlockDissemination(102, gossipServiceAdapter.GossipBlockDisseminations, t)
   247  	os.Shutdown()
   248  	service.Stop()
   249  }
   250  
   251  func TestDeliverServiceServiceUnavailable(t *testing.T) {
   252  	defer ensureNoGoroutineLeak(t)()
   253  	// Scenario: bring up 2 ordering service instances,
   254  	// Make the instance the client connects to fail after a delivery of a block and send SERVICE_UNAVAILABLE
   255  	// whenever subsequent seeks are sent to it.
   256  	// The client is expected to connect to the other instance, and to ask for a block sequence that is the next block
   257  	// after the last block it got from the first ordering service node.
   258  
   259  	os1 := mocks.NewOrderer(5615, t)
   260  	os2 := mocks.NewOrderer(5616, t)
   261  
   262  	time.Sleep(time.Second)
   263  	gossipServiceAdapter := &mocks.MockGossipServiceAdapter{GossipBlockDisseminations: make(chan uint64)}
   264  
   265  	service, err := NewDeliverService(&Config{
   266  		Endpoints:   []string{"localhost:5615", "localhost:5616"},
   267  		Gossip:      gossipServiceAdapter,
   268  		CryptoSvc:   &mockMCS{},
   269  		ABCFactory:  DefaultABCFactory,
   270  		ConnFactory: DefaultConnectionFactory,
   271  	})
   272  	assert.NoError(t, err)
   273  	li := &mocks.MockLedgerInfo{Height: 100}
   274  	os1.SetNextExpectedSeek(100)
   275  	os2.SetNextExpectedSeek(100)
   276  
   277  	err = service.StartDeliverForChannel("TEST_CHAINID", li)
   278  	assert.NoError(t, err, "can't start delivery")
   279  	// We need to discover to which instance the client connected to
   280  	go os1.SendBlock(100)
   281  	// Is it the first instance?
   282  	instance2fail := os1
   283  	nextBlockSeek := uint64(100)
   284  	select {
   285  	case seq := <-gossipServiceAdapter.GossipBlockDisseminations:
   286  		// Just for sanity check, ensure we got block seq 100
   287  		assert.Equal(t, uint64(100), seq)
   288  		// Connected to the first instance
   289  		// Advance ledger's height by 1
   290  		atomic.StoreUint64(&li.Height, 101)
   291  		// Backup instance should expect a seek of 101 since we got 100
   292  		os2.SetNextExpectedSeek(uint64(101))
   293  		nextBlockSeek = uint64(101)
   294  		// Have backup instance prepare to send a block
   295  		os2.SendBlock(101)
   296  	case <-time.After(time.Second * 5):
   297  		// We didn't get a block on time, so seems like we're connected to the 2nd instance
   298  		// and not to the first.
   299  		instance2fail = os2
   300  	}
   301  
   302  	instance2fail.Fail()
   303  	// Ensure the client asks blocks from the other ordering service node
   304  	assertBlockDissemination(nextBlockSeek, gossipServiceAdapter.GossipBlockDisseminations, t)
   305  
   306  	// Cleanup
   307  	os1.Shutdown()
   308  	os2.Shutdown()
   309  	service.Stop()
   310  }
   311  
   312  func TestDeliverServiceShutdown(t *testing.T) {
   313  	defer ensureNoGoroutineLeak(t)()
   314  	// Scenario: Launch an ordering service node and let the client pull some blocks.
   315  	// Then, shut down the client, and check that it is no longer fetching blocks.
   316  	os := mocks.NewOrderer(5614, t)
   317  
   318  	time.Sleep(time.Second)
   319  	gossipServiceAdapter := &mocks.MockGossipServiceAdapter{GossipBlockDisseminations: make(chan uint64)}
   320  
   321  	service, err := NewDeliverService(&Config{
   322  		Endpoints:   []string{"localhost:5614"},
   323  		Gossip:      gossipServiceAdapter,
   324  		CryptoSvc:   &mockMCS{},
   325  		ABCFactory:  DefaultABCFactory,
   326  		ConnFactory: DefaultConnectionFactory,
   327  	})
   328  	assert.NoError(t, err)
   329  
   330  	li := &mocks.MockLedgerInfo{Height: uint64(100)}
   331  	os.SetNextExpectedSeek(uint64(100))
   332  	err = service.StartDeliverForChannel("TEST_CHAINID", li)
   333  	assert.NoError(t, err, "can't start delivery")
   334  
   335  	// Check that delivery service requests blocks in order
   336  	go os.SendBlock(uint64(100))
   337  	assertBlockDissemination(100, gossipServiceAdapter.GossipBlockDisseminations, t)
   338  	go os.SendBlock(uint64(101))
   339  	assertBlockDissemination(101, gossipServiceAdapter.GossipBlockDisseminations, t)
   340  	atomic.StoreUint64(&li.Height, uint64(102))
   341  	os.SetNextExpectedSeek(uint64(102))
   342  	// Now stop the delivery service and make sure we don't disseminate a block
   343  	service.Stop()
   344  	go os.SendBlock(uint64(102))
   345  	select {
   346  	case <-gossipServiceAdapter.GossipBlockDisseminations:
   347  		assert.Fail(t, "Disseminated a block after shutting down the delivery service")
   348  	case <-time.After(time.Second * 2):
   349  	}
   350  	os.Shutdown()
   351  	time.Sleep(time.Second)
   352  }
   353  
   354  func TestDeliverServiceBadConfig(t *testing.T) {
   355  	// Empty endpoints
   356  	service, err := NewDeliverService(&Config{
   357  		Endpoints:   []string{},
   358  		Gossip:      &mocks.MockGossipServiceAdapter{},
   359  		CryptoSvc:   &mockMCS{},
   360  		ABCFactory:  DefaultABCFactory,
   361  		ConnFactory: DefaultConnectionFactory,
   362  	})
   363  	assert.Error(t, err)
   364  	assert.Nil(t, service)
   365  
   366  	// Nil gossip adapter
   367  	service, err = NewDeliverService(&Config{
   368  		Endpoints:   []string{"a"},
   369  		Gossip:      nil,
   370  		CryptoSvc:   &mockMCS{},
   371  		ABCFactory:  DefaultABCFactory,
   372  		ConnFactory: DefaultConnectionFactory,
   373  	})
   374  	assert.Error(t, err)
   375  	assert.Nil(t, service)
   376  
   377  	// Nil crypto service
   378  	service, err = NewDeliverService(&Config{
   379  		Endpoints:   []string{"a"},
   380  		Gossip:      &mocks.MockGossipServiceAdapter{},
   381  		CryptoSvc:   nil,
   382  		ABCFactory:  DefaultABCFactory,
   383  		ConnFactory: DefaultConnectionFactory,
   384  	})
   385  	assert.Error(t, err)
   386  	assert.Nil(t, service)
   387  
   388  	// Nil ABCFactory
   389  	service, err = NewDeliverService(&Config{
   390  		Endpoints:   []string{"a"},
   391  		Gossip:      &mocks.MockGossipServiceAdapter{},
   392  		CryptoSvc:   &mockMCS{},
   393  		ABCFactory:  nil,
   394  		ConnFactory: DefaultConnectionFactory,
   395  	})
   396  	assert.Error(t, err)
   397  	assert.Nil(t, service)
   398  
   399  	// Nil connFactory
   400  	service, err = NewDeliverService(&Config{
   401  		Endpoints:  []string{"a"},
   402  		Gossip:     &mocks.MockGossipServiceAdapter{},
   403  		CryptoSvc:  &mockMCS{},
   404  		ABCFactory: DefaultABCFactory,
   405  	})
   406  	assert.Error(t, err)
   407  	assert.Nil(t, service)
   408  }
   409  
   410  func TestRetryPolicyOverflow(t *testing.T) {
   411  	connFactory := func(channelID string) func(endpoint string) (*grpc.ClientConn, error) {
   412  		return func(_ string) (*grpc.ClientConn, error) {
   413  			return nil, errors.New("")
   414  		}
   415  	}
   416  	client := (&deliverServiceImpl{conf: &Config{ConnFactory: connFactory}}).newClient("TEST", &mocks.MockLedgerInfo{Height: uint64(100)})
   417  	assert.NotNil(t, client.shouldRetry)
   418  	for i := 0; i < 100; i++ {
   419  		retryTime, _ := client.shouldRetry(i, time.Second)
   420  		assert.True(t, retryTime <= time.Hour && retryTime > 0)
   421  	}
   422  }
   423  
   424  func assertBlockDissemination(expectedSeq uint64, ch chan uint64, t *testing.T) {
   425  	select {
   426  	case seq := <-ch:
   427  		assert.Equal(t, expectedSeq, seq)
   428  	case <-time.After(time.Second * 5):
   429  		assert.Fail(t, "Didn't gossip a new block within a timely manner")
   430  	}
   431  }
   432  
   433  func ensureNoGoroutineLeak(t *testing.T) func() {
   434  	goroutineCountAtStart := runtime.NumGoroutine()
   435  	return func() {
   436  		start := time.Now()
   437  		timeLimit := start.Add(goRoutineTestWaitTimeout)
   438  		for time.Now().Before(timeLimit) {
   439  			time.Sleep(time.Millisecond * 500)
   440  			if goroutineCountAtStart >= runtime.NumGoroutine() {
   441  				return
   442  			}
   443  		}
   444  		assert.Fail(t, "Some goroutine(s) didn't finish: %s", getStackTrace())
   445  	}
   446  }
   447  
   448  func getStackTrace() string {
   449  	buf := make([]byte, 1<<16)
   450  	runtime.Stack(buf, true)
   451  	return string(buf)
   452  }