How do I check for LoopingCall ()?
In my code, I am using task.LoopingCall()
to run some deferred function every second. I want to make sure that this function will return the correct values for a certain number of things. So, I thought I could use task.clock()
and call a method advance()
on it. However, I am not getting the correct number of expected responses.
Any idea what I am doing wrong?
Here's some test code to show what I mean. Server first:
from twisted.internet.protocol import Factory
from twisted.protocols.basic import LineReceiver
from twisted.internet import reactor
from twisted.internet import task
import time
class Chat(LineReceiver):
def __init__(self):
self.echo = None
def connectionMade(self):
self.echo = task.LoopingCall(self.echo_print)
self.echo.start(1)
def connectionLost(self, reason='whatever'):
if self.echo is not None and self.echo.running:
self.echo.stop()
def lineReceived(self, line):
if line == 'stop':
self.echo.stop()
def echo_print (self):
self.sendLine("Echo")
class ChatFactory(Factory):
def __init__(self):
pass
def buildProtocol(self, addr):
return Chat()
if __name__ == "__main__":
reactor.listenTCP(8123, ChatFactory())
reactor.run()
And now a test case:
from twisted.internet import task, base
from twisted.trial import unittest
from twisted.test import proto_helpers
from chat import ChatFactory
class TestChat (unittest.TestCase):
def setUp (self):
self.factory = ChatFactory()
self.clock = task.Clock()
self.proto = self.factory.buildProtocol(('127.0.0.1', 0))
self.tr = proto_helpers.StringTransport()
self.proto.callLater = self.clock.callLater
self.proto.makeConnection(self.tr)
def tearDown (self):
if self.proto:
self.proto.connectionLost()
def test_echo (self):
self.proto.dataReceived('ook\n')
seconds_elapsed = 5
self.clock.advance(seconds_elapsed)
expected = 'Echo\r\n' * seconds_elapsed
self.assertEqual(self.tr.value(), expected)
When I run py.test I get:
E FailTest: not equal:
E a = 'Echo\r\n'
E b = 'Echo\r\nEcho\r\nEcho\r\nEcho\r\nEcho\r\n'
Note that the addition import time; time.sleep(5)
does indeed make a trial run. So I suspect that the problem is what task.clock
is being misused.
source to share
I believe I have found problems.
-
LoopingCall
uses the default reactor. I needed to set it up so that it uses my own clock through a class variableclock
. See task.clock . -
self.clock.advance(x)
sets the clock at the momentx
. It does not go through(x-1, x-2, ..., now)
, and therefore any pending that needs to be done in those intermediate stages will not be executed. Hence, a bug in the test is the correct behavior. Callingself.clock.advance(1)
within a loop starting at 0 and ending inseconds_elapsed
had the desired effect.
The twisted section on unit tests is worth reading a few times to get a feel for what's going on. If you have more problems, take a look at the twisted tests of the indoor unit!
source to share