This commit is contained in:
Ryan Williams
2009-12-15 10:36:32 -08:00
22 changed files with 236 additions and 93 deletions

View File

@@ -26,7 +26,7 @@ Thanks To
* Chuck Thier, reporting a bug in processes.py * Chuck Thier, reporting a bug in processes.py
* Brantley Harris, reporting bug #4 * Brantley Harris, reporting bug #4
* Taso Du Val, reproing an exception squelching bug, saving children's lives ;-) * Taso Du Val, reproing an exception squelching bug, saving children's lives ;-)
* R. Tyler Ballance, bug report on tpool on Windows, help with improving corolocal module * R. Tyler Ballance, bug report on tpool on Windows, help with improving corolocal module, profile performance report, suggestion use flush that fixed tpool on Windows
* Sergey Shepelev, PEP 8 police :-), reporting bug #5 * Sergey Shepelev, PEP 8 police :-), reporting bug #5
* Luci Stanescu, for reporting twisted hub bug * Luci Stanescu, for reporting twisted hub bug
* Marcus Cavanaugh, for test case code that has been incredibly useful in tracking down bugs * Marcus Cavanaugh, for test case code that has been incredibly useful in tracking down bugs

4
NEWS
View File

@@ -13,7 +13,9 @@
* Added support for logging x-forwarded-for header in wsgi. * Added support for logging x-forwarded-for header in wsgi.
* api.tcp_server is now deprecated, will be removed in a future release. * api.tcp_server is now deprecated, will be removed in a future release.
* Added instructions on how to generate coverage reports to the documentation. * Added instructions on how to generate coverage reports to the documentation.
* Bug fixes in: wsgi.py, twistedr.py, poll.py, greenio.py, util.py, select.py, processes.py * Renamed GreenFile to Green_fileobject, to better reflect its purpose.
* Deprecated erpc method in tpool.py
* Bug fixes in: wsgi.py, twistedr.py, poll.py, greenio.py, util.py, select.py, processes.py, selects.py
0.9.0 0.9.0
===== =====

View File

@@ -35,7 +35,7 @@ easy_install eventlet
<p>Alternately, you can download the source tarball: <p>Alternately, you can download the source tarball:
<ul> <ul>
<li><a href="http://pypi.python.org/packages/source/e/eventlet/eventlet-0.9.0.tar.gz#md5=4e14ce5070edd078e3a4e8d6df9a5dc4">eventlet-0.9.0.tar.gz</a></li> <li><a href="http://pypi.python.org/packages/source/e/eventlet/eventlet-0.9.1.tar.gz">eventlet-0.9.1.tar.gz</a></li>
</ul> </ul>
</p> </p>

View File

@@ -1,2 +1,2 @@
version_info = (0, 9, '1pre') version_info = (0, 9, 1)
__version__ = '%s.%s.%s' % version_info __version__ = '%s.%s.%s' % version_info

View File

@@ -11,12 +11,23 @@ from thread import get_ident
from eventlet.greenio import set_nonblocking, GreenSocket, SOCKET_CLOSED, CONNECT_ERR, CONNECT_SUCCESS from eventlet.greenio import set_nonblocking, GreenSocket, SOCKET_CLOSED, CONNECT_ERR, CONNECT_SUCCESS
orig_socket = __import__('socket') orig_socket = __import__('socket')
socket = orig_socket.socket socket = orig_socket.socket
timeout_exc = orig_socket.timeout
class GreenSSLSocket(__ssl.SSLSocket): class GreenSSLSocket(__ssl.SSLSocket):
""" This is a green version of the SSLSocket class from the ssl module added """ This is a green version of the SSLSocket class from the ssl module added
in 2.6. For documentation on it, please see the Python standard in 2.6. For documentation on it, please see the Python standard
documentation.""" documentation.
Python nonblocking ssl objects don't give errors when the other end
of the socket is closed (they do notice when the other end is shutdown,
though). Any write/read operations will simply hang if the socket is
closed from the other end. There is no obvious fix for this problem;
it appears to be a limitation of Python's ssl object implementation.
A workaround is to set a reasonable timeout on the socket using
settimeout(), and to close/reopen the connection when a timeout
occurs at an unexpected juncture in the code.
"""
# we are inheriting from SSLSocket because its constructor calls # we are inheriting from SSLSocket because its constructor calls
# do_handshake whose behavior we wish to override # do_handshake whose behavior we wish to override
def __init__(self, sock, *args, **kw): def __init__(self, sock, *args, **kw):
@@ -62,12 +73,12 @@ class GreenSSLSocket(__ssl.SSLSocket):
trampoline(self.fileno(), trampoline(self.fileno(),
read=True, read=True,
timeout=self.gettimeout(), timeout=self.gettimeout(),
timeout_exc=SSLError) timeout_exc=timeout_exc('timed out'))
elif exc[0] == SSL_ERROR_WANT_WRITE: elif exc[0] == SSL_ERROR_WANT_WRITE:
trampoline(self.fileno(), trampoline(self.fileno(),
write=True, write=True,
timeout=self.gettimeout(), timeout=self.gettimeout(),
timeout_exc=SSLError) timeout_exc=timeout_exc('timed out'))
else: else:
raise raise
@@ -121,7 +132,7 @@ class GreenSSLSocket(__ssl.SSLSocket):
raise ValueError("sendto not allowed on instances of %s" % raise ValueError("sendto not allowed on instances of %s" %
self.__class__) self.__class__)
else: else:
trampoline(self.fileno(), write=True, timeout_exc=orig_socket.timeout) trampoline(self.fileno(), write=True, timeout_exc=timeout_exc('timed out'))
return socket.sendto(self, data, addr, flags) return socket.sendto(self, data, addr, flags)
def sendall (self, data, flags=0): def sendall (self, data, flags=0):
@@ -146,7 +157,7 @@ class GreenSSLSocket(__ssl.SSLSocket):
raise raise
if e[0] == errno.EWOULDBLOCK: if e[0] == errno.EWOULDBLOCK:
trampoline(self.fileno(), write=True, trampoline(self.fileno(), write=True,
timeout=self.gettimeout(), timeout_exc=orig_socket.timeout) timeout=self.gettimeout(), timeout_exc=timeout_exc('timed out'))
if e[0] in SOCKET_CLOSED: if e[0] in SOCKET_CLOSED:
return '' return ''
raise raise
@@ -169,7 +180,7 @@ class GreenSSLSocket(__ssl.SSLSocket):
raise raise
if e[0] == errno.EWOULDBLOCK: if e[0] == errno.EWOULDBLOCK:
trampoline(self.fileno(), read=True, trampoline(self.fileno(), read=True,
timeout=self.gettimeout(), timeout_exc=orig_socket.timeout) timeout=self.gettimeout(), timeout_exc=timeout_exc('timed out'))
if e[0] in SOCKET_CLOSED: if e[0] in SOCKET_CLOSED:
return '' return ''
raise raise
@@ -177,17 +188,17 @@ class GreenSSLSocket(__ssl.SSLSocket):
def recv_into (self, buffer, nbytes=None, flags=0): def recv_into (self, buffer, nbytes=None, flags=0):
if not self.act_non_blocking: if not self.act_non_blocking:
trampoline(self.fileno(), read=True, timeout=self.gettimeout(), timeout_exc=orig_socket.timeout) trampoline(self.fileno(), read=True, timeout=self.gettimeout(), timeout_exc=timeout_exc('timed out'))
return super(GreenSSLSocket, self).recv_into(buffer, nbytes, flags) return super(GreenSSLSocket, self).recv_into(buffer, nbytes, flags)
def recvfrom (self, addr, buflen=1024, flags=0): def recvfrom (self, addr, buflen=1024, flags=0):
if not self.act_non_blocking: if not self.act_non_blocking:
trampoline(self.fileno(), read=True, timeout=self.gettimeout(), timeout_exc=orig_socket.timeout) trampoline(self.fileno(), read=True, timeout=self.gettimeout(), timeout_exc=timeout_exc('timed out'))
return super(GreenSSLSocket, self).recvfrom(addr, buflen, flags) return super(GreenSSLSocket, self).recvfrom(addr, buflen, flags)
def recvfrom_into (self, buffer, nbytes=None, flags=0): def recvfrom_into (self, buffer, nbytes=None, flags=0):
if not self.act_non_blocking: if not self.act_non_blocking:
trampoline(self.fileno(), read=True, timeout=self.gettimeout(), timeout_exc=orig_socket.timeout) trampoline(self.fileno(), read=True, timeout=self.gettimeout(), timeout_exc=timeout_exc('timed out'))
return super(GreenSSLSocket, self).recvfrom_into(buffer, nbytes, flags) return super(GreenSSLSocket, self).recvfrom_into(buffer, nbytes, flags)
def unwrap(self): def unwrap(self):
@@ -224,13 +235,13 @@ class GreenSSLSocket(__ssl.SSLSocket):
except orig_socket.error, exc: except orig_socket.error, exc:
if exc[0] in CONNECT_ERR: if exc[0] in CONNECT_ERR:
trampoline(self.fileno(), write=True, trampoline(self.fileno(), write=True,
timeout=end-time.time(), timeout_exc=orig_socket.timeout) timeout=end-time.time(), timeout_exc=timeout_exc('timed out'))
elif exc[0] in CONNECT_SUCCESS: elif exc[0] in CONNECT_SUCCESS:
return return
else: else:
raise raise
if time.time() >= end: if time.time() >= end:
raise orig_socket.timeout raise timeout_exc('timed out')
def connect(self, addr): def connect(self, addr):
@@ -264,7 +275,7 @@ class GreenSSLSocket(__ssl.SSLSocket):
if e[0] != errno.EWOULDBLOCK: if e[0] != errno.EWOULDBLOCK:
raise raise
trampoline(self.fileno(), read=True, timeout=self.gettimeout(), trampoline(self.fileno(), read=True, timeout=self.gettimeout(),
timeout_exc=orig_socket.timeout) timeout_exc=timeout_exc('timed out'))
new_ssl = type(self)(newsock, new_ssl = type(self)(newsock,
keyfile=self.keyfile, keyfile=self.keyfile,

View File

@@ -14,7 +14,7 @@ import warnings
from errno import EWOULDBLOCK, EAGAIN from errno import EWOULDBLOCK, EAGAIN
__all__ = ['GreenSocket', 'GreenFile', 'GreenPipe'] __all__ = ['GreenSocket', 'GreenPipe']
def higher_order_recv(recv_func): def higher_order_recv(recv_func):
def recv(self, buflen, flags=0): def recv(self, buflen, flags=0):
@@ -167,6 +167,10 @@ class GreenSocket(object):
fd = family_or_realsock fd = family_or_realsock
assert not args, args assert not args, args
assert not kwargs, kwargs assert not kwargs, kwargs
try:
orig_timeout = fd.gettimeout()
except AttributeError:
orig_timeout = None
set_nonblocking(fd) set_nonblocking(fd)
self.fd = fd self.fd = fd
@@ -181,6 +185,10 @@ class GreenSocket(object):
# act non-blocking # act non-blocking
self.act_non_blocking = False self.act_non_blocking = False
# import timeout from the other fd if it's distinct
if orig_timeout and orig_timeout is not self.timeout:
self.settimeout(orig_timeout)
@property @property
def _sock(self): def _sock(self):
return self return self
@@ -294,7 +302,7 @@ class GreenSocket(object):
return socket._fileobject(self.dup(), mode, bufsize) return socket._fileobject(self.dup(), mode, bufsize)
def makeGreenFile(self, mode='r', bufsize=-1): def makeGreenFile(self, mode='r', bufsize=-1):
return GreenFile(self.dup()) return Green_fileobject(self.dup())
recv = higher_order_recv(socket_recv) recv = higher_order_recv(socket_recv)
@@ -362,8 +370,9 @@ class GreenSocket(object):
return self.timeout return self.timeout
class Green_fileobject(object):
class GreenFile(object): """Green version of socket._fileobject, for use only with regular
sockets."""
newlines = '\r\n' newlines = '\r\n'
mode = 'wb+' mode = 'wb+'
@@ -486,7 +495,7 @@ class GreenPipeSocket(GreenSocket):
send = higher_order_send(file_send) send = higher_order_send(file_send)
class GreenPipe(GreenFile): class GreenPipe(Green_fileobject):
def __init__(self, fd): def __init__(self, fd):
set_nonblocking(fd) set_nonblocking(fd)
self.fd = GreenPipeSocket(fd) self.fd = GreenPipeSocket(fd)

View File

@@ -61,6 +61,7 @@ class BaseHub(object):
'exit': [], 'exit': [],
} }
self.lclass = FdListener self.lclass = FdListener
self.silent_timer_exceptions = False
def add(self, evtype, fileno, cb): def add(self, evtype, fileno, cb):
""" Signals an intent to or write a particular file descriptor. """ Signals an intent to or write a particular file descriptor.
@@ -220,6 +221,7 @@ class BaseHub(object):
self.squelch_observer_exception(observer, sys.exc_info()) self.squelch_observer_exception(observer, sys.exc_info())
def squelch_timer_exception(self, timer, exc_info): def squelch_timer_exception(self, timer, exc_info):
if not self.silent_timer_exceptions:
traceback.print_exception(*exc_info) traceback.print_exception(*exc_info)
print >>sys.stderr, "Timer raised: %r" % (timer,) print >>sys.stderr, "Timer raised: %r" % (timer,)

View File

@@ -7,7 +7,7 @@ import time
from eventlet.hubs.hub import BaseHub, READ, WRITE from eventlet.hubs.hub import BaseHub, READ, WRITE
EXC_MASK = select.POLLERR | select.POLLHUP EXC_MASK = select.POLLERR | select.POLLHUP
READ_MASK = select.POLLIN READ_MASK = select.POLLIN | select.POLLPRI
WRITE_MASK = select.POLLOUT WRITE_MASK = select.POLLOUT
class Hub(BaseHub): class Hub(BaseHub):

View File

@@ -25,8 +25,8 @@ QUIET=False
_rfile = _wfile = None _rfile = _wfile = None
def _signal_t2e(): def _signal_t2e():
from eventlet import util _wfile.write(' ')
sent = util.__original_write__(_wfile.fileno(), ' ') _wfile.flush()
_reqq = Queue(maxsize=-1) _reqq = Queue(maxsize=-1)
_rspq = Queue(maxsize=-1) _rspq = Queue(maxsize=-1)
@@ -36,9 +36,9 @@ def tpool_trampoline():
while(True): while(True):
try: try:
_c = _rfile.read(1) _c = _rfile.read(1)
assert(_c != "")
except ValueError: except ValueError:
break # will be raised when pipe is closed break # will be raised when pipe is closed
assert(_c != "")
while not _rspq.empty(): while not _rspq.empty():
try: try:
(e,rv) = _rspq.get(block=False) (e,rv) = _rspq.get(block=False)
@@ -197,10 +197,8 @@ def setup():
sock.listen(50) sock.listen(50)
csock = util.__original_socket__(socket.AF_INET, socket.SOCK_STREAM) csock = util.__original_socket__(socket.AF_INET, socket.SOCK_STREAM)
csock.connect(('localhost', sock.getsockname()[1])) csock.connect(('localhost', sock.getsockname()[1]))
csock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
nsock, addr = sock.accept() nsock, addr = sock.accept()
nsock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) _rfile = greenio.Green_fileobject(greenio.GreenSocket(csock))
_rfile = greenio.GreenFile(greenio.GreenSocket(csock))
_wfile = nsock.makefile() _wfile = nsock.makefile()
for i in range(0,_nthreads): for i in range(0,_nthreads):
@@ -218,6 +216,7 @@ def killall():
_reqq.put(None) _reqq.put(None)
for thr in _threads.values(): for thr in _threads.values():
thr.join() thr.join()
if _coro:
api.kill(_coro) api.kill(_coro)
_rfile.close() _rfile.close()
_wfile.close() _wfile.close()

View File

@@ -154,7 +154,7 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
except greenio.SSL.ZeroReturnError: except greenio.SSL.ZeroReturnError:
self.raw_requestline = '' self.raw_requestline = ''
except socket.error, e: except socket.error, e:
if e[0] != errno.EBADF: if e[0] != errno.EBADF and e[0] != 10053:
raise raise
self.raw_requestline = '' self.raw_requestline = ''
@@ -261,11 +261,14 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
'Content-Length' not in [h for h, v in headers_set[1]]: 'Content-Length' not in [h for h, v in headers_set[1]]:
headers_set[1].append(('Content-Length', str(sum(map(len, result))))) headers_set[1].append(('Content-Length', str(sum(map(len, result)))))
towrite = [] towrite = []
towrite_size = 0
for data in result: for data in result:
towrite.append(data) towrite.append(data)
if sum(map(len, towrite)) >= self.minimum_chunk_size: towrite_size += len(data)
if towrite_size >= self.minimum_chunk_size:
write(''.join(towrite)) write(''.join(towrite))
towrite = [] towrite = []
towrite_size = 0
if towrite: if towrite:
write(''.join(towrite)) write(''.join(towrite))
if not headers_sent or use_chunked[0]: if not headers_sent or use_chunked[0]:

View File

@@ -4,6 +4,9 @@ import os
import errno import errno
import unittest import unittest
# convenience
main = unittest.main
def skipped(func): def skipped(func):
""" Decorator that marks a function as skipped. Uses nose's SkipTest exception """ Decorator that marks a function as skipped. Uses nose's SkipTest exception
if installed. Without nose, this will count skipped tests as passing tests.""" if installed. Without nose, this will count skipped tests as passing tests."""
@@ -21,21 +24,36 @@ def skipped(func):
return skipme return skipme
def skip_unless(requirement): def skip_if(condition):
""" Decorator that skips a test if the *requirement* does not return True. """ Decorator that skips a test if the *condition* evaluates True.
*requirement* can be a boolean or a callable that accepts one argument. *condition* can be a boolean or a callable that accepts one argument.
The callable will be called with the function to be decorated, and The callable will be called with the function to be decorated, and
should return True if the requirement is satisfied. should return True to skip the test.
""" """
if isinstance(requirement, bool):
def skipped_wrapper(func): def skipped_wrapper(func):
if not requirement: if isinstance(condition, bool):
result = condition
else:
result = condition(func)
if result:
return skipped(func) return skipped(func)
else: else:
return func return func
else: return skipped_wrapper
def skip_unless(condition):
""" Decorator that skips a test if the *condition* does not return True.
*condition* can be a boolean or a callable that accepts one argument.
The callable will be called with the function to be decorated, and
should return True if the condition is satisfied.
"""
def skipped_wrapper(func): def skipped_wrapper(func):
if not requirement(func): if isinstance(condition, bool):
result = condition
else:
result = condition(func)
if not result:
return skipped(func) return skipped(func)
else: else:
return func return func
@@ -55,10 +73,15 @@ def requires_twisted(func):
def skip_with_libevent(func): def skip_with_libevent(func):
""" Decorator that skips a test if we're using the libevent hub.""" """ Decorator that skips a test if we're using the libevent hub."""
def requirement(_f): def using_libevent(_f):
from eventlet.api import get_hub from eventlet.api import get_hub
return not('libevent' in type(get_hub()).__module__) return 'libevent' in type(get_hub()).__module__
return skip_unless(requirement)(func) return skip_if(using_libevent)(func)
def skip_on_windows(func):
import sys
return skip_if(sys.platform.startswith('win'))(func)
class TestIsTakingTooLong(Exception): class TestIsTakingTooLong(Exception):
@@ -82,6 +105,20 @@ class LimitedTestCase(unittest.TestCase):
self.timer.cancel() self.timer.cancel()
class SilencedTestCase(LimitedTestCase):
""" Subclass of LimitedTestCase that also silences the printing of timer
exceptions."""
def setUp(self):
from eventlet import api
super(SilencedTestCase, self).setUp()
api.get_hub().silent_timer_exceptions = True
def tearDown(self):
from eventlet import api
super(SilencedTestCase, self).tearDown()
api.get_hub().silent_timer_exceptions = False
def find_command(command): def find_command(command):
for dir in os.getenv('PATH', '/usr/bin:/usr/sbin').split(os.pathsep): for dir in os.getenv('PATH', '/usr/bin:/usr/sbin').split(os.pathsep):
p = os.path.join(dir, command) p = os.path.join(dir, command)

View File

@@ -1,15 +1,8 @@
from unittest import TestCase, main from unittest import main, TestCase
from tests import SilencedTestCase
from eventlet import coros, api from eventlet import coros, api
class TestEvent(TestCase): class TestEvent(SilencedTestCase):
mode = 'static'
def setUp(self):
# raise an exception if we're waiting forever
self._cancel_timeout = api.exc_after(1, RuntimeError('test takes too long'))
def tearDown(self):
self._cancel_timeout.cancel()
def test_waiting_for_event(self): def test_waiting_for_event(self):
evt = coros.event() evt = coros.event()
value = 'some stuff' value = 'some stuff'
@@ -81,15 +74,14 @@ class IncrActor(coros.Actor):
if evt: evt.send() if evt: evt.send()
class TestActor(TestCase): class TestActor(SilencedTestCase):
mode = 'static' mode = 'static'
def setUp(self): def setUp(self):
# raise an exception if we're waiting forever super(TestActor, self).setUp()
self._cancel_timeout = api.exc_after(1, api.TimeoutError())
self.actor = IncrActor() self.actor = IncrActor()
def tearDown(self): def tearDown(self):
self._cancel_timeout.cancel() super(TestActor, self).tearDown()
api.kill(self.actor._killer) api.kill(self.actor._killer)
def test_cast(self): def test_cast(self):

View File

@@ -2,6 +2,7 @@ from tests import skipped, LimitedTestCase, skip_with_libevent, TestIsTakingTooL
from unittest import main from unittest import main
from eventlet import api, util, coros, proc, greenio from eventlet import api, util, coros, proc, greenio
from eventlet.green.socket import GreenSSLObject from eventlet.green.socket import GreenSSLObject
import errno
import os import os
import socket import socket
import sys import sys
@@ -29,6 +30,17 @@ def min_buf_size():
return test_sock.getsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF) return test_sock.getsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF)
class TestGreenIo(LimitedTestCase): class TestGreenIo(LimitedTestCase):
def test_connect_timeout(self):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(0.1)
gs = greenio.GreenSocket(s)
try:
self.assertRaises(socket.timeout, gs.connect, ('192.0.2.1', 80))
except socket.error, e:
# unreachable is also a valid outcome
if e[0] != errno.EHOSTUNREACH:
raise
def test_close_with_makefile(self): def test_close_with_makefile(self):
def accept_close_early(listener): def accept_close_early(listener):
# verify that the makefile and the socket are truly independent # verify that the makefile and the socket are truly independent

View File

@@ -1,12 +1,14 @@
import sys import sys
from unittest import TestCase, main from tests import LimitedTestCase, main, skip_on_windows
from eventlet import processes, api from eventlet import processes, api
class TestEchoPool(TestCase): class TestEchoPool(LimitedTestCase):
def setUp(self): def setUp(self):
super(TestEchoPool, self).setUp()
self.pool = processes.ProcessPool('echo', ["hello"]) self.pool = processes.ProcessPool('echo', ["hello"])
@skip_on_windows
def test_echo(self): def test_echo(self):
result = None result = None
@@ -17,6 +19,7 @@ class TestEchoPool(TestCase):
self.pool.put(proc) self.pool.put(proc)
self.assertEquals(result, 'hello\n') self.assertEquals(result, 'hello\n')
@skip_on_windows
def test_read_eof(self): def test_read_eof(self):
proc = self.pool.get() proc = self.pool.get()
try: try:
@@ -25,17 +28,20 @@ class TestEchoPool(TestCase):
finally: finally:
self.pool.put(proc) self.pool.put(proc)
@skip_on_windows
def test_empty_echo(self): def test_empty_echo(self):
p = processes.Process('echo', ['-n']) p = processes.Process('echo', ['-n'])
self.assertEquals('', p.read()) self.assertEquals('', p.read())
self.assertRaises(processes.DeadProcess, p.read) self.assertRaises(processes.DeadProcess, p.read)
class TestCatPool(TestCase): class TestCatPool(LimitedTestCase):
def setUp(self): def setUp(self):
super(TestCatPool, self).setUp()
api.sleep(0) api.sleep(0)
self.pool = processes.ProcessPool('cat') self.pool = processes.ProcessPool('cat')
@skip_on_windows
def test_cat(self): def test_cat(self):
result = None result = None
@@ -49,6 +55,7 @@ class TestCatPool(TestCase):
self.assertEquals(result, 'goodbye') self.assertEquals(result, 'goodbye')
@skip_on_windows
def test_write_to_dead(self): def test_write_to_dead(self):
result = None result = None
@@ -61,6 +68,7 @@ class TestCatPool(TestCase):
finally: finally:
self.pool.put(proc) self.pool.put(proc)
@skip_on_windows
def test_close(self): def test_close(self):
result = None result = None
@@ -73,10 +81,12 @@ class TestCatPool(TestCase):
self.pool.put(proc) self.pool.put(proc)
class TestDyingProcessesLeavePool(TestCase): class TestDyingProcessesLeavePool(LimitedTestCase):
def setUp(self): def setUp(self):
super(TestDyingProcessesLeavePool, self).setUp()
self.pool = processes.ProcessPool('echo', ['hello'], max_size=1) self.pool = processes.ProcessPool('echo', ['hello'], max_size=1)
@skip_on_windows
def test_dead_process_not_inserted_into_pool(self): def test_dead_process_not_inserted_into_pool(self):
proc = self.pool.get() proc = self.pool.get()
try: try:

View File

@@ -5,7 +5,7 @@ import os
import sys import sys
import tempfile import tempfile
import time import time
import unittest from tests import LimitedTestCase, main, skip_on_windows
import re import re
import StringIO import StringIO
@@ -31,12 +31,14 @@ class CoroutineCallingClass(object):
return self._my_dict return self._my_dict
class TestSaranwrap(unittest.TestCase): class TestSaranwrap(LimitedTestCase):
TEST_TIMEOUT=3
def assert_server_exists(self, prox): def assert_server_exists(self, prox):
self.assert_(saranwrap.status(prox)) self.assert_(saranwrap.status(prox))
prox.foo = 0 prox.foo = 0
self.assertEqual(0, prox.foo) self.assertEqual(0, prox.foo)
@skip_on_windows
def test_wrap_tuple(self): def test_wrap_tuple(self):
my_tuple = (1, 2) my_tuple = (1, 2)
prox = saranwrap.wrap(my_tuple) prox = saranwrap.wrap(my_tuple)
@@ -44,6 +46,7 @@ class TestSaranwrap(unittest.TestCase):
self.assertEqual(prox[1], 2) self.assertEqual(prox[1], 2)
self.assertEqual(len(my_tuple), 2) self.assertEqual(len(my_tuple), 2)
@skip_on_windows
def test_wrap_string(self): def test_wrap_string(self):
my_object = "whatever" my_object = "whatever"
prox = saranwrap.wrap(my_object) prox = saranwrap.wrap(my_object)
@@ -51,6 +54,7 @@ class TestSaranwrap(unittest.TestCase):
self.assertEqual(len(my_object), len(prox)) self.assertEqual(len(my_object), len(prox))
self.assertEqual(my_object.join(['a', 'b']), prox.join(['a', 'b'])) self.assertEqual(my_object.join(['a', 'b']), prox.join(['a', 'b']))
@skip_on_windows
def test_wrap_uniterable(self): def test_wrap_uniterable(self):
# here we're treating the exception as just a normal class # here we're treating the exception as just a normal class
prox = saranwrap.wrap(FloatingPointError()) prox = saranwrap.wrap(FloatingPointError())
@@ -62,6 +66,7 @@ class TestSaranwrap(unittest.TestCase):
self.assertRaises(IndexError, index) self.assertRaises(IndexError, index)
self.assertRaises(TypeError, key) self.assertRaises(TypeError, key)
@skip_on_windows
def test_wrap_dict(self): def test_wrap_dict(self):
my_object = {'a':1} my_object = {'a':1}
prox = saranwrap.wrap(my_object) prox = saranwrap.wrap(my_object)
@@ -71,6 +76,7 @@ class TestSaranwrap(unittest.TestCase):
self.assertEqual('saran:' + repr(my_object), repr(prox)) self.assertEqual('saran:' + repr(my_object), repr(prox))
self.assertEqual('saran:' + `my_object`, `prox`) self.assertEqual('saran:' + `my_object`, `prox`)
@skip_on_windows
def test_wrap_module_class(self): def test_wrap_module_class(self):
prox = saranwrap.wrap(re) prox = saranwrap.wrap(re)
self.assertEqual(saranwrap.Proxy, type(prox)) self.assertEqual(saranwrap.Proxy, type(prox))
@@ -78,6 +84,7 @@ class TestSaranwrap(unittest.TestCase):
self.assertEqual(exp.flags, 0) self.assertEqual(exp.flags, 0)
self.assert_(repr(prox.compile)) self.assert_(repr(prox.compile))
@skip_on_windows
def test_wrap_eq(self): def test_wrap_eq(self):
prox = saranwrap.wrap(re) prox = saranwrap.wrap(re)
exp1 = prox.compile('.') exp1 = prox.compile('.')
@@ -86,6 +93,7 @@ class TestSaranwrap(unittest.TestCase):
exp3 = prox.compile('/') exp3 = prox.compile('/')
self.assert_(exp1 != exp3) self.assert_(exp1 != exp3)
@skip_on_windows
def test_wrap_nonzero(self): def test_wrap_nonzero(self):
prox = saranwrap.wrap(re) prox = saranwrap.wrap(re)
exp1 = prox.compile('.') exp1 = prox.compile('.')
@@ -93,6 +101,7 @@ class TestSaranwrap(unittest.TestCase):
prox2 = saranwrap.Proxy([1, 2, 3]) prox2 = saranwrap.Proxy([1, 2, 3])
self.assert_(bool(prox2)) self.assert_(bool(prox2))
@skip_on_windows
def test_multiple_wraps(self): def test_multiple_wraps(self):
prox1 = saranwrap.wrap(re) prox1 = saranwrap.wrap(re)
prox2 = saranwrap.wrap(re) prox2 = saranwrap.wrap(re)
@@ -101,6 +110,7 @@ class TestSaranwrap(unittest.TestCase):
del x2 del x2
x3 = prox2.compile('.') x3 = prox2.compile('.')
@skip_on_windows
def test_dict_passthru(self): def test_dict_passthru(self):
prox = saranwrap.wrap(StringIO) prox = saranwrap.wrap(StringIO)
x = prox.StringIO('a') x = prox.StringIO('a')
@@ -108,25 +118,30 @@ class TestSaranwrap(unittest.TestCase):
# try it all on one line just for the sake of it # try it all on one line just for the sake of it
self.assertEqual(type(saranwrap.wrap(StringIO).StringIO('a').__dict__), saranwrap.ObjectProxy) self.assertEqual(type(saranwrap.wrap(StringIO).StringIO('a').__dict__), saranwrap.ObjectProxy)
@skip_on_windows
def test_is_value(self): def test_is_value(self):
server = saranwrap.Server(None, None, None) server = saranwrap.Server(None, None, None)
self.assert_(server.is_value(None)) self.assert_(server.is_value(None))
@skip_on_windows
def test_wrap_getitem(self): def test_wrap_getitem(self):
prox = saranwrap.wrap([0,1,2]) prox = saranwrap.wrap([0,1,2])
self.assertEqual(prox[0], 0) self.assertEqual(prox[0], 0)
@skip_on_windows
def test_wrap_setitem(self): def test_wrap_setitem(self):
prox = saranwrap.wrap([0,1,2]) prox = saranwrap.wrap([0,1,2])
prox[1] = 2 prox[1] = 2
self.assertEqual(prox[1], 2) self.assertEqual(prox[1], 2)
@skip_on_windows
def test_raising_exceptions(self): def test_raising_exceptions(self):
prox = saranwrap.wrap(re) prox = saranwrap.wrap(re)
def nofunc(): def nofunc():
prox.never_name_a_function_like_this() prox.never_name_a_function_like_this()
self.assertRaises(AttributeError, nofunc) self.assertRaises(AttributeError, nofunc)
@skip_on_windows
def test_unpicklable_server_exception(self): def test_unpicklable_server_exception(self):
prox = saranwrap.wrap(saranwrap) prox = saranwrap.wrap(saranwrap)
def unpickle(): def unpickle():
@@ -137,6 +152,7 @@ class TestSaranwrap(unittest.TestCase):
# It's basically dead # It's basically dead
#self.assert_server_exists(prox) #self.assert_server_exists(prox)
@skip_on_windows
def test_pickleable_server_exception(self): def test_pickleable_server_exception(self):
prox = saranwrap.wrap(saranwrap) prox = saranwrap.wrap(saranwrap)
def fperror(): def fperror():
@@ -145,11 +161,13 @@ class TestSaranwrap(unittest.TestCase):
self.assertRaises(FloatingPointError, fperror) self.assertRaises(FloatingPointError, fperror)
self.assert_server_exists(prox) self.assert_server_exists(prox)
@skip_on_windows
def test_print_does_not_break_wrapper(self): def test_print_does_not_break_wrapper(self):
prox = saranwrap.wrap(saranwrap) prox = saranwrap.wrap(saranwrap)
prox.print_string('hello') prox.print_string('hello')
self.assert_server_exists(prox) self.assert_server_exists(prox)
@skip_on_windows
def test_stderr_does_not_break_wrapper(self): def test_stderr_does_not_break_wrapper(self):
prox = saranwrap.wrap(saranwrap) prox = saranwrap.wrap(saranwrap)
prox.err_string('goodbye') prox.err_string('goodbye')
@@ -158,6 +176,7 @@ class TestSaranwrap(unittest.TestCase):
def assertLessThan(self, a, b): def assertLessThan(self, a, b):
self.assert_(a < b, "%s is not less than %s" % (a, b)) self.assert_(a < b, "%s is not less than %s" % (a, b))
@skip_on_windows
def test_status(self): def test_status(self):
prox = saranwrap.wrap(time) prox = saranwrap.wrap(time)
a = prox.gmtime(0) a = prox.gmtime(0)
@@ -176,6 +195,7 @@ class TestSaranwrap(unittest.TestCase):
prox2 = saranwrap.wrap(re) prox2 = saranwrap.wrap(re)
self.assert_(status['pid'] != saranwrap.status(prox2)['pid']) self.assert_(status['pid'] != saranwrap.status(prox2)['pid'])
@skip_on_windows
def test_del(self): def test_del(self):
prox = saranwrap.wrap(time) prox = saranwrap.wrap(time)
delme = prox.gmtime(0) delme = prox.gmtime(0)
@@ -189,11 +209,13 @@ class TestSaranwrap(unittest.TestCase):
#print status_after['objects'] #print status_after['objects']
self.assertLessThan(status_after['object_count'], status_before['object_count']) self.assertLessThan(status_after['object_count'], status_before['object_count'])
@skip_on_windows
def test_contains(self): def test_contains(self):
prox = saranwrap.wrap({'a':'b'}) prox = saranwrap.wrap({'a':'b'})
self.assert_('a' in prox) self.assert_('a' in prox)
self.assert_('x' not in prox) self.assert_('x' not in prox)
@skip_on_windows
def test_variable_and_keyword_arguments_with_function_calls(self): def test_variable_and_keyword_arguments_with_function_calls(self):
import optparse import optparse
prox = saranwrap.wrap(optparse) prox = saranwrap.wrap(optparse)
@@ -202,6 +224,7 @@ class TestSaranwrap(unittest.TestCase):
opts,args = parser.parse_args(["-nfoo"]) opts,args = parser.parse_args(["-nfoo"])
self.assertEqual(opts.n, 'foo') self.assertEqual(opts.n, 'foo')
@skip_on_windows
def test_original_proxy_going_out_of_scope(self): def test_original_proxy_going_out_of_scope(self):
def make_re(): def make_re():
prox = saranwrap.wrap(re) prox = saranwrap.wrap(re)
@@ -224,6 +247,7 @@ class TestSaranwrap(unittest.TestCase):
except AttributeError, e: except AttributeError, e:
pass pass
@skip_on_windows
def test_not_inheriting_pythonpath(self): def test_not_inheriting_pythonpath(self):
# construct a fake module in the temp directory # construct a fake module in the temp directory
temp_dir = tempfile.mkdtemp("saranwrap_test") temp_dir = tempfile.mkdtemp("saranwrap_test")
@@ -253,6 +277,7 @@ sys_path = sys.path""")
shutil.rmtree(temp_dir) shutil.rmtree(temp_dir)
sys.path.remove(temp_dir) sys.path.remove(temp_dir)
@skip_on_windows
def test_contention(self): def test_contention(self):
from tests import saranwrap_test from tests import saranwrap_test
prox = saranwrap.wrap(saranwrap_test) prox = saranwrap.wrap(saranwrap_test)
@@ -265,6 +290,7 @@ sys_path = sys.path""")
for waiter in waiters: for waiter in waiters:
waiter.wait() waiter.wait()
@skip_on_windows
def test_copy(self): def test_copy(self):
import copy import copy
compound_object = {'a':[1,2,3]} compound_object = {'a':[1,2,3]}
@@ -278,12 +304,14 @@ sys_path = sys.path""")
make_assertions(copy.copy(prox)) make_assertions(copy.copy(prox))
make_assertions(copy.deepcopy(prox)) make_assertions(copy.deepcopy(prox))
@skip_on_windows
def test_list_of_functions(self): def test_list_of_functions(self):
return # this test is known to fail, we can implement it sometime in the future if we wish return # this test is known to fail, we can implement it sometime in the future if we wish
from tests import saranwrap_test from tests import saranwrap_test
prox = saranwrap.wrap([saranwrap_test.list_maker]) prox = saranwrap.wrap([saranwrap_test.list_maker])
self.assertEquals(list_maker(), prox[0]()) self.assertEquals(list_maker(), prox[0]())
@skip_on_windows
def test_under_the_hood_coroutines(self): def test_under_the_hood_coroutines(self):
# so, we want to write a class which uses a coroutine to call # so, we want to write a class which uses a coroutine to call
# a function. Then we want to saranwrap that class, have # a function. Then we want to saranwrap that class, have
@@ -302,6 +330,7 @@ sys_path = sys.path""")
'random' in obj_proxy.get_dict(), 'random' in obj_proxy.get_dict(),
'Coroutine in saranwrapped object did not run') 'Coroutine in saranwrapped object did not run')
@skip_on_windows
def test_child_process_death(self): def test_child_process_death(self):
prox = saranwrap.wrap({}) prox = saranwrap.wrap({})
pid = saranwrap.getpid(prox) pid = saranwrap.getpid(prox)
@@ -310,17 +339,20 @@ sys_path = sys.path""")
api.sleep(0.1) # need to let the signal handler run api.sleep(0.1) # need to let the signal handler run
self.assertRaises(OSError, os.kill, pid, 0) # raises OSError if pid doesn't exist self.assertRaises(OSError, os.kill, pid, 0) # raises OSError if pid doesn't exist
@skip_on_windows
def test_detection_of_server_crash(self): def test_detection_of_server_crash(self):
# make the server crash here # make the server crash here
pass pass
@skip_on_windows
def test_equality_with_local_object(self): def test_equality_with_local_object(self):
# we'll implement this if there's a use case for it # we'll implement this if there's a use case for it
pass pass
@skip_on_windows
def test_non_blocking(self): def test_non_blocking(self):
# here we test whether it's nonblocking # here we test whether it's nonblocking
pass pass
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() main()

View File

@@ -41,6 +41,21 @@ class SSLTest(LimitedTestCase):
client.close() client.close()
server_coro.wait() server_coro.wait()
def test_ssl_connect(self):
def serve(listener):
sock, addr = listener.accept()
stuff = sock.read(8192)
sock = api.ssl_listener(('127.0.0.1', 0), certificate_file, private_key_file)
server_coro = coros.execute(serve, sock)
raw_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ssl_client = util.wrap_ssl(raw_client)
ssl_client.connect(('127.0.0.1', sock.getsockname()[1]))
ssl_client.write('abc')
greenio.shutdown_safe(ssl_client)
ssl_client.close()
server_coro.wait()
class SocketSSLTest(LimitedTestCase): class SocketSSLTest(LimitedTestCase):
@skip_unless(hasattr(socket, 'ssl')) @skip_unless(hasattr(socket, 'ssl'))

View File

@@ -30,9 +30,9 @@ patcher.inject('test.test_ssl',
('threading', threading), ('threading', threading),
('urllib', urllib)) ('urllib', urllib))
# these appear to not work due to some wonkiness in the threading # these don't pass because nonblocking ssl sockets don't report
# module... skipping them for now (can't use SkipTest either because # when the socket is closed uncleanly, per the docstring on
# test_main doesn't understand it) # eventlet.green.GreenSSLSocket
# *TODO: fix and restore these tests # *TODO: fix and restore these tests
ThreadedTests.testProtocolSSL2 = lambda s: None ThreadedTests.testProtocolSSL2 = lambda s: None
ThreadedTests.testProtocolSSL3 = lambda s: None ThreadedTests.testProtocolSSL3 = lambda s: None

View File

@@ -22,6 +22,7 @@ class TestEvent(LimitedTestCase):
obj = Exception() obj = Exception()
e.send(exc=obj) e.send(exc=obj)
sleep(0) sleep(0)
sleep(0)
assert log == [('catched', obj)], log assert log == [('catched', obj)], log
def test_send(self): def test_send(self):

View File

@@ -1,4 +1,5 @@
import unittest import unittest
from tests import SilencedTestCase
import time import time
from eventlet import api from eventlet import api
from eventlet.green import socket from eventlet.green import socket
@@ -29,7 +30,7 @@ class TestDebug(unittest.TestCase):
self.assert_(not api.get_hub().debug) self.assert_(not api.get_hub().debug)
class TestExceptionInMainloop(unittest.TestCase): class TestExceptionInMainloop(SilencedTestCase):
def test_sleep(self): def test_sleep(self):
# even if there was an error in the mainloop, the hub should continue to work # even if there was an error in the mainloop, the hub should continue to work

View File

@@ -2,14 +2,14 @@ import sys
import unittest import unittest
from eventlet.api import sleep, with_timeout from eventlet.api import sleep, with_timeout
from eventlet import api, proc, coros from eventlet import api, proc, coros
from tests import LimitedTestCase, skipped from tests import SilencedTestCase, skipped
DELAY = 0.01 DELAY = 0.01
class ExpectedError(Exception): class ExpectedError(Exception):
pass pass
class TestLink_Signal(LimitedTestCase): class TestLink_Signal(SilencedTestCase):
def test_send(self): def test_send(self):
s = proc.Source() s = proc.Source()
@@ -48,7 +48,7 @@ class TestLink_Signal(LimitedTestCase):
self.assertRaises(OSError, s.wait) self.assertRaises(OSError, s.wait)
class TestProc(LimitedTestCase): class TestProc(SilencedTestCase):
def test_proc(self): def test_proc(self):
p = proc.spawn(lambda : 100) p = proc.spawn(lambda : 100)
@@ -76,13 +76,13 @@ class TestProc(LimitedTestCase):
self.assertRaises(proc.LinkedCompleted, sleep, 0.1) self.assertRaises(proc.LinkedCompleted, sleep, 0.1)
class TestCase(LimitedTestCase): class TestCase(SilencedTestCase):
def link(self, p, listener=None): def link(self, p, listener=None):
getattr(p, self.link_method)(listener) getattr(p, self.link_method)(listener)
def tearDown(self): def tearDown(self):
LimitedTestCase.tearDown(self) SilencedTestCase.tearDown(self)
self.p.unlink() self.p.unlink()
def set_links(self, p, first_time, kill_exc_type): def set_links(self, p, first_time, kill_exc_type):
@@ -252,7 +252,7 @@ class TestRaise_link_exception(TestRaise_link):
link_method = 'link_exception' link_method = 'link_exception'
class TestStuff(unittest.TestCase): class TestStuff(SilencedTestCase):
def test_wait_noerrors(self): def test_wait_noerrors(self):
x = proc.spawn(lambda : 1) x = proc.spawn(lambda : 1)
@@ -297,6 +297,7 @@ class TestStuff(unittest.TestCase):
proc.waitall([a, b]) proc.waitall([a, b])
except ExpectedError, ex: except ExpectedError, ex:
assert 'second' in str(ex), repr(str(ex)) assert 'second' in str(ex), repr(str(ex))
api.sleep(0.2) # sleep to ensure that the other timer is raised
def test_multiple_listeners_error(self): def test_multiple_listeners_error(self):
# if there was an error while calling a callback # if there was an error while calling a callback

View File

@@ -9,12 +9,20 @@ else:
class TestSocketErrors(unittest.TestCase): class TestSocketErrors(unittest.TestCase):
def test_connection_refused(self): def test_connection_refused(self):
# open and close a dummy server to find an unused port
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('127.0.0.1', 0))
server.listen(1)
port = server.getsockname()[1]
server.close()
del server
s = socket.socket() s = socket.socket()
try: try:
s.connect(('127.0.0.1', 81)) s.connect(('127.0.0.1', port))
self.fail("Shouldn't have connected")
except socket.error, ex: except socket.error, ex:
code, text = ex.args code, text = ex.args
assert code in [111, 61], (code, text) assert code in [111, 61, 10061], (code, text)
assert 'refused' in text.lower(), (code, text) assert 'refused' in text.lower(), (code, text)
if __name__=='__main__': if __name__=='__main__':

View File

@@ -84,7 +84,12 @@ class ConnectionClosed(Exception):
def read_http(sock): def read_http(sock):
fd = sock.makeGreenFile() fd = sock.makeGreenFile()
try:
response_line = fd.readline() response_line = fd.readline()
except socket.error, exc:
if exc[0] == 10053:
raise ConnectionClosed
raise
if not response_line: if not response_line:
raise ConnectionClosed raise ConnectionClosed
raw_headers = fd.readuntil('\r\n\r\n').strip() raw_headers = fd.readuntil('\r\n\r\n').strip()
@@ -189,6 +194,9 @@ class TestHttpd(LimitedTestCase):
fd = sock.makeGreenFile() fd = sock.makeGreenFile()
fd.write(request) fd.write(request)
result = fd.readline() result = fd.readline()
if result:
# windows closes the socket before the data is flushed,
# so we never get anything back
status = result.split(' ')[1] status = result.split(' ')[1]
self.assertEqual(status, '414') self.assertEqual(status, '414')
fd.close() fd.close()