github.com/ewagmig/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: ×tamp.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 })