Commit 9e4cf9c0 authored by Jason Madden's avatar Jason Madden

Fix tests on macOS 10.13 (something seems different about the dual IPv4/6 stack setup)

parent 3eb826c6
...@@ -51,6 +51,9 @@ ...@@ -51,6 +51,9 @@
an encoding has been specified. Initial patch in :pr:`939` by an encoding has been specified. Initial patch in :pr:`939` by
William Grzybowski. William Grzybowski.
- Monkey-patching after the :mod:`ssl` module has been imported now
prints a warning because this can produce ``RecursionError``.
1.2.2 (2017-06-05) 1.2.2 (2017-06-05)
================== ==================
......
...@@ -15,6 +15,7 @@ as well as the constants from the :mod:`socket` module are imported into this mo ...@@ -15,6 +15,7 @@ as well as the constants from the :mod:`socket` module are imported into this mo
import sys import sys
from gevent._compat import PY3 from gevent._compat import PY3
from gevent._compat import reraise
from gevent._util import copy_globals from gevent._util import copy_globals
...@@ -74,6 +75,7 @@ def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT, source_address=N ...@@ -74,6 +75,7 @@ def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT, source_address=N
host, port = address host, port = address
err = None err = None
tb = None
for res in getaddrinfo(host, port, 0 if has_ipv6 else AF_INET, SOCK_STREAM): for res in getaddrinfo(host, port, 0 if has_ipv6 else AF_INET, SOCK_STREAM):
af, socktype, proto, _, sa = res af, socktype, proto, _, sa = res
sock = None sock = None
...@@ -90,13 +92,19 @@ def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT, source_address=N ...@@ -90,13 +92,19 @@ def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT, source_address=N
# and the next bind() fails (see test__socket.TestCreateConnection) # and the next bind() fails (see test__socket.TestCreateConnection)
# that does not happen with regular sockets though, because _socket.socket.connect() is a built-in. # that does not happen with regular sockets though, because _socket.socket.connect() is a built-in.
# this is similar to "getnameinfo loses a reference" failure in test_socket.py # this is similar to "getnameinfo loses a reference" failure in test_socket.py
tb = sys.exc_info()[2]
if not PY3: if not PY3:
sys.exc_clear() # pylint:disable=no-member,useless-suppression sys.exc_clear() # pylint:disable=no-member,useless-suppression
if sock is not None: if sock is not None:
sock.close() sock.close()
err = ex err = ex
sock = None
if err is not None: if err is not None:
raise err # pylint:disable=raising-bad-type try:
reraise(type(err), err, tb) # pylint:disable=raising-bad-type
finally:
err = None
tb = None
else: else:
raise error("getaddrinfo returns an empty list") raise error("getaddrinfo returns an empty list")
......
...@@ -677,12 +677,14 @@ if sys.version_info[:2] >= (3, 6): ...@@ -677,12 +677,14 @@ if sys.version_info[:2] >= (3, 6):
# 'test_socketserver.SocketServerTest.test_ForkingUDPServer', # 'test_socketserver.SocketServerTest.test_ForkingUDPServer',
# 'test_socketserver.SocketServerTest.test_ForkingUnixStreamServer']) # 'test_socketserver.SocketServerTest.test_ForkingUnixStreamServer'])
# LibreSSL reports OPENSSL_VERSION_INFO (2, 0, 0, 0, 0) regardless its version # LibreSSL reports OPENSSL_VERSION_INFO (2, 0, 0, 0, 0) regardless of its version,
from ssl import OPENSSL_VERSION # so this is known to fail on some distros. We don't want to detect this because we
if OPENSSL_VERSION.startswith('LibreSSL'): # don't want to trigger the side-effects of importing ssl prematurely if we will
disabled_tests += [ # be monkey-patching, so we skip this test everywhere. It doesn't do much for us
'test_ssl.BasicSocketTests.test_openssl_version' # anyway.
] disabled_tests += [
'test_ssl.BasicSocketTests.test_openssl_version'
]
# Now build up the data structure we'll use to actually find disabled tests # Now build up the data structure we'll use to actually find disabled tests
# to avoid a linear scan for every file (it seems the list could get quite large) # to avoid a linear scan for every file (it seems the list could get quite large)
......
...@@ -46,10 +46,10 @@ for k, v in monkey.saved.items(): ...@@ -46,10 +46,10 @@ for k, v in monkey.saved.items():
import warnings import warnings
with warnings.catch_warnings(record=True) as issued_warnings: with warnings.catch_warnings(record=True) as issued_warnings:
# Patch again, triggering two warnings, on for os=False/signal=True, # Patch again, triggering three warnings, one for os=False/signal=True,
# one for repeated monkey-patching. # one for repeated monkey-patching, one for patching after ssl
monkey.patch_all(os=False) monkey.patch_all(os=False)
assert len(issued_warnings) == 2, len(issued_warnings) assert len(issued_warnings) == 3, [str(x) for x in issued_warnings]
assert 'SIGCHLD' in str(issued_warnings[-1].message), issued_warnings[-1] assert 'SIGCHLD' in str(issued_warnings[-1].message), issued_warnings[-1]
assert 'more than once' in str(issued_warnings[0].message), issued_warnings[0] assert 'more than once' in str(issued_warnings[0].message), issued_warnings[0]
...@@ -59,7 +59,7 @@ with warnings.catch_warnings(record=True) as issued_warnings: ...@@ -59,7 +59,7 @@ with warnings.catch_warnings(record=True) as issued_warnings:
monkey.patch_all(os=False) monkey.patch_all(os=False)
orig_saved['_gevent_saved_patch_all'] = monkey.saved['_gevent_saved_patch_all'] orig_saved['_gevent_saved_patch_all'] = monkey.saved['_gevent_saved_patch_all']
assert len(issued_warnings) == 0, len(issued_warnings) assert not issued_warnings, [str(x) for x in issued_warnings]
# Make sure that re-patching did not change the monkey.saved # Make sure that re-patching did not change the monkey.saved
# attribute, overwriting the original functions. # attribute, overwriting the original functions.
......
...@@ -242,6 +242,14 @@ class TestCase(greentest.TestCase): ...@@ -242,6 +242,14 @@ class TestCase(greentest.TestCase):
validator = staticmethod(validator) validator = staticmethod(validator)
application = None application = None
# Bind to default address, which should give us ipv6 (when available)
# and ipv4. (see self.connect())
listen_addr = ''
# connect on ipv4, even though we bound to ipv6 too
# to prove ipv4 works...except on Windows, it apparently doesn't.
# So use the hostname.
connect_addr = 'localhost'
def init_logger(self): def init_logger(self):
import logging import logging
logger = logging.getLogger('gevent.pywsgi') logger = logging.getLogger('gevent.pywsgi')
...@@ -249,9 +257,7 @@ class TestCase(greentest.TestCase): ...@@ -249,9 +257,7 @@ class TestCase(greentest.TestCase):
def init_server(self, application): def init_server(self, application):
logger = self.logger = self.init_logger() logger = self.logger = self.init_logger()
# Bind to default address, which should give us ipv6 (when available) self.server = pywsgi.WSGIServer((self.listen_addr, 0), application,
# and ipv4. (see self.connect())
self.server = pywsgi.WSGIServer(('', 0), application,
log=logger, error_log=logger) log=logger, error_log=logger)
def setUp(self): def setUp(self):
...@@ -284,10 +290,7 @@ class TestCase(greentest.TestCase): ...@@ -284,10 +290,7 @@ class TestCase(greentest.TestCase):
# XXX currently listening socket is kept open in gevent.wsgi # XXX currently listening socket is kept open in gevent.wsgi
def connect(self): def connect(self):
# connect on ipv4, even though we bound to ipv6 too conn = socket.create_connection((self.connect_addr, self.port))
# to prove ipv4 works...except on Windows, it apparently doesn't.
# So use the hostname.
conn = socket.create_connection(('localhost', self.port))
self.connected.append(weakref.ref(conn)) self.connected.append(weakref.ref(conn))
result = conn result = conn
if PY3: if PY3:
...@@ -718,7 +721,8 @@ class HttpsTestCase(TestCase): ...@@ -718,7 +721,8 @@ class HttpsTestCase(TestCase):
keyfile = os.path.join(os.path.dirname(__file__), 'test_server.key') keyfile = os.path.join(os.path.dirname(__file__), 'test_server.key')
def init_server(self, application): def init_server(self, application):
self.server = pywsgi.WSGIServer(('127.0.0.1', 0), application, certfile=self.certfile, keyfile=self.keyfile) self.server = pywsgi.WSGIServer((self.listen_addr, 0), application,
certfile=self.certfile, keyfile=self.keyfile)
def urlopen(self, method='GET', post_body=None, **kwargs): def urlopen(self, method='GET', post_body=None, **kwargs):
import ssl import ssl
...@@ -760,7 +764,8 @@ else: ...@@ -760,7 +764,8 @@ else:
from gevent.ssl import _create_unverified_context from gevent.ssl import _create_unverified_context
context = _create_unverified_context() context = _create_unverified_context()
context.load_cert_chain(certfile=self.certfile, keyfile=self.keyfile) context.load_cert_chain(certfile=self.certfile, keyfile=self.keyfile)
self.server = pywsgi.WSGIServer(('127.0.0.1', 0), application, ssl_context=context) self.server = pywsgi.WSGIServer((self.listen_addr, 0),
application, ssl_context=context)
class TestHttps(HttpsTestCase): class TestHttps(HttpsTestCase):
...@@ -1422,7 +1427,7 @@ class Handler(pywsgi.WSGIHandler): ...@@ -1422,7 +1427,7 @@ class Handler(pywsgi.WSGIHandler):
return data + self.rfile.readline() return data + self.rfile.readline()
class TestSubclass1(TestCase): class TestHandlerSubclass(TestCase):
validator = None validator = None
...@@ -1431,7 +1436,9 @@ class TestSubclass1(TestCase): ...@@ -1431,7 +1436,9 @@ class TestSubclass1(TestCase):
return [] return []
def init_server(self, application): def init_server(self, application):
self.server = pywsgi.WSGIServer(('127.0.0.1', 0), application, handler_class=Handler) self.server = pywsgi.WSGIServer((self.listen_addr, 0),
application,
handler_class=Handler)
def test(self): def test(self):
fd = self.makefile() fd = self.makefile()
......
...@@ -34,8 +34,8 @@ class Test(greentest.TestCase): ...@@ -34,8 +34,8 @@ class Test(greentest.TestCase):
thread.start() thread.start()
thread.join() thread.join()
self.assertFalse(isinstance(current, threading._DummyThread)) self.assertNotIsInstance(current, threading._DummyThread)
self.assertTrue(isinstance(current, monkey.get_original('threading', 'Thread'))) self.assertIsInstance(current, monkey.get_original('threading', 'Thread'))
# We generated some warnings # We generated some warnings
......
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