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 }