github.com/pvitto98/fabric@v2.1.1+incompatible/common/deliver/deliver_test.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package deliver_test
     8  
     9  import (
    10  	"context"
    11  	"crypto/x509"
    12  	"encoding/pem"
    13  	"io"
    14  	"time"
    15  
    16  	"github.com/golang/protobuf/proto"
    17  	"github.com/golang/protobuf/ptypes/timestamp"
    18  	cb "github.com/hyperledger/fabric-protos-go/common"
    19  	"github.com/hyperledger/fabric-protos-go/msp"
    20  	ab "github.com/hyperledger/fabric-protos-go/orderer"
    21  	"github.com/hyperledger/fabric/common/crypto/tlsgen"
    22  	"github.com/hyperledger/fabric/common/deliver"
    23  	"github.com/hyperledger/fabric/common/deliver/mock"
    24  	"github.com/hyperledger/fabric/common/ledger/blockledger"
    25  	"github.com/hyperledger/fabric/common/metrics/disabled"
    26  	"github.com/hyperledger/fabric/common/metrics/metricsfakes"
    27  	"github.com/hyperledger/fabric/common/util"
    28  	"github.com/hyperledger/fabric/protoutil"
    29  	. "github.com/onsi/ginkgo"
    30  	. "github.com/onsi/gomega"
    31  	"github.com/pkg/errors"
    32  )
    33  
    34  var (
    35  	seekOldest = &ab.SeekPosition{
    36  		Type: &ab.SeekPosition_Oldest{Oldest: &ab.SeekOldest{}},
    37  	}
    38  
    39  	seekNewest = &ab.SeekPosition{
    40  		Type: &ab.SeekPosition_Newest{Newest: &ab.SeekNewest{}},
    41  	}
    42  )
    43  
    44  var _ = Describe("Deliver", func() {
    45  	Describe("NewHandler", func() {
    46  		var fakeChainManager *mock.ChainManager
    47  		var cert *x509.Certificate
    48  		var certBytes []byte
    49  		var serializedIdentity []byte
    50  		BeforeEach(func() {
    51  			fakeChainManager = &mock.ChainManager{}
    52  
    53  			ca, err := tlsgen.NewCA()
    54  			Expect(err).NotTo(HaveOccurred())
    55  
    56  			certBytes = ca.CertBytes()
    57  
    58  			der, _ := pem.Decode(ca.CertBytes())
    59  			cert, err = x509.ParseCertificate(der.Bytes)
    60  			Expect(err).NotTo(HaveOccurred())
    61  
    62  			serializedIdentity = protoutil.MarshalOrPanic(&msp.SerializedIdentity{IdBytes: certBytes})
    63  		})
    64  
    65  		It("returns a new handler", func() {
    66  			handler := deliver.NewHandler(
    67  				fakeChainManager,
    68  				time.Second,
    69  				false,
    70  				deliver.NewMetrics(&disabled.Provider{}),
    71  				false)
    72  			Expect(handler).NotTo(BeNil())
    73  
    74  			Expect(handler.ChainManager).To(Equal(fakeChainManager))
    75  			Expect(handler.TimeWindow).To(Equal(time.Second))
    76  			// binding inspector is func; unable to easily validate
    77  			Expect(handler.BindingInspector).NotTo(BeNil())
    78  		})
    79  
    80  		Context("Handler is initialized with expiration checks", func() {
    81  			It("Returns exactly what is found in the certificate", func() {
    82  				handler := deliver.NewHandler(
    83  					fakeChainManager,
    84  					time.Second,
    85  					false,
    86  					deliver.NewMetrics(&disabled.Provider{}),
    87  					false)
    88  
    89  				Expect(handler.ExpirationCheckFunc(serializedIdentity)).To(Equal(cert.NotAfter))
    90  			})
    91  		})
    92  
    93  		Context("Handler is initialized without expiration checks", func() {
    94  			It("Doesn't parse the NotAfter time of the certificate", func() {
    95  				handler := deliver.NewHandler(
    96  					fakeChainManager,
    97  					time.Second,
    98  					false,
    99  					deliver.NewMetrics(&disabled.Provider{}),
   100  					true)
   101  
   102  				Expect(handler.ExpirationCheckFunc(serializedIdentity)).NotTo(Equal(cert.NotAfter))
   103  			})
   104  		})
   105  	})
   106  
   107  	Describe("ExtractChannelHeaderCertHash", func() {
   108  		It("extracts the TLS certificate hash from a channel header", func() {
   109  			chdr := &cb.ChannelHeader{TlsCertHash: []byte("tls-cert")}
   110  
   111  			result := deliver.ExtractChannelHeaderCertHash(chdr)
   112  			Expect(result).To(Equal([]byte("tls-cert")))
   113  		})
   114  
   115  		Context("when the message is not a channel header", func() {
   116  			It("returns nil", func() {
   117  				result := deliver.ExtractChannelHeaderCertHash(&cb.Envelope{})
   118  				Expect(result).To(BeNil())
   119  			})
   120  		})
   121  
   122  		Context("when the message is nil", func() {
   123  			It("returns nil", func() {
   124  				var ch *cb.ChannelHeader
   125  				result := deliver.ExtractChannelHeaderCertHash(ch)
   126  				Expect(result).To(BeNil())
   127  			})
   128  		})
   129  	})
   130  
   131  	Describe("Handle", func() {
   132  		var (
   133  			errCh                 chan struct{}
   134  			fakeChain             *mock.Chain
   135  			fakeBlockReader       *mock.BlockReader
   136  			fakeBlockIterator     *mock.BlockIterator
   137  			fakeChainManager      *mock.ChainManager
   138  			fakePolicyChecker     *mock.PolicyChecker
   139  			fakeReceiver          *mock.Receiver
   140  			fakeResponseSender    *mock.ResponseSender
   141  			fakeInspector         *mock.Inspector
   142  			fakeStreamsOpened     *metricsfakes.Counter
   143  			fakeStreamsClosed     *metricsfakes.Counter
   144  			fakeRequestsReceived  *metricsfakes.Counter
   145  			fakeRequestsCompleted *metricsfakes.Counter
   146  			fakeBlocksSent        *metricsfakes.Counter
   147  
   148  			handler *deliver.Handler
   149  			server  *deliver.Server
   150  
   151  			channelHeader *cb.ChannelHeader
   152  			seekInfo      *ab.SeekInfo
   153  			ts            *timestamp.Timestamp
   154  
   155  			channelHeaderPayload []byte
   156  			seekInfoPayload      []byte
   157  			envelope             *cb.Envelope
   158  		)
   159  
   160  		BeforeEach(func() {
   161  			errCh = make(chan struct{})
   162  			fakeChain = &mock.Chain{}
   163  			fakeChain.ErroredReturns(errCh)
   164  
   165  			block := &cb.Block{
   166  				Header: &cb.BlockHeader{Number: 100},
   167  			}
   168  			fakeBlockIterator = &mock.BlockIterator{}
   169  			fakeBlockIterator.NextReturns(block, cb.Status_SUCCESS)
   170  
   171  			fakeBlockReader = &mock.BlockReader{}
   172  			fakeBlockReader.HeightReturns(1000)
   173  			fakeBlockReader.IteratorReturns(fakeBlockIterator, 100)
   174  			fakeChain.ReaderReturns(fakeBlockReader)
   175  
   176  			fakeChainManager = &mock.ChainManager{}
   177  			fakeChainManager.GetChainReturns(fakeChain)
   178  
   179  			fakePolicyChecker = &mock.PolicyChecker{}
   180  			fakeReceiver = &mock.Receiver{}
   181  			fakeResponseSender = &mock.ResponseSender{}
   182  			fakeResponseSender.DataTypeReturns("block")
   183  
   184  			fakeInspector = &mock.Inspector{}
   185  
   186  			fakeStreamsOpened = &metricsfakes.Counter{}
   187  			fakeStreamsOpened.WithReturns(fakeStreamsOpened)
   188  			fakeStreamsClosed = &metricsfakes.Counter{}
   189  			fakeStreamsClosed.WithReturns(fakeStreamsClosed)
   190  			fakeRequestsReceived = &metricsfakes.Counter{}
   191  			fakeRequestsReceived.WithReturns(fakeRequestsReceived)
   192  			fakeRequestsCompleted = &metricsfakes.Counter{}
   193  			fakeRequestsCompleted.WithReturns(fakeRequestsCompleted)
   194  			fakeBlocksSent = &metricsfakes.Counter{}
   195  			fakeBlocksSent.WithReturns(fakeBlocksSent)
   196  
   197  			deliverMetrics := &deliver.Metrics{
   198  				StreamsOpened:     fakeStreamsOpened,
   199  				StreamsClosed:     fakeStreamsClosed,
   200  				RequestsReceived:  fakeRequestsReceived,
   201  				RequestsCompleted: fakeRequestsCompleted,
   202  				BlocksSent:        fakeBlocksSent,
   203  			}
   204  
   205  			handler = &deliver.Handler{
   206  				ChainManager:     fakeChainManager,
   207  				TimeWindow:       time.Second,
   208  				BindingInspector: fakeInspector,
   209  				Metrics:          deliverMetrics,
   210  				ExpirationCheckFunc: func([]byte) time.Time {
   211  					return time.Time{}
   212  				},
   213  			}
   214  			server = &deliver.Server{
   215  				Receiver:       fakeReceiver,
   216  				PolicyChecker:  fakePolicyChecker,
   217  				ResponseSender: fakeResponseSender,
   218  			}
   219  
   220  			ts = util.CreateUtcTimestamp()
   221  			channelHeader = &cb.ChannelHeader{
   222  				ChannelId: "chain-id",
   223  				Timestamp: ts,
   224  			}
   225  			seekInfo = &ab.SeekInfo{
   226  				Start: &ab.SeekPosition{
   227  					Type: &ab.SeekPosition_Specified{
   228  						Specified: &ab.SeekSpecified{Number: 100},
   229  					},
   230  				},
   231  				Stop: &ab.SeekPosition{
   232  					Type: &ab.SeekPosition_Specified{
   233  						Specified: &ab.SeekSpecified{Number: 100},
   234  					},
   235  				},
   236  			}
   237  
   238  			channelHeaderPayload = nil
   239  			seekInfoPayload = nil
   240  
   241  			envelope = &cb.Envelope{}
   242  			fakeReceiver.RecvReturns(envelope, nil)
   243  			fakeReceiver.RecvReturnsOnCall(1, nil, io.EOF)
   244  		})
   245  
   246  		JustBeforeEach(func() {
   247  			if channelHeaderPayload == nil {
   248  				channelHeaderPayload = protoutil.MarshalOrPanic(channelHeader)
   249  			}
   250  			if seekInfoPayload == nil {
   251  				seekInfoPayload = protoutil.MarshalOrPanic(seekInfo)
   252  			}
   253  			if envelope.Payload == nil {
   254  				payload := &cb.Payload{
   255  					Header: &cb.Header{
   256  						ChannelHeader:   channelHeaderPayload,
   257  						SignatureHeader: protoutil.MarshalOrPanic(&cb.SignatureHeader{}),
   258  					},
   259  					Data: seekInfoPayload,
   260  				}
   261  				envelope.Payload = protoutil.MarshalOrPanic(payload)
   262  			}
   263  		})
   264  
   265  		It("records streams opened before streams closed", func() {
   266  			fakeStreamsOpened.AddStub = func(delta float64) {
   267  				defer GinkgoRecover()
   268  				Expect(fakeStreamsClosed.AddCallCount()).To(Equal(0))
   269  			}
   270  
   271  			err := handler.Handle(context.Background(), server)
   272  			Expect(err).NotTo(HaveOccurred())
   273  
   274  			Expect(fakeStreamsOpened.AddCallCount()).To(Equal(1))
   275  			Expect(fakeStreamsOpened.AddArgsForCall(0)).To(BeNumerically("~", 1.0))
   276  		})
   277  
   278  		It("records streams closed after streams opened", func() {
   279  			fakeStreamsClosed.AddStub = func(delta float64) {
   280  				defer GinkgoRecover()
   281  				Expect(fakeStreamsOpened.AddCallCount()).To(Equal(1))
   282  			}
   283  
   284  			err := handler.Handle(context.Background(), server)
   285  			Expect(err).NotTo(HaveOccurred())
   286  
   287  			Expect(fakeStreamsClosed.AddCallCount()).To(Equal(1))
   288  			Expect(fakeStreamsClosed.AddArgsForCall(0)).To(BeNumerically("~", 1.0))
   289  		})
   290  
   291  		It("validates the channel header with the binding inspector", func() {
   292  			err := handler.Handle(context.Background(), server)
   293  			Expect(err).NotTo(HaveOccurred())
   294  
   295  			Expect(fakeInspector.InspectCallCount()).To(Equal(1))
   296  			ctx, header := fakeInspector.InspectArgsForCall(0)
   297  			Expect(ctx).To(Equal(context.Background()))
   298  			Expect(proto.Equal(header, channelHeader)).To(BeTrue())
   299  		})
   300  
   301  		Context("when channel header validation fails", func() {
   302  			BeforeEach(func() {
   303  				fakeInspector.InspectReturns(errors.New("bad-header-thingy"))
   304  			})
   305  
   306  			It("sends a bad request message", func() {
   307  				err := handler.Handle(context.Background(), server)
   308  				Expect(err).NotTo(HaveOccurred())
   309  
   310  				Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
   311  				resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
   312  				Expect(resp).To(Equal(cb.Status_BAD_REQUEST))
   313  			})
   314  		})
   315  
   316  		It("gets the chain from the chain manager", func() {
   317  			err := handler.Handle(context.Background(), server)
   318  			Expect(err).NotTo(HaveOccurred())
   319  
   320  			Expect(fakeChainManager.GetChainCallCount()).To(Equal(1))
   321  			chid := fakeChainManager.GetChainArgsForCall(0)
   322  			Expect(chid).To(Equal("chain-id"))
   323  		})
   324  
   325  		It("receives messages until io.EOF is returned", func() {
   326  			err := handler.Handle(context.Background(), server)
   327  			Expect(err).NotTo(HaveOccurred())
   328  
   329  			Expect(fakeReceiver.RecvCallCount()).To(Equal(2))
   330  		})
   331  
   332  		It("evaluates access control", func() {
   333  			err := handler.Handle(context.Background(), server)
   334  			Expect(err).NotTo(HaveOccurred())
   335  
   336  			Expect(fakePolicyChecker.CheckPolicyCallCount()).To(BeNumerically(">=", 1))
   337  			e, cid := fakePolicyChecker.CheckPolicyArgsForCall(0)
   338  			Expect(proto.Equal(e, envelope)).To(BeTrue())
   339  			Expect(cid).To(Equal("chain-id"))
   340  		})
   341  
   342  		It("gets a block iterator from the starting block", func() {
   343  			err := handler.Handle(context.Background(), server)
   344  			Expect(err).NotTo(HaveOccurred())
   345  
   346  			Expect(fakeBlockReader.IteratorCallCount()).To(Equal(1))
   347  			startPosition := fakeBlockReader.IteratorArgsForCall(0)
   348  			Expect(proto.Equal(startPosition, seekInfo.Start)).To(BeTrue())
   349  		})
   350  
   351  		Context("when multiple blocks are requested", func() {
   352  			BeforeEach(func() {
   353  				fakeBlockIterator.NextStub = func() (*cb.Block, cb.Status) {
   354  					blk := &cb.Block{
   355  						Header: &cb.BlockHeader{Number: 994 + uint64(fakeBlockIterator.NextCallCount())},
   356  					}
   357  					return blk, cb.Status_SUCCESS
   358  				}
   359  				seekInfo = &ab.SeekInfo{
   360  					Start: &ab.SeekPosition{
   361  						Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 995}},
   362  					},
   363  					Stop: seekNewest,
   364  				}
   365  			})
   366  
   367  			It("sends all requested blocks", func() {
   368  				err := handler.Handle(context.Background(), server)
   369  				Expect(err).NotTo(HaveOccurred())
   370  
   371  				Expect(fakeResponseSender.SendBlockResponseCallCount()).To(Equal(5))
   372  				for i := 0; i < 5; i++ {
   373  					b, _, _, _ := fakeResponseSender.SendBlockResponseArgsForCall(i)
   374  					Expect(b).To(Equal(&cb.Block{
   375  						Header: &cb.BlockHeader{Number: 995 + uint64(i)},
   376  					}))
   377  				}
   378  			})
   379  
   380  			It("records requests received, blocks sent, and requests completed", func() {
   381  				err := handler.Handle(context.Background(), server)
   382  				Expect(err).NotTo(HaveOccurred())
   383  
   384  				Expect(fakeRequestsReceived.AddCallCount()).To(Equal(1))
   385  				Expect(fakeRequestsReceived.AddArgsForCall(0)).To(BeNumerically("~", 1.0))
   386  				Expect(fakeRequestsReceived.WithCallCount()).To(Equal(1))
   387  				labelValues := fakeRequestsReceived.WithArgsForCall(0)
   388  				Expect(labelValues).To(Equal([]string{
   389  					"channel", "chain-id",
   390  					"filtered", "false",
   391  					"data_type", "block",
   392  				}))
   393  
   394  				Expect(fakeBlocksSent.AddCallCount()).To(Equal(5))
   395  				Expect(fakeBlocksSent.WithCallCount()).To(Equal(5))
   396  				for i := 0; i < 5; i++ {
   397  					Expect(fakeBlocksSent.AddArgsForCall(i)).To(BeNumerically("~", 1.0))
   398  					labelValues := fakeBlocksSent.WithArgsForCall(i)
   399  					Expect(labelValues).To(Equal([]string{
   400  						"channel", "chain-id",
   401  						"filtered", "false",
   402  						"data_type", "block",
   403  					}))
   404  				}
   405  
   406  				Expect(fakeRequestsCompleted.AddCallCount()).To(Equal(1))
   407  				Expect(fakeRequestsCompleted.AddArgsForCall(0)).To(BeNumerically("~", 1.0))
   408  				Expect(fakeRequestsCompleted.WithCallCount()).To(Equal(1))
   409  				labelValues = fakeRequestsCompleted.WithArgsForCall(0)
   410  				Expect(labelValues).To(Equal([]string{
   411  					"channel", "chain-id",
   412  					"filtered", "false",
   413  					"data_type", "block",
   414  					"success", "true",
   415  				}))
   416  			})
   417  		})
   418  
   419  		Context("when seek info is configured to stop at the oldest block", func() {
   420  			BeforeEach(func() {
   421  				seekInfo = &ab.SeekInfo{Start: &ab.SeekPosition{}, Stop: seekOldest}
   422  			})
   423  
   424  			It("sends only the first block returned by the iterator", func() {
   425  				err := handler.Handle(context.Background(), server)
   426  				Expect(err).NotTo(HaveOccurred())
   427  
   428  				Expect(fakeBlockReader.IteratorCallCount()).To(Equal(1))
   429  				start := fakeBlockReader.IteratorArgsForCall(0)
   430  				Expect(start).To(Equal(&ab.SeekPosition{}))
   431  				Expect(fakeBlockIterator.NextCallCount()).To(Equal(1))
   432  
   433  				Expect(fakeResponseSender.SendBlockResponseCallCount()).To(Equal(1))
   434  				b, _, _, _ := fakeResponseSender.SendBlockResponseArgsForCall(0)
   435  				Expect(b).To(Equal(&cb.Block{
   436  					Header: &cb.BlockHeader{Number: 100},
   437  				}))
   438  			})
   439  		})
   440  
   441  		Context("when seek info is configured to stop at the newest block", func() {
   442  			BeforeEach(func() {
   443  				seekInfo = &ab.SeekInfo{Start: &ab.SeekPosition{}, Stop: seekNewest}
   444  
   445  				fakeBlockReader.HeightReturns(3)
   446  				fakeBlockIterator.NextStub = func() (*cb.Block, cb.Status) {
   447  					blk := &cb.Block{
   448  						Header: &cb.BlockHeader{Number: uint64(fakeBlockIterator.NextCallCount())},
   449  					}
   450  					return blk, cb.Status_SUCCESS
   451  				}
   452  			})
   453  
   454  			It("sends blocks until the iterator reaches the reader height", func() {
   455  				err := handler.Handle(context.Background(), server)
   456  				Expect(err).NotTo(HaveOccurred())
   457  
   458  				Expect(fakeBlockReader.IteratorCallCount()).To(Equal(1))
   459  				start := fakeBlockReader.IteratorArgsForCall(0)
   460  				Expect(start).To(Equal(&ab.SeekPosition{}))
   461  
   462  				Expect(fakeBlockIterator.NextCallCount()).To(Equal(2))
   463  				Expect(fakeResponseSender.SendBlockResponseCallCount()).To(Equal(2))
   464  				for i := 0; i < fakeResponseSender.SendBlockResponseCallCount(); i++ {
   465  					b, _, _, _ := fakeResponseSender.SendBlockResponseArgsForCall(i)
   466  					Expect(b).To(Equal(&cb.Block{
   467  						Header: &cb.BlockHeader{Number: uint64(i + 1)},
   468  					}))
   469  				}
   470  			})
   471  		})
   472  
   473  		Context("when seek info is configured to send just the newest block and a new block is committed to the ledger after the iterator is acquired", func() {
   474  			BeforeEach(func() {
   475  				seekInfo = &ab.SeekInfo{Start: seekNewest, Stop: seekNewest}
   476  
   477  				fakeBlockReader.IteratorReturns(fakeBlockIterator, 0)
   478  				fakeBlockReader.HeightReturns(2)
   479  				fakeChain.ReaderReturns(fakeBlockReader)
   480  				fakeBlockIterator.NextStub = func() (*cb.Block, cb.Status) {
   481  					blk := &cb.Block{
   482  						Header: &cb.BlockHeader{Number: uint64(fakeBlockIterator.NextCallCount() - 1)},
   483  					}
   484  					return blk, cb.Status_SUCCESS
   485  				}
   486  			})
   487  
   488  			It("sends only the newest block at the time the iterator was acquired", func() {
   489  				err := handler.Handle(context.Background(), server)
   490  				Expect(err).NotTo(HaveOccurred())
   491  
   492  				Expect(fakeBlockReader.IteratorCallCount()).To(Equal(1))
   493  				Expect(fakeBlockIterator.NextCallCount()).To(Equal(1))
   494  				Expect(fakeResponseSender.SendBlockResponseCallCount()).To(Equal(1))
   495  				for i := 0; i < fakeResponseSender.SendBlockResponseCallCount(); i++ {
   496  					b, _, _, _ := fakeResponseSender.SendBlockResponseArgsForCall(i)
   497  					Expect(b).To(Equal(&cb.Block{
   498  						Header: &cb.BlockHeader{Number: uint64(i)},
   499  					}))
   500  				}
   501  			})
   502  		})
   503  
   504  		Context("when filtered blocks are requested", func() {
   505  			var fakeResponseSender *mock.FilteredResponseSender
   506  
   507  			BeforeEach(func() {
   508  				fakeResponseSender = &mock.FilteredResponseSender{}
   509  				fakeResponseSender.IsFilteredReturns(true)
   510  				fakeResponseSender.DataTypeReturns("filtered_block")
   511  				server.ResponseSender = fakeResponseSender
   512  			})
   513  
   514  			It("checks if the response sender is filtered", func() {
   515  				err := handler.Handle(context.Background(), server)
   516  				Expect(err).NotTo(HaveOccurred())
   517  
   518  				Expect(fakeResponseSender.IsFilteredCallCount()).To(Equal(1))
   519  			})
   520  
   521  			Context("when the response sender indicates it is not filtered", func() {
   522  				BeforeEach(func() {
   523  					fakeResponseSender.IsFilteredReturns(false)
   524  				})
   525  
   526  				It("labels the metric with filtered=false", func() {
   527  					err := handler.Handle(context.Background(), server)
   528  					Expect(err).NotTo(HaveOccurred())
   529  
   530  					Expect(fakeRequestsReceived.WithCallCount()).To(Equal(1))
   531  					labelValues := fakeRequestsReceived.WithArgsForCall(0)
   532  					Expect(labelValues).To(Equal([]string{
   533  						"channel", "chain-id",
   534  						"filtered", "false",
   535  						"data_type", "filtered_block",
   536  					}))
   537  				})
   538  			})
   539  
   540  			It("records requests received, blocks sent, and requests completed with the filtered label set to true", func() {
   541  				err := handler.Handle(context.Background(), server)
   542  				Expect(err).NotTo(HaveOccurred())
   543  
   544  				Expect(fakeRequestsReceived.AddCallCount()).To(Equal(1))
   545  				Expect(fakeRequestsReceived.AddArgsForCall(0)).To(BeNumerically("~", 1.0))
   546  				Expect(fakeRequestsReceived.WithCallCount()).To(Equal(1))
   547  				labelValues := fakeRequestsReceived.WithArgsForCall(0)
   548  				Expect(labelValues).To(Equal([]string{
   549  					"channel", "chain-id",
   550  					"filtered", "true",
   551  					"data_type", "filtered_block",
   552  				}))
   553  
   554  				Expect(fakeBlocksSent.AddCallCount()).To(Equal(1))
   555  				Expect(fakeBlocksSent.WithCallCount()).To(Equal(1))
   556  				Expect(fakeBlocksSent.AddArgsForCall(0)).To(BeNumerically("~", 1.0))
   557  				labelValues = fakeBlocksSent.WithArgsForCall(0)
   558  				Expect(labelValues).To(Equal([]string{
   559  					"channel", "chain-id",
   560  					"filtered", "true",
   561  					"data_type", "filtered_block",
   562  				}))
   563  
   564  				Expect(fakeRequestsCompleted.AddCallCount()).To(Equal(1))
   565  				Expect(fakeRequestsCompleted.AddArgsForCall(0)).To(BeNumerically("~", 1.0))
   566  				Expect(fakeRequestsCompleted.WithCallCount()).To(Equal(1))
   567  				labelValues = fakeRequestsCompleted.WithArgsForCall(0)
   568  				Expect(labelValues).To(Equal([]string{
   569  					"channel", "chain-id",
   570  					"filtered", "true",
   571  					"data_type", "filtered_block",
   572  					"success", "true",
   573  				}))
   574  			})
   575  		})
   576  
   577  		Context("when blocks with private data are requested", func() {
   578  			var (
   579  				fakeResponseSender *mock.PrivateDataResponseSender
   580  			)
   581  
   582  			BeforeEach(func() {
   583  				fakeResponseSender = &mock.PrivateDataResponseSender{}
   584  				fakeResponseSender.DataTypeReturns("block_and_pvtdata")
   585  				server.ResponseSender = fakeResponseSender
   586  			})
   587  
   588  			It("handles the request and returns private data for all collections", func() {
   589  				err := handler.Handle(context.Background(), server)
   590  				Expect(err).NotTo(HaveOccurred())
   591  				Expect(fakeResponseSender.DataTypeCallCount()).To(Equal(1))
   592  				Expect(fakeResponseSender.SendBlockResponseCallCount()).To(Equal(1))
   593  				b, _, _, _ := fakeResponseSender.SendBlockResponseArgsForCall(0)
   594  				Expect(b).To(Equal(&cb.Block{
   595  					Header: &cb.BlockHeader{Number: 100},
   596  				}))
   597  			})
   598  
   599  			It("records requests received, blocks sent, and requests completed with the privatedata label set to true", func() {
   600  				err := handler.Handle(context.Background(), server)
   601  				Expect(err).NotTo(HaveOccurred())
   602  
   603  				Expect(fakeRequestsReceived.AddCallCount()).To(Equal(1))
   604  				Expect(fakeRequestsReceived.AddArgsForCall(0)).To(BeNumerically("~", 1.0))
   605  				Expect(fakeRequestsReceived.WithCallCount()).To(Equal(1))
   606  				labelValues := fakeRequestsReceived.WithArgsForCall(0)
   607  				Expect(labelValues).To(Equal([]string{
   608  					"channel", "chain-id",
   609  					"filtered", "false",
   610  					"data_type", "block_and_pvtdata",
   611  				}))
   612  
   613  				Expect(fakeBlocksSent.AddCallCount()).To(Equal(1))
   614  				Expect(fakeBlocksSent.WithCallCount()).To(Equal(1))
   615  				Expect(fakeBlocksSent.AddArgsForCall(0)).To(BeNumerically("~", 1.0))
   616  				labelValues = fakeBlocksSent.WithArgsForCall(0)
   617  				Expect(labelValues).To(Equal([]string{
   618  					"channel", "chain-id",
   619  					"filtered", "false",
   620  					"data_type", "block_and_pvtdata",
   621  				}))
   622  
   623  				Expect(fakeRequestsCompleted.AddCallCount()).To(Equal(1))
   624  				Expect(fakeRequestsCompleted.AddArgsForCall(0)).To(BeNumerically("~", 1.0))
   625  				Expect(fakeRequestsCompleted.WithCallCount()).To(Equal(1))
   626  				labelValues = fakeRequestsCompleted.WithArgsForCall(0)
   627  				Expect(labelValues).To(Equal([]string{
   628  					"channel", "chain-id",
   629  					"filtered", "false",
   630  					"data_type", "block_and_pvtdata",
   631  					"success", "true",
   632  				}))
   633  			})
   634  		})
   635  
   636  		Context("when sending the block fails", func() {
   637  			BeforeEach(func() {
   638  				fakeResponseSender.SendBlockResponseReturns(errors.New("send-fails"))
   639  			})
   640  
   641  			It("returns the error", func() {
   642  				err := handler.Handle(context.Background(), server)
   643  				Expect(err).To(MatchError("send-fails"))
   644  			})
   645  		})
   646  
   647  		It("sends a success response", func() {
   648  			err := handler.Handle(context.Background(), server)
   649  			Expect(err).NotTo(HaveOccurred())
   650  
   651  			Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
   652  			resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
   653  			Expect(resp).To(Equal(cb.Status_SUCCESS))
   654  		})
   655  
   656  		Context("when sending the success status fails", func() {
   657  			BeforeEach(func() {
   658  				fakeResponseSender.SendStatusResponseReturns(errors.New("send-success-fails"))
   659  			})
   660  
   661  			It("returns the error", func() {
   662  				err := handler.Handle(context.Background(), server)
   663  				Expect(err).To(MatchError("send-success-fails"))
   664  			})
   665  		})
   666  
   667  		Context("when receive fails", func() {
   668  			BeforeEach(func() {
   669  				fakeReceiver.RecvReturns(nil, errors.New("oh bother"))
   670  			})
   671  
   672  			It("returns the error", func() {
   673  				err := handler.Handle(context.Background(), server)
   674  				Expect(err).To(MatchError("oh bother"))
   675  			})
   676  		})
   677  
   678  		Context("when unmarshaling the payload fails", func() {
   679  			BeforeEach(func() {
   680  				envelope.Payload = []byte("completely-bogus-data")
   681  			})
   682  
   683  			It("sends a bad request message", func() {
   684  				err := handler.Handle(context.Background(), server)
   685  				Expect(err).NotTo(HaveOccurred())
   686  
   687  				Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
   688  				resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
   689  				Expect(resp).To(Equal(cb.Status_BAD_REQUEST))
   690  			})
   691  		})
   692  
   693  		Context("when the payload header is nil", func() {
   694  			BeforeEach(func() {
   695  				envelope.Payload = protoutil.MarshalOrPanic(&cb.Payload{
   696  					Header: nil,
   697  				})
   698  			})
   699  
   700  			It("sends a bad request message", func() {
   701  				err := handler.Handle(context.Background(), server)
   702  				Expect(err).NotTo(HaveOccurred())
   703  
   704  				Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
   705  				resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
   706  				Expect(resp).To(Equal(cb.Status_BAD_REQUEST))
   707  			})
   708  		})
   709  
   710  		Context("when unmarshaling the channel header fails", func() {
   711  			BeforeEach(func() {
   712  				channelHeaderPayload = []byte("complete-nonsense")
   713  			})
   714  
   715  			It("sends a bad request message", func() {
   716  				err := handler.Handle(context.Background(), server)
   717  				Expect(err).NotTo(HaveOccurred())
   718  
   719  				Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
   720  				resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
   721  				Expect(resp).To(Equal(cb.Status_BAD_REQUEST))
   722  			})
   723  		})
   724  
   725  		Context("when the channel header timestamp is nil", func() {
   726  			BeforeEach(func() {
   727  				channelHeaderPayload = protoutil.MarshalOrPanic(&cb.ChannelHeader{
   728  					Timestamp: nil,
   729  				})
   730  			})
   731  
   732  			It("sends a bad request message", func() {
   733  				err := handler.Handle(context.Background(), server)
   734  				Expect(err).NotTo(HaveOccurred())
   735  
   736  				Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
   737  				resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
   738  				Expect(resp).To(Equal(cb.Status_BAD_REQUEST))
   739  			})
   740  		})
   741  
   742  		Context("when the channel header timestamp is out of the time window", func() {
   743  			BeforeEach(func() {
   744  				channelHeaderPayload = protoutil.MarshalOrPanic(&cb.ChannelHeader{
   745  					Timestamp: &timestamp.Timestamp{},
   746  				})
   747  			})
   748  
   749  			It("sends status bad request", func() {
   750  				err := handler.Handle(context.Background(), server)
   751  				Expect(err).NotTo(HaveOccurred())
   752  
   753  				Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
   754  				resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
   755  				Expect(resp).To(Equal(cb.Status_BAD_REQUEST))
   756  			})
   757  		})
   758  
   759  		Context("when the channel is not found", func() {
   760  			BeforeEach(func() {
   761  				fakeChainManager.GetChainReturns(nil)
   762  			})
   763  
   764  			It("sends status not found", func() {
   765  				err := handler.Handle(context.Background(), server)
   766  				Expect(err).NotTo(HaveOccurred())
   767  
   768  				Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
   769  				resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
   770  				Expect(resp).To(Equal(cb.Status_NOT_FOUND))
   771  			})
   772  		})
   773  
   774  		Context("when the client disconnects before reading from the chain", func() {
   775  			var (
   776  				ctx    context.Context
   777  				cancel func()
   778  				done   chan struct{}
   779  			)
   780  
   781  			BeforeEach(func() {
   782  				done = make(chan struct{})
   783  				ctx, cancel = context.WithCancel(context.Background())
   784  				cancel()
   785  				fakeBlockIterator.NextStub = func() (*cb.Block, cb.Status) {
   786  					<-done
   787  					return nil, cb.Status_BAD_REQUEST
   788  				}
   789  			})
   790  
   791  			AfterEach(func() {
   792  				close(done)
   793  			})
   794  
   795  			It("aborts the deliver stream", func() {
   796  				err := handler.Handle(ctx, server)
   797  				Expect(err).To(MatchError("context finished before block retrieved: context canceled"))
   798  			})
   799  		})
   800  
   801  		Context("when the chain errors before reading from the chain", func() {
   802  			BeforeEach(func() {
   803  				close(errCh)
   804  			})
   805  
   806  			It("sends status service unavailable", func() {
   807  				err := handler.Handle(context.Background(), server)
   808  				Expect(err).NotTo(HaveOccurred())
   809  
   810  				Expect(fakeChain.ReaderCallCount()).To(Equal(0))
   811  				Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
   812  				resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
   813  				Expect(resp).To(Equal(cb.Status_SERVICE_UNAVAILABLE))
   814  			})
   815  
   816  			Context("when the seek info requests a best effort error response", func() {
   817  				BeforeEach(func() {
   818  					seekInfo.ErrorResponse = ab.SeekInfo_BEST_EFFORT
   819  				})
   820  
   821  				It("replies with the desired blocks", func() {
   822  					err := handler.Handle(context.Background(), server)
   823  					Expect(err).NotTo(HaveOccurred())
   824  
   825  					Expect(fakeResponseSender.SendBlockResponseCallCount()).To(Equal(1))
   826  					Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
   827  					resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
   828  					Expect(resp).To(Equal(cb.Status_SUCCESS))
   829  				})
   830  			})
   831  		})
   832  
   833  		Context("when the chain errors while reading from the chain", func() {
   834  			var doneCh chan struct{}
   835  
   836  			BeforeEach(func() {
   837  				doneCh = make(chan struct{})
   838  				fakeBlockIterator.NextStub = func() (*cb.Block, cb.Status) {
   839  					<-doneCh
   840  					return &cb.Block{}, cb.Status_INTERNAL_SERVER_ERROR
   841  				}
   842  				fakeChain.ReaderStub = func() blockledger.Reader {
   843  					close(errCh)
   844  					return fakeBlockReader
   845  				}
   846  			})
   847  
   848  			AfterEach(func() {
   849  				close(doneCh)
   850  			})
   851  
   852  			It("sends status service unavailable", func() {
   853  				err := handler.Handle(context.Background(), server)
   854  				Expect(err).NotTo(HaveOccurred())
   855  
   856  				Expect(fakeChain.ReaderCallCount()).To(Equal(1))
   857  				Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
   858  				resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
   859  				Expect(resp).To(Equal(cb.Status_SERVICE_UNAVAILABLE))
   860  			})
   861  		})
   862  
   863  		Context("when the access evaluation fails", func() {
   864  			BeforeEach(func() {
   865  				fakePolicyChecker.CheckPolicyReturns(errors.New("no-access-for-you"))
   866  			})
   867  
   868  			It("sends status not found", func() {
   869  				err := handler.Handle(context.Background(), server)
   870  				Expect(err).NotTo(HaveOccurred())
   871  
   872  				Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
   873  				resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
   874  				Expect(resp).To(Equal(cb.Status_FORBIDDEN))
   875  			})
   876  
   877  			It("records requests received, (unsuccessful) requests completed, and (zero) blocks sent", func() {
   878  				err := handler.Handle(context.Background(), server)
   879  				Expect(err).NotTo(HaveOccurred())
   880  
   881  				Expect(fakeRequestsReceived.AddCallCount()).To(Equal(1))
   882  				Expect(fakeRequestsReceived.AddArgsForCall(0)).To(BeNumerically("~", 1.0))
   883  				Expect(fakeRequestsReceived.WithCallCount()).To(Equal(1))
   884  				labelValues := fakeRequestsReceived.WithArgsForCall(0)
   885  				Expect(labelValues).To(Equal([]string{
   886  					"channel", "chain-id",
   887  					"filtered", "false",
   888  					"data_type", "block",
   889  				}))
   890  
   891  				Expect(fakeBlocksSent.AddCallCount()).To(Equal(0))
   892  				Expect(fakeBlocksSent.WithCallCount()).To(Equal(0))
   893  
   894  				Expect(fakeRequestsCompleted.AddCallCount()).To(Equal(1))
   895  				Expect(fakeRequestsCompleted.AddArgsForCall(0)).To(BeNumerically("~", 1.0))
   896  				Expect(fakeRequestsCompleted.WithCallCount()).To(Equal(1))
   897  				labelValues = fakeRequestsCompleted.WithArgsForCall(0)
   898  				Expect(labelValues).To(Equal([]string{
   899  					"channel", "chain-id",
   900  					"filtered", "false",
   901  					"data_type", "block",
   902  					"success", "false",
   903  				}))
   904  			})
   905  		})
   906  
   907  		Context("when the access expires", func() {
   908  			BeforeEach(func() {
   909  				fakeChain.SequenceStub = func() uint64 {
   910  					return uint64(fakeChain.SequenceCallCount())
   911  				}
   912  				fakePolicyChecker.CheckPolicyReturnsOnCall(1, errors.New("no-access-for-you"))
   913  			})
   914  
   915  			It("sends status not found", func() {
   916  				err := handler.Handle(context.Background(), server)
   917  				Expect(err).NotTo(HaveOccurred())
   918  
   919  				Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
   920  				resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
   921  				Expect(resp).To(Equal(cb.Status_FORBIDDEN))
   922  
   923  				Expect(fakePolicyChecker.CheckPolicyCallCount()).To(Equal(2))
   924  			})
   925  		})
   926  
   927  		Context("when unmarshaling seek info fails", func() {
   928  			BeforeEach(func() {
   929  				seekInfoPayload = []byte("complete-nonsense")
   930  			})
   931  
   932  			It("sends status bad request", func() {
   933  				err := handler.Handle(context.Background(), server)
   934  				Expect(err).NotTo(HaveOccurred())
   935  
   936  				Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
   937  				resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
   938  				Expect(resp).To(Equal(cb.Status_BAD_REQUEST))
   939  			})
   940  		})
   941  
   942  		Context("when seek start and stop are nil", func() {
   943  			BeforeEach(func() {
   944  				seekInfo = &ab.SeekInfo{Start: nil, Stop: nil}
   945  			})
   946  
   947  			It("sends status bad request", func() {
   948  				err := handler.Handle(context.Background(), server)
   949  				Expect(err).NotTo(HaveOccurred())
   950  
   951  				Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
   952  				resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
   953  				Expect(resp).To(Equal(cb.Status_BAD_REQUEST))
   954  			})
   955  		})
   956  
   957  		Context("when seek info start number is greater than stop number", func() {
   958  			BeforeEach(func() {
   959  				seekInfo = &ab.SeekInfo{
   960  					Start: seekNewest,
   961  					Stop: &ab.SeekPosition{
   962  						Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 99}},
   963  					},
   964  				}
   965  			})
   966  
   967  			It("sends status bad request", func() {
   968  				err := handler.Handle(context.Background(), server)
   969  				Expect(err).NotTo(HaveOccurred())
   970  
   971  				Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
   972  				resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
   973  				Expect(resp).To(Equal(cb.Status_BAD_REQUEST))
   974  			})
   975  		})
   976  
   977  		Context("when fail if not ready is set and the next block is unavailable", func() {
   978  			BeforeEach(func() {
   979  				fakeBlockReader.HeightReturns(1000)
   980  				fakeBlockReader.IteratorReturns(fakeBlockIterator, 1000)
   981  
   982  				seekInfo = &ab.SeekInfo{
   983  					Behavior: ab.SeekInfo_FAIL_IF_NOT_READY,
   984  					Start: &ab.SeekPosition{
   985  						Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 1002}},
   986  					},
   987  					Stop: &ab.SeekPosition{
   988  						Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 1003}},
   989  					},
   990  				}
   991  			})
   992  
   993  			It("sends status not found", func() {
   994  				err := handler.Handle(context.Background(), server)
   995  				Expect(err).NotTo(HaveOccurred())
   996  
   997  				Expect(fakeBlockIterator.NextCallCount()).To(Equal(0))
   998  				Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
   999  				resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
  1000  				Expect(resp).To(Equal(cb.Status_NOT_FOUND))
  1001  			})
  1002  		})
  1003  
  1004  		Context("when next block status does not indicate success", func() {
  1005  			BeforeEach(func() {
  1006  				fakeBlockIterator.NextReturns(nil, cb.Status_UNKNOWN)
  1007  			})
  1008  
  1009  			It("forwards the status response", func() {
  1010  				err := handler.Handle(context.Background(), server)
  1011  				Expect(err).NotTo(HaveOccurred())
  1012  
  1013  				Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
  1014  				resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
  1015  				Expect(resp).To(Equal(cb.Status_UNKNOWN))
  1016  			})
  1017  		})
  1018  	})
  1019  })