import warnings import sys import errno import functools import logging import socket import ssl import os import pytest try: import brotli except ImportError: brotli = None from urllib3.exceptions import HTTPWarning from urllib3.packages import six from urllib3.util import ssl_ # We need a host that will not immediately close the connection with a TCP # Reset. SO suggests this hostname TARPIT_HOST = '10.255.255.1' # (Arguments for socket, is it IPv6 address?) VALID_SOURCE_ADDRESSES = [(('::1', 0), True), (('127.0.0.1', 0), False)] # RFC 5737: 192.0.2.0/24 is for testing only. # RFC 3849: 2001:db8::/32 is for documentation only. INVALID_SOURCE_ADDRESSES = [('192.0.2.255', 0), ('2001:db8::1', 0)] def clear_warnings(cls=HTTPWarning): new_filters = [] for f in warnings.filters: if issubclass(f[2], cls): continue new_filters.append(f) warnings.filters[:] = new_filters def setUp(): clear_warnings() warnings.simplefilter('ignore', HTTPWarning) def onlyPy279OrNewer(test): """Skips this test unless you are on Python 2.7.9 or later.""" @functools.wraps(test) def wrapper(*args, **kwargs): msg = "{name} requires Python 2.7.9+ to run".format(name=test.__name__) if sys.version_info < (2, 7, 9): pytest.skip(msg) return test(*args, **kwargs) return wrapper def onlyPy2(test): """Skips this test unless you are on Python 2.x""" @functools.wraps(test) def wrapper(*args, **kwargs): msg = "{name} requires Python 2.x to run".format(name=test.__name__) if six.PY3: pytest.skip(msg) return test(*args, **kwargs) return wrapper def onlyPy3(test): """Skips this test unless you are on Python3.x""" @functools.wraps(test) def wrapper(*args, **kwargs): msg = "{name} requires Python3.x to run".format(name=test.__name__) if not six.PY3: pytest.skip(msg) return test(*args, **kwargs) return wrapper def onlyBrotlipy(): return pytest.mark.skipif( brotli is None, reason='only run if brotlipy is present') def notBrotlipy(): return pytest.mark.skipif( brotli is not None, reason='only run if brotlipy is absent') def notSecureTransport(test): """Skips this test when SecureTransport is in use.""" @functools.wraps(test) def wrapper(*args, **kwargs): msg = "{name} does not run with SecureTransport".format(name=test.__name__) if ssl_.IS_SECURETRANSPORT: pytest.skip(msg) return test(*args, **kwargs) return wrapper def notOpenSSL098(test): """Skips this test for Python 3.4 and 3.5 macOS python.org distributions""" @functools.wraps(test) def wrapper(*args, **kwargs): is_stdlib_ssl = not ssl_.IS_SECURETRANSPORT and not ssl_.IS_PYOPENSSL if is_stdlib_ssl and ssl.OPENSSL_VERSION == "OpenSSL 0.9.8zh 14 Jan 2016": pytest.xfail("{name} fails with OpenSSL 0.9.8zh".format(name=test.__name__)) return test(*args, **kwargs) return wrapper _requires_network_has_route = None def requires_network(test): """Helps you skip tests that require the network""" def _is_unreachable_err(err): return getattr(err, 'errno', None) in (errno.ENETUNREACH, errno.EHOSTUNREACH) # For OSX def _has_route(): try: sock = socket.create_connection((TARPIT_HOST, 80), 0.0001) sock.close() return True except socket.timeout: return True except socket.error as e: if _is_unreachable_err(e): return False else: raise @functools.wraps(test) def wrapper(*args, **kwargs): global _requires_network_has_route if _requires_network_has_route is None: _requires_network_has_route = _has_route() if _requires_network_has_route: return test(*args, **kwargs) else: msg = "Can't run {name} because the network is unreachable".format( name=test.__name__) pytest.skip(msg) return wrapper def requires_ssl_context_keyfile_password(test): @functools.wraps(test) def wrapper(*args, **kwargs): if ((not ssl_.IS_PYOPENSSL and sys.version_info < (2, 7, 9)) or ssl_.IS_SECURETRANSPORT): pytest.skip("%s requires password parameter for " "SSLContext.load_cert_chain()" % test.__name__) return test(*args, **kwargs) return wrapper def fails_on_travis_gce(test): """Expect the test to fail on Google Compute Engine instances for Travis. Travis uses GCE for its sudo: enabled builds. Reason for this decorator: https://github.com/urllib3/urllib3/pull/1475#issuecomment-440788064 """ @functools.wraps(test) def wrapper(*args, **kwargs): if os.environ.get("TRAVIS_INFRA") == "gce": pytest.xfail("%s is expected to fail on Travis GCE builds" % test.__name__) return test(*args, **kwargs) return wrapper def requiresTLSv1(): """Test requires TLSv1 available""" return pytest.mark.skipif(not hasattr(ssl, "PROTOCOL_TLSv1"), reason="Test requires TLSv1") def requiresTLSv1_1(): """Test requires TLSv1.1 available""" return pytest.mark.skipif(not hasattr(ssl, "PROTOCOL_TLSv1_1"), reason="Test requires TLSv1.1") def requiresTLSv1_2(): """Test requires TLSv1.2 available""" return pytest.mark.skipif(not hasattr(ssl, "PROTOCOL_TLSv1_2"), reason="Test requires TLSv1.2") def requiresTLSv1_3(): """Test requires TLSv1.3 available""" return pytest.mark.skipif( not getattr(ssl, "HAS_TLSv1_3", False), reason="Test requires TLSv1.3" ) class _ListHandler(logging.Handler): def __init__(self): super(_ListHandler, self).__init__() self.records = [] def emit(self, record): self.records.append(record) class LogRecorder(object): def __init__(self, target=logging.root): super(LogRecorder, self).__init__() self._target = target self._handler = _ListHandler() @property def records(self): return self._handler.records def install(self): self._target.addHandler(self._handler) def uninstall(self): self._target.removeHandler(self._handler) def __enter__(self): self.install() return self.records def __exit__(self, exc_type, exc_value, traceback): self.uninstall() return False