[Twisted-Python] TDD: How to test that a Timeout Exception occurs within the timeout period

exarkun at twistedmatrix.com exarkun at twistedmatrix.com
Mon Nov 7 08:46:12 EST 2011

On 01:27 pm, tom.sheffler at gmail.com wrote:
>I am investigating timeout properties of the FTP server module.  I
>have written the following trial test, that when functioning properly
>will throw a PortConnectionError with a "DTPFactory timeout"
>I would like to use something like
>   self.failUnlessRaises()

Unrelated to the real intent of your question: adjust this desire, you 
should want to use self.assertRaises() instead.
>but the test is also constructed using defer.deferredGenerator, and it
>doesn't seem possible to apply the test for an exception to a
>Generator-based test.

This is somewhat true-ish.  There is another trial method that helps out 
with this case: assertFailure.  The new trial documentation written by 
Thomas Hervé addresses this use case a bit:


However, it's not clear to me that you actually have a Deferred that is 
going to fire with a Failure.  It sounds like maybe you have an error 
that will get logged and no other indication that what you were waiting 
for has happened?  If so, you might want to aim for a Deferred that 
fires when the important thing has happened.

>This is a useful type of test to be able to
>write: to assert that an exceptional condition *will* occur within a
>timeout period.  Failure is if the exceptional condition is *never*
>raised.  Suggestions for attacking these types of properties is 
>FYI: Here is my test, along with the trial directive that if it runs
>for 60 seconds it is a failure.  But first, here is the ERROR
>traceback that a "successful" run of this test produces.
>Traceback (most recent call last):
>Failure: twisted.protocols.ftp.PortConnectionError: DTPFactory timeout
>    def test_FtpControlChannelTimesOut(self):
>        """Test that after the FTP timeout, the control channel closes
>        # Set the timeout to something small, but greater than 
>        self.serverProtocol.timeOut = 15
>        # Login
>        wfd = defer.waitForDeferred(self._anonymousLogin())
>        yield wfd
>        wfd.getResult()
>        log.msg("Login Anonymous")
>        # Wait for N seconds, protocol timeOut not fired yet
>        wait1 = defer.waitForDeferred(self.mywait(2))
>        yield wait1
>        # Should get here and not fail
>        log.msg("FTP is ok here")
>        # Issue a PASV command, and extract the host and port from the 
>        pasvCmd = 
>        yield pasvCmd
>        responseLines = pasvCmd.getResult()
>        log.msg("PASV responseLines", responseLines)
>        host, port = ftp.decodeHostPort(responseLines[-1][4:])
>        # Wait for N seconds, protocol timeOut will fire
>        wait2 = defer.waitForDeferred(self.mywait(20))
>        yield wait2
>        log.msg("FTP should have timed out and left reactor clean")
>    test_FtpControlChannelTimesOut =
>    # test_FtpControlChannelTimesOut.skip = "skipping"
>    test_FtpControlChannelTimesOut.timeout = 60 # is a real error if
>it takes this long
>Twisted-Python mailing list
>Twisted-Python at twistedmatrix.com

More information about the Twisted-Python mailing list