Commit dbe77ded authored by Jason Madden's avatar Jason Madden

Merge pull request #552 from NextThought/pypy-with-ssl279

PyPy 2.5.1 support improvements, and ssl 2.7.9 support. Fixes #546.
parents 72119c8c bfaa1a63
...@@ -3,6 +3,8 @@ build/ ...@@ -3,6 +3,8 @@ build/
*.so *.so
gevent.*.[ch] gevent.*.[ch]
gevent/core.pyx gevent/core.pyx
gevent/__pycache__
gevent/libev
*.egg-info *.egg-info
doc/changelog.rst doc/changelog.rst
......
Gevent is written and maintained by Gevent is written and maintained by
Denis Bilenko Denis Bilenko
Matt Iversen
Steffen Prince
Jason Madden
and the contributors (ordered by the date of first contribution): and the contributors (ordered by the date of first contribution):
...@@ -43,7 +46,7 @@ and the contributors (ordered by the date of first contribution): ...@@ -43,7 +46,7 @@ and the contributors (ordered by the date of first contribution):
陈小玉 陈小玉
Philip Conrad Philip Conrad
See https://github.com/surfly/gevent/graphs/contributors for more info. See https://github.com/gevent/gevent/graphs/contributors for more info.
Gevent is inspired by and uses some code from eventlet which was written by Gevent is inspired by and uses some code from eventlet which was written by
......
...@@ -59,6 +59,14 @@ travistest: ...@@ -59,6 +59,14 @@ travistest:
cd greentest && GEVENT_RESOLVER=ares GEVENTARES_SERVERS=8.8.8.8 ${PYTHON} testrunner.py --config ../known_failures.py --ignore tests_that_dont_use_resolver.txt cd greentest && GEVENT_RESOLVER=ares GEVENTARES_SERVERS=8.8.8.8 ${PYTHON} testrunner.py --config ../known_failures.py --ignore tests_that_dont_use_resolver.txt
cd greentest && GEVENT_FILE=thread ${PYTHON} testrunner.py --config ../known_failures.py `grep -l subprocess test_*.py` cd greentest && GEVENT_FILE=thread ${PYTHON} testrunner.py --config ../known_failures.py `grep -l subprocess test_*.py`
toxtest:
cd greentest && GEVENT_RESOLVER=thread python testrunner.py --config ../known_failures.py
fulltoxtest:
cd greentest && GEVENT_RESOLVER=thread python testrunner.py --config ../known_failures.py
cd greentest && GEVENT_RESOLVER=ares GEVENTARES_SERVERS=8.8.8.8 python testrunner.py --config ../known_failures.py --ignore tests_that_dont_use_resolver.txt
cd greentest && GEVENT_FILE=thread python testrunner.py --config ../known_failures.py `grep -l subprocess test_*.py`
bench: bench:
${PYTHON} greentest/bench_sendall.py ${PYTHON} greentest/bench_sendall.py
...@@ -71,14 +79,6 @@ travis_pypy: ...@@ -71,14 +79,6 @@ travis_pypy:
cd greentest && ${PYTHON} testrunner.py --config ../known_failures.py cd greentest && ${PYTHON} testrunner.py --config ../known_failures.py
travis_cpython: travis_cpython:
make whitespace
pip install -q pep8
PYTHON=python make pep8
pip install -q pyflakes
PYTHON=python make pyflakes
sudo add-apt-repository -y ppa:chris-lea/cython sudo add-apt-repository -y ppa:chris-lea/cython
# somehow travis changed something and python2.6 and python3.3 no longer accessible anymore # somehow travis changed something and python2.6 and python3.3 no longer accessible anymore
......
...@@ -31,9 +31,11 @@ class PortForwarder(StreamServer): ...@@ -31,9 +31,11 @@ class PortForwarder(StreamServer):
except IOError as ex: except IOError as ex:
log('%s:%s failed to connect to %s:%s: %s', address[0], address[1], self.dest[0], self.dest[1], ex) log('%s:%s failed to connect to %s:%s: %s', address[0], address[1], self.dest[0], self.dest[1], ex)
return return
gevent.spawn(forward, source, dest) forwarders = (gevent.spawn(forward, source, dest),
gevent.spawn(forward, dest, source) gevent.spawn(forward, dest, source))
# XXX only one spawn() is needed # if we return from this method, the stream will be closed out
# from under us, so wait for our children
gevent.joinall(forwarders)
def close(self): def close(self):
if self.closed: if self.closed:
......
...@@ -124,6 +124,8 @@ class Semaphore(object): ...@@ -124,6 +124,8 @@ class Semaphore(object):
assert self.counter >= 0 assert self.counter >= 0
return True return True
_py3k_acquire = acquire # PyPy needs this; it must be static for Cython
def __enter__(self): def __enter__(self):
self.acquire() self.acquire()
......
...@@ -334,10 +334,10 @@ class socket(object): ...@@ -334,10 +334,10 @@ class socket(object):
howlong = f() howlong = f()
if howlong < 0.0: if howlong < 0.0:
raise ValueError('Timeout value out of range') raise ValueError('Timeout value out of range')
self.timeout = howlong self.__dict__['timeout'] = howlong # avoid recursion with any property on self.timeout
def gettimeout(self): def gettimeout(self):
return self.timeout return self.__dict__['timeout'] # avoid recursion with any property on self.timeout
def shutdown(self, how): def shutdown(self, how):
if how == 0: # SHUT_RD if how == 0: # SHUT_RD
...@@ -396,5 +396,16 @@ if hasattr(_socket, 'fromfd'): ...@@ -396,5 +396,16 @@ if hasattr(_socket, 'fromfd'):
else: else:
__implements__.remove('fromfd') __implements__.remove('fromfd')
if hasattr(__socket__, 'ssl'):
from gevent.hub import PYGTE279
def ssl(sock, keyfile=None, certfile=None):
# deprecated in 2.7.9 but still present
if PYGTE279:
from . import _sslgte279
return _sslgte279.wrap_socket(sock, keyfile, certfile)
else:
from . import _ssl2
return _ssl2.sslwrap_simple(sock, keyfile, certfile)
__implements__.append('ssl')
__all__ = __implements__ + __extensions__ + __imports__ __all__ = __implements__ + __extensions__ + __imports__
...@@ -379,6 +379,17 @@ class SSLSocket(socket): ...@@ -379,6 +379,17 @@ class SSLSocket(socket):
# the file-like object. # the file-like object.
return _fileobject(self, mode, bufsize, close=True) return _fileobject(self, mode, bufsize, close=True)
if PYPY or not hasattr(SSLSocket, 'timeout'):
# PyPy (and certain versions of CPython) doesn't have a direct
# 'timeout' property on raw sockets, because that's not part of
# the documented specification. We may wind up wrapping a raw
# socket (when ssl is used with PyWSGI) or a gevent socket, which
# does have a read/write timeout property as an alias for
# get/settimeout, so make sure that's always the case because
# pywsgi can depend on that.
SSLSocket.timeout = property(lambda self: self.gettimeout(),
lambda self, value: self.settimeout(value))
_SSLErrorReadTimeout = SSLError('The read operation timed out') _SSLErrorReadTimeout = SSLError('The read operation timed out')
_SSLErrorWriteTimeout = SSLError('The write operation timed out') _SSLErrorWriteTimeout = SSLError('The write operation timed out')
......
This diff is collapsed.
...@@ -7,8 +7,10 @@ from code import InteractiveConsole ...@@ -7,8 +7,10 @@ from code import InteractiveConsole
from gevent import socket from gevent import socket
from gevent.greenlet import Greenlet from gevent.greenlet import Greenlet
from gevent.hub import PY3, getcurrent from gevent.hub import PY3, PYPY, getcurrent
from gevent.server import StreamServer from gevent.server import StreamServer
if PYPY:
import gc
__all__ = ['BackdoorServer'] __all__ = ['BackdoorServer']
...@@ -77,6 +79,12 @@ class BackdoorServer(StreamServer): ...@@ -77,6 +79,12 @@ class BackdoorServer(StreamServer):
finally: finally:
conn.close() conn.close()
f.close() f.close()
if PYPY:
# The underlying socket somewhere has a reference
# that's not getting closed until finalizers run.
# Without running them, test__backdoor.Test.test_sys_exit
# hangs forever
gc.collect()
class _fileobject(socket._fileobject): class _fileobject(socket._fileobject):
...@@ -93,7 +101,6 @@ class _fileobject(socket._fileobject): ...@@ -93,7 +101,6 @@ class _fileobject(socket._fileobject):
def readline(self, *a): def readline(self, *a):
return socket._fileobject.readline(self, *a).replace("\r\n", "\n") return socket._fileobject.readline(self, *a).replace("\r\n", "\n")
if __name__ == '__main__': if __name__ == '__main__':
if not sys.argv[1:]: if not sys.argv[1:]:
print('USAGE: %s PORT' % sys.argv[0]) print('USAGE: %s PORT' % sys.argv[0])
......
...@@ -126,11 +126,18 @@ class BaseServer(object): ...@@ -126,11 +126,18 @@ class BaseServer(object):
def do_handle(self, *args): def do_handle(self, *args):
spawn = self._spawn spawn = self._spawn
handle = self._handle
def _close_when_done(*args):
try:
return handle(*args)
finally:
self.do_close(*args)
try: try:
if spawn is None: if spawn is None:
self._handle(*args) _close_when_done(*args)
else: else:
spawn(self._handle, *args) spawn(_close_when_done, *args)
except: except:
self.do_close(*args) self.do_close(*args)
raise raise
......
...@@ -114,6 +114,7 @@ struct stat { ...@@ -114,6 +114,7 @@ struct stat {
struct ev_stat { struct ev_stat {
struct stat attr; struct stat attr;
const char* path;
struct stat prev; struct stat prev;
double interval; double interval;
...; ...;
...@@ -648,6 +649,9 @@ class loop(object): ...@@ -648,6 +649,9 @@ class loop(object):
def install_sigchld(self): def install_sigchld(self):
libev.gevent_install_sigchld_handler() libev.gevent_install_sigchld_handler()
def stat(self, path, interval=0.0, ref=True, priority=None):
return stat(self, path, interval, ref, priority)
def callback(self, priority=None): def callback(self, priority=None):
return callback(self, priority) return callback(self, priority)
...@@ -1054,6 +1058,53 @@ class child(watcher): ...@@ -1054,6 +1058,53 @@ class child(watcher):
def rstatus(self, value): def rstatus(self, value):
self._watcher.rstatus = value self._watcher.rstatus = value
class stat(watcher):
_watcher_start = libev.ev_stat_start
_watcher_stop = libev.ev_stat_stop
_watcher_init = libev.ev_stat_init
_watcher_type = 'ev_stat'
_watcher_ffi_type = "struct %s *" % _watcher_type
_watcher_ffi_cb = "void(*)(struct ev_loop *, struct %s *, int)" % _watcher_type
def __init__(self, _loop, path, interval=0.0, ref=True, priority=None):
if not isinstance(path, bytes):
# XXX: Filesystem encoding? Python itself has issues here, were they fixed?
path = path.encode('utf-8')
watcher.__init__(self, _loop, ref=ref, priority=priority,
# cffi doesn't automatically marshal byte strings to
# char* in the function call; instead it passes an
# empty string or garbage pointer. If the watcher's
# path is incorrect, watching silently fails
# (the underlying call to lstat() keeps erroring out)
args=(ffi.new('char[]', path),
interval))
def start(self, callback, *args):
watcher.start(self, callback, *args)
def stop(self):
watcher.stop(self)
@property
def path(self):
return ffi.string(self._watcher.path)
@property
def attr(self):
if not self._watcher.attr.st_nlink:
return
return self._watcher.attr
@property
def prev(self):
if not self._watcher.prev.st_nlink:
return
return self._watcher.prev
@property
def interval(self):
return self._watcher.interval
def _syserr_cb(msg): def _syserr_cb(msg):
try: try:
......
...@@ -26,6 +26,13 @@ __all__ = ['getcurrent', ...@@ -26,6 +26,13 @@ __all__ = ['getcurrent',
'Hub', 'Hub',
'Waiter'] 'Waiter']
# Sniff Python > 2.7.9 for new SSL interfaces
# If True, Python is greater than or equal to 2.7.9 (but not Python 3).
PYGTE279 = (
sys.version_info[0] == 2
and sys.version_info[1] >= 7
and sys.version_info[2] >= 9
)
PY3 = sys.version_info[0] >= 3 PY3 = sys.version_info[0] >= 3
PYPY = hasattr(sys, 'pypy_version_info') PYPY = hasattr(sys, 'pypy_version_info')
......
from gevent.hub import PY3 from gevent.hub import PY3
from gevent.hub import PYGTE279
if PY3: if PYGTE279:
from gevent import _sslgte279 as _source
elif PY3:
from gevent import _ssl3 as _source from gevent import _ssl3 as _source
else: else:
from gevent import _ssl2 as _source from gevent import _ssl2 as _source
......
...@@ -142,14 +142,16 @@ def check_output(*popenargs, **kwargs): ...@@ -142,14 +142,16 @@ def check_output(*popenargs, **kwargs):
The arguments are the same as for the Popen constructor. Example: The arguments are the same as for the Popen constructor. Example:
>>> check_output(["ls", "-1", "/dev/null"]) >>> print(check_output(["ls", "-1", "/dev/null"]))
b'/dev/null\n' /dev/null
<BLANKLINE>
The stdout argument is not allowed as it is used internally. The stdout argument is not allowed as it is used internally.
To capture standard error in the result, use stderr=STDOUT. To capture standard error in the result, use stderr=STDOUT.
>>> check_output(["/bin/sh", "-c", "echo hello world"], stderr=STDOUT) >>> print(check_output(["/bin/sh", "-c", "echo hello world"], stderr=STDOUT))
b'hello world\n' hello world
<BLANKLINE>
""" """
if 'stdout' in kwargs: if 'stdout' in kwargs:
raise ValueError('stdout argument not allowed, it will be overridden.') raise ValueError('stdout argument not allowed, it will be overridden.')
......
...@@ -14,7 +14,7 @@ import threading as __threading__ ...@@ -14,7 +14,7 @@ import threading as __threading__
_DummyThread_ = __threading__._DummyThread _DummyThread_ = __threading__._DummyThread
from gevent.local import local from gevent.local import local
from gevent.thread import start_new_thread as _start_new_thread, allocate_lock as _allocate_lock, get_ident as _get_ident from gevent.thread import start_new_thread as _start_new_thread, allocate_lock as _allocate_lock, get_ident as _get_ident
from gevent.hub import sleep as _sleep, getcurrent from gevent.hub import sleep as _sleep, getcurrent, PYPY
Lock = _allocate_lock Lock = _allocate_lock
...@@ -35,3 +35,12 @@ class _DummyThread(_DummyThread_): ...@@ -35,3 +35,12 @@ class _DummyThread(_DummyThread_):
def _Thread__stop(self): def _Thread__stop(self):
pass pass
if PYPY:
# Make sure the MainThread can be found by our current greenlet ID,
# otherwise we get a new DummyThread, which cannot be joined.
# Fixes tests in test_threading_2
if _get_ident() not in __threading__._active and len(__threading__._active) == 1:
k,v = __threading__._active.items()[0]
del __threading__._active[k]
__threading__._active[_get_ident()] = v
-----BEGIN RSA PRIVATE KEY----- -----BEGIN PRIVATE KEY-----
MIICXwIBAAKBgQC8ddrhm+LutBvjYcQlnH21PPIseJ1JVG2HMmN2CmZk2YukO+9L MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANtb0+YrKuxevGpm
opdJhTvbGfEj0DQs1IE8M+kTUyOmuKfVrFMKwtVeCJphrAnhoz7TYOuLBSqt7lVH LrjaUhZSgz6zFAmuGFmKmUbdjmfv9zSmmdsQIksK++jK0Be9LeZy20j6ahOfuVa0
fhi/VwovESJlaBOp+WMnfhcduPEYHYx/6cnVapIkZnLt30zu2um+DzA9jQIDAQAB ufEmPoP7Fy4hXegKZR9cCWcIe/A6H2xWF1IIJLRTLaU8ol/I7T+um5HD5AwAwNPP
AoGBAK0FZpaKj6WnJZN0RqhhK+ggtBWwBnc0U/ozgKz2j1s3fsShYeiGtW6CK5nU USNU0Eegmvp+xxWu3NX2m1Veot85AgMBAAECgYA3ZdZ673X0oexFlq7AAmrutkHt
D1dZ5wzhbGThI7LiOXDvRucc9n7vUgi0alqPQ/PFodPxAN/eEYkmXQ7W2k7zwsDA CL7LvwrpOiaBjhyTxTeSNWzvtQBkIU8DOI0bIazA4UreAFffwtvEuPmonDb3F+Iq
IUK0KUhktQbLu8qF/m8qM86ba9y9/9YkXuQbZ3COl5ahTZrhAkEA301P08RKv3KM SMAu42XcGyVZEl+gHlTPU9XRX7nTOXVt+MlRRRxL6t9GkGfUAXI3XxJDXW3c0vBK
oXnGU2UHTuJ1MAD2hOrPxjD4/wxA/39EWG9bZczbJyggB4RHu0I3NOSFjAm3HQm0 UL9xqD8cORXOfE06rQJBAP8mEX1ERkR64Ptsoe4281vjTlNfIbs7NMPkUnrn9N/Y
ANOu5QK9owJBANgOeLfNNcF4pp+UikRFqxk5hULqRAWzVxVrWe85FlPm0VVmHbb/ BLhjNIfQ3HFZG8BTMLfX7kCS9D593DW5tV4Z9BP/c6cCQQDcFzCcVArNh2JSywOQ
loif7mqjU8o1jTd/LM7RD9f2usZyE2psaw8CQQCNLhkpX3KO5kKJmS9N7JMZSc4j ZfTfRbJg/Z5Lt9Fkngv1meeGNPgIMLN8Sg679pAOOWmzdMO3V706rNPzSVMME7E5
oog58yeYO8BBqKKzpug0LXuQultYv2K4veaIO04iL9VLe5z9S/Q1jaCHBBuXAkEA oPIfAkEA8pDddarP5tCvTTgUpmTFbakm0KoTZm2+FzHcnA4jRh+XNTjTOv98Y6Ik
z8gjGoi1AOp6PBBLZNsncCvcV/0aC+1se4HxTNo2+duKSDnbq+ljqOM+E7odU+Nq eO5d1ZnKXseWvkZncQgxfdnMqqpj5wJAcNq/RVne1DbYlwWchT2Si65MYmmJ8t+F
ewvIWOG//e8fssd0mq3HywJBAJ8l/c8GVmrpFTx8r/nZ2Pyyjt3dH1widooDXYSV 0mcsULqjOnEMwf5e+ptq5LzwbyrHZYq5FNk7ocufPv/ZQrcSSC+cFwJBAKvOJByS
q6Gbf41Llo5sYAtmxdndTLASuHKecacTgZVhy0FryZpLKrU= x56qyGeZLOQlWS2JS3KJo59XuLFGqcbgN9Om9xFa41Yb4N9NvplFivsvZdw3m1Q/
-----END RSA PRIVATE KEY----- SPIXQuT8RMPDVNQ=
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIICpzCCAhCgAwIBAgIJAP+qStv1cIGNMA0GCSqGSIb3DQEBBQUAMIGJMQswCQYD MIICVDCCAb2gAwIBAgIJANfHOBkZr8JOMA0GCSqGSIb3DQEBBQUAMF8xCzAJBgNV
VQQGEwJVUzERMA8GA1UECBMIRGVsYXdhcmUxEzARBgNVBAcTCldpbG1pbmd0b24x BAYTAlhZMRcwFQYDVQQHEw5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9u
IzAhBgNVBAoTGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uMQwwCgYDVQQLEwNT IFNvZnR3YXJlIEZvdW5kYXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0xMDEw
U0wxHzAdBgNVBAMTFnNvbWVtYWNoaW5lLnB5dGhvbi5vcmcwHhcNMDcwODI3MTY1 MDgyMzAxNTZaFw0yMDEwMDUyMzAxNTZaMF8xCzAJBgNVBAYTAlhZMRcwFQYDVQQH
NDUwWhcNMTMwMjE2MTY1NDUwWjCBiTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCERl Ew5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9uIFNvZnR3YXJlIEZvdW5k
bGF3YXJlMRMwEQYDVQQHEwpXaWxtaW5ndG9uMSMwIQYDVQQKExpQeXRob24gU29m YXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
dHdhcmUgRm91bmRhdGlvbjEMMAoGA1UECxMDU1NMMR8wHQYDVQQDExZzb21lbWFj gYkCgYEA21vT5isq7F68amYuuNpSFlKDPrMUCa4YWYqZRt2OZ+/3NKaZ2xAiSwr7
aGluZS5weXRob24ub3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8ddrh 6MrQF70t5nLbSPpqE5+5VrS58SY+g/sXLiFd6AplH1wJZwh78DofbFYXUggktFMt
m+LutBvjYcQlnH21PPIseJ1JVG2HMmN2CmZk2YukO+9LopdJhTvbGfEj0DQs1IE8 pTyiX8jtP66bkcPkDADA089RI1TQR6Ca+n7HFa7c1fabVV6i3zkCAwEAAaMYMBYw
M+kTUyOmuKfVrFMKwtVeCJphrAnhoz7TYOuLBSqt7lVHfhi/VwovESJlaBOp+WMn FAYDVR0RBA0wC4IJbG9jYWxob3N0MA0GCSqGSIb3DQEBBQUAA4GBAHPctQBEQ4wd
fhcduPEYHYx/6cnVapIkZnLt30zu2um+DzA9jQIDAQABoxUwEzARBglghkgBhvhC BJ6+JcpIraopLn8BGhbjNWj40mmRqWB/NAWF6M5ne7KpGAu7tLeG4hb1zLaldK8G
AQEEBAMCBkAwDQYJKoZIhvcNAQEFBQADgYEAF4Q5BVqmCOLv1n8je/Jw9K669VXb lxy2GPSRF6LFS48dpEj2HbMv2nvv6xxalDMJ9+DicWgAKTQ6bcX2j3GUkCR0g/T1
08hyGzQhkemEBYQd6fzQ9A/1ZzHkJKb1P6yreOLSEh4KcxYPyrLRC1ll8nr5OlCx CRlNBAAlvhKzO7Clpf9l0YKBEfraJByX
CMhKkTnR6qBsdNV0XtdU2+N25hqW+Ma4ZeqsN/iiJVCGNOZGnvQuvCAGWF8+J/f/
iHkC6gGdBJhogs4=
-----END CERTIFICATE----- -----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY----- -----BEGIN PRIVATE KEY-----
MIICXwIBAAKBgQC8ddrhm+LutBvjYcQlnH21PPIseJ1JVG2HMmN2CmZk2YukO+9L MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANtb0+YrKuxevGpm
opdJhTvbGfEj0DQs1IE8M+kTUyOmuKfVrFMKwtVeCJphrAnhoz7TYOuLBSqt7lVH LrjaUhZSgz6zFAmuGFmKmUbdjmfv9zSmmdsQIksK++jK0Be9LeZy20j6ahOfuVa0
fhi/VwovESJlaBOp+WMnfhcduPEYHYx/6cnVapIkZnLt30zu2um+DzA9jQIDAQAB ufEmPoP7Fy4hXegKZR9cCWcIe/A6H2xWF1IIJLRTLaU8ol/I7T+um5HD5AwAwNPP
AoGBAK0FZpaKj6WnJZN0RqhhK+ggtBWwBnc0U/ozgKz2j1s3fsShYeiGtW6CK5nU USNU0Eegmvp+xxWu3NX2m1Veot85AgMBAAECgYA3ZdZ673X0oexFlq7AAmrutkHt
D1dZ5wzhbGThI7LiOXDvRucc9n7vUgi0alqPQ/PFodPxAN/eEYkmXQ7W2k7zwsDA CL7LvwrpOiaBjhyTxTeSNWzvtQBkIU8DOI0bIazA4UreAFffwtvEuPmonDb3F+Iq
IUK0KUhktQbLu8qF/m8qM86ba9y9/9YkXuQbZ3COl5ahTZrhAkEA301P08RKv3KM SMAu42XcGyVZEl+gHlTPU9XRX7nTOXVt+MlRRRxL6t9GkGfUAXI3XxJDXW3c0vBK
oXnGU2UHTuJ1MAD2hOrPxjD4/wxA/39EWG9bZczbJyggB4RHu0I3NOSFjAm3HQm0 UL9xqD8cORXOfE06rQJBAP8mEX1ERkR64Ptsoe4281vjTlNfIbs7NMPkUnrn9N/Y
ANOu5QK9owJBANgOeLfNNcF4pp+UikRFqxk5hULqRAWzVxVrWe85FlPm0VVmHbb/ BLhjNIfQ3HFZG8BTMLfX7kCS9D593DW5tV4Z9BP/c6cCQQDcFzCcVArNh2JSywOQ
loif7mqjU8o1jTd/LM7RD9f2usZyE2psaw8CQQCNLhkpX3KO5kKJmS9N7JMZSc4j ZfTfRbJg/Z5Lt9Fkngv1meeGNPgIMLN8Sg679pAOOWmzdMO3V706rNPzSVMME7E5
oog58yeYO8BBqKKzpug0LXuQultYv2K4veaIO04iL9VLe5z9S/Q1jaCHBBuXAkEA oPIfAkEA8pDddarP5tCvTTgUpmTFbakm0KoTZm2+FzHcnA4jRh+XNTjTOv98Y6Ik
z8gjGoi1AOp6PBBLZNsncCvcV/0aC+1se4HxTNo2+duKSDnbq+ljqOM+E7odU+Nq eO5d1ZnKXseWvkZncQgxfdnMqqpj5wJAcNq/RVne1DbYlwWchT2Si65MYmmJ8t+F
ewvIWOG//e8fssd0mq3HywJBAJ8l/c8GVmrpFTx8r/nZ2Pyyjt3dH1widooDXYSV 0mcsULqjOnEMwf5e+ptq5LzwbyrHZYq5FNk7ocufPv/ZQrcSSC+cFwJBAKvOJByS
q6Gbf41Llo5sYAtmxdndTLASuHKecacTgZVhy0FryZpLKrU= x56qyGeZLOQlWS2JS3KJo59XuLFGqcbgN9Om9xFa41Yb4N9NvplFivsvZdw3m1Q/
-----END RSA PRIVATE KEY----- SPIXQuT8RMPDVNQ=
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIICpzCCAhCgAwIBAgIJAP+qStv1cIGNMA0GCSqGSIb3DQEBBQUAMIGJMQswCQYD MIICVDCCAb2gAwIBAgIJANfHOBkZr8JOMA0GCSqGSIb3DQEBBQUAMF8xCzAJBgNV
VQQGEwJVUzERMA8GA1UECBMIRGVsYXdhcmUxEzARBgNVBAcTCldpbG1pbmd0b24x BAYTAlhZMRcwFQYDVQQHEw5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9u
IzAhBgNVBAoTGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uMQwwCgYDVQQLEwNT IFNvZnR3YXJlIEZvdW5kYXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0xMDEw
U0wxHzAdBgNVBAMTFnNvbWVtYWNoaW5lLnB5dGhvbi5vcmcwHhcNMDcwODI3MTY1 MDgyMzAxNTZaFw0yMDEwMDUyMzAxNTZaMF8xCzAJBgNVBAYTAlhZMRcwFQYDVQQH
NDUwWhcNMTMwMjE2MTY1NDUwWjCBiTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCERl Ew5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9uIFNvZnR3YXJlIEZvdW5k
bGF3YXJlMRMwEQYDVQQHEwpXaWxtaW5ndG9uMSMwIQYDVQQKExpQeXRob24gU29m YXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
dHdhcmUgRm91bmRhdGlvbjEMMAoGA1UECxMDU1NMMR8wHQYDVQQDExZzb21lbWFj gYkCgYEA21vT5isq7F68amYuuNpSFlKDPrMUCa4YWYqZRt2OZ+/3NKaZ2xAiSwr7
aGluZS5weXRob24ub3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8ddrh 6MrQF70t5nLbSPpqE5+5VrS58SY+g/sXLiFd6AplH1wJZwh78DofbFYXUggktFMt
m+LutBvjYcQlnH21PPIseJ1JVG2HMmN2CmZk2YukO+9LopdJhTvbGfEj0DQs1IE8 pTyiX8jtP66bkcPkDADA089RI1TQR6Ca+n7HFa7c1fabVV6i3zkCAwEAAaMYMBYw
M+kTUyOmuKfVrFMKwtVeCJphrAnhoz7TYOuLBSqt7lVHfhi/VwovESJlaBOp+WMn FAYDVR0RBA0wC4IJbG9jYWxob3N0MA0GCSqGSIb3DQEBBQUAA4GBAHPctQBEQ4wd
fhcduPEYHYx/6cnVapIkZnLt30zu2um+DzA9jQIDAQABoxUwEzARBglghkgBhvhC BJ6+JcpIraopLn8BGhbjNWj40mmRqWB/NAWF6M5ne7KpGAu7tLeG4hb1zLaldK8G
AQEEBAMCBkAwDQYJKoZIhvcNAQEFBQADgYEAF4Q5BVqmCOLv1n8je/Jw9K669VXb lxy2GPSRF6LFS48dpEj2HbMv2nvv6xxalDMJ9+DicWgAKTQ6bcX2j3GUkCR0g/T1
08hyGzQhkemEBYQd6fzQ9A/1ZzHkJKb1P6yreOLSEh4KcxYPyrLRC1ll8nr5OlCx CRlNBAAlvhKzO7Clpf9l0YKBEfraJByX
CMhKkTnR6qBsdNV0XtdU2+N25hqW+Ma4ZeqsN/iiJVCGNOZGnvQuvCAGWF8+J/f/
iHkC6gGdBJhogs4=
-----END CERTIFICATE----- -----END CERTIFICATE-----
...@@ -2,41 +2,40 @@ ...@@ -2,41 +2,40 @@
0 s:/C=FR/postalCode=14000/ST=Calvados/L=CAEN/street=22 rue de Bretagne/O=TBS INTERNET/OU=0002 440443810/OU=sha-256 production/CN=sha256.tbs-internet.com 0 s:/C=FR/postalCode=14000/ST=Calvados/L=CAEN/street=22 rue de Bretagne/O=TBS INTERNET/OU=0002 440443810/OU=sha-256 production/CN=sha256.tbs-internet.com
i:/C=FR/ST=Calvados/L=Caen/O=TBS INTERNET/OU=Terms and Conditions: http://www.tbs-internet.com/CA/repository/OU=TBS INTERNET CA/CN=TBS X509 CA SGC i:/C=FR/ST=Calvados/L=Caen/O=TBS INTERNET/OU=Terms and Conditions: http://www.tbs-internet.com/CA/repository/OU=TBS INTERNET CA/CN=TBS X509 CA SGC
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIGXTCCBUWgAwIBAgIRAMmag+ygSAdxZsbyzYjhuW0wDQYJKoZIhvcNAQELBQAw MIIGXDCCBUSgAwIBAgIRAKpVmHgg9nfCodAVwcP4siwwDQYJKoZIhvcNAQELBQAw
gcQxCzAJBgNVBAYTAkZSMREwDwYDVQQIEwhDYWx2YWRvczENMAsGA1UEBxMEQ2Fl gcQxCzAJBgNVBAYTAkZSMREwDwYDVQQIEwhDYWx2YWRvczENMAsGA1UEBxMEQ2Fl
bjEVMBMGA1UEChMMVEJTIElOVEVSTkVUMUgwRgYDVQQLEz9UZXJtcyBhbmQgQ29u bjEVMBMGA1UEChMMVEJTIElOVEVSTkVUMUgwRgYDVQQLEz9UZXJtcyBhbmQgQ29u
ZGl0aW9uczogaHR0cDovL3d3dy50YnMtaW50ZXJuZXQuY29tL0NBL3JlcG9zaXRv ZGl0aW9uczogaHR0cDovL3d3dy50YnMtaW50ZXJuZXQuY29tL0NBL3JlcG9zaXRv
cnkxGDAWBgNVBAsTD1RCUyBJTlRFUk5FVCBDQTEYMBYGA1UEAxMPVEJTIFg1MDkg cnkxGDAWBgNVBAsTD1RCUyBJTlRFUk5FVCBDQTEYMBYGA1UEAxMPVEJTIFg1MDkg
Q0EgU0dDMB4XDTEwMDIxODAwMDAwMFoXDTEyMDIxOTIzNTk1OVowgcsxCzAJBgNV Q0EgU0dDMB4XDTEyMDEwNDAwMDAwMFoXDTE0MDIxNzIzNTk1OVowgcsxCzAJBgNV
BAYTAkZSMQ4wDAYDVQQREwUxNDAwMDERMA8GA1UECBMIQ2FsdmFkb3MxDTALBgNV BAYTAkZSMQ4wDAYDVQQREwUxNDAwMDERMA8GA1UECBMIQ2FsdmFkb3MxDTALBgNV
BAcTBENBRU4xGzAZBgNVBAkTEjIyIHJ1ZSBkZSBCcmV0YWduZTEVMBMGA1UEChMM BAcTBENBRU4xGzAZBgNVBAkTEjIyIHJ1ZSBkZSBCcmV0YWduZTEVMBMGA1UEChMM
VEJTIElOVEVSTkVUMRcwFQYDVQQLEw4wMDAyIDQ0MDQ0MzgxMDEbMBkGA1UECxMS VEJTIElOVEVSTkVUMRcwFQYDVQQLEw4wMDAyIDQ0MDQ0MzgxMDEbMBkGA1UECxMS
c2hhLTI1NiBwcm9kdWN0aW9uMSAwHgYDVQQDExdzaGEyNTYudGJzLWludGVybmV0 c2hhLTI1NiBwcm9kdWN0aW9uMSAwHgYDVQQDExdzaGEyNTYudGJzLWludGVybmV0
LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbuM8VT7f0nntwu LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKQIX/zdJcyxty0m
N3F7v9KIBlhKNAxqCrziOXU5iqUt8HrQB3DtHbdmII+CpVUlwlmepsx6G+srEZ9a PM1XQSoSSifueS3AVcgqMsaIKS/u+rYzsv4hQ/qA6vLn5m5/ewUcZDj7zdi6rBVf
MIGAy0nxi5aLb7watkyIdPjJTMvTUBQ/+RPWzt5JtYbbY9BlJ+yci0dctP74f4NU PaVNXJ6YinLX0tkaW8TEjeVuZG5yksGZlhCt1CJ1Ho9XLiLaP4uJ7MCoNUntpJ+E
ISLtlrEjUbf2gTohLrcE01TfmOF6PDEbB5PKDi38cB3NzKfizWfrOaJW6Q1C1qOJ LfrOdgsIj91kPmwjDJeztVcQCvKzhjVJA/KxdInc0JvOATn7rpaSmQI5bvIjufgo
y4/4jkUREX1UFUIxzx7v62VfjXSGlcjGpBX1fvtABQOSLeE0a6gciDZs1REqroFf qVsTPwVFzuUYULXBk7KxRT7MiEqnd5HvviNh0285QC478zl3v0I0Fb5El4yD3p49
5eXtqYphpTa14Z83ITXMfgg5Nze1VtMnzI9Qx4blYBw4dgQVEuIsYr7FDBOITDzc IthcRnxzMKc0UhU5ogi0SbONyBfm/mzONVfSxpM+MlyvZmJqrbuuLoEDzJD+t8PU
VEVXZx0CAwEAAaOCAj8wggI7MB8GA1UdIwQYMBaAFAdEdoWTKLx/bXjSCuv6TEvf xSuzgbcCAwEAAaOCAj4wggI6MB8GA1UdIwQYMBaAFAdEdoWTKLx/bXjSCuv6TEvf
2YIfMB0GA1UdDgQWBBSJKI/AYVI9RQNY0QPIqc8ej2QivTAOBgNVHQ8BAf8EBAMC 2YIfMB0GA1UdDgQWBBT/qTGYdaj+f61c2IRFL/B1eEsM8DAOBgNVHQ8BAf8EBAMC
BaAwDAYDVR0TAQH/BAIwADA0BgNVHSUELTArBggrBgEFBQcDAQYIKwYBBQUHAwIG BaAwDAYDVR0TAQH/BAIwADA0BgNVHSUELTArBggrBgEFBQcDAQYIKwYBBQUHAwIG
CisGAQQBgjcKAwMGCWCGSAGG+EIEATBMBgNVHSAERTBDMEEGCysGAQQBgOU3AgQB CisGAQQBgjcKAwMGCWCGSAGG+EIEATBLBgNVHSAERDBCMEAGCisGAQQB5TcCBAEw
MDIwMAYIKwYBBQUHAgEWJGh0dHBzOi8vd3d3LnRicy1pbnRlcm5ldC5jb20vQ0Ev MjAwBggrBgEFBQcCARYkaHR0cHM6Ly93d3cudGJzLWludGVybmV0LmNvbS9DQS9D
Q1BTNDBtBgNVHR8EZjBkMDKgMKAuhixodHRwOi8vY3JsLnRicy1pbnRlcm5ldC5j UFM0MG0GA1UdHwRmMGQwMqAwoC6GLGh0dHA6Ly9jcmwudGJzLWludGVybmV0LmNv
b20vVEJTWDUwOUNBU0dDLmNybDAuoCygKoYoaHR0cDovL2NybC50YnMteDUwOS5j bS9UQlNYNTA5Q0FTR0MuY3JsMC6gLKAqhihodHRwOi8vY3JsLnRicy14NTA5LmNv
b20vVEJTWDUwOUNBU0dDLmNybDCBpgYIKwYBBQUHAQEEgZkwgZYwOAYIKwYBBQUH bS9UQlNYNTA5Q0FTR0MuY3JsMIGmBggrBgEFBQcBAQSBmTCBljA4BggrBgEFBQcw
MAKGLGh0dHA6Ly9jcnQudGJzLWludGVybmV0LmNvbS9UQlNYNTA5Q0FTR0MuY3J0 AoYsaHR0cDovL2NydC50YnMtaW50ZXJuZXQuY29tL1RCU1g1MDlDQVNHQy5jcnQw
MDQGCCsGAQUFBzAChihodHRwOi8vY3J0LnRicy14NTA5LmNvbS9UQlNYNTA5Q0FT NAYIKwYBBQUHMAKGKGh0dHA6Ly9jcnQudGJzLXg1MDkuY29tL1RCU1g1MDlDQVNH
R0MuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC50YnMteDUwOS5jb20wPwYD Qy5jcnQwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLnRicy14NTA5LmNvbTA/BgNV
VR0RBDgwNoIXc2hhMjU2LnRicy1pbnRlcm5ldC5jb22CG3d3dy5zaGEyNTYudGJz HREEODA2ghdzaGEyNTYudGJzLWludGVybmV0LmNvbYIbd3d3LnNoYTI1Ni50YnMt
LWludGVybmV0LmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAA5NL0D4QSqhErhlkdPmz aW50ZXJuZXQuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQA0pOuL8QvAa5yksTbGShzX
XtiMvdGL+ZehM4coTRIpasM/Agt36Rc0NzCvnQwKE+wkngg1Gy2qe7Q0E/ziqBtB ABApagunUGoEydv4YJT1MXy9tTp7DrWaozZSlsqBxrYAXP1d9r2fuKbEniYHxaQ0
fZYzdVgu1zdiL4kTaf+wFKYAFGsFbyeEmXysy+CMwaNoF2vpSjCU1UD56bEnTX/W UYaf1VSIlDo1yuC8wE7wxbHDIpQ/E5KAyxiaJ8obtDhFstWAPAH+UoGXq0kj2teN
fxVZYxtBQUpnu2wOsm8cDZuZRv9XrYgAhGj9Tt6F0aVHSDGn59uwShG1+BVF/uju 21sFQ5dXgA95nldvVFsFhrRUNB6xXAcaj0VZFhttI0ZfQZmQwEI/P+N9Jr40OGun
SCyPTTjL1oc7YElJUzR/x4mQJYvtQI8gDIDAGEOs7v3R/gKa5EMfbUQUI4C84UbI aa+Dn0TMeUH4U20YntfLbu2nDcJcYfyurm+8/0Tr4HznLnedXu9pCPYj0TaddrgT
Yz09Jdnws/MkC/Hm1BZEqk89u7Hvfv+oHqEb0XaUo0TDfsxE0M1sMdnLb91QNQBm XO0oFiyy7qGaY6+qKh71yD64Y3ycCJ/HR9Wm39mjZYc9ezYwT4noP6r7Lk8YO7/q
UQ==
-----END CERTIFICATE----- -----END CERTIFICATE-----
1 s:/C=FR/ST=Calvados/L=Caen/O=TBS INTERNET/OU=Terms and Conditions: http://www.tbs-internet.com/CA/repository/OU=TBS INTERNET CA/CN=TBS X509 CA SGC 1 s:/C=FR/ST=Calvados/L=Caen/O=TBS INTERNET/OU=Terms and Conditions: http://www.tbs-internet.com/CA/repository/OU=TBS INTERNET CA/CN=TBS X509 CA SGC
i:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root i:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
......
...@@ -418,6 +418,8 @@ class CGIHTTPServerTestCase(BaseTestCase): ...@@ -418,6 +418,8 @@ class CGIHTTPServerTestCase(BaseTestCase):
finally: finally:
BaseTestCase.tearDown(self) BaseTestCase.tearDown(self)
@unittest.skipIf(hasattr(CGIHTTPServer, '_url_collapse_path'),
"Only on <= 2.7.3")
def test_url_collapse_path_split(self): def test_url_collapse_path_split(self):
test_vectors = { test_vectors = {
'': ('/', ''), '': ('/', ''),
...@@ -457,6 +459,50 @@ class CGIHTTPServerTestCase(BaseTestCase): ...@@ -457,6 +459,50 @@ class CGIHTTPServerTestCase(BaseTestCase):
msg='path = %r\nGot: %r\nWanted: %r' % msg='path = %r\nGot: %r\nWanted: %r' %
(path, actual, expected)) (path, actual, expected))
@unittest.skipIf(hasattr(CGIHTTPServer, '_url_collapse_path_split'),
"Only on >= 2.7.3")
def test_url_collapse_path(self):
# verify tail is the last portion and head is the rest on proper urls
test_vectors = {
'': '//',
'..': IndexError,
'/.//..': IndexError,
'/': '//',
'//': '//',
'/\\': '//\\',
'/.//': '//',
'cgi-bin/file1.py': '/cgi-bin/file1.py',
'/cgi-bin/file1.py': '/cgi-bin/file1.py',
'a': '//a',
'/a': '//a',
'//a': '//a',
'./a': '//a',
'./C:/': '/C:/',
'/a/b': '/a/b',
'/a/b/': '/a/b/',
'/a/b/.': '/a/b/',
'/a/b/c/..': '/a/b/',
'/a/b/c/../d': '/a/b/d',
'/a/b/c/../d/e/../f': '/a/b/d/f',
'/a/b/c/../d/e/../../f': '/a/b/f',
'/a/b/c/../d/e/.././././..//f': '/a/b/f',
'../a/b/c/../d/e/.././././..//f': IndexError,
'/a/b/c/../d/e/../../../f': '/a/f',
'/a/b/c/../d/e/../../../../f': '//f',
'/a/b/c/../d/e/../../../../../f': IndexError,
'/a/b/c/../d/e/../../../../f/..': '//',
'/a/b/c/../d/e/../../../../f/../.': '//',
}
for path, expected in test_vectors.iteritems():
if isinstance(expected, type) and issubclass(expected, Exception):
self.assertRaises(expected,
CGIHTTPServer._url_collapse_path, path)
else:
actual = CGIHTTPServer._url_collapse_path(path)
self.assertEqual(expected, actual,
msg='path = %r\nGot: %r\nWanted: %r' %
(path, actual, expected))
def test_headers_and_content(self): def test_headers_and_content(self):
res = self.request('/cgi-bin/file1.py') res = self.request('/cgi-bin/file1.py')
self.assertEqual(('Hello World\n', 'text/html', 200), self.assertEqual(('Hello World\n', 'text/html', 200),
......
...@@ -1177,11 +1177,15 @@ class NetworkConnectionNoServer(unittest.TestCase): ...@@ -1177,11 +1177,15 @@ class NetworkConnectionNoServer(unittest.TestCase):
def mocked_socket_module(self): def mocked_socket_module(self):
"""Return a socket which times out on connect""" """Return a socket which times out on connect"""
old_socket = socket.socket old_socket = socket.socket
import gevent.socket
old_g_socket = gevent.socket.socket
socket.socket = self.MockSocket socket.socket = self.MockSocket
gevent.socket.socket = self.MockSocket
try: try:
yield yield
finally: finally:
socket.socket = old_socket socket.socket = old_socket
gevent.socket.socket = old_g_socket
def test_connect(self): def test_connect(self):
port = test_support.find_unused_port() port = test_support.find_unused_port()
......
This diff is collapsed.
...@@ -706,6 +706,7 @@ class GeneralModuleTests(unittest.TestCase): ...@@ -706,6 +706,7 @@ class GeneralModuleTests(unittest.TestCase):
c.close() c.close()
s.close() s.close()
@unittest.skip("Needs fix in CFFI; hangs forever")
def test_sendall_interrupted(self): def test_sendall_interrupted(self):
self.check_sendall_interrupted(False) self.check_sendall_interrupted(False)
...@@ -1291,11 +1292,15 @@ class NetworkConnectionNoServer(unittest.TestCase): ...@@ -1291,11 +1292,15 @@ class NetworkConnectionNoServer(unittest.TestCase):
def mocked_socket_module(self): def mocked_socket_module(self):
"""Return a socket which times out on connect""" """Return a socket which times out on connect"""
old_socket = socket.socket old_socket = socket.socket
import gevent.socket
old_g_socket = gevent.socket.socket
socket.socket = self.MockSocket socket.socket = self.MockSocket
gevent.socket.socket = self.MockSocket
try: try:
yield yield
finally: finally:
socket.socket = old_socket socket.socket = old_socket
gevent.socket.socket = old_g_socket
def test_connect(self): def test_connect(self):
port = test_support.find_unused_port() port = test_support.find_unused_port()
......
This diff is collapsed.
...@@ -20,6 +20,7 @@ except ImportError: ...@@ -20,6 +20,7 @@ except ImportError:
threading = None threading = None
mswindows = (sys.platform == "win32") mswindows = (sys.platform == "win32")
PYPY = hasattr(sys, 'pypy_version_info')
# #
# Depends on the following external programs: Python # Depends on the following external programs: Python
...@@ -193,8 +194,8 @@ class ProcessTestCase(BaseTestCase): ...@@ -193,8 +194,8 @@ class ProcessTestCase(BaseTestCase):
p.wait() p.wait()
self.assertEqual(p.returncode, 47) self.assertEqual(p.returncode, 47)
@unittest.skipIf(sysconfig.is_python_build(), @unittest.skipIf(sysconfig.is_python_build() or PYPY,
"need an installed Python. See #7774") "need an installed Python. See #7774. Also fails to get sys.prefix on stock PyPy")
def test_executable_without_cwd(self): def test_executable_without_cwd(self):
# For a normal installation, it should work without 'cwd' # For a normal installation, it should work without 'cwd'
# argument. For test runs in the build directory, see #7774. # argument. For test runs in the build directory, see #7774.
......
...@@ -182,7 +182,9 @@ def _get_class_attr(classDict, bases, attr, default=AttributeError): ...@@ -182,7 +182,9 @@ def _get_class_attr(classDict, bases, attr, default=AttributeError):
class TestCaseMetaClass(type): class TestCaseMetaClass(type):
# wrap each test method with # wrap each test method with
# a) timeout check # a) timeout check
# b) totalrefcount check # b) fatal error check
# c) restore the hub's error handler (see expect_one_error)
# d) totalrefcount check
def __new__(meta, classname, bases, classDict): def __new__(meta, classname, bases, classDict):
timeout = classDict.get('__timeout__', 'NONE') timeout = classDict.get('__timeout__', 'NONE')
if timeout == 'NONE': if timeout == 'NONE':
...@@ -223,6 +225,7 @@ class TestCase(TestCaseMetaClass("NewBase", (BaseTestCase,), {})): ...@@ -223,6 +225,7 @@ class TestCase(TestCaseMetaClass("NewBase", (BaseTestCase,), {})):
return return
if hasattr(self, 'cleanup'): if hasattr(self, 'cleanup'):
self.cleanup() self.cleanup()
self._error = self._none
@property @property
def testname(self): def testname(self):
......
...@@ -8,19 +8,28 @@ else: ...@@ -8,19 +8,28 @@ else:
import util import util
import ssl
class Test_wsgiserver(util.TestServer): class Test_wsgiserver(util.TestServer):
server = 'wsgiserver.py' server = 'wsgiserver.py'
URL = 'http://127.0.0.1:8088' URL = 'http://127.0.0.1:8088'
not_found_message = '<h1>Not Found</h1>' not_found_message = '<h1>Not Found</h1>'
ssl_ctx = None
def read(self, path='/'): def read(self, path='/'):
url = self.URL + path url = self.URL + path
try: try:
if self.ssl_ctx is not None:
response = urllib2.urlopen(url, context=self.ssl_ctx)
else:
response = urllib2.urlopen(url) response = urllib2.urlopen(url)
except urllib2.HTTPError: except urllib2.HTTPError:
response = sys.exc_info()[1] response = sys.exc_info()[1]
return '%s %s' % (response.code, response.msg), response.read() result = '%s %s' % (response.code, response.msg), response.read()
# XXX: It looks like under PyPy this isn't directly closing the socket
# when SSL is in use. It takes a GC cycle to make that true.
response.close()
return result
def _test_hello(self): def _test_hello(self):
status, data = self.read('/') status, data = self.read('/')
...@@ -37,6 +46,11 @@ class Test_wsgiserver_ssl(Test_wsgiserver): ...@@ -37,6 +46,11 @@ class Test_wsgiserver_ssl(Test_wsgiserver):
server = 'wsgiserver_ssl.py' server = 'wsgiserver_ssl.py'
URL = 'https://127.0.0.1:8443' URL = 'https://127.0.0.1:8443'
if hasattr(ssl, '_create_unverified_context'):
# Disable verification for our self-signed cert
# on Python >= 2.7.9 and 3.4
ssl_ctx = ssl._create_unverified_context()
class Test_webproxy(Test_wsgiserver): class Test_webproxy(Test_wsgiserver):
server = 'webproxy.py' server = 'webproxy.py'
......
...@@ -140,7 +140,7 @@ are missing from %r: ...@@ -140,7 +140,7 @@ are missing from %r:
raise AssertionError(msg) raise AssertionError(msg)
def _test(self, modname): def _test(self, modname):
if modname.endswith('2'): if modname.endswith('2') or modname.endswith("279"):
return return
if modname.endswith('3'): if modname.endswith('3'):
return return
......
from __future__ import print_function
import pickle import pickle
import sys
import greentest import greentest
from gevent.ares import ares_host_result try:
from gevent.ares import ares_host_result
except ImportError as ex:
print(ex)
sys.exit(0)
class TestPickle(greentest.TestCase): class TestPickle(greentest.TestCase):
......
...@@ -22,10 +22,16 @@ try: ...@@ -22,10 +22,16 @@ try:
f.write('x') f.write('x')
f.close() f.close()
greenlet = gevent.spawn_later(DELAY, write)
watcher = hub.loop.stat(filename)
start = time.time() start = time.time()
greenlet = gevent.spawn_later(DELAY, write)
# If we don't specify an interval, we default to zero.
# libev interprets that as meaning to use its default interval,
# which is about 5 seconds. If we go below it's minimum check
# threshold, it bumps it up to the minimum.
watcher = hub.loop.stat(filename, interval=-1)
if hasattr(watcher, 'path'):
assert watcher.path == filename
assert watcher.interval == -1
with gevent.Timeout(5 + DELAY + 0.5): with gevent.Timeout(5 + DELAY + 0.5):
hub.wait(watcher) hub.wait(watcher)
...@@ -37,6 +43,8 @@ try: ...@@ -37,6 +43,8 @@ try:
assert reaction >= 0.0, 'Watcher %s reacted too early (write): %.3fs' % (watcher, reaction) assert reaction >= 0.0, 'Watcher %s reacted too early (write): %.3fs' % (watcher, reaction)
assert watcher.attr is not None, watcher.attr assert watcher.attr is not None, watcher.attr
assert watcher.prev is not None, watcher.prev assert watcher.prev is not None, watcher.prev
# The watcher interval changed after it started; -1 is illegal
assert watcher.interval != -1
greenlet.join() greenlet.join()
gevent.spawn_later(DELAY, os.unlink, filename) gevent.spawn_later(DELAY, os.unlink, filename)
......
import sys import sys
from gevent.hub import PYGTE279
from greentest import walk_modules, BaseTestCase, main from greentest import walk_modules, BaseTestCase, main
import six import six
...@@ -26,6 +27,8 @@ for path, module in walk_modules(): ...@@ -26,6 +27,8 @@ for path, module in walk_modules():
continue continue
if sys.version_info[0] == 2 and path.endswith('3.py'): if sys.version_info[0] == 2 and path.endswith('3.py'):
continue continue
if not PYGTE279 and path.endswith('279.py'):
continue
make_exec_test(path, module) make_exec_test(path, module)
......
...@@ -55,6 +55,10 @@ try: ...@@ -55,6 +55,10 @@ try:
except ImportError: except ImportError:
pass pass
if greentest.PYPY:
from errno import ECONNRESET
CONN_ABORTED_ERRORS.append(ECONNRESET)
REASONS = {200: 'OK', REASONS = {200: 'OK',
500: 'Internal Server Error'} 500: 'Internal Server Error'}
...@@ -581,6 +585,7 @@ class HttpsTestCase(TestCase): ...@@ -581,6 +585,7 @@ class HttpsTestCase(TestCase):
kwargs['body'] = post_body kwargs['body'] = post_body
else: else:
fd.write('\r\n') fd.write('\r\n')
fd.flush()
return read_http(fd, **kwargs) return read_http(fd, **kwargs)
def application(self, environ, start_response): def application(self, environ, start_response):
...@@ -979,11 +984,23 @@ class ChunkedInputTests(TestCase): ...@@ -979,11 +984,23 @@ class ChunkedInputTests(TestCase):
fd = self.connect().makefile(bufsize=1) fd = self.connect().makefile(bufsize=1)
fd.write(req) fd.write(req)
fd.close() fd.close()
gevent.sleep(0.01) gevent.sleep(0.01) # timing needed for cpython
if server_implements_chunked: if server_implements_chunked:
if greentest.PYPY:
# XXX: Something is keeping the socket alive,
# by which I mean, the close event is not propagating to the server
# and waking up its recv() loop...we are stuck with the three bytes of
# 'thi' in the buffer and trying to read the forth. No amount of tinkering
# with the timing changes this...the only thing that does is running a
# GC and letting some object get collected. Might this be a problem in real life?
import gc
gc.collect()
gevent.sleep(0.01)
self.assert_error(IOError, 'unexpected end of file while parsing chunked data') self.assert_error(IOError, 'unexpected end of file while parsing chunked data')
class Expect100ContinueTests(TestCase): class Expect100ContinueTests(TestCase):
validator = None validator = None
...@@ -1120,14 +1137,17 @@ class TestSubclass1(TestCase): ...@@ -1120,14 +1137,17 @@ class TestSubclass1(TestCase):
def test(self): def test(self):
fd = self.makefile() fd = self.makefile()
fd.write('<policy-file-request/>\x00') fd.write('<policy-file-request/>\x00')
fd.flush() # flush() is needed on PyPy, apparently it buffers slightly differently
self.assertEqual(fd.read(), 'HELLO') self.assertEqual(fd.read(), 'HELLO')
fd = self.makefile() fd = self.makefile()
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n') fd.write('GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
fd.flush()
read_http(fd) read_http(fd)
fd = self.makefile() fd = self.makefile()
fd.write('<policy-file-XXXuest/>\x00') fd.write('<policy-file-XXXuest/>\x00')
fd.flush()
self.assertEqual(fd.read(), '') self.assertEqual(fd.read(), '')
......
...@@ -25,7 +25,6 @@ are not leaked by the hub. ...@@ -25,7 +25,6 @@ are not leaked by the hub.
from __future__ import print_function from __future__ import print_function
from _socket import socket from _socket import socket
class Socket(socket): class Socket(socket):
"Something we can have a weakref to" "Something we can have a weakref to"
...@@ -104,6 +103,10 @@ def run_interaction(run_client): ...@@ -104,6 +103,10 @@ def run_interaction(run_client):
def run_and_check(run_client): def run_and_check(run_client):
w = run_interaction(run_client=run_client) w = run_interaction(run_client=run_client)
if greentest.PYPY:
# PyPy doesn't use a strict ref counting and must
# run a gc, but the object should be gone
gc.collect()
if w(): if w():
print(pformat(gc.get_referrers(w()))) print(pformat(gc.get_referrers(w())))
for x in gc.get_referrers(w()): for x in gc.get_referrers(w()):
......
...@@ -33,7 +33,6 @@ class SimpleStreamServer(StreamServer): ...@@ -33,7 +33,6 @@ class SimpleStreamServer(StreamServer):
finally: finally:
fd.close() fd.close()
class Settings: class Settings:
ServerClass = StreamServer ServerClass = StreamServer
ServerSubClass = SimpleStreamServer ServerSubClass = SimpleStreamServer
......
...@@ -86,15 +86,32 @@ def compare_relaxed(a, b): ...@@ -86,15 +86,32 @@ def compare_relaxed(a, b):
>>> compare_relaxed('2a00:1450:4016:800::1013', '2a00:1450:4008:c01::93') >>> compare_relaxed('2a00:1450:4016:800::1013', '2a00:1450:4008:c01::93')
True True
>>> compare_relaxed('2001:470::e852:4a38:9d7f:0', '2001:470:6d00:1c:1::d00')
True
>>> compare_relaxed('2001:470:4147:4943:6161:6161:2e74:6573', '2001:470::')
True
>>> compare_relaxed('2607:f8b0:6708:24af:1fd:700:60d4:4af', '2607:f8b0:2d00::f000:0')
True
>>> compare_relaxed('a.surfly.com', 'b.surfly.com') >>> compare_relaxed('a.surfly.com', 'b.surfly.com')
True True
>>> compare_relaxed('a.surfly.com', 'a.gevent.org') >>> compare_relaxed('a.surfly.com', 'a.gevent.org')
False False
""" """
if a.count(':') == 5 and b.count(':') == 5:
# IPv6 address from different requests might be different # IPv6 address from different requests might be different
a_segments = a.count(':')
b_segments = b.count(':')
if a_segments and b_segments:
if a_segments == b_segments and a_segments in (4,5,6,7):
return True return True
if a.rstrip(':').startswith(b.rstrip(':')) or b.rstrip(':').startswith(a.rstrip(':')):
return True
if a_segments >= 2 and b_segments >= 2 and a.split(':')[:2] == b.split(':')[:2]:
return True
return a.split('.', 1)[-1] == b.split('.', 1)[-1] return a.split('.', 1)[-1] == b.split('.', 1)[-1]
...@@ -223,7 +240,13 @@ class TestCase(greentest.TestCase): ...@@ -223,7 +240,13 @@ class TestCase(greentest.TestCase):
return return
if relaxed_is_equal(gevent_result, real_result): if relaxed_is_equal(gevent_result, real_result):
return return
raise AssertionError('%r != %r\n %s' % (gevent_result, real_result, format_call(func, args)))
# From 2.7 on, assertEqual does a better job highlighting the results than we would
# because it calls assertSequenceEqual, which highlights the exact
# difference in the tuple
msg = format_call(func, args)
self.assertEqual((msg,gevent_result), (msg,real_result))
class TestTypeError(TestCase): class TestTypeError(TestCase):
......
from __future__ import print_function from __future__ import print_function
import sys import sys
import errno
import gevent import gevent
try: try:
from gevent.resolver_ares import Resolver from gevent.resolver_ares import Resolver
...@@ -9,13 +10,14 @@ except ImportError as ex: ...@@ -9,13 +10,14 @@ except ImportError as ex:
from gevent import socket from gevent import socket
print(gevent.__file__) print(gevent.__file__)
address = ('127.0.0.10', 53) address = ('', 7153)
listener = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) listener = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try: try:
listener.bind(address) listener.bind(address)
except socket.error as ex: except socket.error as ex:
if 'permission denied' in str(ex).lower(): if ex.errno in (errno.EPERM, errno.EADDRNOTAVAIL) or 'permission denied' in str(ex).lower():
sys.stderr.write('This test binds on port 53 and thus must be run as root.\n') sys.stderr.write('This test binds on port a port that was already in use or not allowed.\n')
sys.exit(0) sys.exit(0)
raise raise
...@@ -26,7 +28,7 @@ def reader(): ...@@ -26,7 +28,7 @@ def reader():
gevent.spawn(reader) gevent.spawn(reader)
r = gevent.get_hub().resolver = Resolver(servers=['127.0.0.10'], timeout=0.001, tries=1) r = gevent.get_hub().resolver = Resolver(servers=['127.0.0.1'], timeout=0.001, tries=1, udp_port=address[-1])
try: try:
result = r.gethostbyname('www.google.com') result = r.gethostbyname('www.google.com')
except socket.gaierror as ex: except socket.gaierror as ex:
......
...@@ -120,9 +120,11 @@ class ThreadTests(unittest.TestCase): ...@@ -120,9 +120,11 @@ class ThreadTests(unittest.TestCase):
for i in range(NUMTASKS): for i in range(NUMTASKS):
t = TestThread("<thread %d>" % i, self, sema, mutex, numrunning) t = TestThread("<thread %d>" % i, self, sema, mutex, numrunning)
threads.append(t) threads.append(t)
t.daemon = False # Under PYPY we get daemon by default?
if hasattr(t, 'ident'): if hasattr(t, 'ident'):
self.failUnlessEqual(t.ident, None) self.failUnlessEqual(t.ident, None)
self.assert_(re.match('<TestThread\(.*, initial\)>', repr(t))) self.assertFalse(t.daemon)
self.assert_(re.match(r'<TestThread\(.*, initial\)>', repr(t)))
t.start() t.start()
if verbose: if verbose:
...@@ -133,7 +135,7 @@ class ThreadTests(unittest.TestCase): ...@@ -133,7 +135,7 @@ class ThreadTests(unittest.TestCase):
if hasattr(t, 'ident'): if hasattr(t, 'ident'):
self.failIfEqual(t.ident, 0) self.failIfEqual(t.ident, 0)
self.assertFalse(t.ident is None) self.assertFalse(t.ident is None)
self.assert_(re.match('<TestThread\(.*, \w+ -?\d+\)>', repr(t))) self.assert_(re.match(r'<TestThread\(.*, \w+ -?\d+\)>', repr(t)))
if verbose: if verbose:
print('all tasks done') print('all tasks done')
self.assertEqual(numrunning.get(), 0) self.assertEqual(numrunning.get(), 0)
...@@ -292,7 +294,8 @@ class ThreadTests(unittest.TestCase): ...@@ -292,7 +294,8 @@ class ThreadTests(unittest.TestCase):
# example. # example.
try: try:
import ctypes import ctypes
except ImportError: getattr(ctypes, 'pythonapi') # not available on PyPy
except (ImportError,AttributeError):
if verbose: if verbose:
print("test_finalize_with_runnning_thread can't import ctypes") print("test_finalize_with_runnning_thread can't import ctypes")
return # can't do anything return # can't do anything
...@@ -413,7 +416,6 @@ class ThreadJoinOnShutdown(unittest.TestCase): ...@@ -413,7 +416,6 @@ class ThreadJoinOnShutdown(unittest.TestCase):
script = """if 1: script = """if 1:
%s %s
import sys, os, time, threading import sys, os, time, threading
# a thread, which waits for the main program to terminate # a thread, which waits for the main program to terminate
def joiningfunc(mainthread): def joiningfunc(mainthread):
mainthread.join() mainthread.join()
......
...@@ -14,11 +14,6 @@ FAILING_TESTS = [ ...@@ -14,11 +14,6 @@ FAILING_TESTS = [
# needs investigating # needs investigating
'FLAKY test__issue6.py', 'FLAKY test__issue6.py',
# bunch of SSLError: [Errno 1] _ssl.c:504: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
# seems to be Python/OpenSSL problem, not gevent's
'monkey_test --Event test_ssl.py',
'monkey_test test_ssl.py',
# Sometimes fails with AssertionError: ...\nIOError: close() called during concurrent operation on the same file object.\n' # Sometimes fails with AssertionError: ...\nIOError: close() called during concurrent operation on the same file object.\n'
# Sometimes it contains "\nUnhandled exception in thread started by \nsys.excepthook is missing\nlost sys.stderr\n" # Sometimes it contains "\nUnhandled exception in thread started by \nsys.excepthook is missing\nlost sys.stderr\n"
"FLAKY test__subprocess_interrupted.py", "FLAKY test__subprocess_interrupted.py",
...@@ -31,7 +26,15 @@ if os.environ.get('GEVENT_RESOLVER') == 'ares' or CPYTHON_DBG: ...@@ -31,7 +26,15 @@ if os.environ.get('GEVENT_RESOLVER') == 'ares' or CPYTHON_DBG:
'FLAKY test__socket_dns.py', 'FLAKY test__socket_dns.py',
'FLAKY test__socket_dns6.py', 'FLAKY test__socket_dns6.py',
] ]
else:
FAILING_TESTS += [
# A number of the host names hardcoded have multiple, load
# balanced DNS entries. Therefore, multiple sequential calls
# of the resolution function, whether gevent or stdlib, can
# return non-equal results, possibly dependent on the host
# dns configuration
'FLAKY test__socket_dns6.py',
]
if sys.platform == 'win32': if sys.platform == 'win32':
# currently gevent.core.stat watcher does not implement 'prev' and 'attr' attributes on Windows # currently gevent.core.stat watcher does not implement 'prev' and 'attr' attributes on Windows
...@@ -55,35 +58,25 @@ if PYPY: ...@@ -55,35 +58,25 @@ if PYPY:
FAILING_TESTS += [ FAILING_TESTS += [
# Not implemented: # Not implemented:
# stat watchers are not implemented on pypy
'test__core_stat.py',
# ares not supported on PyPy yet
'test__ares_host_result.py',
# --- # ---
# BUGS: # BUGS:
# in CPython we compile _semaphore.py with Cython to make its operation atomic # in CPython we compile _semaphore.py with Cython to make its operation atomic
# how to do atomic operations on PyPy? # how to do atomic operations on PyPy?.
# Note that PyPy will compile and load the Cython version of gevent._semaphore,
# thus fixing this test case (making it load it is a manual process now because
# _semaphore.py still exists and PyPy prefers that to the .so---some things would have
# to be renamed to make it work automatically). However, on at least one machine, the Cython
# version causes the test suite to run slower: ~2:52 vs ~2:37. Is that worth the
# non-traceability? (Is it even repeatable? Possibly not; a lot of the test time is spent in,
# e.g., test__socket_dns.py doing network stuff.)
'test__threading_vs_settrace.py', 'test__threading_vs_settrace.py',
# check_sendall_interrupted and testInterruptedTimeout fail due to # check_sendall_interrupted and testInterruptedTimeout fail due to
# https://bitbucket.org/cffi/cffi/issue/152/handling-errors-from-signal-handlers-in # https://bitbucket.org/cffi/cffi/issue/152/handling-errors-from-signal-handlers-in
'test_socket.py', 'test_socket.py',
# No idea!
'test_threading_2.py',
'test_threading.py',
'test__pywsgi.py',
'test__backdoor.py',
'test__refcount.py',
'test__server.py',
'test_subprocess.py', # test_executable_without_cwd
'FLAKY test___example_servers.py',
'FLAKY test_queue.py',
] ]
......
[tox]
envlist =
py26,py27,pypy,py33,py34
[testenv]
deps =
greenlet
whitelist_externals =
*
commands =
make toxtest
[testenv:py27-full]
basepython = python2.7
commands =
make fulltoxtest
[testenv:pypy]
deps =
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