From b525e423c3d143f3e67dba26fea2f1103b9bb6d4 Mon Sep 17 00:00:00 2001 From: Ben Darnell Date: Sun, 5 Nov 2017 10:38:03 -0500 Subject: [PATCH] test: More robust ipv6 detection There are many ways ipv6 can be disabled or broken (and it just stopped working on travis-ci), so instead of checking flags like socket.has_ipv6, attempt to actually bind to an ipv6 address. Closes #2185 --- tornado/test/simple_httpclient_test.py | 13 +++---------- tornado/test/util.py | 23 ++++++++++++++++++++--- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/tornado/test/simple_httpclient_test.py b/tornado/test/simple_httpclient_test.py index 451942d28..0e75e530c 100644 --- a/tornado/test/simple_httpclient_test.py +++ b/tornado/test/simple_httpclient_test.py @@ -272,16 +272,9 @@ class SimpleHTTPClientTestMixin(object): @skipIfNoIPv6 def test_ipv6(self): - try: - [sock] = bind_sockets(None, '::1', family=socket.AF_INET6) - port = sock.getsockname()[1] - self.http_server.add_socket(sock) - except socket.gaierror as e: - if e.args[0] == socket.EAI_ADDRFAMILY: - # python supports ipv6, but it's not configured on the network - # interface, so skip this test. - return - raise + [sock] = bind_sockets(None, '::1', family=socket.AF_INET6) + port = sock.getsockname()[1] + self.http_server.add_socket(sock) url = '%s://[::1]:%d/hello' % (self.get_protocol(), port) # ipv6 is currently enabled by default but can be disabled diff --git a/tornado/test/util.py b/tornado/test/util.py index 5f534e84e..7958d92b2 100644 --- a/tornado/test/util.py +++ b/tornado/test/util.py @@ -35,15 +35,32 @@ skipOnAppEngine = unittest.skipIf('APPENGINE_RUNTIME' in os.environ, skipIfNoNetwork = unittest.skipIf('NO_NETWORK' in os.environ, 'network access disabled') -skipIfNoIPv6 = unittest.skipIf(not socket.has_ipv6, 'ipv6 support not present') - - skipBefore33 = unittest.skipIf(sys.version_info < (3, 3), 'PEP 380 (yield from) not available') skipBefore35 = unittest.skipIf(sys.version_info < (3, 5), 'PEP 492 (async/await) not available') skipNotCPython = unittest.skipIf(platform.python_implementation() != 'CPython', 'Not CPython implementation') +def _detect_ipv6(): + if not socket.has_ipv6: + # socket.has_ipv6 check reports whether ipv6 was present at compile + # time. It's usually true even when ipv6 doesn't work for other reasons. + return False + sock = None + try: + sock = socket.socket(socket.AF_INET6) + sock.bind(('::1', 0)) + except socket.error: + return False + finally: + if sock is not None: + sock.close() + return True + + +skipIfNoIPv6 = unittest.skipIf(not _detect_ipv6(), 'ipv6 support not present') + + def refusing_port(): """Returns a local port number that will refuse all connections. -- 2.47.2