github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/core/deliverservice/blocksprovider/blocksprovider_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  package blocksprovider
    17  
    18  import (
    19  	"errors"
    20  	"sync"
    21  	"sync/atomic"
    22  	"testing"
    23  	"time"
    24  
    25  	"github.com/hyperledger/fabric/core/deliverservice/mocks"
    26  	"github.com/hyperledger/fabric/gossip/api"
    27  	common2 "github.com/hyperledger/fabric/gossip/common"
    28  	"github.com/hyperledger/fabric/protos/common"
    29  	"github.com/hyperledger/fabric/protos/orderer"
    30  	"github.com/stretchr/testify/assert"
    31  	"github.com/stretchr/testify/mock"
    32  )
    33  
    34  type mockMCS struct {
    35  	mock.Mock
    36  }
    37  
    38  func (*mockMCS) GetPKIidOfCert(peerIdentity api.PeerIdentityType) common2.PKIidType {
    39  	return common2.PKIidType("pkiID")
    40  }
    41  
    42  func (m *mockMCS) VerifyBlock(chainID common2.ChainID, signedBlock []byte) error {
    43  	args := m.Called()
    44  	if args.Get(0) != nil {
    45  		return args.Get(0).(error)
    46  	}
    47  	return nil
    48  }
    49  
    50  func (*mockMCS) Sign(msg []byte) ([]byte, error) {
    51  	return msg, nil
    52  }
    53  
    54  func (*mockMCS) Verify(peerIdentity api.PeerIdentityType, signature, message []byte) error {
    55  	return nil
    56  }
    57  
    58  func (*mockMCS) VerifyByChannel(chainID common2.ChainID, peerIdentity api.PeerIdentityType, signature, message []byte) error {
    59  	return nil
    60  }
    61  
    62  func (*mockMCS) ValidateIdentity(peerIdentity api.PeerIdentityType) error {
    63  	return nil
    64  }
    65  
    66  type rcvFunc func(mock *mocks.MockBlocksDeliverer) (*orderer.DeliverResponse, error)
    67  
    68  // Used to generate a simple test case to initialize delivery
    69  // from given block sequence number.
    70  func makeTestCase(ledgerHeight uint64, mcs api.MessageCryptoService, shouldSucceed bool, rcv rcvFunc) func(*testing.T) {
    71  	return func(t *testing.T) {
    72  		gossipServiceAdapter := &mocks.MockGossipServiceAdapter{GossipBlockDisseminations: make(chan uint64)}
    73  		deliverer := &mocks.MockBlocksDeliverer{Pos: ledgerHeight}
    74  		deliverer.MockRecv = rcv
    75  		provider := NewBlocksProvider("***TEST_CHAINID***", deliverer, gossipServiceAdapter, mcs)
    76  		defer provider.Stop()
    77  		ready := make(chan struct{})
    78  		go func() {
    79  			go provider.DeliverBlocks()
    80  			// Send notification
    81  			ready <- struct{}{}
    82  		}()
    83  
    84  		time.Sleep(time.Second)
    85  
    86  		assertDelivery(t, gossipServiceAdapter, deliverer, shouldSucceed)
    87  	}
    88  }
    89  
    90  func assertDelivery(t *testing.T, ga *mocks.MockGossipServiceAdapter, deliverer *mocks.MockBlocksDeliverer, shouldSucceed bool) {
    91  	// Check that all blocks received eventually get gossiped and locally committed
    92  
    93  	select {
    94  	case <-ga.GossipBlockDisseminations:
    95  		if !shouldSucceed {
    96  			assert.Fail(t, "Should not have succeede")
    97  		}
    98  		assert.True(t, deliverer.RecvCnt == ga.AddPayloadsCnt)
    99  	case <-time.After(time.Second):
   100  		if shouldSucceed {
   101  			assert.Fail(t, "Didn't gossip a block within a timely manner")
   102  		}
   103  	}
   104  }
   105  
   106  /*
   107     Test to check whenever blocks provider starts calling new blocks from the
   108     oldest and that eventually it terminates after the Stop method has been called.
   109  */
   110  func TestBlocksProviderImpl_GetBlockFromTheOldest(t *testing.T) {
   111  	mcs := &mockMCS{}
   112  	mcs.On("VerifyBlock", mock.Anything).Return(nil)
   113  	makeTestCase(uint64(0), mcs, true, mocks.MockRecv)(t)
   114  }
   115  
   116  /*
   117     Test to check whenever blocks provider starts calling new blocks from the
   118     oldest and that eventually it terminates after the Stop method has been called.
   119  */
   120  func TestBlocksProviderImpl_GetBlockFromSpecified(t *testing.T) {
   121  	mcs := &mockMCS{}
   122  	mcs.On("VerifyBlock", mock.Anything).Return(nil)
   123  	makeTestCase(uint64(101), mcs, true, mocks.MockRecv)(t)
   124  }
   125  
   126  func TestBlocksProvider_CheckTerminationDeliveryResponseStatus(t *testing.T) {
   127  	tmp := struct{ mocks.MockBlocksDeliverer }{}
   128  
   129  	// Making mocked Recv() function to return DeliverResponse_Status to force block
   130  	// provider to fail and exit, cheking that in that case to block was actually
   131  	// delivered.
   132  	tmp.MockRecv = func(mock *mocks.MockBlocksDeliverer) (*orderer.DeliverResponse, error) {
   133  		return &orderer.DeliverResponse{
   134  			Type: &orderer.DeliverResponse_Status{
   135  				Status: common.Status_SUCCESS,
   136  			},
   137  		}, nil
   138  	}
   139  
   140  	gossipServiceAdapter := &mocks.MockGossipServiceAdapter{}
   141  	provider := &blocksProviderImpl{
   142  		chainID: "***TEST_CHAINID***",
   143  		gossip:  gossipServiceAdapter,
   144  		client:  &tmp,
   145  	}
   146  
   147  	var wg sync.WaitGroup
   148  	wg.Add(1)
   149  
   150  	ready := make(chan struct{})
   151  	go func() {
   152  		provider.DeliverBlocks()
   153  		wg.Done()
   154  		// Send notification
   155  		ready <- struct{}{}
   156  	}()
   157  
   158  	time.Sleep(time.Duration(10) * time.Millisecond)
   159  	provider.Stop()
   160  
   161  	select {
   162  	case <-ready:
   163  		{
   164  			assert.Equal(t, int32(1), tmp.RecvCnt)
   165  			// No payload should commit locally
   166  			assert.Equal(t, int32(0), gossipServiceAdapter.AddPayloadsCnt)
   167  			// No payload should be transferred to other peers
   168  			select {
   169  			case <-gossipServiceAdapter.GossipBlockDisseminations:
   170  				assert.Fail(t, "Gossiped block but shouldn't have")
   171  			case <-time.After(time.Second):
   172  			}
   173  			return
   174  		}
   175  	case <-time.After(time.Duration(1) * time.Second):
   176  		{
   177  			t.Fatal("Test hasn't finished in timely manner, failing.")
   178  		}
   179  	}
   180  }
   181  
   182  func TestBlockFetchFailure(t *testing.T) {
   183  	rcvr := func(mock *mocks.MockBlocksDeliverer) (*orderer.DeliverResponse, error) {
   184  		return nil, errors.New("Failed fetching block")
   185  	}
   186  	mcs := &mockMCS{}
   187  	mcs.On("VerifyBlock", mock.Anything).Return(nil)
   188  	makeTestCase(uint64(0), mcs, false, rcvr)(t)
   189  }
   190  
   191  func TestBlockVerificationFailure(t *testing.T) {
   192  	attempts := int32(0)
   193  	rcvr := func(mock *mocks.MockBlocksDeliverer) (*orderer.DeliverResponse, error) {
   194  		if atomic.LoadInt32(&attempts) == int32(1) {
   195  			return &orderer.DeliverResponse{
   196  				Type: &orderer.DeliverResponse_Status{
   197  					Status: common.Status_SUCCESS,
   198  				},
   199  			}, nil
   200  		}
   201  		atomic.AddInt32(&attempts, int32(1))
   202  		return &orderer.DeliverResponse{
   203  			Type: &orderer.DeliverResponse_Block{
   204  				Block: &common.Block{
   205  					Header: &common.BlockHeader{
   206  						Number:       0,
   207  						DataHash:     []byte{},
   208  						PreviousHash: []byte{},
   209  					},
   210  					Data: &common.BlockData{
   211  						Data: [][]byte{},
   212  					},
   213  				}},
   214  		}, nil
   215  	}
   216  	mcs := &mockMCS{}
   217  	mcs.On("VerifyBlock", mock.Anything).Return(errors.New("Invalid signature"))
   218  	makeTestCase(uint64(0), mcs, false, rcvr)(t)
   219  }