summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Shepelev <temotor@gmail.com>2016-12-22 04:35:14 +0300
committerSergey Shepelev <temotor@gmail.com>2017-01-04 23:42:32 +0300
commite4049a8a0016b28cbbdf3ab01425fc92a623e380 (patch)
tree58d140b6e9f784e5b28a0435fb41ae8f238984af
parent461348f9a8459724be87c281eea4e0408138a82c (diff)
downloadeventlet-is-timeout.tar.gz
WIP https://github.com/eventlet/eventlet/pull/346is-timeout
-rw-r--r--.travis.yml2
-rw-r--r--codecov.yml4
-rw-r--r--eventlet/__init__.py12
-rw-r--r--eventlet/green/_socket_nodns.py16
-rw-r--r--eventlet/greenio/base.py27
-rw-r--r--eventlet/greenthread.py8
-rw-r--r--eventlet/hubs/__init__.py1
-rw-r--r--eventlet/support/__init__.py38
-rw-r--r--eventlet/timeout.py41
-rw-r--r--tests/__init__.py7
-rw-r--r--tests/api_test.py44
-rw-r--r--tests/fork_test.py52
-rw-r--r--tests/greenio_test.py2
-rw-r--r--tests/hub_test.py63
-rw-r--r--tests/hub_test_fork.py25
-rw-r--r--tests/isolated/hub_fork.py33
-rw-r--r--tests/isolated/hub_fork_simple.py58
-rw-r--r--tests/socket_test.py11
-rw-r--r--tests/test__refcount.py65
-rw-r--r--tests/test__socket_errors.py2
-rw-r--r--tests/timeout_test.py10
-rw-r--r--tests/tpool_test.py15
-rw-r--r--tox.ini5
23 files changed, 327 insertions, 214 deletions
diff --git a/.travis.yml b/.travis.yml
index 15f5459..3fb1915 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -51,7 +51,7 @@ before_script:
- "export PATH=/usr/lib/ccache:$PATH"
script:
- tox -v -v -e $TOX_ENV
- - codecov
+ - codecov --flags $TOX_ENV
after_failure:
- for X in .tox/$TOX_ENV/log/*; do echo "$X\n"; cat "$X"; echo "\n\n"; done
- echo "pip.log\n"; cat $HOME/.pip/pip.log
diff --git a/codecov.yml b/codecov.yml
index 676557d..6e9350e 100644
--- a/codecov.yml
+++ b/codecov.yml
@@ -1,2 +1,6 @@
codecov:
token: 2a926756-1923-42a1-89c7-97925ea0e17a
+
+coverage:
+ precision: 0
+ round: down
diff --git a/eventlet/__init__.py b/eventlet/__init__.py
index 4700261..0f57a1d 100644
--- a/eventlet/__init__.py
+++ b/eventlet/__init__.py
@@ -14,6 +14,7 @@ if os.environ.get('EVENTLET_IMPORT_VERSION_ONLY') != '1':
from eventlet import patcher
from eventlet import queue
from eventlet import semaphore
+ from eventlet import support
from eventlet import timeout
import greenlet
@@ -45,10 +46,15 @@ if os.environ.get('EVENTLET_IMPORT_VERSION_ONLY') != '1':
Timeout = timeout.Timeout
with_timeout = timeout.with_timeout
+ wrap_is_timeout = timeout.wrap_is_timeout
+ is_timeout = timeout.is_timeout
getcurrent = greenlet.greenlet.getcurrent
# deprecated
- TimeoutError = timeout.Timeout
- exc_after = greenthread.exc_after
- call_after_global = greenthread.call_after_global
+ TimeoutError, exc_after, call_after_global = (
+ support.wrap_deprecated(old, new)(fun) for old, new, fun in (
+ ('TimeoutError', 'Timeout', Timeout),
+ ('exc_after', 'greenthread.exc_after', greenthread.exc_after),
+ ('call_after_global', 'greenthread.call_after_global', greenthread.call_after_global),
+ ))
diff --git a/eventlet/green/_socket_nodns.py b/eventlet/green/_socket_nodns.py
index 8bfecfd..7dca20a 100644
--- a/eventlet/green/_socket_nodns.py
+++ b/eventlet/green/_socket_nodns.py
@@ -1,17 +1,19 @@
__socket = __import__('socket')
__all__ = __socket.__all__
-__patched__ = ['fromfd', 'socketpair', 'ssl', 'socket']
+__patched__ = ['fromfd', 'socketpair', 'ssl', 'socket', 'timeout']
-from eventlet.patcher import slurp_properties
-slurp_properties(__socket, globals(),
- ignore=__patched__, srckeys=dir(__socket))
+import eventlet.patcher
+eventlet.patcher.slurp_properties(__socket, globals(), ignore=__patched__, srckeys=dir(__socket))
os = __import__('os')
import sys
-from eventlet.hubs import get_hub
-from eventlet.greenio import GreenSocket as socket
-from eventlet.greenio import _GLOBAL_DEFAULT_TIMEOUT
+from eventlet import greenio
+
+
+socket = greenio.GreenSocket
+_GLOBAL_DEFAULT_TIMEOUT = greenio._GLOBAL_DEFAULT_TIMEOUT
+timeout = greenio.socket_timeout
try:
__original_fromfd__ = __socket.fromfd
diff --git a/eventlet/greenio/base.py b/eventlet/greenio/base.py
index 7cb68c1..042f7d8 100644
--- a/eventlet/greenio/base.py
+++ b/eventlet/greenio/base.py
@@ -13,6 +13,7 @@ __all__ = [
'GreenSocket', '_GLOBAL_DEFAULT_TIMEOUT', 'set_nonblocking',
'SOCKET_BLOCKING', 'SOCKET_CLOSED', 'CONNECT_ERR', 'CONNECT_SUCCESS',
'shutdown_safe', 'SSL',
+ 'socket_timeout',
]
BUFFER_SIZE = 4096
@@ -27,6 +28,9 @@ if six.PY2:
_original_socket = eventlet.patcher.original('socket').socket
+socket_timeout = eventlet.timeout.wrap_is_timeout(socket.timeout)
+
+
def socket_connect(descriptor, address):
"""
Attempts to connect to the address, returns the descriptor if it succeeds,
@@ -210,14 +214,14 @@ class GreenSocket(object):
if self.act_non_blocking:
return self.fd.accept()
fd = self.fd
+ _timeout_exc = socket_timeout('timed out')
while True:
res = socket_accept(fd)
if res is not None:
client, addr = res
set_nonblocking(client)
return type(self)(client), addr
- self._trampoline(fd, read=True, timeout=self.gettimeout(),
- timeout_exc=socket.timeout("timed out"))
+ self._trampoline(fd, read=True, timeout=self.gettimeout(), timeout_exc=_timeout_exc)
def _mark_as_closed(self):
""" Mark this socket as being closed """
@@ -233,6 +237,7 @@ class GreenSocket(object):
if self.act_non_blocking:
return self.fd.connect(address)
fd = self.fd
+ _timeout_exc = socket_timeout('timed out')
if self.gettimeout() is None:
while not socket_connect(fd, address):
try:
@@ -246,10 +251,10 @@ class GreenSocket(object):
if socket_connect(fd, address):
return
if time.time() >= end:
- raise socket.timeout("timed out")
+ raise _timeout_exc
+ timeout = end - time.time()
try:
- self._trampoline(fd, write=True, timeout=end - time.time(),
- timeout_exc=socket.timeout("timed out"))
+ self._trampoline(fd, write=True, timeout=timeout, timeout_exc=_timeout_exc)
except IOClosed:
# ... we need some workable errno here.
raise socket.error(errno.EBADFD)
@@ -270,14 +275,15 @@ class GreenSocket(object):
return errno.EBADFD
else:
end = time.time() + self.gettimeout()
+ timeout_exc = socket.timeout(errno.EAGAIN)
while True:
try:
if socket_connect(fd, address):
return 0
if time.time() >= end:
- raise socket.timeout(errno.EAGAIN)
+ raise timeout_exc
self._trampoline(fd, write=True, timeout=end - time.time(),
- timeout_exc=socket.timeout(errno.EAGAIN))
+ timeout_exc=timeout_exc)
socket_checkerr(fd)
except socket.error as ex:
return get_errno(ex)
@@ -316,7 +322,7 @@ class GreenSocket(object):
self.fd,
read=True,
timeout=self.gettimeout(),
- timeout_exc=socket.timeout("timed out"))
+ timeout_exc=socket_timeout('timed out'))
def _recv_loop(self, recv_meth, empty_val, *args):
fd = self.fd
@@ -366,7 +372,8 @@ class GreenSocket(object):
if self.act_non_blocking:
return send_method(data, *args)
- while 1:
+ _timeout_exc = socket_timeout('timed out')
+ while True:
try:
return send_method(data, *args)
except socket.error as e:
@@ -376,7 +383,7 @@ class GreenSocket(object):
try:
self._trampoline(self.fd, write=True, timeout=self.gettimeout(),
- timeout_exc=socket.timeout("timed out"))
+ timeout_exc=_timeout_exc)
except IOClosed:
raise socket.error(errno.ECONNRESET, 'Connection closed by another thread')
diff --git a/eventlet/greenthread.py b/eventlet/greenthread.py
index 921d7a9..c0f2982 100644
--- a/eventlet/greenthread.py
+++ b/eventlet/greenthread.py
@@ -3,6 +3,7 @@ import sys
from eventlet import event
from eventlet import hubs
+from eventlet import support
from eventlet import timeout
from eventlet.hubs import timer
from eventlet.support import greenlets as greenlet, six
@@ -144,8 +145,11 @@ def exc_after(seconds, *throw_args):
return hub.schedule_call_local(seconds, getcurrent().throw, *throw_args)
# deprecate, remove
-TimeoutError = timeout.Timeout
-with_timeout = timeout.with_timeout
+TimeoutError, with_timeout = (
+ support.wrap_deprecated(old, new)(fun) for old, new, fun in (
+ ('greenthread.TimeoutError', 'Timeout', timeout.Timeout),
+ ('greenthread.with_timeout', 'with_timeout', timeout.with_timeout),
+ ))
def _spawn_n(seconds, func, args, kwargs):
diff --git a/eventlet/hubs/__init__.py b/eventlet/hubs/__init__.py
index 9f72c16..879ec9a 100644
--- a/eventlet/hubs/__init__.py
+++ b/eventlet/hubs/__init__.py
@@ -118,6 +118,7 @@ def get_hub():
return hub
+# Lame middle file import because complex dependencies in import graph
from eventlet import timeout
diff --git a/eventlet/support/__init__.py b/eventlet/support/__init__.py
index 4c2b75d..b311c8a 100644
--- a/eventlet/support/__init__.py
+++ b/eventlet/support/__init__.py
@@ -1,9 +1,15 @@
+import inspect
+import functools
import sys
-from contextlib import contextmanager
+import warnings
+import contextlib
from eventlet.support import greenlets, six
+_MISSING = object()
+
+
def get_errno(exc):
""" Get the error code out of socket.error objects.
socket.error in <2.5 does not have errno attribute
@@ -43,7 +49,8 @@ else:
PY33 = sys.version_info[:2] == (3, 3)
-@contextmanager
+
+@contextlib.contextmanager
def capture_stderr():
stream = six.StringIO()
original = sys.stderr
@@ -53,3 +60,30 @@ def capture_stderr():
finally:
sys.stderr = original
stream.seek(0)
+
+
+def wrap_deprecated(old, new):
+ def _resolve(s):
+ return 'eventlet.'+s if '.' not in s else s
+ msg = '''\
+{old} is deprecated and will be removed in next version. Use {new} instead.
+Autoupgrade: fgrep -rl '{old}' . |xargs -t sed --in-place='' -e 's/{old}/{new}/'
+'''.format(old=_resolve(old), new=_resolve(new))
+
+ def wrapper(base):
+ klass = None
+ if inspect.isclass(base):
+ klass = base
+ base = klass.__init__
+
+ @functools.wraps(base)
+ def wrapped(*a, **kw):
+ warnings.warn(msg, DeprecationWarning, stacklevel=5)
+ return base(*a, **kw)
+
+ if klass is not None:
+ klass.__init__ = wrapped
+ return klass
+
+ return wrapped
+ return wrapper
diff --git a/eventlet/timeout.py b/eventlet/timeout.py
index f45c6d1..f431871 100644
--- a/eventlet/timeout.py
+++ b/eventlet/timeout.py
@@ -20,13 +20,16 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.from eventlet.support import greenlets as greenlet
+import functools
+import inspect
+
+import eventlet
from eventlet.support import greenlets as greenlet
from eventlet.hubs import get_hub
-__all__ = ['Timeout',
- 'with_timeout']
+__all__ = ['Timeout', 'with_timeout', 'wrap_is_timeout', 'is_timeout']
-_NONE = object()
+_MISSING = object()
# deriving from BaseException so that "except Exception as e" doesn't catch
# Timeout exceptions.
@@ -128,20 +131,48 @@ class Timeout(BaseException):
if value is self and self.exception is False:
return True
+ @property
+ def is_timeout(self):
+ return True
+
def with_timeout(seconds, function, *args, **kwds):
"""Wrap a call to some (yielding) function with a timeout; if the called
function fails to return before the timeout, cancel it and return a flag
value.
"""
- timeout_value = kwds.pop("timeout_value", _NONE)
+ timeout_value = kwds.pop("timeout_value", _MISSING)
timeout = Timeout(seconds)
try:
try:
return function(*args, **kwds)
except Timeout as ex:
- if ex is timeout and timeout_value is not _NONE:
+ if ex is timeout and timeout_value is not _MISSING:
return timeout_value
raise
finally:
timeout.cancel()
+
+
+def wrap_is_timeout(base):
+ '''Adds `.is_timeout=True` attribute to objects returned by `base()`.
+
+ When `base` is class, attribute is added as read-only property. Returns `base`.
+ Otherwise, it returns a function that sets attribute on result of `base()` call.
+
+ Wrappers make best effort to be transparent.
+ '''
+ if inspect.isclass(base):
+ base.is_timeout = property(lambda _: True)
+ return base
+
+ @functools.wraps(base)
+ def fun(*args, **kwargs):
+ ex = base(*args, **kwargs)
+ ex.is_timeout = True
+ return ex
+ return fun
+
+
+def is_timeout(obj):
+ return bool(getattr(obj, 'is_timeout', False))
diff --git a/tests/__init__.py b/tests/__init__.py
index 1c7a5b3..7b6bd09 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -304,6 +304,8 @@ def get_database_auth():
def run_python(path, env=None, args=None, timeout=None, pythonpath_extend=None, expect_pass=False):
new_argv = [sys.executable]
+ if sys.version[:2] <= (2, 6):
+ new_argv += ['-W', 'ignore::DeprecationWarning']
new_env = os.environ.copy()
new_env.setdefault('eventlet_test_in_progress', 'yes')
src_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
@@ -357,6 +359,11 @@ def run_isolated(path, prefix='tests/isolated/', **kwargs):
run_python(prefix + path, **kwargs)
+def check_is_timeout(obj):
+ value_text = getattr(obj, 'is_timeout', '(missing)')
+ assert obj.is_timeout, 'type={0} str={1} .is_timeout={2}'.format(type(obj), str(obj), value_text)
+
+
certificate_file = os.path.join(os.path.dirname(__file__), 'test_server.crt')
private_key_file = os.path.join(os.path.dirname(__file__), 'test_server.key')
diff --git a/tests/api_test.py b/tests/api_test.py
index 1cdab88..2b2e93f 100644
--- a/tests/api_test.py
+++ b/tests/api_test.py
@@ -1,12 +1,7 @@
-import os
-from unittest import TestCase, main
-
-from nose.tools import eq_
-
import eventlet
-from eventlet import greenio, hubs, greenthread, spawn
+from eventlet import greenio, hubs, greenthread
from eventlet.green import ssl
-from tests import skip_if_no_ssl
+import tests
def check_hub():
@@ -21,10 +16,7 @@ def check_hub():
assert not hub.running
-class TestApi(TestCase):
-
- certificate_file = os.path.join(os.path.dirname(__file__), 'test_server.crt')
- private_key_file = os.path.join(os.path.dirname(__file__), 'test_server.key')
+class TestApi(tests.LimitedTestCase):
def test_tcp_listener(self):
socket = eventlet.listen(('0.0.0.0', 0))
@@ -50,13 +42,13 @@ class TestApi(TestCase):
client = eventlet.connect(('127.0.0.1', server.getsockname()[1]))
fd = client.makefile('rb')
client.close()
- eq_(fd.readline(), b'hello\n')
- eq_(fd.read(), b'')
+ assert fd.readline() == b'hello\n'
+ assert fd.read() == b''
fd.close()
check_hub()
- @skip_if_no_ssl
+ @tests.skip_if_no_ssl
def test_connect_ssl(self):
def accept_once(listenfd):
try:
@@ -70,8 +62,8 @@ class TestApi(TestCase):
server = eventlet.wrap_ssl(
eventlet.listen(('0.0.0.0', 0)),
- self.private_key_file,
- self.certificate_file,
+ tests.private_key_file,
+ tests.certificate_file,
server_side=True
)
eventlet.spawn_n(accept_once, server)
@@ -98,12 +90,12 @@ class TestApi(TestCase):
def server(sock):
client, addr = sock.accept()
eventlet.sleep(0.1)
- server_evt = spawn(server, server_sock)
+ server_evt = eventlet.spawn(server, server_sock)
eventlet.sleep(0)
try:
desc = eventlet.connect(('127.0.0.1', bound_port))
hubs.trampoline(desc, read=True, write=False, timeout=0.001)
- except eventlet.TimeoutError:
+ except eventlet.Timeout:
pass # test passed
else:
assert False, "Didn't timeout"
@@ -126,7 +118,7 @@ class TestApi(TestCase):
desc = eventlet.connect(('127.0.0.1', bound_port))
try:
hubs.trampoline(desc, read=True, timeout=0.1)
- except eventlet.TimeoutError:
+ except eventlet.Timeout:
assert False, "Timed out"
server.close()
@@ -174,14 +166,14 @@ class TestApi(TestCase):
try:
eventlet.with_timeout(0.1, func)
- self.fail(u'Expected TimeoutError')
- except eventlet.TimeoutError:
+ self.fail(u'Expected Timeout')
+ except eventlet.Timeout:
pass
-class Foo(object):
- pass
-
+def test_wrap_is_timeout():
+ class A(object):
+ pass
-if __name__ == '__main__':
- main()
+ obj = eventlet.wrap_is_timeout(A)()
+ tests.check_is_timeout(obj)
diff --git a/tests/fork_test.py b/tests/fork_test.py
deleted file mode 100644
index f15883f..0000000
--- a/tests/fork_test.py
+++ /dev/null
@@ -1,52 +0,0 @@
-from tests.patcher_test import ProcessBase
-
-
-class ForkTest(ProcessBase):
- def test_simple(self):
- newmod = '''
-import eventlet
-import os
-import sys
-import signal
-from eventlet.support import bytes_to_str, six
-mydir = %r
-signal_file = os.path.join(mydir, "output.txt")
-pid = os.fork()
-if (pid != 0):
- eventlet.Timeout(10)
- try:
- port = None
- while True:
- try:
- contents = open(signal_file, "rb").read()
- port = int(contents.split()[0])
- break
- except (IOError, IndexError, ValueError, TypeError):
- eventlet.sleep(0.1)
- eventlet.connect(('127.0.0.1', port))
- while True:
- try:
- contents = open(signal_file, "rb").read()
- result = contents.split()[1]
- break
- except (IOError, IndexError):
- eventlet.sleep(0.1)
- print('result {0}'.format(bytes_to_str(result)))
- finally:
- os.kill(pid, signal.SIGTERM)
-else:
- try:
- s = eventlet.listen(('', 0))
- fd = open(signal_file, "wb")
- fd.write(six.b(str(s.getsockname()[1])))
- fd.write(b"\\n")
- fd.flush()
- s.accept()
- fd.write(b"done")
- fd.flush()
- finally:
- fd.close()
-'''
- self.write_to_tempfile("newmod", newmod % self.tempdir)
- output, lines = self.launch_subprocess('newmod.py')
- self.assertEqual(lines[0], "result done", output)
diff --git a/tests/greenio_test.py b/tests/greenio_test.py
index 619ccd0..6d01857 100644
--- a/tests/greenio_test.py
+++ b/tests/greenio_test.py
@@ -443,7 +443,7 @@ class TestGreenSocket(tests.LimitedTestCase):
wrap_rfile = client.makefile()
wrap_rfile.read(1)
self.fail()
- except eventlet.TimeoutError:
+ except eventlet.Timeout:
pass
result = evt.wait()
diff --git a/tests/hub_test.py b/tests/hub_test.py
index fc0ce6f..65ba0a9 100644
--- a/tests/hub_test.py
+++ b/tests/hub_test.py
@@ -1,14 +1,12 @@
from __future__ import with_statement
import sys
+import time
import tests
-from tests import LimitedTestCase, main, skip_with_pyevent, skip_if_no_itimer, skip_unless
+from tests import skip_with_pyevent, skip_if_no_itimer, skip_unless
from tests.patcher_test import ProcessBase
-import time
import eventlet
from eventlet import hubs
-from eventlet.event import Event
-from eventlet.semaphore import Semaphore
from eventlet.support import greenlets, six
@@ -19,7 +17,7 @@ def noop():
pass
-class TestTimerCleanup(LimitedTestCase):
+class TestTimerCleanup(tests.LimitedTestCase):
TEST_TIMEOUT = 2
@skip_with_pyevent
@@ -85,7 +83,7 @@ class TestTimerCleanup(LimitedTestCase):
eventlet.sleep()
-class TestScheduleCall(LimitedTestCase):
+class TestScheduleCall(tests.LimitedTestCase):
def test_local(self):
lst = [1]
@@ -111,7 +109,7 @@ class TestScheduleCall(LimitedTestCase):
self.assertEqual(lst, [1, 2, 3])
-class TestDebug(LimitedTestCase):
+class TestDebug(tests.LimitedTestCase):
def test_debug_listeners(self):
hubs.get_hub().set_debug_listeners(True)
@@ -122,7 +120,7 @@ class TestDebug(LimitedTestCase):
hubs.get_hub().set_timer_exceptions(False)
-class TestExceptionInMainloop(LimitedTestCase):
+class TestExceptionInMainloop(tests.LimitedTestCase):
def test_sleep(self):
# even if there was an error in the mainloop, the hub should continue
@@ -149,13 +147,13 @@ class TestExceptionInMainloop(LimitedTestCase):
delay, DELAY)
-class TestExceptionInGreenthread(LimitedTestCase):
+class TestExceptionInGreenthread(tests.LimitedTestCase):
@skip_unless(greenlets.preserves_excinfo)
def test_exceptionpreservation(self):
# events for controlling execution order
- gt1event = Event()
- gt2event = Event()
+ gt1event = eventlet.Event()
+ gt2event = eventlet.Event()
def test_gt1():
try:
@@ -196,7 +194,7 @@ class TestExceptionInGreenthread(LimitedTestCase):
hubs.get_hub().switch()
# semaphores for controlling execution order
- sem = Semaphore()
+ sem = eventlet.Semaphore()
sem.acquire()
g = eventlet.spawn(test_gt, sem)
try:
@@ -206,7 +204,7 @@ class TestExceptionInGreenthread(LimitedTestCase):
g.kill()
-class TestHubSelection(LimitedTestCase):
+class TestHubSelection(tests.LimitedTestCase):
def test_explicit_hub(self):
oldhub = hubs.get_hub()
@@ -217,7 +215,7 @@ class TestHubSelection(LimitedTestCase):
hubs._threadlocal.hub = oldhub
-class TestHubBlockingDetector(LimitedTestCase):
+class TestHubBlockingDetector(tests.LimitedTestCase):
TEST_TIMEOUT = 10
@skip_with_pyevent
@@ -245,7 +243,7 @@ class TestHubBlockingDetector(LimitedTestCase):
debug.hub_blocking_detection(False)
-class TestSuspend(LimitedTestCase):
+class TestSuspend(tests.LimitedTestCase):
TEST_TIMEOUT = 4
longMessage = True
maxDiff = None
@@ -283,25 +281,30 @@ except eventlet.Timeout:
shutil.rmtree(self.tempdir)
-class TestBadFilenos(LimitedTestCase):
+def test_repeated_select_bad_fd():
+ from eventlet.green import select
- @skip_with_pyevent
- def test_repeated_selects(self):
- from eventlet.green import select
- self.assertRaises(ValueError, select.select, [-1], [], [])
- self.assertRaises(ValueError, select.select, [-1], [], [])
+ def once():
+ try:
+ select.select([-1], [], [])
+ assert False, 'Expected ValueError'
+ except ValueError:
+ pass
+ once()
+ once()
-class TestFork(LimitedTestCase):
- @skip_with_pyevent
- def test_fork(self):
- output = tests.run_python('tests/hub_test_fork.py')
- lines = output.splitlines()
- self.assertEqual(lines, [b"accept blocked", b"child died ok"], output)
+@skip_with_pyevent
+def test_fork():
+ tests.run_isolated('hub_fork.py')
+
+
+def test_fork_simple():
+ tests.run_isolated('hub_fork_simple.py')
-class TestDeadRunLoop(LimitedTestCase):
+class TestDeadRunLoop(tests.LimitedTestCase):
TEST_TIMEOUT = 2
class CustomException(Exception):
@@ -397,7 +400,3 @@ print('ok')
self.write_to_tempfile('newmod', module_source)
output, _ = self.launch_subprocess('newmod.py')
self.assertEqual(output, 'kqueue tried\nok\n')
-
-
-if __name__ == '__main__':
- main()
diff --git a/tests/hub_test_fork.py b/tests/hub_test_fork.py
deleted file mode 100644
index f886a96..0000000
--- a/tests/hub_test_fork.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# no standard tests in this file, ignore
-__test__ = False
-
-if __name__ == '__main__':
- import os
- import eventlet
- server = eventlet.listen(('localhost', 12345))
- t = eventlet.Timeout(0.01)
- try:
- new_sock, address = server.accept()
- except eventlet.Timeout as t:
- pass
-
- pid = os.fork()
- if not pid:
- t = eventlet.Timeout(0.1)
- try:
- new_sock, address = server.accept()
- except eventlet.Timeout as t:
- print("accept blocked")
- else:
- kpid, status = os.wait()
- assert kpid == pid
- assert status == 0
- print("child died ok")
diff --git a/tests/isolated/hub_fork.py b/tests/isolated/hub_fork.py
new file mode 100644
index 0000000..1872942
--- /dev/null
+++ b/tests/isolated/hub_fork.py
@@ -0,0 +1,33 @@
+# verify eventlet.listen() accepts in forked children
+__test__ = False
+
+if __name__ == '__main__':
+ import os
+ import sys
+ import eventlet
+
+ server = eventlet.listen(('127.0.0.1', 0))
+ result = eventlet.with_timeout(0.01, server.accept, timeout_value=True)
+ assert result is True, 'Expected timeout'
+
+ pid = os.fork()
+ if pid < 0:
+ print('fork error')
+ sys.exit(1)
+ elif pid == 0:
+ with eventlet.Timeout(1):
+ sock, _ = server.accept()
+ sock.sendall('ok {0}'.format(os.getpid()).encode())
+ sock.close()
+ sys.exit(0)
+ elif pid > 0:
+ with eventlet.Timeout(1):
+ sock = eventlet.connect(server.getsockname())
+ data = sock.recv(20).decode()
+ assert data.startswith('ok ')
+ spid = int(data[3:].strip())
+ assert spid == pid
+ kpid, status = os.wait()
+ assert kpid == pid
+ assert status == 0
+ print('pass')
diff --git a/tests/isolated/hub_fork_simple.py b/tests/isolated/hub_fork_simple.py
new file mode 100644
index 0000000..96389de
--- /dev/null
+++ b/tests/isolated/hub_fork_simple.py
@@ -0,0 +1,58 @@
+import os
+import signal
+import sys
+import tempfile
+__test__ = False
+
+
+def parent(signal_path, pid):
+ eventlet.Timeout(5)
+ port = None
+ while True:
+ try:
+ contents = open(signal_path, 'rb').read()
+ port = int(contents.strip())
+ break
+ except Exception:
+ eventlet.sleep(0.1)
+ eventlet.connect(('127.0.0.1', port))
+ while True:
+ try:
+ contents = open(signal_path, 'rb').read()
+ result = contents.split()[1]
+ break
+ except Exception:
+ eventlet.sleep(0.1)
+ assert result == b'done', repr(result)
+ print('pass')
+
+
+def child(signal_path):
+ eventlet.Timeout(5)
+ s = eventlet.listen(('127.0.0.1', 0))
+ with open(signal_path, 'wb') as f:
+ f.write(str(s.getsockname()[1]).encode() + b'\n')
+ f.flush()
+ s.accept()
+ f.write(b'done\n')
+ f.flush()
+
+
+if __name__ == '__main__':
+ import eventlet
+
+ with tempfile.NamedTemporaryFile() as signal_file:
+ signal_path = signal_file.name
+
+ pid = os.fork()
+ if pid < 0:
+ sys.stderr.write('fork error\n')
+ sys.exit(1)
+ elif pid == 0:
+ child(signal_path)
+ sys.exit(0)
+ elif pid > 0:
+ try:
+ parent(signal_path, pid)
+ except Exception:
+ os.kill(pid, signal.SIGTERM)
diff --git a/tests/socket_test.py b/tests/socket_test.py
index 7b61a7f..740c2c3 100644
--- a/tests/socket_test.py
+++ b/tests/socket_test.py
@@ -88,3 +88,14 @@ def test_getaddrinfo_ipv6_scope():
if not socket.has_ipv6:
return
socket.getaddrinfo('::1%2', 80, socket.AF_INET6)
+
+
+def test_error_is_timeout():
+ s1, _ = socket.socketpair()
+ s1.settimeout(0.01)
+ try:
+ s1.recv(1)
+ except socket.error as e:
+ tests.check_is_timeout(e)
+ else:
+ assert False, 'No timeout, socket.error was not raised'
diff --git a/tests/test__refcount.py b/tests/test__refcount.py
index 6ccfed7..1090a1f 100644
--- a/tests/test__refcount.py
+++ b/tests/test__refcount.py
@@ -2,78 +2,71 @@
are not leaked by the hub.
"""
import gc
-from pprint import pformat
+import pprint
+import sys
import weakref
-from eventlet.support import clear_sys_exc_info
+import eventlet
from eventlet.green import socket
-from eventlet.green.thread import start_new_thread
-from eventlet.green.time import sleep
-
-SOCKET_TIMEOUT = 0.1
-def init_server():
- s = socket.socket()
- s.settimeout(SOCKET_TIMEOUT)
- s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- s.bind(('localhost', 0))
- s.listen(5)
- return s, s.getsockname()[1]
+SOCKET_TIMEOUT = 0.1
def handle_request(s, raise_on_timeout):
try:
conn, address = s.accept()
except socket.timeout:
+ print('handle_request: server accept timeout')
if raise_on_timeout:
raise
else:
return
- # print('handle_request - accepted')
+ print('handle_request: accepted')
res = conn.recv(100)
assert res == b'hello', repr(res)
- # print('handle_request - recvd %r' % res)
- res = conn.send(b'bye')
- # print('handle_request - sent %r' % res)
- # print('handle_request - conn refcount: %s' % sys.getrefcount(conn))
- # conn.close()
+ # print('handle_request: recvd %r' % res)
+ res = conn.sendall(b'bye')
+ # print('handle_request: sent %r' % res)
+ # print('handle_request: conn refcount: %s' % sys.getrefcount(conn))
-def make_request(port):
+def make_request(addr):
# print('make_request')
- s = socket.socket()
- s.connect(('localhost', port))
+ s = eventlet.connect(addr)
# print('make_request - connected')
- res = s.send(b'hello')
+ res = s.sendall(b'hello')
# print('make_request - sent %s' % res)
res = s.recv(100)
assert res == b'bye', repr(res)
# print('make_request - recvd %r' % res)
- # s.close()
def run_interaction(run_client):
- s, port = init_server()
- start_new_thread(handle_request, (s, run_client))
+ s = eventlet.listen(('127.0.0.1', 0))
+ s.settimeout(SOCKET_TIMEOUT)
+ addr = s.getsockname()
+ print('run_interaction: addr:', addr)
+ eventlet.spawn(handle_request, s, run_client)
if run_client:
- start_new_thread(make_request, (port,))
- sleep(0.1 + SOCKET_TIMEOUT)
- # print(sys.getrefcount(s.fd))
- # s.close()
+ eventlet.spawn(make_request, addr)
+ eventlet.sleep(0.1 + SOCKET_TIMEOUT)
+ print('run_interaction: refcount(s.fd)', sys.getrefcount(s.fd))
return weakref.ref(s.fd)
def run_and_check(run_client):
w = run_interaction(run_client=run_client)
- clear_sys_exc_info()
+ # clear_sys_exc_info()
gc.collect()
- if w():
- print(pformat(gc.get_referrers(w())))
- for x in gc.get_referrers(w()):
- print(pformat(x))
+ fd = w()
+ print('run_and_check: weakref fd:', fd)
+ if fd:
+ print(pprint.pformat(gc.get_referrers(fd)))
+ for x in gc.get_referrers(fd):
+ print(pprint.pformat(x))
for y in gc.get_referrers(x):
- print('- {0}'.format(pformat(y)))
+ print('- {0}'.format(pprint.pformat(y)))
raise AssertionError('server should be dead by now')
diff --git a/tests/test__socket_errors.py b/tests/test__socket_errors.py
index c33b227..8cb1f87 100644
--- a/tests/test__socket_errors.py
+++ b/tests/test__socket_errors.py
@@ -56,7 +56,7 @@ class TestSocketErrors(unittest.TestCase):
def test_create_connection_refused():
errno = None
try:
- socket.create_connection(('127.0.0.1', 0))
+ socket.create_connection(('127.0.0.1', 1))
except socket.error as ex:
errno = ex.errno
assert errno in [111, 61, 10061], 'Expected socket.error ECONNREFUSED, got {0}'.format(errno)
diff --git a/tests/timeout_test.py b/tests/timeout_test.py
index 0254b79..e33003f 100644
--- a/tests/timeout_test.py
+++ b/tests/timeout_test.py
@@ -1,12 +1,12 @@
import eventlet
-from tests import LimitedTestCase
+import tests
DELAY = 0.01
-class TestDirectRaise(LimitedTestCase):
+class TestDirectRaise(tests.LimitedTestCase):
def test_direct_raise_class(self):
try:
raise eventlet.Timeout
@@ -36,7 +36,7 @@ class TestDirectRaise(LimitedTestCase):
str(tm)
-class TestWithTimeout(LimitedTestCase):
+class TestWithTimeout(tests.LimitedTestCase):
def test_with_timeout(self):
self.assertRaises(eventlet.Timeout, eventlet.with_timeout, DELAY, eventlet.sleep, DELAY * 10)
X = object()
@@ -53,3 +53,7 @@ class TestWithTimeout(LimitedTestCase):
eventlet.Timeout,
eventlet.with_timeout,
DELAY, longer_timeout)
+
+
+def test_is_timeout_attribute():
+ tests.check_is_timeout(eventlet.Timeout())
diff --git a/tests/tpool_test.py b/tests/tpool_test.py
index d44ff6b..78e3437 100644
--- a/tests/tpool_test.py
+++ b/tests/tpool_test.py
@@ -20,7 +20,7 @@ import re
import time
import eventlet
-from eventlet import tpool, debug, event
+from eventlet import tpool
from eventlet.support import six
import tests
@@ -218,10 +218,13 @@ class TestTpool(tests.LimitedTestCase):
@tests.skip_with_pyevent
def test_timeout(self):
- import time
- eventlet.Timeout(0.1, eventlet.TimeoutError())
- self.assertRaises(eventlet.TimeoutError,
- tpool.execute, time.sleep, 0.3)
+ blocking = eventlet.patcher.original('time')
+ eventlet.Timeout(0.1, eventlet.Timeout())
+ try:
+ tpool.execute(blocking.sleep, 0.3)
+ assert False, 'Expected Timeout'
+ except eventlet.Timeout:
+ pass
@tests.skip_with_pyevent
def test_killall(self):
@@ -230,7 +233,7 @@ class TestTpool(tests.LimitedTestCase):
@tests.skip_with_pyevent
def test_killall_remaining_results(self):
- semaphore = event.Event()
+ semaphore = eventlet.Event()
def native_fun():
time.sleep(.5)
diff --git a/tox.ini b/tox.ini
index 7e9daec..db9673b 100644
--- a/tox.ini
+++ b/tox.ini
@@ -14,7 +14,7 @@ show-source = 1
statistics = 1
[tox]
-minversion=1.8
+minversion=2.5
envlist =
pep8, py{26,27,33,34,35,py}-{selects,poll,epolls}
@@ -34,6 +34,7 @@ setenv =
selects: EVENTLET_HUB = selects
poll: EVENTLET_HUB = poll
epolls: EVENTLET_HUB = epolls
+ tox_cover_args = --with-coverage --cover-erase --cover-package=eventlet
basepython =
py26: python2.6
py27: python2.7
@@ -52,5 +53,5 @@ deps =
{selects,poll,epolls}: psycopg2cffi-compat==1.1
{selects,poll,epolls}: pyzmq==13.1.0
commands =
- nosetests --verbose --with-coverage --cover-erase --cover-package=eventlet {posargs:tests/}
+ nosetests --verbose {env:tox_cover_args} {posargs:tests/}
coverage xml -i