github.com/myafeier/fabric@v1.0.1-0.20170722181825-3a4b1f2bce86/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  func init() {
    35  	MaxRetryDelay = time.Second
    36  }
    37  
    38  type mockMCS struct {
    39  	mock.Mock
    40  }
    41  
    42  func (*mockMCS) GetPKIidOfCert(peerIdentity api.PeerIdentityType) common2.PKIidType {
    43  	return common2.PKIidType("pkiID")
    44  }
    45  
    46  func (m *mockMCS) VerifyBlock(chainID common2.ChainID, seqNum uint64, signedBlock []byte) error {
    47  	args := m.Called()
    48  	if args.Get(0) != nil {
    49  		return args.Get(0).(error)
    50  	}
    51  	return nil
    52  }
    53  
    54  func (*mockMCS) Sign(msg []byte) ([]byte, error) {
    55  	return msg, nil
    56  }
    57  
    58  func (*mockMCS) Verify(peerIdentity api.PeerIdentityType, signature, message []byte) error {
    59  	return nil
    60  }
    61  
    62  func (*mockMCS) VerifyByChannel(chainID common2.ChainID, peerIdentity api.PeerIdentityType, signature, message []byte) error {
    63  	return nil
    64  }
    65  
    66  func (*mockMCS) ValidateIdentity(peerIdentity api.PeerIdentityType) error {
    67  	return nil
    68  }
    69  
    70  type rcvFunc func(mock *mocks.MockBlocksDeliverer) (*orderer.DeliverResponse, error)
    71  
    72  // Used to generate a simple test case to initialize delivery
    73  // from given block sequence number.
    74  func makeTestCase(ledgerHeight uint64, mcs api.MessageCryptoService, shouldSucceed bool, rcv rcvFunc) func(*testing.T) {
    75  	return func(t *testing.T) {
    76  		gossipServiceAdapter := &mocks.MockGossipServiceAdapter{GossipBlockDisseminations: make(chan uint64)}
    77  		deliverer := &mocks.MockBlocksDeliverer{Pos: ledgerHeight}
    78  		deliverer.MockRecv = rcv
    79  		provider := NewBlocksProvider("***TEST_CHAINID***", deliverer, gossipServiceAdapter, mcs)
    80  		defer provider.Stop()
    81  		ready := make(chan struct{})
    82  		go func() {
    83  			go provider.DeliverBlocks()
    84  			// Send notification
    85  			ready <- struct{}{}
    86  		}()
    87  
    88  		time.Sleep(time.Second)
    89  
    90  		assertDelivery(t, gossipServiceAdapter, deliverer, shouldSucceed)
    91  	}
    92  }
    93  
    94  func assertDelivery(t *testing.T, ga *mocks.MockGossipServiceAdapter, deliverer *mocks.MockBlocksDeliverer, shouldSucceed bool) {
    95  	// Check that all blocks received eventually get gossiped and locally committed
    96  
    97  	select {
    98  	case <-ga.GossipBlockDisseminations:
    99  		if !shouldSucceed {
   100  			assert.Fail(t, "Should not have succeede")
   101  		}
   102  		assert.True(t, deliverer.RecvCnt == ga.AddPayloadsCnt)
   103  	case <-time.After(time.Second):
   104  		if shouldSucceed {
   105  			assert.Fail(t, "Didn't gossip a block within a timely manner")
   106  		}
   107  	}
   108  }
   109  
   110  func waitUntilOrFail(t *testing.T, pred func() bool) {
   111  	timeout := time.Second * 30
   112  	start := time.Now()
   113  	limit := start.UnixNano() + timeout.Nanoseconds()
   114  	for time.Now().UnixNano() < limit {
   115  		if pred() {
   116  			return
   117  		}
   118  		time.Sleep(timeout / 60)
   119  	}
   120  	assert.Fail(t, "Timeout expired!")
   121  }
   122  
   123  /*
   124     Test to check whenever blocks provider starts calling new blocks from the
   125     oldest and that eventually it terminates after the Stop method has been called.
   126  */
   127  func TestBlocksProviderImpl_GetBlockFromTheOldest(t *testing.T) {
   128  	mcs := &mockMCS{}
   129  	mcs.On("VerifyBlock", mock.Anything).Return(nil)
   130  	makeTestCase(uint64(0), mcs, true, mocks.MockRecv)(t)
   131  }
   132  
   133  /*
   134     Test to check whenever blocks provider starts calling new blocks from the
   135     oldest and that eventually it terminates after the Stop method has been called.
   136  */
   137  func TestBlocksProviderImpl_GetBlockFromSpecified(t *testing.T) {
   138  	mcs := &mockMCS{}
   139  	mcs.On("VerifyBlock", mock.Anything).Return(nil)
   140  	makeTestCase(uint64(101), mcs, true, mocks.MockRecv)(t)
   141  }
   142  
   143  func TestBlocksProvider_CheckTerminationDeliveryResponseStatus(t *testing.T) {
   144  	tmp := struct{ mocks.MockBlocksDeliverer }{}
   145  
   146  	// Making mocked Recv() function to return DeliverResponse_Status to force block
   147  	// provider to fail and exit, checking that in that case to block was actually
   148  	// delivered.
   149  	tmp.MockRecv = func(mock *mocks.MockBlocksDeliverer) (*orderer.DeliverResponse, error) {
   150  		return &orderer.DeliverResponse{
   151  			Type: &orderer.DeliverResponse_Status{
   152  				Status: common.Status_SUCCESS,
   153  			},
   154  		}, nil
   155  	}
   156  
   157  	gossipServiceAdapter := &mocks.MockGossipServiceAdapter{}
   158  	provider := &blocksProviderImpl{
   159  		chainID: "***TEST_CHAINID***",
   160  		gossip:  gossipServiceAdapter,
   161  		client:  &tmp,
   162  	}
   163  
   164  	var wg sync.WaitGroup
   165  	wg.Add(1)
   166  
   167  	ready := make(chan struct{})
   168  	go func() {
   169  		provider.DeliverBlocks()
   170  		wg.Done()
   171  		// Send notification
   172  		ready <- struct{}{}
   173  	}()
   174  
   175  	time.Sleep(time.Duration(10) * time.Millisecond)
   176  	provider.Stop()
   177  
   178  	select {
   179  	case <-ready:
   180  		{
   181  			assert.Equal(t, int32(1), tmp.RecvCnt)
   182  			// No payload should commit locally
   183  			assert.Equal(t, int32(0), gossipServiceAdapter.AddPayloadsCnt)
   184  			// No payload should be transferred to other peers
   185  			select {
   186  			case <-gossipServiceAdapter.GossipBlockDisseminations:
   187  				assert.Fail(t, "Gossiped block but shouldn't have")
   188  			case <-time.After(time.Second):
   189  			}
   190  			return
   191  		}
   192  	case <-time.After(time.Duration(1) * time.Second):
   193  		{
   194  			t.Fatal("Test hasn't finished in timely manner, failing.")
   195  		}
   196  	}
   197  }
   198  
   199  func TestBlocksProvider_DeliveryWrongStatus(t *testing.T) {
   200  	sendBlock := func(seqNum uint64) *orderer.DeliverResponse {
   201  		return &orderer.DeliverResponse{
   202  			Type: &orderer.DeliverResponse_Block{
   203  				Block: &common.Block{
   204  					Header: &common.BlockHeader{
   205  						Number:       seqNum,
   206  						DataHash:     []byte{},
   207  						PreviousHash: []byte{},
   208  					},
   209  					Data: &common.BlockData{
   210  						Data: [][]byte{},
   211  					},
   212  				}},
   213  		}
   214  	}
   215  	sendStatus := func(status common.Status) *orderer.DeliverResponse {
   216  		return &orderer.DeliverResponse{
   217  			Type: &orderer.DeliverResponse_Status{
   218  				Status: status,
   219  			},
   220  		}
   221  	}
   222  
   223  	bd := mocks.MockBlocksDeliverer{DisconnectCalled: make(chan struct{}, 10)}
   224  	mcs := &mockMCS{}
   225  	mcs.On("VerifyBlock", mock.Anything).Return(nil)
   226  	gossipServiceAdapter := &mocks.MockGossipServiceAdapter{GossipBlockDisseminations: make(chan uint64, 2)}
   227  	provider := &blocksProviderImpl{
   228  		chainID:              "***TEST_CHAINID***",
   229  		gossip:               gossipServiceAdapter,
   230  		client:               &bd,
   231  		mcs:                  mcs,
   232  		wrongStatusThreshold: wrongStatusThreshold,
   233  	}
   234  
   235  	attempts := int32(0)
   236  	bd.MockRecv = func(mock *mocks.MockBlocksDeliverer) (*orderer.DeliverResponse, error) {
   237  		atomic.AddInt32(&attempts, 1)
   238  		switch atomic.LoadInt32(&attempts) {
   239  		case int32(1):
   240  			return sendBlock(0), nil
   241  		case int32(2):
   242  			return sendStatus(common.Status_SERVICE_UNAVAILABLE), nil
   243  		case int32(3):
   244  			return sendStatus(common.Status_BAD_REQUEST), nil
   245  		case int32(4):
   246  			return sendStatus(common.Status_FORBIDDEN), nil
   247  		case int32(5):
   248  			return sendStatus(common.Status_NOT_FOUND), nil
   249  		case int32(6):
   250  			return sendStatus(common.Status_INTERNAL_SERVER_ERROR), nil
   251  		case int32(7):
   252  			return sendBlock(1), nil
   253  		default:
   254  			provider.Stop()
   255  			return nil, errors.New("Stopping")
   256  		}
   257  	}
   258  
   259  	go provider.DeliverBlocks()
   260  	assert.Len(t, bd.DisconnectCalled, 0)
   261  	for i := 0; i < 2; i++ {
   262  		select {
   263  		case seq := <-gossipServiceAdapter.GossipBlockDisseminations:
   264  			assert.Equal(t, uint64(i), seq)
   265  		case <-time.After(time.Second * 10):
   266  			assert.Fail(t, "Didn't receive a block within a timely manner")
   267  		}
   268  	}
   269  	// Make sure disconnect was called in between the deliveries
   270  	assert.Len(t, bd.DisconnectCalled, 5)
   271  }
   272  
   273  func TestBlocksProvider_DeliveryWrongStatusClose(t *testing.T) {
   274  	// Test emulate receive of wrong statuses from orderer
   275  	// Once test get sequence of wrongStatusThreshold (5) FORBIDDEN or BAD_REQUEST statuses,
   276  	// it stop blocks deliver go routine
   277  	// At start is sends all 5 statuses and check is each one of them caused disconnect and reconnect
   278  	// but blocks deliver still running
   279  	// At next step it sends 2 FORBIDDEN or BAD_REQUEST statuses, followed by SERVICE_UNAVAILABLE
   280  	// and 4 more FORBIDDEN or BAD_REQUEST statuses. It checks if enough disconnects called, but
   281  	// blocks deliver still running
   282  	// At the end, it send 2 FORBIDDEN or BAD_REQUEST statuses and check is blocks deliver stopped
   283  
   284  	sendStatus := func(status common.Status) *orderer.DeliverResponse {
   285  		return &orderer.DeliverResponse{
   286  			Type: &orderer.DeliverResponse_Status{
   287  				Status: status,
   288  			},
   289  		}
   290  	}
   291  
   292  	bd := mocks.MockBlocksDeliverer{DisconnectCalled: make(chan struct{}, 100), CloseCalled: make(chan struct{}, 1)}
   293  	mcs := &mockMCS{}
   294  	mcs.On("VerifyBlock", mock.Anything).Return(nil)
   295  	gossipServiceAdapter := &mocks.MockGossipServiceAdapter{GossipBlockDisseminations: make(chan uint64, 2)}
   296  	provider := &blocksProviderImpl{
   297  		chainID:              "***TEST_CHAINID***",
   298  		gossip:               gossipServiceAdapter,
   299  		client:               &bd,
   300  		mcs:                  mcs,
   301  		wrongStatusThreshold: 5,
   302  	}
   303  
   304  	incomingMsgs := make(chan *orderer.DeliverResponse)
   305  
   306  	bd.MockRecv = func(mock *mocks.MockBlocksDeliverer) (*orderer.DeliverResponse, error) {
   307  		inMsg := <-incomingMsgs
   308  		return inMsg, nil
   309  	}
   310  
   311  	go provider.DeliverBlocks()
   312  
   313  	incomingMsgs <- sendStatus(common.Status_SERVICE_UNAVAILABLE)
   314  	incomingMsgs <- sendStatus(common.Status_BAD_REQUEST)
   315  	incomingMsgs <- sendStatus(common.Status_FORBIDDEN)
   316  	incomingMsgs <- sendStatus(common.Status_NOT_FOUND)
   317  	incomingMsgs <- sendStatus(common.Status_INTERNAL_SERVER_ERROR)
   318  
   319  	waitUntilOrFail(t, func() bool {
   320  		return len(bd.DisconnectCalled) == 5
   321  	})
   322  
   323  	waitUntilOrFail(t, func() bool {
   324  		return len(bd.CloseCalled) == 0
   325  	})
   326  
   327  	incomingMsgs <- sendStatus(common.Status_FORBIDDEN)
   328  	incomingMsgs <- sendStatus(common.Status_BAD_REQUEST)
   329  	incomingMsgs <- sendStatus(common.Status_SERVICE_UNAVAILABLE)
   330  	incomingMsgs <- sendStatus(common.Status_FORBIDDEN)
   331  	incomingMsgs <- sendStatus(common.Status_BAD_REQUEST)
   332  	incomingMsgs <- sendStatus(common.Status_FORBIDDEN)
   333  	incomingMsgs <- sendStatus(common.Status_BAD_REQUEST)
   334  
   335  	waitUntilOrFail(t, func() bool {
   336  		return len(bd.DisconnectCalled) == 12
   337  	})
   338  
   339  	waitUntilOrFail(t, func() bool {
   340  		return len(bd.CloseCalled) == 0
   341  	})
   342  
   343  	incomingMsgs <- sendStatus(common.Status_BAD_REQUEST)
   344  	incomingMsgs <- sendStatus(common.Status_FORBIDDEN)
   345  
   346  	waitUntilOrFail(t, func() bool {
   347  		return len(bd.CloseCalled) == 1
   348  	})
   349  }
   350  
   351  func TestBlockFetchFailure(t *testing.T) {
   352  	rcvr := func(mock *mocks.MockBlocksDeliverer) (*orderer.DeliverResponse, error) {
   353  		return nil, errors.New("Failed fetching block")
   354  	}
   355  	mcs := &mockMCS{}
   356  	mcs.On("VerifyBlock", mock.Anything).Return(nil)
   357  	makeTestCase(uint64(0), mcs, false, rcvr)(t)
   358  }
   359  
   360  func TestBlockVerificationFailure(t *testing.T) {
   361  	attempts := int32(0)
   362  	rcvr := func(mock *mocks.MockBlocksDeliverer) (*orderer.DeliverResponse, error) {
   363  		if atomic.LoadInt32(&attempts) == int32(1) {
   364  			return &orderer.DeliverResponse{
   365  				Type: &orderer.DeliverResponse_Status{
   366  					Status: common.Status_SUCCESS,
   367  				},
   368  			}, nil
   369  		}
   370  		atomic.AddInt32(&attempts, int32(1))
   371  		return &orderer.DeliverResponse{
   372  			Type: &orderer.DeliverResponse_Block{
   373  				Block: &common.Block{
   374  					Header: &common.BlockHeader{
   375  						Number:       0,
   376  						DataHash:     []byte{},
   377  						PreviousHash: []byte{},
   378  					},
   379  					Data: &common.BlockData{
   380  						Data: [][]byte{},
   381  					},
   382  				}},
   383  		}, nil
   384  	}
   385  	mcs := &mockMCS{}
   386  	mcs.On("VerifyBlock", mock.Anything).Return(errors.New("Invalid signature"))
   387  	makeTestCase(uint64(0), mcs, false, rcvr)(t)
   388  }