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 }