tests: LimitedTestCase.set_alarm() detects busy loops like while True: pass

This commit is contained in:
Sergey Shepelev
2013-01-10 16:37:02 +04:00
parent a5bcca9d03
commit e90285a561

View File

@@ -2,6 +2,7 @@
import errno import errno
import os import os
import resource import resource
import signal
import unittest import unittest
import warnings import warnings
@@ -132,31 +133,52 @@ class TestIsTakingTooLong(Exception):
class LimitedTestCase(unittest.TestCase): class LimitedTestCase(unittest.TestCase):
""" Unittest subclass that adds a timeout to all tests. Subclasses must """ Unittest subclass that adds a timeout to all tests. Subclasses must
be sure to call the LimitedTestCase setUp and tearDown methods. The default be sure to call the LimitedTestCase setUp and tearDown methods. The default
timeout is 1 second, change it by setting self.TEST_TIMEOUT to the desired timeout is 1 second, change it by setting TEST_TIMEOUT to the desired
quantity.""" quantity."""
TEST_TIMEOUT = 1 TEST_TIMEOUT = 1
def setUp(self): def setUp(self):
import eventlet self.previous_alarm = None
self.timer = eventlet.Timeout(self.TEST_TIMEOUT, self.timer = eventlet.Timeout(self.TEST_TIMEOUT,
TestIsTakingTooLong(self.TEST_TIMEOUT)) TestIsTakingTooLong(self.TEST_TIMEOUT))
def reset_timeout(self, new_timeout): def reset_timeout(self, new_timeout):
"""Changes the timeout duration; only has effect during one test case""" """Changes the timeout duration; only has effect during one test.
import eventlet `new_timeout` can be int or float.
"""
self.timer.cancel() self.timer.cancel()
self.timer = eventlet.Timeout(new_timeout, self.timer = eventlet.Timeout(new_timeout,
TestIsTakingTooLong(new_timeout)) TestIsTakingTooLong(new_timeout))
def set_alarm(self, new_timeout):
"""Call this in the beginning of your test if you expect busy loops.
Only has effect during one test.
`new_timeout` must be int.
"""
def sig_alarm_handler(sig, frame):
# Could arm previous alarm but test is failed anyway
# seems to be no point in restoring previous state.
raise TestIsTakingTooLong(new_timeout)
self.previous_alarm = (
signal.signal(signal.SIGALRM, sig_alarm_handler),
signal.alarm(new_timeout),
)
def tearDown(self): def tearDown(self):
self.timer.cancel() self.timer.cancel()
if self.previous_alarm:
signal.signal(signal.SIGALRM, self.previous_alarm[0])
signal.alarm(self.previous_alarm[1])
try: try:
hub = hubs.get_hub() hub = hubs.get_hub()
num_readers = len(hub.get_readers()) num_readers = len(hub.get_readers())
num_writers = len(hub.get_writers()) num_writers = len(hub.get_writers())
assert num_readers == num_writers == 0 assert num_readers == num_writers == 0
except AssertionError, e: except AssertionError:
print "ERROR: Hub not empty" print "ERROR: Hub not empty"
print debug.format_hub_timers() print debug.format_hub_timers()
print debug.format_hub_listeners() print debug.format_hub_listeners()