github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/common/deliver/deliver_test.go (about)

     1  /*
     2  Copyright hechain. 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  	"github.com/hechain20/hechain/common/crypto/tlsgen"
    19  	"github.com/hechain20/hechain/common/deliver"
    20  	"github.com/hechain20/hechain/common/deliver/mock"
    21  	"github.com/hechain20/hechain/common/ledger/blockledger"
    22  	"github.com/hechain20/hechain/common/metrics/disabled"
    23  	"github.com/hechain20/hechain/common/metrics/metricsfakes"
    24  	"github.com/hechain20/hechain/common/util"
    25  	"github.com/hechain20/hechain/protoutil"
    26  	cb "github.com/hyperledger/fabric-protos-go/common"
    27  	"github.com/hyperledger/fabric-protos-go/msp"
    28  	ab "github.com/hyperledger/fabric-protos-go/orderer"
    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 fakeResponseSender *mock.PrivateDataResponseSender
   579  
   580  			BeforeEach(func() {
   581  				fakeResponseSender = &mock.PrivateDataResponseSender{}
   582  				fakeResponseSender.DataTypeReturns("block_and_pvtdata")
   583  				server.ResponseSender = fakeResponseSender
   584  			})
   585  
   586  			It("handles the request and returns private data for all collections", func() {
   587  				err := handler.Handle(context.Background(), server)
   588  				Expect(err).NotTo(HaveOccurred())
   589  				Expect(fakeResponseSender.DataTypeCallCount()).To(Equal(1))
   590  				Expect(fakeResponseSender.SendBlockResponseCallCount()).To(Equal(1))
   591  				b, _, _, _ := fakeResponseSender.SendBlockResponseArgsForCall(0)
   592  				Expect(b).To(Equal(&cb.Block{
   593  					Header: &cb.BlockHeader{Number: 100},
   594  				}))
   595  			})
   596  
   597  			It("records requests received, blocks sent, and requests completed with the privatedata label set to true", func() {
   598  				err := handler.Handle(context.Background(), server)
   599  				Expect(err).NotTo(HaveOccurred())
   600  
   601  				Expect(fakeRequestsReceived.AddCallCount()).To(Equal(1))
   602  				Expect(fakeRequestsReceived.AddArgsForCall(0)).To(BeNumerically("~", 1.0))
   603  				Expect(fakeRequestsReceived.WithCallCount()).To(Equal(1))
   604  				labelValues := fakeRequestsReceived.WithArgsForCall(0)
   605  				Expect(labelValues).To(Equal([]string{
   606  					"channel", "chain-id",
   607  					"filtered", "false",
   608  					"data_type", "block_and_pvtdata",
   609  				}))
   610  
   611  				Expect(fakeBlocksSent.AddCallCount()).To(Equal(1))
   612  				Expect(fakeBlocksSent.WithCallCount()).To(Equal(1))
   613  				Expect(fakeBlocksSent.AddArgsForCall(0)).To(BeNumerically("~", 1.0))
   614  				labelValues = fakeBlocksSent.WithArgsForCall(0)
   615  				Expect(labelValues).To(Equal([]string{
   616  					"channel", "chain-id",
   617  					"filtered", "false",
   618  					"data_type", "block_and_pvtdata",
   619  				}))
   620  
   621  				Expect(fakeRequestsCompleted.AddCallCount()).To(Equal(1))
   622  				Expect(fakeRequestsCompleted.AddArgsForCall(0)).To(BeNumerically("~", 1.0))
   623  				Expect(fakeRequestsCompleted.WithCallCount()).To(Equal(1))
   624  				labelValues = fakeRequestsCompleted.WithArgsForCall(0)
   625  				Expect(labelValues).To(Equal([]string{
   626  					"channel", "chain-id",
   627  					"filtered", "false",
   628  					"data_type", "block_and_pvtdata",
   629  					"success", "true",
   630  				}))
   631  			})
   632  		})
   633  
   634  		Context("when sending the block fails", func() {
   635  			BeforeEach(func() {
   636  				fakeResponseSender.SendBlockResponseReturns(errors.New("send-fails"))
   637  			})
   638  
   639  			It("returns the error", func() {
   640  				err := handler.Handle(context.Background(), server)
   641  				Expect(err).To(MatchError("send-fails"))
   642  			})
   643  		})
   644  
   645  		It("sends a success response", func() {
   646  			err := handler.Handle(context.Background(), server)
   647  			Expect(err).NotTo(HaveOccurred())
   648  
   649  			Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
   650  			resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
   651  			Expect(resp).To(Equal(cb.Status_SUCCESS))
   652  		})
   653  
   654  		Context("when sending the success status fails", func() {
   655  			BeforeEach(func() {
   656  				fakeResponseSender.SendStatusResponseReturns(errors.New("send-success-fails"))
   657  			})
   658  
   659  			It("returns the error", func() {
   660  				err := handler.Handle(context.Background(), server)
   661  				Expect(err).To(MatchError("send-success-fails"))
   662  			})
   663  		})
   664  
   665  		Context("when receive fails", func() {
   666  			BeforeEach(func() {
   667  				fakeReceiver.RecvReturns(nil, errors.New("oh bother"))
   668  			})
   669  
   670  			It("returns the error", func() {
   671  				err := handler.Handle(context.Background(), server)
   672  				Expect(err).To(MatchError("oh bother"))
   673  			})
   674  		})
   675  
   676  		Context("when unmarshalling the payload fails", func() {
   677  			BeforeEach(func() {
   678  				envelope.Payload = []byte("completely-bogus-data")
   679  			})
   680  
   681  			It("sends a bad request message", func() {
   682  				err := handler.Handle(context.Background(), server)
   683  				Expect(err).NotTo(HaveOccurred())
   684  
   685  				Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
   686  				resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
   687  				Expect(resp).To(Equal(cb.Status_BAD_REQUEST))
   688  			})
   689  		})
   690  
   691  		Context("when the payload header is nil", func() {
   692  			BeforeEach(func() {
   693  				envelope.Payload = protoutil.MarshalOrPanic(&cb.Payload{
   694  					Header: nil,
   695  				})
   696  			})
   697  
   698  			It("sends a bad request message", func() {
   699  				err := handler.Handle(context.Background(), server)
   700  				Expect(err).NotTo(HaveOccurred())
   701  
   702  				Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
   703  				resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
   704  				Expect(resp).To(Equal(cb.Status_BAD_REQUEST))
   705  			})
   706  		})
   707  
   708  		Context("when unmarshalling the channel header fails", func() {
   709  			BeforeEach(func() {
   710  				channelHeaderPayload = []byte("complete-nonsense")
   711  			})
   712  
   713  			It("sends a bad request message", func() {
   714  				err := handler.Handle(context.Background(), server)
   715  				Expect(err).NotTo(HaveOccurred())
   716  
   717  				Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
   718  				resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
   719  				Expect(resp).To(Equal(cb.Status_BAD_REQUEST))
   720  			})
   721  		})
   722  
   723  		Context("when the channel header timestamp is nil", func() {
   724  			BeforeEach(func() {
   725  				channelHeaderPayload = protoutil.MarshalOrPanic(&cb.ChannelHeader{
   726  					Timestamp: nil,
   727  				})
   728  			})
   729  
   730  			It("sends a bad request message", func() {
   731  				err := handler.Handle(context.Background(), server)
   732  				Expect(err).NotTo(HaveOccurred())
   733  
   734  				Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
   735  				resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
   736  				Expect(resp).To(Equal(cb.Status_BAD_REQUEST))
   737  			})
   738  		})
   739  
   740  		Context("when the channel header timestamp is out of the time window", func() {
   741  			BeforeEach(func() {
   742  				channelHeaderPayload = protoutil.MarshalOrPanic(&cb.ChannelHeader{
   743  					Timestamp: &timestamp.Timestamp{},
   744  				})
   745  			})
   746  
   747  			It("sends status bad request", func() {
   748  				err := handler.Handle(context.Background(), server)
   749  				Expect(err).NotTo(HaveOccurred())
   750  
   751  				Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
   752  				resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
   753  				Expect(resp).To(Equal(cb.Status_BAD_REQUEST))
   754  			})
   755  		})
   756  
   757  		Context("when the channel is not found", func() {
   758  			BeforeEach(func() {
   759  				fakeChainManager.GetChainReturns(nil)
   760  			})
   761  
   762  			It("sends status not found", func() {
   763  				err := handler.Handle(context.Background(), server)
   764  				Expect(err).NotTo(HaveOccurred())
   765  
   766  				Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
   767  				resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
   768  				Expect(resp).To(Equal(cb.Status_NOT_FOUND))
   769  			})
   770  		})
   771  
   772  		Context("when the client disconnects before reading from the chain", func() {
   773  			var (
   774  				ctx    context.Context
   775  				cancel func()
   776  				done   chan struct{}
   777  			)
   778  
   779  			BeforeEach(func() {
   780  				done = make(chan struct{})
   781  				ctx, cancel = context.WithCancel(context.Background())
   782  				cancel()
   783  				fakeBlockIterator.NextStub = func() (*cb.Block, cb.Status) {
   784  					<-done
   785  					return nil, cb.Status_BAD_REQUEST
   786  				}
   787  			})
   788  
   789  			AfterEach(func() {
   790  				close(done)
   791  			})
   792  
   793  			It("aborts the deliver stream", func() {
   794  				err := handler.Handle(ctx, server)
   795  				Expect(err).To(MatchError("context finished before block retrieved: context canceled"))
   796  			})
   797  		})
   798  
   799  		Context("when the chain errors before reading from the chain", func() {
   800  			BeforeEach(func() {
   801  				close(errCh)
   802  			})
   803  
   804  			It("sends status service unavailable", func() {
   805  				err := handler.Handle(context.Background(), server)
   806  				Expect(err).NotTo(HaveOccurred())
   807  
   808  				Expect(fakeChain.ReaderCallCount()).To(Equal(0))
   809  				Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
   810  				resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
   811  				Expect(resp).To(Equal(cb.Status_SERVICE_UNAVAILABLE))
   812  			})
   813  
   814  			Context("when the seek info requests a best effort error response", func() {
   815  				BeforeEach(func() {
   816  					seekInfo.ErrorResponse = ab.SeekInfo_BEST_EFFORT
   817  				})
   818  
   819  				It("replies with the desired blocks", func() {
   820  					err := handler.Handle(context.Background(), server)
   821  					Expect(err).NotTo(HaveOccurred())
   822  
   823  					Expect(fakeResponseSender.SendBlockResponseCallCount()).To(Equal(1))
   824  					Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
   825  					resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
   826  					Expect(resp).To(Equal(cb.Status_SUCCESS))
   827  				})
   828  			})
   829  		})
   830  
   831  		Context("when the chain errors while reading from the chain", func() {
   832  			var doneCh chan struct{}
   833  
   834  			BeforeEach(func() {
   835  				doneCh = make(chan struct{})
   836  				fakeBlockIterator.NextStub = func() (*cb.Block, cb.Status) {
   837  					<-doneCh
   838  					return &cb.Block{}, cb.Status_INTERNAL_SERVER_ERROR
   839  				}
   840  				fakeChain.ReaderStub = func() blockledger.Reader {
   841  					close(errCh)
   842  					return fakeBlockReader
   843  				}
   844  			})
   845  
   846  			AfterEach(func() {
   847  				close(doneCh)
   848  			})
   849  
   850  			It("sends status service unavailable", func() {
   851  				err := handler.Handle(context.Background(), server)
   852  				Expect(err).NotTo(HaveOccurred())
   853  
   854  				Expect(fakeChain.ReaderCallCount()).To(Equal(1))
   855  				Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
   856  				resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
   857  				Expect(resp).To(Equal(cb.Status_SERVICE_UNAVAILABLE))
   858  			})
   859  		})
   860  
   861  		Context("when the access evaluation fails", func() {
   862  			BeforeEach(func() {
   863  				fakePolicyChecker.CheckPolicyReturns(errors.New("no-access-for-you"))
   864  			})
   865  
   866  			It("sends status not found", func() {
   867  				err := handler.Handle(context.Background(), server)
   868  				Expect(err).NotTo(HaveOccurred())
   869  
   870  				Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
   871  				resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
   872  				Expect(resp).To(Equal(cb.Status_FORBIDDEN))
   873  			})
   874  
   875  			It("records requests received, (unsuccessful) requests completed, and (zero) blocks sent", func() {
   876  				err := handler.Handle(context.Background(), server)
   877  				Expect(err).NotTo(HaveOccurred())
   878  
   879  				Expect(fakeRequestsReceived.AddCallCount()).To(Equal(1))
   880  				Expect(fakeRequestsReceived.AddArgsForCall(0)).To(BeNumerically("~", 1.0))
   881  				Expect(fakeRequestsReceived.WithCallCount()).To(Equal(1))
   882  				labelValues := fakeRequestsReceived.WithArgsForCall(0)
   883  				Expect(labelValues).To(Equal([]string{
   884  					"channel", "chain-id",
   885  					"filtered", "false",
   886  					"data_type", "block",
   887  				}))
   888  
   889  				Expect(fakeBlocksSent.AddCallCount()).To(Equal(0))
   890  				Expect(fakeBlocksSent.WithCallCount()).To(Equal(0))
   891  
   892  				Expect(fakeRequestsCompleted.AddCallCount()).To(Equal(1))
   893  				Expect(fakeRequestsCompleted.AddArgsForCall(0)).To(BeNumerically("~", 1.0))
   894  				Expect(fakeRequestsCompleted.WithCallCount()).To(Equal(1))
   895  				labelValues = fakeRequestsCompleted.WithArgsForCall(0)
   896  				Expect(labelValues).To(Equal([]string{
   897  					"channel", "chain-id",
   898  					"filtered", "false",
   899  					"data_type", "block",
   900  					"success", "false",
   901  				}))
   902  			})
   903  		})
   904  
   905  		Context("when the access expires", func() {
   906  			BeforeEach(func() {
   907  				fakeChain.SequenceStub = func() uint64 {
   908  					return uint64(fakeChain.SequenceCallCount())
   909  				}
   910  				fakePolicyChecker.CheckPolicyReturnsOnCall(1, errors.New("no-access-for-you"))
   911  			})
   912  
   913  			It("sends status not found", func() {
   914  				err := handler.Handle(context.Background(), server)
   915  				Expect(err).NotTo(HaveOccurred())
   916  
   917  				Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
   918  				resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
   919  				Expect(resp).To(Equal(cb.Status_FORBIDDEN))
   920  
   921  				Expect(fakePolicyChecker.CheckPolicyCallCount()).To(Equal(2))
   922  			})
   923  		})
   924  
   925  		Context("when unmarshalling seek info fails", func() {
   926  			BeforeEach(func() {
   927  				seekInfoPayload = []byte("complete-nonsense")
   928  			})
   929  
   930  			It("sends status bad request", func() {
   931  				err := handler.Handle(context.Background(), server)
   932  				Expect(err).NotTo(HaveOccurred())
   933  
   934  				Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
   935  				resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
   936  				Expect(resp).To(Equal(cb.Status_BAD_REQUEST))
   937  			})
   938  		})
   939  
   940  		Context("when seek start and stop are nil", func() {
   941  			BeforeEach(func() {
   942  				seekInfo = &ab.SeekInfo{Start: nil, Stop: nil}
   943  			})
   944  
   945  			It("sends status bad request", func() {
   946  				err := handler.Handle(context.Background(), server)
   947  				Expect(err).NotTo(HaveOccurred())
   948  
   949  				Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
   950  				resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
   951  				Expect(resp).To(Equal(cb.Status_BAD_REQUEST))
   952  			})
   953  		})
   954  
   955  		Context("when seek info start number is greater than stop number", func() {
   956  			BeforeEach(func() {
   957  				seekInfo = &ab.SeekInfo{
   958  					Start: seekNewest,
   959  					Stop: &ab.SeekPosition{
   960  						Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 99}},
   961  					},
   962  				}
   963  			})
   964  
   965  			It("sends status bad request", func() {
   966  				err := handler.Handle(context.Background(), server)
   967  				Expect(err).NotTo(HaveOccurred())
   968  
   969  				Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
   970  				resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
   971  				Expect(resp).To(Equal(cb.Status_BAD_REQUEST))
   972  			})
   973  		})
   974  
   975  		Context("when fail if not ready is set and the next block is unavailable", func() {
   976  			BeforeEach(func() {
   977  				fakeBlockReader.HeightReturns(1000)
   978  				fakeBlockReader.IteratorReturns(fakeBlockIterator, 1000)
   979  
   980  				seekInfo = &ab.SeekInfo{
   981  					Behavior: ab.SeekInfo_FAIL_IF_NOT_READY,
   982  					Start: &ab.SeekPosition{
   983  						Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 1002}},
   984  					},
   985  					Stop: &ab.SeekPosition{
   986  						Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 1003}},
   987  					},
   988  				}
   989  			})
   990  
   991  			It("sends status not found", func() {
   992  				err := handler.Handle(context.Background(), server)
   993  				Expect(err).NotTo(HaveOccurred())
   994  
   995  				Expect(fakeBlockIterator.NextCallCount()).To(Equal(0))
   996  				Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
   997  				resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
   998  				Expect(resp).To(Equal(cb.Status_NOT_FOUND))
   999  			})
  1000  		})
  1001  
  1002  		Context("when next block status does not indicate success", func() {
  1003  			BeforeEach(func() {
  1004  				fakeBlockIterator.NextReturns(nil, cb.Status_UNKNOWN)
  1005  			})
  1006  
  1007  			It("forwards the status response", func() {
  1008  				err := handler.Handle(context.Background(), server)
  1009  				Expect(err).NotTo(HaveOccurred())
  1010  
  1011  				Expect(fakeResponseSender.SendStatusResponseCallCount()).To(Equal(1))
  1012  				resp := fakeResponseSender.SendStatusResponseArgsForCall(0)
  1013  				Expect(resp).To(Equal(cb.Status_UNKNOWN))
  1014  			})
  1015  		})
  1016  	})
  1017  })