github.com/yacovm/fabric@v2.0.0-alpha.0.20191128145320-c5d4087dc723+incompatible/internal/pkg/peer/blocksprovider/blocksprovider_test.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package blocksprovider_test
     8  
     9  import (
    10  	"crypto/x509"
    11  	"fmt"
    12  	"sync"
    13  	"time"
    14  
    15  	. "github.com/onsi/ginkgo"
    16  	. "github.com/onsi/gomega"
    17  
    18  	"github.com/hyperledger/fabric-protos-go/common"
    19  	"github.com/hyperledger/fabric-protos-go/gossip"
    20  	"github.com/hyperledger/fabric-protos-go/orderer"
    21  	"github.com/hyperledger/fabric/common/flogging"
    22  	gossipcommon "github.com/hyperledger/fabric/gossip/common"
    23  	"github.com/hyperledger/fabric/internal/pkg/peer/blocksprovider"
    24  	"github.com/hyperledger/fabric/internal/pkg/peer/blocksprovider/fake"
    25  	"github.com/hyperledger/fabric/internal/pkg/peer/orderers"
    26  	"github.com/hyperledger/fabric/protoutil"
    27  
    28  	"github.com/golang/protobuf/proto"
    29  	"google.golang.org/grpc"
    30  	"google.golang.org/grpc/connectivity"
    31  )
    32  
    33  var _ = Describe("Blocksprovider", func() {
    34  	var (
    35  		d                           *blocksprovider.Deliverer
    36  		ccs                         []*grpc.ClientConn
    37  		fakeDialer                  *fake.Dialer
    38  		fakeGossipServiceAdapter    *fake.GossipServiceAdapter
    39  		fakeOrdererConnectionSource *fake.OrdererConnectionSource
    40  		fakeLedgerInfo              *fake.LedgerInfo
    41  		fakeBlockVerifier           *fake.BlockVerifier
    42  		fakeSigner                  *fake.Signer
    43  		fakeDeliverStreamer         *fake.DeliverStreamer
    44  		fakeDeliverClient           *fake.DeliverClient
    45  		fakeSleeper                 *fake.Sleeper
    46  		doneC                       chan struct{}
    47  		recvStep                    chan struct{}
    48  		endC                        chan struct{}
    49  		mutex                       sync.Mutex
    50  	)
    51  
    52  	BeforeEach(func() {
    53  		doneC = make(chan struct{})
    54  		recvStep = make(chan struct{})
    55  
    56  		// appease the race detector
    57  		recvStep := recvStep
    58  		doneC := doneC
    59  
    60  		fakeDialer = &fake.Dialer{}
    61  		ccs = nil
    62  		fakeDialer.DialStub = func(string, *x509.CertPool) (*grpc.ClientConn, error) {
    63  			mutex.Lock()
    64  			defer mutex.Unlock()
    65  			cc, err := grpc.Dial("", grpc.WithInsecure())
    66  			ccs = append(ccs, cc)
    67  			Expect(err).NotTo(HaveOccurred())
    68  			Expect(cc.GetState()).NotTo(Equal(connectivity.Shutdown))
    69  			return cc, nil
    70  		}
    71  
    72  		fakeGossipServiceAdapter = &fake.GossipServiceAdapter{}
    73  		fakeBlockVerifier = &fake.BlockVerifier{}
    74  		fakeSigner = &fake.Signer{}
    75  
    76  		fakeLedgerInfo = &fake.LedgerInfo{}
    77  		fakeLedgerInfo.LedgerHeightReturns(7, nil)
    78  
    79  		fakeOrdererConnectionSource = &fake.OrdererConnectionSource{}
    80  		fakeOrdererConnectionSource.RandomEndpointReturns(&orderers.Endpoint{
    81  			Address: "orderer-address",
    82  		}, nil)
    83  
    84  		fakeDeliverClient = &fake.DeliverClient{}
    85  		fakeDeliverClient.RecvStub = func() (*orderer.DeliverResponse, error) {
    86  			select {
    87  			case <-recvStep:
    88  				return nil, fmt.Errorf("fake-recv-step-error")
    89  			case <-doneC:
    90  				return nil, nil
    91  			}
    92  		}
    93  
    94  		fakeDeliverClient.CloseSendStub = func() error {
    95  			select {
    96  			case recvStep <- struct{}{}:
    97  			case <-doneC:
    98  			}
    99  			return nil
   100  		}
   101  
   102  		fakeDeliverStreamer = &fake.DeliverStreamer{}
   103  		fakeDeliverStreamer.DeliverReturns(fakeDeliverClient, nil)
   104  
   105  		d = &blocksprovider.Deliverer{
   106  			ChannelID:         "channel-id",
   107  			Gossip:            fakeGossipServiceAdapter,
   108  			Ledger:            fakeLedgerInfo,
   109  			BlockVerifier:     fakeBlockVerifier,
   110  			Dialer:            fakeDialer,
   111  			Orderers:          fakeOrdererConnectionSource,
   112  			DoneC:             doneC,
   113  			Signer:            fakeSigner,
   114  			DeliverStreamer:   fakeDeliverStreamer,
   115  			Logger:            flogging.MustGetLogger("blocksprovider"),
   116  			TLSCertHash:       []byte("tls-cert-hash"),
   117  			MaxRetryDuration:  time.Hour,
   118  			MaxRetryDelay:     10 * time.Second,
   119  			InitialRetryDelay: 100 * time.Millisecond,
   120  		}
   121  
   122  		fakeSleeper = &fake.Sleeper{}
   123  		blocksprovider.SetSleeper(d, fakeSleeper)
   124  	})
   125  
   126  	JustBeforeEach(func() {
   127  		endC = make(chan struct{})
   128  		go func() {
   129  			d.DeliverBlocks()
   130  			close(endC)
   131  		}()
   132  	})
   133  
   134  	AfterEach(func() {
   135  		close(doneC)
   136  		<-endC
   137  	})
   138  
   139  	It("waits patiently for new blocks from the orderer", func() {
   140  		Consistently(endC).ShouldNot(BeClosed())
   141  		mutex.Lock()
   142  		defer mutex.Unlock()
   143  		Expect(ccs[0].GetState()).NotTo(Equal(connectivity.Shutdown))
   144  	})
   145  
   146  	It("checks the ledger height", func() {
   147  		Eventually(fakeLedgerInfo.LedgerHeightCallCount).Should(Equal(1))
   148  	})
   149  
   150  	When("the ledger returns an error", func() {
   151  		BeforeEach(func() {
   152  			fakeLedgerInfo.LedgerHeightReturns(0, fmt.Errorf("fake-ledger-error"))
   153  		})
   154  
   155  		It("exits the loop", func() {
   156  			Eventually(endC).Should(BeClosed())
   157  		})
   158  	})
   159  
   160  	It("signs the seek info request", func() {
   161  		Eventually(fakeSigner.SignCallCount).Should(Equal(1))
   162  		// Note, the signer is used inside a util method
   163  		// which has its own set of tests, so checking the args
   164  		// in this test is unnecessary
   165  	})
   166  
   167  	When("the signer returns an error", func() {
   168  		BeforeEach(func() {
   169  			fakeSigner.SignReturns(nil, fmt.Errorf("fake-signer-error"))
   170  		})
   171  
   172  		It("exits the loop", func() {
   173  			Eventually(endC).Should(BeClosed())
   174  		})
   175  	})
   176  
   177  	It("gets a random endpoint to connect to from the orderer connection source", func() {
   178  		Eventually(fakeOrdererConnectionSource.RandomEndpointCallCount).Should(Equal(1))
   179  	})
   180  
   181  	When("the orderer connection source returns an error", func() {
   182  		BeforeEach(func() {
   183  			fakeOrdererConnectionSource.RandomEndpointReturnsOnCall(0, nil, fmt.Errorf("fake-endpoint-error"))
   184  			fakeOrdererConnectionSource.RandomEndpointReturnsOnCall(1, &orderers.Endpoint{
   185  				Address: "orderer-address",
   186  			}, nil)
   187  		})
   188  
   189  		It("sleeps and retries until a valid endpoint is selected", func() {
   190  			Eventually(fakeOrdererConnectionSource.RandomEndpointCallCount).Should(Equal(2))
   191  			Expect(fakeSleeper.SleepCallCount()).To(Equal(1))
   192  			Expect(fakeSleeper.SleepArgsForCall(0)).To(Equal(100 * time.Millisecond))
   193  		})
   194  	})
   195  
   196  	When("the orderer connect is refreshed", func() {
   197  		BeforeEach(func() {
   198  			refreshedC := make(chan struct{})
   199  			close(refreshedC)
   200  			fakeOrdererConnectionSource.RandomEndpointReturnsOnCall(0, &orderers.Endpoint{
   201  				Address:   "orderer-address",
   202  				Refreshed: refreshedC,
   203  			}, nil)
   204  			fakeOrdererConnectionSource.RandomEndpointReturnsOnCall(1, &orderers.Endpoint{
   205  				Address: "orderer-address",
   206  			}, nil)
   207  		})
   208  
   209  		It("does not sleep, but disconnects and immediately tries to reconnect", func() {
   210  			Eventually(fakeOrdererConnectionSource.RandomEndpointCallCount).Should(Equal(2))
   211  			Expect(fakeSleeper.SleepCallCount()).To(Equal(0))
   212  		})
   213  	})
   214  
   215  	It("dials the random endpoint", func() {
   216  		Eventually(fakeDialer.DialCallCount).Should(Equal(1))
   217  		addr, tlsCerts := fakeDialer.DialArgsForCall(0)
   218  		Expect(addr).To(Equal("orderer-address"))
   219  		Expect(tlsCerts).To(BeNil()) // TODO
   220  	})
   221  
   222  	When("the dialer returns an error", func() {
   223  		BeforeEach(func() {
   224  			fakeDialer.DialReturnsOnCall(0, nil, fmt.Errorf("fake-dial-error"))
   225  			cc, err := grpc.Dial("", grpc.WithInsecure())
   226  			Expect(err).NotTo(HaveOccurred())
   227  			fakeDialer.DialReturnsOnCall(1, cc, nil)
   228  		})
   229  
   230  		It("sleeps and retries until dial is successful", func() {
   231  			Eventually(fakeDialer.DialCallCount).Should(Equal(2))
   232  			Expect(fakeSleeper.SleepCallCount()).To(Equal(1))
   233  			Expect(fakeSleeper.SleepArgsForCall(0)).To(Equal(100 * time.Millisecond))
   234  		})
   235  	})
   236  
   237  	It("constructs a deliver client", func() {
   238  		Eventually(fakeDeliverStreamer.DeliverCallCount).Should(Equal(1))
   239  	})
   240  
   241  	When("the deliver client cannot be created", func() {
   242  		BeforeEach(func() {
   243  			fakeDeliverStreamer.DeliverReturnsOnCall(0, nil, fmt.Errorf("deliver-error"))
   244  			fakeDeliverStreamer.DeliverReturnsOnCall(1, fakeDeliverClient, nil)
   245  		})
   246  
   247  		It("closes the grpc connection, sleeps, and tries again", func() {
   248  			Eventually(fakeDeliverStreamer.DeliverCallCount).Should(Equal(2))
   249  			Expect(fakeSleeper.SleepCallCount()).To(Equal(1))
   250  			Expect(fakeSleeper.SleepArgsForCall(0)).To(Equal(100 * time.Millisecond))
   251  		})
   252  	})
   253  
   254  	When("there are consecutive errors", func() {
   255  		BeforeEach(func() {
   256  			fakeDeliverStreamer.DeliverReturnsOnCall(0, nil, fmt.Errorf("deliver-error"))
   257  			fakeDeliverStreamer.DeliverReturnsOnCall(1, nil, fmt.Errorf("deliver-error"))
   258  			fakeDeliverStreamer.DeliverReturnsOnCall(2, nil, fmt.Errorf("deliver-error"))
   259  			fakeDeliverStreamer.DeliverReturnsOnCall(3, fakeDeliverClient, nil)
   260  		})
   261  
   262  		It("sleeps in an exponential fashion and retries until dial is successful", func() {
   263  			Eventually(fakeDeliverStreamer.DeliverCallCount).Should(Equal(4))
   264  			Expect(fakeSleeper.SleepCallCount()).To(Equal(3))
   265  			Expect(fakeSleeper.SleepArgsForCall(0)).To(Equal(100 * time.Millisecond))
   266  			Expect(fakeSleeper.SleepArgsForCall(1)).To(Equal(120 * time.Millisecond))
   267  			Expect(fakeSleeper.SleepArgsForCall(2)).To(Equal(144 * time.Millisecond))
   268  		})
   269  	})
   270  
   271  	When("the consecutive errors are unbounded", func() {
   272  		BeforeEach(func() {
   273  			fakeDeliverStreamer.DeliverReturns(nil, fmt.Errorf("deliver-error"))
   274  			fakeDeliverStreamer.DeliverReturnsOnCall(500, fakeDeliverClient, nil)
   275  		})
   276  
   277  		It("the sleep time hits the maximum value in an exponential fashion and retries until exceeding the max retry duration", func() {
   278  			Eventually(fakeSleeper.SleepCallCount).Should(Equal(380))
   279  			Expect(fakeSleeper.SleepArgsForCall(25)).To(Equal(9539 * time.Millisecond))
   280  			Expect(fakeSleeper.SleepArgsForCall(26)).To(Equal(10 * time.Second))
   281  			Expect(fakeSleeper.SleepArgsForCall(27)).To(Equal(10 * time.Second))
   282  			Expect(fakeSleeper.SleepArgsForCall(379)).To(Equal(10 * time.Second))
   283  		})
   284  	})
   285  
   286  	When("an error occurs, then a block is successfully delivered", func() {
   287  		BeforeEach(func() {
   288  			fakeDeliverStreamer.DeliverReturnsOnCall(0, nil, fmt.Errorf("deliver-error"))
   289  			fakeDeliverStreamer.DeliverReturnsOnCall(1, fakeDeliverClient, nil)
   290  			fakeDeliverStreamer.DeliverReturnsOnCall(1, nil, fmt.Errorf("deliver-error"))
   291  			fakeDeliverStreamer.DeliverReturnsOnCall(2, nil, fmt.Errorf("deliver-error"))
   292  		})
   293  
   294  		It("sleeps in an exponential fashion and retries until dial is successful", func() {
   295  			Eventually(fakeDeliverStreamer.DeliverCallCount).Should(Equal(4))
   296  			Expect(fakeSleeper.SleepCallCount()).To(Equal(3))
   297  			Expect(fakeSleeper.SleepArgsForCall(0)).To(Equal(100 * time.Millisecond))
   298  			Expect(fakeSleeper.SleepArgsForCall(1)).To(Equal(120 * time.Millisecond))
   299  			Expect(fakeSleeper.SleepArgsForCall(2)).To(Equal(144 * time.Millisecond))
   300  		})
   301  	})
   302  
   303  	It("sends a request to the deliver client for new blocks", func() {
   304  		Eventually(fakeDeliverClient.SendCallCount).Should(Equal(1))
   305  		mutex.Lock()
   306  		defer mutex.Unlock()
   307  		Expect(len(ccs)).To(Equal(1))
   308  	})
   309  
   310  	When("the send fails", func() {
   311  		BeforeEach(func() {
   312  			fakeDeliverClient.SendReturnsOnCall(0, fmt.Errorf("fake-send-error"))
   313  			fakeDeliverClient.SendReturnsOnCall(1, nil)
   314  			fakeDeliverClient.CloseSendStub = nil
   315  		})
   316  
   317  		It("disconnects, sleeps and retries until the send is successful", func() {
   318  			Eventually(fakeDeliverClient.SendCallCount).Should(Equal(2))
   319  			Expect(fakeDeliverClient.CloseSendCallCount()).To(Equal(1))
   320  			Expect(fakeSleeper.SleepCallCount()).To(Equal(1))
   321  			Expect(fakeSleeper.SleepArgsForCall(0)).To(Equal(100 * time.Millisecond))
   322  			mutex.Lock()
   323  			defer mutex.Unlock()
   324  			Expect(len(ccs)).To(Equal(2))
   325  			Eventually(ccs[0].GetState).Should(Equal(connectivity.Shutdown))
   326  		})
   327  	})
   328  
   329  	It("attempts to read blocks from the deliver stream", func() {
   330  		Eventually(fakeDeliverClient.RecvCallCount).Should(Equal(1))
   331  	})
   332  
   333  	When("reading blocks from the deliver stream fails", func() {
   334  		BeforeEach(func() {
   335  			// appease the race detector
   336  			doneC := doneC
   337  			recvStep := recvStep
   338  			fakeDeliverClient := fakeDeliverClient
   339  
   340  			fakeDeliverClient.CloseSendStub = nil
   341  			fakeDeliverClient.RecvStub = func() (*orderer.DeliverResponse, error) {
   342  				if fakeDeliverClient.RecvCallCount() == 1 {
   343  					return nil, fmt.Errorf("fake-recv-error")
   344  				}
   345  				select {
   346  				case <-recvStep:
   347  					return nil, fmt.Errorf("fake-recv-step-error")
   348  				case <-doneC:
   349  					return nil, nil
   350  				}
   351  			}
   352  		})
   353  
   354  		It("disconnects, sleeps, and retries until the recv is successfull", func() {
   355  			Eventually(fakeDeliverClient.RecvCallCount).Should(Equal(2))
   356  			Expect(fakeSleeper.SleepCallCount()).To(Equal(1))
   357  			Expect(fakeSleeper.SleepArgsForCall(0)).To(Equal(100 * time.Millisecond))
   358  		})
   359  	})
   360  
   361  	When("reading blocks from the deliver stream fails and then recovers", func() {
   362  		BeforeEach(func() {
   363  			// appease the race detector
   364  			doneC := doneC
   365  			recvStep := recvStep
   366  			fakeDeliverClient := fakeDeliverClient
   367  
   368  			fakeDeliverClient.CloseSendStub = func() error {
   369  				if fakeDeliverClient.CloseSendCallCount() >= 5 {
   370  					select {
   371  					case <-doneC:
   372  					case recvStep <- struct{}{}:
   373  					}
   374  				}
   375  				return nil
   376  			}
   377  			fakeDeliverClient.RecvStub = func() (*orderer.DeliverResponse, error) {
   378  				switch fakeDeliverClient.RecvCallCount() {
   379  				case 1, 2, 4:
   380  					return nil, fmt.Errorf("fake-recv-error")
   381  				case 3:
   382  					return &orderer.DeliverResponse{
   383  						Type: &orderer.DeliverResponse_Block{
   384  							Block: &common.Block{
   385  								Header: &common.BlockHeader{
   386  									Number: 8,
   387  								},
   388  							},
   389  						},
   390  					}, nil
   391  				default:
   392  					select {
   393  					case <-recvStep:
   394  						return nil, fmt.Errorf("fake-recv-step-error")
   395  					case <-doneC:
   396  						return nil, nil
   397  					}
   398  				}
   399  			}
   400  		})
   401  
   402  		It("disconnects, sleeps, and retries until the recv is successfull and resets the failure count", func() {
   403  			Eventually(fakeDeliverClient.RecvCallCount).Should(Equal(5))
   404  			Expect(fakeSleeper.SleepCallCount()).To(Equal(3))
   405  			Expect(fakeSleeper.SleepArgsForCall(0)).To(Equal(100 * time.Millisecond))
   406  			Expect(fakeSleeper.SleepArgsForCall(1)).To(Equal(120 * time.Millisecond))
   407  			Expect(fakeSleeper.SleepArgsForCall(2)).To(Equal(100 * time.Millisecond))
   408  		})
   409  	})
   410  
   411  	When("the deliver client returns a block", func() {
   412  		BeforeEach(func() {
   413  			// appease the race detector
   414  			doneC := doneC
   415  			recvStep := recvStep
   416  			fakeDeliverClient := fakeDeliverClient
   417  
   418  			fakeDeliverClient.RecvStub = func() (*orderer.DeliverResponse, error) {
   419  				if fakeDeliverClient.RecvCallCount() == 1 {
   420  					return &orderer.DeliverResponse{
   421  						Type: &orderer.DeliverResponse_Block{
   422  							Block: &common.Block{
   423  								Header: &common.BlockHeader{
   424  									Number: 8,
   425  								},
   426  							},
   427  						},
   428  					}, nil
   429  				}
   430  				select {
   431  				case <-recvStep:
   432  					return nil, fmt.Errorf("fake-recv-step-error")
   433  				case <-doneC:
   434  					return nil, nil
   435  				}
   436  			}
   437  		})
   438  
   439  		It("receives the block and loops, not sleeping", func() {
   440  			Eventually(fakeDeliverClient.RecvCallCount).Should(Equal(2))
   441  			Expect(fakeSleeper.SleepCallCount()).To(Equal(0))
   442  		})
   443  
   444  		It("checks the validity of the block", func() {
   445  			Eventually(fakeBlockVerifier.VerifyBlockCallCount).Should(Equal(1))
   446  			channelID, blockNum, block := fakeBlockVerifier.VerifyBlockArgsForCall(0)
   447  			Expect(channelID).To(Equal(gossipcommon.ChannelID("channel-id")))
   448  			Expect(blockNum).To(Equal(uint64(8)))
   449  			Expect(proto.Equal(block, &common.Block{
   450  				Header: &common.BlockHeader{
   451  					Number: 8,
   452  				},
   453  			})).To(BeTrue())
   454  		})
   455  
   456  		When("the block is invalid", func() {
   457  			BeforeEach(func() {
   458  				fakeBlockVerifier.VerifyBlockReturns(fmt.Errorf("fake-verify-error"))
   459  			})
   460  
   461  			It("disconnects, sleeps, and tries again", func() {
   462  				Eventually(fakeSleeper.SleepCallCount).Should(Equal(1))
   463  				Expect(fakeDeliverClient.CloseSendCallCount()).To(Equal(1))
   464  				mutex.Lock()
   465  				defer mutex.Unlock()
   466  				Expect(len(ccs)).To(Equal(2))
   467  			})
   468  		})
   469  
   470  		It("adds the payload to gossip", func() {
   471  			Eventually(fakeGossipServiceAdapter.AddPayloadCallCount).Should(Equal(1))
   472  			channelID, payload := fakeGossipServiceAdapter.AddPayloadArgsForCall(0)
   473  			Expect(channelID).To(Equal("channel-id"))
   474  			Expect(payload).To(Equal(&gossip.Payload{
   475  				Data: protoutil.MarshalOrPanic(&common.Block{
   476  					Header: &common.BlockHeader{
   477  						Number: 8,
   478  					},
   479  				}),
   480  				SeqNum: 8,
   481  			}))
   482  		})
   483  
   484  		When("adding the payload fails", func() {
   485  			BeforeEach(func() {
   486  				fakeGossipServiceAdapter.AddPayloadReturns(fmt.Errorf("payload-error"))
   487  			})
   488  
   489  			It("disconnects, sleeps, and tries again", func() {
   490  				Eventually(fakeSleeper.SleepCallCount).Should(Equal(1))
   491  				Expect(fakeDeliverClient.CloseSendCallCount()).To(Equal(1))
   492  				mutex.Lock()
   493  				defer mutex.Unlock()
   494  				Expect(len(ccs)).To(Equal(2))
   495  			})
   496  		})
   497  
   498  		It("gossips the block to the other peers", func() {
   499  			Eventually(fakeGossipServiceAdapter.GossipCallCount).Should(Equal(1))
   500  			msg := fakeGossipServiceAdapter.GossipArgsForCall(0)
   501  			Expect(msg).To(Equal(&gossip.GossipMessage{
   502  				Nonce:   0,
   503  				Tag:     gossip.GossipMessage_CHAN_AND_ORG,
   504  				Channel: []byte("channel-id"),
   505  				Content: &gossip.GossipMessage_DataMsg{
   506  					DataMsg: &gossip.DataMessage{
   507  						Payload: &gossip.Payload{
   508  							Data: protoutil.MarshalOrPanic(&common.Block{
   509  								Header: &common.BlockHeader{
   510  									Number: 8,
   511  								},
   512  							}),
   513  							SeqNum: 8,
   514  						},
   515  					},
   516  				},
   517  			}))
   518  		})
   519  	})
   520  
   521  	When("the deliver client returns a status", func() {
   522  		var (
   523  			status common.Status
   524  		)
   525  
   526  		BeforeEach(func() {
   527  			// appease the race detector
   528  			doneC := doneC
   529  			recvStep := recvStep
   530  			fakeDeliverClient := fakeDeliverClient
   531  
   532  			status = common.Status_SUCCESS
   533  			fakeDeliverClient.RecvStub = func() (*orderer.DeliverResponse, error) {
   534  				if fakeDeliverClient.RecvCallCount() == 1 {
   535  					return &orderer.DeliverResponse{
   536  						Type: &orderer.DeliverResponse_Status{
   537  							Status: status,
   538  						},
   539  					}, nil
   540  				}
   541  				select {
   542  				case <-recvStep:
   543  					return nil, fmt.Errorf("fake-recv-step-error")
   544  				case <-doneC:
   545  					return nil, nil
   546  				}
   547  			}
   548  		})
   549  
   550  		It("disconnects with an error, and sleeps because the block request is infinite and should never complete", func() {
   551  			Eventually(fakeSleeper.SleepCallCount).Should(Equal(1))
   552  		})
   553  
   554  		When("the status is not successful", func() {
   555  			BeforeEach(func() {
   556  				status = common.Status_FORBIDDEN
   557  			})
   558  
   559  			It("still disconnects with an error", func() {
   560  				Eventually(fakeSleeper.SleepCallCount).Should(Equal(1))
   561  			})
   562  		})
   563  	})
   564  })