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 }