github.com/myafeier/fabric@v1.0.1-0.20170722181825-3a4b1f2bce86/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, config grpc.BalancerConfig) 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 go func() { 494 for fakeOrderer.ConnCount() == 0 { 495 time.Sleep(time.Second) 496 } 497 atomic.StoreInt32(&flag, int32(1)) 498 bc.Close() 499 bc.Close() // Try to close a second time 500 }() 501 resp, err := bc.Recv() 502 // Ensure we returned because bc.Close() was called and not because some other reason 503 assert.Equal(t, int32(1), atomic.LoadInt32(&flag), "Recv returned before bc.Close() was called") 504 assert.Nil(t, resp) 505 assert.Error(t, err) 506 assert.Contains(t, "Client is closing", err.Error()) 507 } 508 509 func TestCloseWhileSleep(t *testing.T) { 510 testCloseWhileSleep(t, blockDelivererConsumerWithRecv) 511 testCloseWhileSleep(t, blockDelivererConsumerWithSend) 512 assert.Equal(t, 0, connNumber) 513 } 514 515 func testCloseWhileSleep(t *testing.T, bdc blocksDelivererConsumer) { 516 // Scenario: Recv/Send is being called while sleeping because 517 // of the backoff policy is programmed to sleep 1000000 seconds 518 // between retries. 519 // The Recv/Send should return pretty soon 520 cp := &connProducer{} 521 abcClient := &abclient{shouldFail: true} 522 clFactory := func(*grpc.ClientConn) orderer.AtomicBroadcastClient { 523 return abcClient 524 } 525 526 setupInvoked := 0 527 setup := func(blocksprovider.BlocksDeliverer) error { 528 setupInvoked++ 529 return nil 530 } 531 var wg sync.WaitGroup 532 wg.Add(1) 533 backoffStrategy := func(attemptNum int, elapsedTime time.Duration) (time.Duration, bool) { 534 if attemptNum == 1 { 535 go func() { 536 time.Sleep(time.Second) 537 wg.Done() 538 }() 539 } 540 return time.Second * 1000000, true 541 } 542 bc := NewBroadcastClient(cp, clFactory, setup, backoffStrategy) 543 go func() { 544 wg.Wait() 545 bc.Close() 546 bc.Close() // Try to close a second time 547 }() 548 err := bdc(bc) 549 assert.Error(t, err) 550 assert.Equal(t, 1, cp.connAttempts) 551 assert.Equal(t, 0, setupInvoked) 552 } 553 554 type signerMock struct { 555 } 556 557 func (s *signerMock) NewSignatureHeader() (*common.SignatureHeader, error) { 558 return &common.SignatureHeader{}, nil 559 } 560 561 func (s *signerMock) Sign(message []byte) ([]byte, error) { 562 hasher := sha256.New() 563 hasher.Write(message) 564 return hasher.Sum(nil), nil 565 } 566 567 func TestProductionUsage(t *testing.T) { 568 defer ensureNoGoroutineLeak(t)() 569 // This test configures the client in a similar fashion as will be 570 // in production, and tests against a live gRPC server. 571 os := mocks.NewOrderer(5612, t) 572 os.SetNextExpectedSeek(5) 573 574 connFact := func(endpoint string) (*grpc.ClientConn, error) { 575 return grpc.Dial(endpoint, grpc.WithInsecure(), grpc.WithBlock()) 576 } 577 prod := comm.NewConnectionProducer(connFact, []string{"localhost:5612"}) 578 clFact := func(cc *grpc.ClientConn) orderer.AtomicBroadcastClient { 579 return orderer.NewAtomicBroadcastClient(cc) 580 } 581 onConnect := func(bd blocksprovider.BlocksDeliverer) error { 582 env, err := utils.CreateSignedEnvelope(common.HeaderType_CONFIG_UPDATE, 583 "TEST", 584 &signerMock{}, newTestSeekInfo(), 0, 0) 585 assert.NoError(t, err) 586 return bd.Send(env) 587 } 588 retryPol := func(attemptNum int, elapsedTime time.Duration) (time.Duration, bool) { 589 return time.Second * 3, attemptNum < 2 590 } 591 cl := NewBroadcastClient(prod, clFact, onConnect, retryPol) 592 go os.SendBlock(5) 593 resp, err := cl.Recv() 594 assert.NoError(t, err) 595 assert.NotNil(t, resp) 596 assert.Equal(t, uint64(5), resp.GetBlock().Header.Number) 597 os.Shutdown() 598 cl.Close() 599 } 600 601 func TestDisconnect(t *testing.T) { 602 // Scenario: spawn 2 ordering service instances 603 // and a client. 604 // Have the client try to Recv() from one of them, 605 // and disconnect the client until it tries connecting 606 // to the other instance. 607 608 defer ensureNoGoroutineLeak(t)() 609 os1 := mocks.NewOrderer(5613, t) 610 os1.SetNextExpectedSeek(5) 611 os2 := mocks.NewOrderer(5614, t) 612 os2.SetNextExpectedSeek(5) 613 614 defer os1.Shutdown() 615 defer os2.Shutdown() 616 617 waitForConnectionToSomeOSN := func() { 618 for { 619 if os1.ConnCount() > 0 || os2.ConnCount() > 0 { 620 return 621 } 622 time.Sleep(time.Millisecond * 100) 623 } 624 } 625 626 connFact := func(endpoint string) (*grpc.ClientConn, error) { 627 return grpc.Dial(endpoint, grpc.WithInsecure(), grpc.WithBlock()) 628 } 629 prod := comm.NewConnectionProducer(connFact, []string{"localhost:5613", "localhost:5614"}) 630 clFact := func(cc *grpc.ClientConn) orderer.AtomicBroadcastClient { 631 return orderer.NewAtomicBroadcastClient(cc) 632 } 633 onConnect := func(bd blocksprovider.BlocksDeliverer) error { 634 return nil 635 } 636 retryPol := func(attemptNum int, elapsedTime time.Duration) (time.Duration, bool) { 637 return time.Millisecond * 10, attemptNum < 100 638 } 639 640 cl := NewBroadcastClient(prod, clFact, onConnect, retryPol) 641 stopChan := make(chan struct{}) 642 go func() { 643 cl.Recv() 644 stopChan <- struct{}{} 645 }() 646 waitForConnectionToSomeOSN() 647 cl.Disconnect() 648 649 i := 0 650 for (os1.ConnCount() == 0 || os2.ConnCount() == 0) && i < 100 { 651 t.Log("Attempt", i, "os1ConnCount()=", os1.ConnCount(), "os2ConnCount()=", os2.ConnCount()) 652 i++ 653 if i == 100 { 654 assert.Fail(t, "Didn't switch to other instance after many attempts") 655 } 656 cl.Disconnect() 657 time.Sleep(time.Millisecond * 500) 658 } 659 cl.Close() 660 select { 661 case <-stopChan: 662 case <-time.After(time.Second * 20): 663 assert.Fail(t, "Didn't stop within a timely manner") 664 } 665 } 666 667 func newTestSeekInfo() *orderer.SeekInfo { 668 return &orderer.SeekInfo{Start: &orderer.SeekPosition{Type: &orderer.SeekPosition_Specified{Specified: &orderer.SeekSpecified{Number: 5}}}, 669 Stop: &orderer.SeekPosition{Type: &orderer.SeekPosition_Specified{Specified: &orderer.SeekSpecified{Number: math.MaxUint64}}}, 670 Behavior: orderer.SeekInfo_BLOCK_UNTIL_READY, 671 } 672 }