[Dev] Mock Reactor for tests?

Phillip J. Eby pje at telecommunity.com
Tue Jun 7 11:04:56 PDT 2005


At 04:23 PM 6/6/2005 -0700, Brian Kirsch wrote:
>Ok sounds good. Especially if you wanna do the work of implementing the 
>mock reactor :)

Well, I took a look this morning, and implementing simulated time may 
actually be easier than I thought, because ReactorBase now has a 
'timeout()' method that does the hard part - computing how much time there 
is until the next delayed call.  In earlier versions of Twisted, that logic 
was buried inside something else.  There are also nice new functions like 
'installReactor' to play with.

So, I'm thinking I'll create a 'testreactor' module (maybe living in 
osaf.framework.twisted?) with 'install()' and 'uninstall()' 
functions.  When installed, it'll mixin test methods into the standard 
reactor, and the reactor will run on simulated time.  I'm thinking that 
these will probably be very simple, like a 'reset()' to completely clear 
the reactor's state between tests.

I've also investigated the run()/stop() issue, and as far as I can tell 
this should be a non-issue for tests that run using the Twisted default 
reactor (which is what Chandler uses).  The reason that you aren't supposed 
to use run()/stop() or certain other functions multiple times (AFAICT), is 
because certain GUI-platform-specific reactor implementations won't 
tolerate it.  However, tests that don't run with a GUI don't need to use a 
GUI-specific reactor, and we're not using one in Chandler currently anyway.

Assuming that StringTransport is sufficient for all our simulated-socket 
needs, I should only need to add a few methods.  Here are the ones I have 
in mind:

reactor.start() -- completely reset the reactor's state and reinitialize it 
so that the current test runs with a clean slate.  Also sets the reactor's 
state to "running", so that the test will appear to be called from within 
the reactor run loop, but in fact will have control over the reactor.

reactor.getTime() -- return the current simulated "now" moment (initially 
set to the time when the test mixin is installed)

reactor.setTime(seconds) -- change the simulated "now" moment

reactor.waitFor(deferred, timeout) -- iterate until the deferred succeeds 
or fails, or until the timeout occurs.  Raise a TimeoutError if the timeout 
happens first, or raises the deferred's exception if the deferred 
fails.  Otherwise, returns the deferred's value.  (Note: the timeout is in 
*simulated* time, not real time, so you can safely set large values if you 
have a test with complex timing.)


So, I'm thinking there would also be a 'testreactor.ReactorTestCase' whose 
setUp() would testreactor.install(), and reactor.start(), and whose 
tearDown() would reactor.stop() (if it's still running), and perhaps 
testreactor.uninstall() as well.

Then, test methods would just set up whatever conditions they want, and 
then reactor.waitFor() results.  Tests could safely call waitFor() multiple 
times, even within the same test.

Heikki, does that sound about like what you need for your tests?



More information about the Dev mailing list