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