3

I've got a relatively simple SSL server running in Twisted and I'd like to write some unit tests for it. I'm not really sure the best way to do this when using Python 3. All the documentation I've found describes using Twisted Trial which unfortunately is incomplete for Py3k.

What I'm thinking is doing something like this:

  • loading up my code and doing everything but reactor.run()
  • send the data I want my code to handle
  • run reactor.doIteration() (or maybe reactor.iterate() is better?)
  • check that my server did what it was supposed to

Is this a legitimate way of handling this sort of situation?

EDIT:

answer from glyph that this may be a bad idea (but it's not specifically talking about testing)

EDIT 2:

I guess the major issue is when you're trying to test components intertwined with Twisted and you're not sure how to pull it apart to properly test the individual components. Is there any reliable way to test this? Should .run() be called and then insert an event that's run a few seconds after you've completed your action to stop the reactor and test the result?

Community
  • 1
  • 1
Tim Tisdall
  • 9,914
  • 3
  • 52
  • 82

1 Answers1

1

Are you writing low-level networking code? Does your application interact with BSD socket APIs? If not, why do you want to run the reactor at all in your tests? Unit tests should exercise a well-defined, narrow set of code. This should be your application code - not the implementation of the TLS transport in Twisted.

To specifically address the idea of calling reactor.iterate, either in your unit tests or elsewhere: yes, it is a bad idea. This is not how Twisted itself is tested. There is no reason to expect that because you write code that works when you call reactor.iterate it will work when you call reactor.run instead. reactor.iterate is a left-over from a mistaken idea about how event loops should be integrated with other systems. There may be an extreme edge case or two where the idea of reactor.iterate is correct and useful but in practice no one uses Twisted in such cases and no one who works on Twisted bears them in mind when making changes. So this is not a place you want your application to be. When things go wrong you'll be very lonely.

Jean-Paul Calderone
  • 47,755
  • 6
  • 94
  • 122
  • 1
    There's two major parts... testing the handling of data in `dataReceived` of the protocol and testing that only certain connections get through depending on the common name on the client certificate. I wanted to mimic things as much as possible to what would happen in real code. I'm not sure how to test the later without actually creating a socket and testing a connection with different client certificates. – Tim Tisdall Jul 07 '14 at 21:09
  • The latter sounds like a function that returns True or False given a common name. The code that actually sets up a connection is a separate unit. – Jean-Paul Calderone Jul 08 '14 at 10:32
  • The latter is partially an `ssl.ContextFactory` that I'd like to test to make sure it's working the way I expect. I can read the sparse docs so many times before I'd like to actually run it and make sure it's doing what's needed. Also, I'd like to make it into a test case so after changes are made I can re-test it. – Tim Tisdall Jul 08 '14 at 13:42
  • It's true that pyOpenSSL's context objects are really opaque and obnoxious to test. You can test them without doing I/O, though. pyOpenSSL supports in-memory "connections". So you can demonstrate that your context is usable to establish connections that way - no I/O. You may be able to make some other assertions, such as what cipher or certificate was selected, if that's what you're interested in. Other pieces will be hard to make assertions about because even a pyOpenSSL Connection instance is still pretty opaque. – Jean-Paul Calderone Jul 08 '14 at 19:25
  • Also, in most cases you should just use `twisted.internet.ssl.CertificateOptions` as long as you can depend on Twisted 14.0 or newer. It automatically does a bunch of the standard TLS things that you want all the time. – Jean-Paul Calderone Jul 08 '14 at 19:26