Commit 0b220651 authored by Denis Bilenko's avatar Denis Bilenko

greentest.py: fix switch_count check to work

it was not enabled in patched tests because monkey.patch_all() imports threading and that prevents Hub from being patched with CountingHub
parent 9f32d104
......@@ -29,6 +29,7 @@ import os
from os.path import basename, splitext
import gevent
from patched_tests_setup import get_switch_expected
from gevent.hub import _get_hub
from functools import wraps
VERBOSE = sys.argv.count('-v') > 1
......@@ -63,7 +64,7 @@ def wrap_refcount(method):
deltas = []
d = None
try:
for _ in xrange(4):
while True:
d = gettotalrefcount()
method(self, *args, **kwargs)
if hasattr(self, 'cleanup'):
......@@ -72,13 +73,12 @@ def wrap_refcount(method):
sys.modules['urlparse'].clear_cache()
d = gettotalrefcount() - d
deltas.append(d)
if len(deltas) >= 2 and deltas[-1] <= 0 and deltas[-2] <= 0:
if 2 <= len(deltas) <= 3 and deltas[-2:] == [0, 0]:
break
elif len(deltas) >= 3 and deltas[-3:] == [-1, 1, -1]:
# as seen on test__server.py: test_assertion_in_blocking_func (__main__.TestNoneSpawn)
if 3 <= len(deltas) and deltas[-3:] == [0, 0, 0]:
break
else:
raise AssertionError('refcount increased by %r' % (deltas, ))
if len(deltas) >= 6:
raise AssertionError('refcount increased by %r' % (deltas, ))
finally:
gc.collect()
gc.enable()
......@@ -88,23 +88,23 @@ def wrap_refcount(method):
def wrap_error_fatal(method):
@wraps(method)
def wrapped(self, *args, **kwargs):
SYSTEM_ERROR = self._hub.SYSTEM_ERROR
self._hub.SYSTEM_ERROR = object
SYSTEM_ERROR = gevent.get_hub().SYSTEM_ERROR
gevent.get_hub().SYSTEM_ERROR = object
try:
return method(self, *args, **kwargs)
finally:
self._hub.SYSTEM_ERROR = SYSTEM_ERROR
gevent.get_hub().SYSTEM_ERROR = SYSTEM_ERROR
return wrapped
def wrap_restore_handle_error(method):
@wraps(method)
def wrapped(self, *args, **kwargs):
old = self._hub.handle_error
old = gevent.get_hub().handle_error
try:
return method(self, *args, **kwargs)
finally:
self._hub.handle_error = old
gevent.get_hub().handle_error = old
if self.peek_error()[0] is not None:
gevent.getcurrent().throw(*self.peek_error()[1:])
return wrapped
......@@ -132,6 +132,8 @@ class TestCaseMetaClass(type):
timeout = classDict.get('__timeout__', 'NONE')
if timeout == 'NONE':
timeout = getattr(bases[0], '__timeout__', None)
if gettotalrefcount is not None and timeout is not None:
timeout *= 6
check_totalrefcount = _get_class_attr(classDict, bases, 'check_totalrefcount', True)
error_fatal = _get_class_attr(classDict, bases, 'error_fatal', True)
for key, value in classDict.items():
......@@ -156,12 +158,6 @@ class TestCase(BaseTestCase):
__timeout__ = 1
switch_expected = 'default'
error_fatal = True
_switch_count = None
def __init__(self, *args, **kwargs):
BaseTestCase.__init__(self, *args, **kwargs)
self._hub = gevent.hub.get_hub()
self._switch_count = None
def run(self, *args, **kwargs):
if self.switch_expected == 'default':
......@@ -169,14 +165,12 @@ class TestCase(BaseTestCase):
return BaseTestCase.run(self, *args, **kwargs)
def setUp(self):
if hasattr(self._hub, 'switch_count'):
self._switch_count = self._hub.switch_count
self.initial_switch_count = getattr(_get_hub(), 'switch_count', 0)
def tearDown(self):
if hasattr(self, 'cleanup'):
self.cleanup()
if self.switch_count is not None:
msg = None
if self.switch_count < 0:
raise AssertionError('hub.switch_count decreased???')
if self.switch_expected is None:
......@@ -192,8 +186,13 @@ class TestCase(BaseTestCase):
@property
def switch_count(self):
if self._switch_count is not None and hasattr(self._hub, 'switch_count'):
return self._hub.switch_count - self._switch_count
if self.switch_expected is None:
return
initial = getattr(self, 'initial_switch_count', None)
if initial is None:
raise AssertionError('Cannot check switch_count (setUp() was not called)')
current = getattr(_get_hub(), 'switch_count', 0)
return current - initial
@property
def testname(self):
......@@ -205,16 +204,7 @@ class TestCase(BaseTestCase):
@property
def modulename(self):
test_method = getattr(self, self.testname)
try:
func = test_method.__func__
except AttributeError:
func = test_method.im_func
try:
return func.func_code.co_filename
except AttributeError:
return func.__code__.co_filename
return os.path.basename(sys.modules[self.__class__.__module__].__file__).rsplit('.', 1)[0]
@property
def fullname(self):
......@@ -225,13 +215,13 @@ class TestCase(BaseTestCase):
def expect_one_error(self):
assert self._error == self._none, self._error
self._old_handle_error = self._hub.handle_error
self._hub.handle_error = self._store_error
self._old_handle_error = gevent.get_hub().handle_error
gevent.get_hub().handle_error = self._store_error
def _store_error(self, where, type, value, tb):
del tb
if self._error != self._none:
self._hub.parent.throw(type, value)
gevent.get_hub().parent.throw(type, value)
else:
self._error = (where, type, value)
......
......@@ -3,35 +3,66 @@ import re
# By default, test cases are expected to switch and emit warnings if there was none
# If a test is found in this list, it's expected not to switch.
tests = '''test_select.SelectTestCase.test_error_conditions
test_ftplib.TestFTPClass.test_all_errors
test_ftplib.TestFTPClass.test_getwelcome
test_ftplib.TestFTPClass.test_sanitize
test_ftplib.TestFTPClass.test_set_pasv
test_ftplib.TestIPv6Environment.test_af
test_socket.TestExceptions.testExceptionTree
test_socket.Urllib2FileobjectTest.testClose
test_socket.TestLinuxAbstractNamespace.testLinuxAbstractNamespace
test_socket.TestLinuxAbstractNamespace.testMaxName
test_socket.TestLinuxAbstractNamespace.testNameOverflow
test_socket.GeneralModuleTests.*
no_switch_tests = '''test_patched_select.SelectTestCase.test_error_conditions
test_patched_ftplib.TestFTPClass.test_all_errors
test_patched_ftplib.TestFTPClass.test_getwelcome
test_patched_ftplib.TestFTPClass.test_sanitize
test_patched_ftplib.TestFTPClass.test_set_pasv
test_patched_ftplib.TestIPv6Environment.test_af
test_patched_socket.TestExceptions.testExceptionTree
test_patched_socket.Urllib2FileobjectTest.testClose
test_patched_socket.TestLinuxAbstractNamespace.testLinuxAbstractNamespace
test_patched_socket.TestLinuxAbstractNamespace.testMaxName
test_patched_socket.TestLinuxAbstractNamespace.testNameOverflow
test_patched_socket.FileObjectInterruptedTestCase.*
test_patched_urllib.*
test_patched_asyncore.HelperFunctionTests.*
test_patched_httplib.BasicTest.*
test_patched_httplib.HTTPSTimeoutTest.test_attributes
test_patched_httplib.HeaderTests.*
test_patched_httplib.OfflineTest.*
test_patched_select.SelectTestCase.test_error_conditions
test_patched_smtplib.NonConnectingTests.*
test_patched_urllib2net.OtherNetworkTests.*
test_patched_wsgiref.*
'''
tests = [x.strip().replace('\.', '\\.').replace('*', '.*?') for x in tests.split('\n') if x.strip()]
tests = re.compile('^%s$' % '|'.join(tests))
ignore_switch_tests = '''
test_patched_socket.GeneralModuleTests.*
test_patched_httpservers.BaseHTTPRequestHandlerTestCase.*
test_patched_queue.*
test_patched_signal.SiginterruptTest.*
test_patched_urllib2.*
test_patched_ssl.*
test_patched_signal.BasicSignalTests.*
test_patched_threading_local.*
'''
def make_re(tests):
tests = [x.strip().replace('\.', '\\.').replace('*', '.*?') for x in tests.split('\n') if x.strip()]
tests = re.compile('^%s$' % '|'.join(tests))
return tests
no_switch_tests = make_re(no_switch_tests)
ignore_switch_tests = make_re(ignore_switch_tests)
def get_switch_expected(fullname):
"""
>>> get_switch_expected('test_select.SelectTestCase.test_error_conditions')
>>> get_switch_expected('test_patched_select.SelectTestCase.test_error_conditions')
False
>>> get_switch_expected('test_socket.GeneralModuleTests.testCrucialConstants')
>>> get_switch_expected('test_patched_socket.GeneralModuleTests.testCrucialConstants')
False
>>> get_switch_expected('test_socket.SomeOtherTest.testHello')
>>> get_switch_expected('test_patched_socket.SomeOtherTest.testHello')
True
>>> get_switch_expected("test_patched_httplib.BasicTest.test_bad_status_repr")
False
"""
if tests.match(fullname) is not None:
print (fullname)
if ignore_switch_tests.match(fullname) is not None:
return None
if no_switch_tests.match(fullname) is not None:
return False
return True
......@@ -44,7 +75,7 @@ disabled_tests = \
, 'test_urllib2net.TimeoutTest.test_ftp_timeout'
, 'test_urllib2net.TimeoutTest.test_http_no_timeout'
, 'test_urllib2net.TimeoutTest.test_http_timeout'
# access _sock.gettimeout() which is always in non-blocking mode
# accesses _sock.gettimeout() which is always in non-blocking mode
, 'test_socket.UDPTimeoutTest.testUDPTimeout'
# has a bug which makes it fail with error: (107, 'Transport endpoint is not connected')
......@@ -53,7 +84,7 @@ disabled_tests = \
, 'test_socket.GeneralModuleTests.testRefCountGetNameInfo'
# fails with "socket.getnameinfo loses a reference" while the reference is only "lost"
# because it is referenced by the traceback - any Python function would lose a reference like that.
# the original getnameinfo does not lose it because it's in C.
# the original getnameinfo does not "lose" it because it's in C.
, 'test_socket.NetworkConnectionNoServer.test_create_connection_timeout'
# replaces socket.socket with MockSocket and then calls create_connection.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment