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: ×tamp.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 })