| | 538 | |
| | 539 | |
| | 540 | |
| | 541 | class DTPFactoryTests(unittest.TestCase): |
| | 542 | """ |
| | 543 | Tests for L{ftp.DTPFactory}. |
| | 544 | """ |
| | 545 | def setUp(self): |
| | 546 | """ |
| | 547 | Create a fake protocol interpreter and a L{ftp.DTPFactory} instance to |
| | 548 | test. |
| | 549 | """ |
| | 550 | self.reactor = task.Clock() |
| | 551 | |
| | 552 | class ProtocolInterpreter(object): |
| | 553 | dtpInstance = None |
| | 554 | |
| | 555 | self.protocolInterpreter = ProtocolInterpreter() |
| | 556 | self.factory = ftp.DTPFactory( |
| | 557 | self.protocolInterpreter, None, self.reactor) |
| | 558 | |
| | 559 | |
| | 560 | def test_setTimeout(self): |
| | 561 | """ |
| | 562 | L{ftp.DTPFactory.setTimeout} uses the reactor passed to its initializer |
| | 563 | to set up a timed event to time out the DTP setup after the specified |
| | 564 | number of seconds. |
| | 565 | """ |
| | 566 | # Make sure the factory's deferred fails with the right exception, and |
| | 567 | # make it so we can tell exactly when it fires. |
| | 568 | finished = [] |
| | 569 | d = self.assertFailure(self.factory.deferred, ftp.PortConnectionError) |
| | 570 | d.addCallback(finished.append) |
| | 571 | |
| | 572 | self.factory.setTimeout(6) |
| | 573 | |
| | 574 | # Advance the clock almost to the timeout |
| | 575 | self.reactor.advance(5) |
| | 576 | |
| | 577 | # Nothing should have happened yet. |
| | 578 | self.assertFalse(finished) |
| | 579 | |
| | 580 | # Advance it to the configured timeout. |
| | 581 | self.reactor.advance(1) |
| | 582 | |
| | 583 | # Now the Deferred should have failed with TimeoutError. |
| | 584 | self.assertTrue(finished) |
| | 585 | |
| | 586 | # There should also be no calls left in the reactor. |
| | 587 | self.assertFalse(self.reactor.calls) |
| | 588 | |
| | 589 | |
| | 590 | def test_buildProtocolOnce(self): |
| | 591 | """ |
| | 592 | A L{ftp.DTPFactory} instance's C{buildProtocol} method can be used once |
| | 593 | to create a L{ftp.DTP} instance. |
| | 594 | """ |
| | 595 | protocol = self.factory.buildProtocol(None) |
| | 596 | self.assertIsInstance(protocol, ftp.DTP) |
| | 597 | |
| | 598 | # A subsequent call returns None. |
| | 599 | self.assertIdentical(self.factory.buildProtocol(None), None) |
| | 600 | |
| | 601 | |
| | 602 | def test_timeoutAfterConnection(self): |
| | 603 | """ |
| | 604 | If a timeout has been set up using L{ftp.DTPFactory.setTimeout}, it is |
| | 605 | cancelled by L{ftp.DTPFactory.buildProtocol}. |
| | 606 | """ |
| | 607 | self.factory.setTimeout(10) |
| | 608 | protocol = self.factory.buildProtocol(None) |
| | 609 | # Make sure the call is no longer active. |
| | 610 | self.assertFalse(self.reactor.calls) |
| | 611 | |
| | 612 | |
| | 613 | def test_connectionAfterTimeout(self): |
| | 614 | """ |
| | 615 | If L{ftp.DTPFactory.buildProtocol} is called after the timeout |
| | 616 | specified by L{ftp.DTPFactory.setTimeout} has elapsed, C{None} is |
| | 617 | returned. |
| | 618 | """ |
| | 619 | # Handle the error so it doesn't get logged. |
| | 620 | d = self.assertFailure(self.factory.deferred, ftp.PortConnectionError) |
| | 621 | |
| | 622 | # Set up the timeout and then cause it to elapse so the Deferred does |
| | 623 | # fail. |
| | 624 | self.factory.setTimeout(10) |
| | 625 | self.reactor.advance(10) |
| | 626 | |
| | 627 | # Try to get a protocol - we should not be able to. |
| | 628 | self.assertIdentical(self.factory.buildProtocol(None), None) |
| | 629 | |
| | 630 | # Make sure the Deferred is doing the right thing. |
| | 631 | return d |
| | 632 | |
| | 633 | |
| | 634 | def test_timeoutAfterConnectionFailed(self): |
| | 635 | """ |
| | 636 | L{ftp.DTPFactory.deferred} fails with L{PortConnectionError} when |
| | 637 | L{ftp.DTPFactory.clientConnectionFailed} is called. If the timeout |
| | 638 | specified with L{ftp.DTPFactory.setTimeout} expires after that, nothing |
| | 639 | additional happens. |
| | 640 | """ |
| | 641 | finished = [] |
| | 642 | d = self.assertFailure(self.factory.deferred, ftp.PortConnectionError) |
| | 643 | d.addCallback(finished.append) |
| | 644 | |
| | 645 | self.factory.setTimeout(10) |
| | 646 | self.assertFalse(finished) |
| | 647 | self.factory.clientConnectionFailed(None, None) |
| | 648 | self.assertTrue(finished) |
| | 649 | self.reactor.advance(10) |
| | 650 | return d |
| | 651 | |
| | 652 | |
| | 653 | def test_connectionFailedAfterTimeout(self): |
| | 654 | """ |
| | 655 | If L{ftp.DTPFactory.clientConnectionFailed} is called after the timeout |
| | 656 | specified by L{ftp.DTPFactory.setTimeout} has elapsed, nothing beyond |
| | 657 | the normal timeout before happens. |
| | 658 | """ |
| | 659 | # Handle the error so it doesn't get logged. |
| | 660 | d = self.assertFailure(self.factory.deferred, ftp.PortConnectionError) |
| | 661 | |
| | 662 | # Set up the timeout and then cause it to elapse so the Deferred does |
| | 663 | # fail. |
| | 664 | self.factory.setTimeout(10) |
| | 665 | self.reactor.advance(10) |
| | 666 | |
| | 667 | # Now fail the connection attempt. This should do nothing. In |
| | 668 | # particular, it should not raise an exception. |
| | 669 | self.factory.clientConnectionFailed(None, defer.TimeoutError("foo")) |
| | 670 | |
| | 671 | # Give the Deferred to trial so it can make sure it did what we |
| | 672 | # expected. |
| | 673 | return d |
| | 674 | |