github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/core/deliverservice/client_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 "crypto/sha256" 21 "errors" 22 "math" 23 "sync" 24 "sync/atomic" 25 "testing" 26 "time" 27 28 "github.com/hyperledger/fabric/core/comm" 29 "github.com/hyperledger/fabric/core/deliverservice/blocksprovider" 30 "github.com/hyperledger/fabric/core/deliverservice/mocks" 31 "github.com/hyperledger/fabric/protos/common" 32 "github.com/hyperledger/fabric/protos/orderer" 33 "github.com/hyperledger/fabric/protos/utils" 34 "github.com/stretchr/testify/assert" 35 "golang.org/x/net/context" 36 "google.golang.org/grpc" 37 ) 38 39 var connNumber = 0 40 41 func newConnection() *grpc.ClientConn { 42 connNumber++ 43 // The balancer is in order to check connection leaks. 44 // When grpc.ClientConn.Close() is called, it calls the balancer's Close() 45 // method which decrements the connNumber 46 cc, _ := grpc.Dial("", grpc.WithInsecure(), grpc.WithBalancer(&balancer{})) 47 return cc 48 } 49 50 type balancer struct { 51 } 52 53 func (*balancer) Start(target string) error { 54 return nil 55 } 56 57 func (*balancer) Up(addr grpc.Address) (down func(error)) { 58 return func(error) {} 59 } 60 61 func (*balancer) Get(ctx context.Context, opts grpc.BalancerGetOptions) (addr grpc.Address, put func(), err error) { 62 return grpc.Address{}, func() {}, errors.New("") 63 } 64 65 func (*balancer) Notify() <-chan []grpc.Address { 66 return nil 67 } 68 69 func (*balancer) Close() error { 70 connNumber-- 71 return nil 72 } 73 74 type blocksDelivererConsumer func(blocksprovider.BlocksDeliverer) error 75 76 var blockDelivererConsumerWithRecv = func(bd blocksprovider.BlocksDeliverer) error { 77 _, err := bd.Recv() 78 return err 79 } 80 81 var blockDelivererConsumerWithSend = func(bd blocksprovider.BlocksDeliverer) error { 82 return bd.Send(&common.Envelope{}) 83 } 84 85 type abc struct { 86 shouldFail bool 87 grpc.ClientStream 88 } 89 90 func (a *abc) Send(*common.Envelope) error { 91 if a.shouldFail { 92 return errors.New("Failed sending") 93 } 94 return nil 95 } 96 97 func (a *abc) Recv() (*orderer.DeliverResponse, error) { 98 if a.shouldFail { 99 return nil, errors.New("Failed Recv") 100 } 101 return &orderer.DeliverResponse{}, nil 102 } 103 104 type abclient struct { 105 shouldFail bool 106 stream *abc 107 } 108 109 func (ac *abclient) Broadcast(ctx context.Context, opts ...grpc.CallOption) (orderer.AtomicBroadcast_BroadcastClient, error) { 110 panic("Not implemented") 111 } 112 113 func (ac *abclient) Deliver(ctx context.Context, opts ...grpc.CallOption) (orderer.AtomicBroadcast_DeliverClient, error) { 114 if ac.stream != nil { 115 return ac.stream, nil 116 } 117 if ac.shouldFail { 118 return nil, errors.New("Failed creating ABC") 119 } 120 return &abc{}, nil 121 } 122 123 type connProducer struct { 124 shouldFail bool 125 connAttempts int 126 connTime time.Duration 127 ordererEndpoint string 128 } 129 130 func (cp *connProducer) realConnection() (*grpc.ClientConn, string, error) { 131 cc, err := grpc.Dial(cp.ordererEndpoint, grpc.WithInsecure()) 132 if err != nil { 133 return nil, "", err 134 } 135 return cc, cp.ordererEndpoint, nil 136 } 137 138 func (cp *connProducer) NewConnection() (*grpc.ClientConn, string, error) { 139 time.Sleep(cp.connTime) 140 cp.connAttempts++ 141 if cp.ordererEndpoint != "" { 142 return cp.realConnection() 143 } 144 if cp.shouldFail { 145 return nil, "", errors.New("Failed connecting") 146 } 147 return newConnection(), "localhost:5611", nil 148 } 149 150 // UpdateEndpoints updates the endpoints of the ConnectionProducer 151 // to be the given endpoints 152 func (cp *connProducer) UpdateEndpoints(endpoints []string) { 153 panic("Not implemented") 154 } 155 156 func TestOrderingServiceConnFailure(t *testing.T) { 157 testOrderingServiceConnFailure(t, blockDelivererConsumerWithRecv) 158 testOrderingServiceConnFailure(t, blockDelivererConsumerWithSend) 159 assert.Equal(t, 0, connNumber) 160 } 161 162 func testOrderingServiceConnFailure(t *testing.T, bdc blocksDelivererConsumer) { 163 // Scenario: Create a broadcast client and call Recv/Send. 164 // Connection to the ordering service should be possible only at second attempt 165 cp := &connProducer{shouldFail: true} 166 clFactory := func(*grpc.ClientConn) orderer.AtomicBroadcastClient { 167 return &abclient{} 168 } 169 setupInvoked := 0 170 setup := func(blocksprovider.BlocksDeliverer) error { 171 setupInvoked++ 172 return nil 173 } 174 backoffStrategy := func(attemptNum int, elapsedTime time.Duration) (time.Duration, bool) { 175 // When called with the second attempt (iteration number 1), 176 // we should be able to connect to the ordering service. 177 // Set connection provider mock shouldFail flag to false 178 // to enable next connection attempt to succeed 179 if attemptNum == 1 { 180 cp.shouldFail = false 181 } 182 183 return time.Duration(0), attemptNum < 2 184 } 185 bc := NewBroadcastClient(cp, clFactory, setup, backoffStrategy) 186 defer bc.Close() 187 err := bdc(bc) 188 assert.NoError(t, err) 189 assert.Equal(t, 2, cp.connAttempts) 190 assert.Equal(t, 1, setupInvoked) 191 } 192 193 func TestOrderingServiceStreamFailure(t *testing.T) { 194 testOrderingServiceStreamFailure(t, blockDelivererConsumerWithRecv) 195 testOrderingServiceStreamFailure(t, blockDelivererConsumerWithSend) 196 assert.Equal(t, 0, connNumber) 197 } 198 199 func testOrderingServiceStreamFailure(t *testing.T, bdc blocksDelivererConsumer) { 200 // Scenario: Create a broadcast client and call Recv/Send. 201 // Connection to the ordering service should be possible at first attempt, 202 // but the atomic broadcast client creation fails at first attempt 203 abcClient := &abclient{shouldFail: true} 204 cp := &connProducer{} 205 clFactory := func(*grpc.ClientConn) orderer.AtomicBroadcastClient { 206 return abcClient 207 } 208 setupInvoked := 0 209 setup := func(blocksprovider.BlocksDeliverer) error { 210 setupInvoked++ 211 return nil 212 } 213 backoffStrategy := func(attemptNum int, elapsedTime time.Duration) (time.Duration, bool) { 214 // When called with the second attempt (iteration number 1), 215 // we should be able to finally call Deliver() by the atomic broadcast client 216 if attemptNum == 1 { 217 abcClient.shouldFail = false 218 } 219 return time.Duration(0), attemptNum < 2 220 } 221 bc := NewBroadcastClient(cp, clFactory, setup, backoffStrategy) 222 defer bc.Close() 223 err := bdc(bc) 224 assert.NoError(t, err) 225 assert.Equal(t, 2, cp.connAttempts) 226 assert.Equal(t, 1, setupInvoked) 227 } 228 229 func TestOrderingServiceSetupFailure(t *testing.T) { 230 testOrderingServiceSetupFailure(t, blockDelivererConsumerWithRecv) 231 testOrderingServiceSetupFailure(t, blockDelivererConsumerWithSend) 232 assert.Equal(t, 0, connNumber) 233 } 234 235 func testOrderingServiceSetupFailure(t *testing.T, bdc blocksDelivererConsumer) { 236 // Scenario: Create a broadcast client and call Recv/Send. 237 // Connection to the ordering service should be possible, 238 // the atomic broadcast client creation succeeds, but invoking the setup function 239 // fails at the first attempt and succeeds at the second one. 240 cp := &connProducer{} 241 clFactory := func(*grpc.ClientConn) orderer.AtomicBroadcastClient { 242 return &abclient{} 243 } 244 setupInvoked := 0 245 setup := func(blocksprovider.BlocksDeliverer) error { 246 setupInvoked++ 247 if setupInvoked == 1 { 248 return errors.New("Setup failed") 249 } 250 return nil 251 } 252 backoffStrategy := func(attemptNum int, elapsedTime time.Duration) (time.Duration, bool) { 253 return time.Duration(0), true 254 } 255 bc := NewBroadcastClient(cp, clFactory, setup, backoffStrategy) 256 defer bc.Close() 257 err := bdc(bc) 258 assert.NoError(t, err) 259 assert.Equal(t, 2, cp.connAttempts) 260 assert.Equal(t, 2, setupInvoked) 261 } 262 263 func TestOrderingServiceFirstOperationFailure(t *testing.T) { 264 testOrderingServiceFirstOperationFailure(t, blockDelivererConsumerWithRecv) 265 testOrderingServiceFirstOperationFailure(t, blockDelivererConsumerWithSend) 266 assert.Equal(t, 0, connNumber) 267 } 268 269 func testOrderingServiceFirstOperationFailure(t *testing.T, bdc blocksDelivererConsumer) { 270 // Scenario: Creation and connection to the ordering service succeeded 271 // but the first Recv/Send failed. 272 // The client should reconnect to the ordering service 273 cp := &connProducer{} 274 abStream := &abc{shouldFail: true} 275 abcClient := &abclient{stream: abStream} 276 clFactory := func(*grpc.ClientConn) orderer.AtomicBroadcastClient { 277 return abcClient 278 } 279 280 setupInvoked := 0 281 setup := func(blocksprovider.BlocksDeliverer) error { 282 // Fix stream success logic at 2nd attempt 283 if setupInvoked == 1 { 284 abStream.shouldFail = false 285 } 286 setupInvoked++ 287 return nil 288 } 289 backoffStrategy := func(attemptNum int, elapsedTime time.Duration) (time.Duration, bool) { 290 return time.Duration(0), true 291 } 292 bc := NewBroadcastClient(cp, clFactory, setup, backoffStrategy) 293 defer bc.Close() 294 err := bdc(bc) 295 assert.NoError(t, err) 296 assert.Equal(t, 2, setupInvoked) 297 assert.Equal(t, cp.connAttempts, 2) 298 } 299 300 func TestOrderingServiceCrashAndRecover(t *testing.T) { 301 testOrderingServiceCrashAndRecover(t, blockDelivererConsumerWithRecv) 302 testOrderingServiceCrashAndRecover(t, blockDelivererConsumerWithSend) 303 assert.Equal(t, 0, connNumber) 304 } 305 306 func testOrderingServiceCrashAndRecover(t *testing.T, bdc blocksDelivererConsumer) { 307 // Scenario: The ordering service is OK at first usage of Recv/Send, 308 // but subsequent calls fails because of connection error. 309 // A reconnect is needed and only then Recv/Send should succeed 310 cp := &connProducer{} 311 abStream := &abc{} 312 abcClient := &abclient{stream: abStream} 313 clFactory := func(*grpc.ClientConn) orderer.AtomicBroadcastClient { 314 return abcClient 315 } 316 317 setupInvoked := 0 318 setup := func(blocksprovider.BlocksDeliverer) error { 319 // Fix stream success logic at 2nd attempt 320 if setupInvoked == 1 { 321 abStream.shouldFail = false 322 } 323 setupInvoked++ 324 return nil 325 } 326 backoffStrategy := func(attemptNum int, elapsedTime time.Duration) (time.Duration, bool) { 327 return time.Duration(0), true 328 } 329 bc := NewBroadcastClient(cp, clFactory, setup, backoffStrategy) 330 defer bc.Close() 331 err := bdc(bc) 332 assert.NoError(t, err) 333 // Now fail the subsequent Recv/Send 334 abStream.shouldFail = true 335 err = bdc(bc) 336 assert.NoError(t, err) 337 assert.Equal(t, 2, cp.connAttempts) 338 assert.Equal(t, 2, setupInvoked) 339 } 340 341 func TestOrderingServicePermanentCrash(t *testing.T) { 342 testOrderingServicePermanentCrash(t, blockDelivererConsumerWithRecv) 343 testOrderingServicePermanentCrash(t, blockDelivererConsumerWithSend) 344 assert.Equal(t, 0, connNumber) 345 } 346 347 func testOrderingServicePermanentCrash(t *testing.T, bdc blocksDelivererConsumer) { 348 // Scenario: The ordering service is OK at first usage of Recv/Send, 349 // but subsequent calls fail because it crashes. 350 // The client should give up after 10 attempts in the second reconnect 351 cp := &connProducer{} 352 abStream := &abc{} 353 abcClient := &abclient{stream: abStream} 354 clFactory := func(*grpc.ClientConn) orderer.AtomicBroadcastClient { 355 return abcClient 356 } 357 358 setupInvoked := 0 359 setup := func(blocksprovider.BlocksDeliverer) error { 360 setupInvoked++ 361 return nil 362 } 363 backoffStrategy := func(attemptNum int, elapsedTime time.Duration) (time.Duration, bool) { 364 return time.Duration(0), attemptNum < 10 365 } 366 bc := NewBroadcastClient(cp, clFactory, setup, backoffStrategy) 367 defer bc.Close() 368 err := bdc(bc) 369 assert.NoError(t, err) 370 // Now fail the subsequent Recv/Send 371 abStream.shouldFail = true 372 cp.shouldFail = true 373 err = bdc(bc) 374 assert.Error(t, err) 375 assert.Equal(t, 10, cp.connAttempts) 376 assert.Equal(t, 1, setupInvoked) 377 } 378 379 func TestLimitedConnAttempts(t *testing.T) { 380 testLimitedConnAttempts(t, blockDelivererConsumerWithRecv) 381 testLimitedConnAttempts(t, blockDelivererConsumerWithSend) 382 assert.Equal(t, 0, connNumber) 383 } 384 385 func testLimitedConnAttempts(t *testing.T, bdc blocksDelivererConsumer) { 386 // Scenario: The ordering service isn't available, and the backoff strategy 387 // specifies an upper bound of 10 connection attempts 388 cp := &connProducer{shouldFail: true} 389 clFactory := func(*grpc.ClientConn) orderer.AtomicBroadcastClient { 390 return &abclient{} 391 } 392 setupInvoked := 0 393 setup := func(blocksprovider.BlocksDeliverer) error { 394 setupInvoked++ 395 return nil 396 } 397 backoffStrategy := func(attemptNum int, elapsedTime time.Duration) (time.Duration, bool) { 398 return time.Duration(0), attemptNum < 10 399 } 400 bc := NewBroadcastClient(cp, clFactory, setup, backoffStrategy) 401 defer bc.Close() 402 err := bdc(bc) 403 assert.Error(t, err) 404 assert.Equal(t, 10, cp.connAttempts) 405 assert.Equal(t, 0, setupInvoked) 406 } 407 408 func TestLimitedTotalConnTimeRcv(t *testing.T) { 409 testLimitedTotalConnTime(t, blockDelivererConsumerWithRecv) 410 assert.Equal(t, 0, connNumber) 411 } 412 413 func TestLimitedTotalConnTimeSnd(t *testing.T) { 414 testLimitedTotalConnTime(t, blockDelivererConsumerWithSend) 415 assert.Equal(t, 0, connNumber) 416 } 417 418 func testLimitedTotalConnTime(t *testing.T, bdc blocksDelivererConsumer) { 419 // Scenario: The ordering service isn't available, and the backoff strategy 420 // specifies an upper bound of 1 second 421 // The first attempt fails, and the second attempt doesn't take place 422 // becuse the creation of connection takes 1.5 seconds. 423 cp := &connProducer{shouldFail: true, connTime: 1500 * time.Millisecond} 424 clFactory := func(*grpc.ClientConn) orderer.AtomicBroadcastClient { 425 return &abclient{} 426 } 427 setupInvoked := 0 428 setup := func(blocksprovider.BlocksDeliverer) error { 429 setupInvoked++ 430 return nil 431 } 432 backoffStrategy := func(attemptNum int, elapsedTime time.Duration) (time.Duration, bool) { 433 return 0, elapsedTime.Nanoseconds() < time.Second.Nanoseconds() 434 } 435 bc := NewBroadcastClient(cp, clFactory, setup, backoffStrategy) 436 defer bc.Close() 437 err := bdc(bc) 438 assert.Error(t, err) 439 assert.Equal(t, 1, cp.connAttempts) 440 assert.Equal(t, 0, setupInvoked) 441 } 442 443 func TestGreenPath(t *testing.T) { 444 testGreenPath(t, blockDelivererConsumerWithRecv) 445 testGreenPath(t, blockDelivererConsumerWithSend) 446 assert.Equal(t, 0, connNumber) 447 } 448 449 func testGreenPath(t *testing.T, bdc blocksDelivererConsumer) { 450 // Scenario: Everything succeeds 451 cp := &connProducer{} 452 abcClient := &abclient{} 453 clFactory := func(*grpc.ClientConn) orderer.AtomicBroadcastClient { 454 return abcClient 455 } 456 457 setupInvoked := 0 458 setup := func(blocksprovider.BlocksDeliverer) error { 459 setupInvoked++ 460 return nil 461 } 462 backoffStrategy := func(attemptNum int, elapsedTime time.Duration) (time.Duration, bool) { 463 return time.Duration(0), attemptNum < 1 464 } 465 bc := NewBroadcastClient(cp, clFactory, setup, backoffStrategy) 466 defer bc.Close() 467 err := bdc(bc) 468 assert.NoError(t, err) 469 assert.Equal(t, 1, cp.connAttempts) 470 assert.Equal(t, 1, setupInvoked) 471 } 472 473 func TestCloseWhileRecv(t *testing.T) { 474 // Scenario: Recv is being called and after a while, 475 // the connection is closed. 476 // The Recv should return immediately in such a case 477 fakeOrderer := mocks.NewOrderer(5611, t) 478 time.Sleep(time.Second) 479 defer fakeOrderer.Shutdown() 480 cp := &connProducer{ordererEndpoint: "localhost:5611"} 481 clFactory := func(conn *grpc.ClientConn) orderer.AtomicBroadcastClient { 482 return orderer.NewAtomicBroadcastClient(conn) 483 } 484 485 setup := func(blocksprovider.BlocksDeliverer) error { 486 return nil 487 } 488 backoffStrategy := func(attemptNum int, elapsedTime time.Duration) (time.Duration, bool) { 489 return 0, true 490 } 491 bc := NewBroadcastClient(cp, clFactory, setup, backoffStrategy) 492 var flag int32 493 time.AfterFunc(time.Second, func() { 494 atomic.StoreInt32(&flag, int32(1)) 495 bc.Close() 496 bc.Close() // Try to close a second time 497 }) 498 resp, err := bc.Recv() 499 // Ensure we returned because bc.Close() was called and not because some other reason 500 assert.Equal(t, int32(1), atomic.LoadInt32(&flag), "Recv returned before bc.Close() was called") 501 assert.Nil(t, resp) 502 assert.Error(t, err) 503 assert.Contains(t, "Client is closing", err.Error()) 504 } 505 506 func TestCloseWhileSleep(t *testing.T) { 507 testCloseWhileSleep(t, blockDelivererConsumerWithRecv) 508 testCloseWhileSleep(t, blockDelivererConsumerWithSend) 509 assert.Equal(t, 0, connNumber) 510 } 511 512 func testCloseWhileSleep(t *testing.T, bdc blocksDelivererConsumer) { 513 // Scenario: Recv/Send is being called while sleeping because 514 // of the backoff policy is programmed to sleep 1000000 seconds 515 // between retries. 516 // The Recv/Send should return pretty soon 517 cp := &connProducer{} 518 abcClient := &abclient{shouldFail: true} 519 clFactory := func(*grpc.ClientConn) orderer.AtomicBroadcastClient { 520 return abcClient 521 } 522 523 setupInvoked := 0 524 setup := func(blocksprovider.BlocksDeliverer) error { 525 setupInvoked++ 526 return nil 527 } 528 var wg sync.WaitGroup 529 wg.Add(1) 530 backoffStrategy := func(attemptNum int, elapsedTime time.Duration) (time.Duration, bool) { 531 if attemptNum == 1 { 532 go func() { 533 time.Sleep(time.Second) 534 wg.Done() 535 }() 536 } 537 return time.Second * 1000000, true 538 } 539 bc := NewBroadcastClient(cp, clFactory, setup, backoffStrategy) 540 go func() { 541 wg.Wait() 542 bc.Close() 543 bc.Close() // Try to close a second time 544 }() 545 err := bdc(bc) 546 assert.Error(t, err) 547 assert.Equal(t, 1, cp.connAttempts) 548 assert.Equal(t, 0, setupInvoked) 549 } 550 551 type signerMock struct { 552 } 553 554 func (s *signerMock) NewSignatureHeader() (*common.SignatureHeader, error) { 555 return &common.SignatureHeader{}, nil 556 } 557 558 func (s *signerMock) Sign(message []byte) ([]byte, error) { 559 hasher := sha256.New() 560 hasher.Write(message) 561 return hasher.Sum(nil), nil 562 } 563 564 func TestProductionUsage(t *testing.T) { 565 defer ensureNoGoroutineLeak(t)() 566 // This test configures the client in a similar fashion as will be 567 // in production, and tests against a live gRPC server. 568 os := mocks.NewOrderer(5612, t) 569 os.SetNextExpectedSeek(5) 570 571 connFact := func(endpoint string) (*grpc.ClientConn, error) { 572 return grpc.Dial(endpoint, grpc.WithInsecure(), grpc.WithBlock()) 573 } 574 prod := comm.NewConnectionProducer(connFact, []string{"localhost:5612"}) 575 clFact := func(cc *grpc.ClientConn) orderer.AtomicBroadcastClient { 576 return orderer.NewAtomicBroadcastClient(cc) 577 } 578 onConnect := func(bd blocksprovider.BlocksDeliverer) error { 579 env, err := utils.CreateSignedEnvelope(common.HeaderType_CONFIG_UPDATE, 580 "TEST", 581 &signerMock{}, newTestSeekInfo(), 0, 0) 582 assert.NoError(t, err) 583 return bd.Send(env) 584 } 585 retryPol := func(attemptNum int, elapsedTime time.Duration) (time.Duration, bool) { 586 return time.Second * 3, attemptNum < 2 587 } 588 cl := NewBroadcastClient(prod, clFact, onConnect, retryPol) 589 go os.SendBlock(5) 590 resp, err := cl.Recv() 591 assert.NoError(t, err) 592 assert.NotNil(t, resp) 593 assert.Equal(t, uint64(5), resp.GetBlock().Header.Number) 594 os.Shutdown() 595 cl.Close() 596 } 597 598 func newTestSeekInfo() *orderer.SeekInfo { 599 return &orderer.SeekInfo{Start: &orderer.SeekPosition{Type: &orderer.SeekPosition_Specified{Specified: &orderer.SeekSpecified{Number: 5}}}, 600 Stop: &orderer.SeekPosition{Type: &orderer.SeekPosition_Specified{Specified: &orderer.SeekSpecified{Number: math.MaxUint64}}}, 601 Behavior: orderer.SeekInfo_BLOCK_UNTIL_READY, 602 } 603 }