Commit 4f9bb1d9 authored by Jason Madden's avatar Jason Madden Committed by GitHub

Merge pull request #1053 from gevent/test-363

Test on 3.6.3 on Travis; appveyor was already there. 
parents 5d2bcb8d 7c9842b3
...@@ -149,6 +149,14 @@ ...@@ -149,6 +149,14 @@
See :issue:`790` for history and more in-depth discussion. See :issue:`790` for history and more in-depth discussion.
- gevent is now tested on Python 3.6.3. This includes the following
fixes and changes:
- Errors raised from :mod:`gevent.subprocess` will have a
``filename`` attribute set.
- The :class:`threading.Timer` class is now monkey-patched and can
be joined.
1.2.2 (2017-06-05) 1.2.2 (2017-06-05)
================== ==================
......
...@@ -116,7 +116,7 @@ PY278=$(BUILD_RUNTIMES)/snakepit/python2.7.8 ...@@ -116,7 +116,7 @@ PY278=$(BUILD_RUNTIMES)/snakepit/python2.7.8
PY27=$(BUILD_RUNTIMES)/snakepit/python2.7.14 PY27=$(BUILD_RUNTIMES)/snakepit/python2.7.14
PY34=$(BUILD_RUNTIMES)/snakepit/python3.4.7 PY34=$(BUILD_RUNTIMES)/snakepit/python3.4.7
PY35=$(BUILD_RUNTIMES)/snakepit/python3.5.4 PY35=$(BUILD_RUNTIMES)/snakepit/python3.5.4
PY36=$(BUILD_RUNTIMES)/snakepit/python3.6.2 PY36=$(BUILD_RUNTIMES)/snakepit/python3.6.3
PYPY=$(BUILD_RUNTIMES)/snakepit/pypy590 PYPY=$(BUILD_RUNTIMES)/snakepit/pypy590
PYPY3=$(BUILD_RUNTIMES)/snakepit/pypy3.5_590 PYPY3=$(BUILD_RUNTIMES)/snakepit/pypy3.5_590
...@@ -181,7 +181,7 @@ test-py35: $(PY35) ...@@ -181,7 +181,7 @@ test-py35: $(PY35)
PYTHON=python3.5.4 PATH=$(BUILD_RUNTIMES)/versions/python3.5.4/bin:$(PATH) make develop fulltoxtest PYTHON=python3.5.4 PATH=$(BUILD_RUNTIMES)/versions/python3.5.4/bin:$(PATH) make develop fulltoxtest
test-py36: $(PY36) test-py36: $(PY36)
PYTHON=python3.6.2 PATH=$(BUILD_RUNTIMES)/versions/python3.6.2/bin:$(PATH) make develop toxtest PYTHON=python3.6.3 PATH=$(BUILD_RUNTIMES)/versions/python3.6.3/bin:$(PATH) make develop toxtest
test-py36-libuv: $(PY36) test-py36-libuv: $(PY36)
GEVENT_CORE_CFFI_ONLY=libuv make test-py36 GEVENT_CORE_CFFI_ONLY=libuv make test-py36
......
...@@ -94,7 +94,7 @@ for var in "$@"; do ...@@ -94,7 +94,7 @@ for var in "$@"; do
install 3.5.4 python3.5.4 install 3.5.4 python3.5.4
;; ;;
3.6) 3.6)
install 3.6.2 python3.6.2 install 3.6.3 python3.6.3
;; ;;
pypy) pypy)
install pypy2.7-5.9.0 pypy590 install pypy2.7-5.9.0 pypy590
......
...@@ -464,6 +464,11 @@ class socket(object): ...@@ -464,6 +464,11 @@ class socket(object):
raise raise
def setblocking(self, flag): def setblocking(self, flag):
# Beginning in 3.6.0b3 this is supposed to raise
# if the file descriptor is closed, but the test for it
# involves closing the fileno directly. Since we
# don't touch the fileno here, it doesn't make sense for
# us.
if flag: if flag:
self.timeout = None self.timeout = None
else: else:
......
...@@ -1236,7 +1236,11 @@ class Popen(object): ...@@ -1236,7 +1236,11 @@ class Popen(object):
closed.add(fd) closed.add(fd)
if cwd is not None: if cwd is not None:
try:
os.chdir(cwd) os.chdir(cwd)
except OSError as e:
e._failed_chdir = True
raise
if preexec_fn: if preexec_fn:
preexec_fn() preexec_fn()
...@@ -1340,6 +1344,10 @@ class Popen(object): ...@@ -1340,6 +1344,10 @@ class Popen(object):
for fd in (p2cwrite, c2pread, errread): for fd in (p2cwrite, c2pread, errread):
if fd is not None: if fd is not None:
os.close(fd) os.close(fd)
if isinstance(child_exception, OSError):
child_exception.filename = executable
if hasattr(child_exception, '_failed_chdir'):
child_exception.filename = cwd
raise child_exception raise child_exception
def _handle_exitstatus(self, sts): def _handle_exitstatus(self, sts):
......
...@@ -188,11 +188,13 @@ if sys.version_info[:2] >= (3, 4): ...@@ -188,11 +188,13 @@ if sys.version_info[:2] >= (3, 4):
__implements__.append('Thread') __implements__.append('Thread')
# The main thread is patched up with more care in monkey.py class Timer(Thread, __threading__.Timer): # pylint:disable=abstract-method,inherit-non-class
#t = __threading__.current_thread() pass
#if isinstance(t, __threading__.Thread):
# t.__class__ = Thread __implements__.append('Timer')
# t._greenlet = getcurrent()
# The main thread is patched up with more care
# in _gevent_will_monkey_patch
if sys.version_info[:2] >= (3, 3): if sys.version_info[:2] >= (3, 3):
__implements__.remove('_get_ident') __implements__.remove('_get_ident')
......
...@@ -278,7 +278,13 @@ class ThreadableTest: ...@@ -278,7 +278,13 @@ class ThreadableTest:
def clientRun(self, test_func): def clientRun(self, test_func):
self.server_ready.wait() self.server_ready.wait()
try:
self.clientSetUp() self.clientSetUp()
except BaseException as e:
self.queue.put(e)
self.clientTearDown()
return
finally:
self.client_ready.set() self.client_ready.set()
if self.server_crashed: if self.server_crashed:
self.clientTearDown() self.clientTearDown()
...@@ -520,8 +526,11 @@ class ConnectedStreamTestMixin(SocketListeningTestMixin, ...@@ -520,8 +526,11 @@ class ConnectedStreamTestMixin(SocketListeningTestMixin,
self.serv_conn = self.cli self.serv_conn = self.cli
def clientTearDown(self): def clientTearDown(self):
try:
self.serv_conn.close() self.serv_conn.close()
self.serv_conn = None self.serv_conn = None
except AttributeError:
pass
super().clientTearDown() super().clientTearDown()
...@@ -540,7 +549,7 @@ class UnixSocketTestBase(SocketTestBase): ...@@ -540,7 +549,7 @@ class UnixSocketTestBase(SocketTestBase):
def bindSock(self, sock): def bindSock(self, sock):
path = tempfile.mktemp(dir=self.dir_path) path = tempfile.mktemp(dir=self.dir_path)
sock.bind(path) support.bind_unix_socket(sock, path)
self.addCleanup(support.unlink, path) self.addCleanup(support.unlink, path)
class UnixStreamBase(UnixSocketTestBase): class UnixStreamBase(UnixSocketTestBase):
...@@ -794,11 +803,6 @@ class GeneralModuleTests(unittest.TestCase): ...@@ -794,11 +803,6 @@ class GeneralModuleTests(unittest.TestCase):
self.fail("Error testing host resolution mechanisms. (fqdn: %s, all: %s)" % (fqhn, repr(all_host_names))) self.fail("Error testing host resolution mechanisms. (fqdn: %s, all: %s)" % (fqhn, repr(all_host_names)))
def test_host_resolution(self): def test_host_resolution(self):
for addr in ['0.1.1.~1', '1+.1.1.1', '::1q', '::1::2',
'1:1:1:1:1:1:1:1:1']:
self.assertRaises(OSError, socket.gethostbyname, addr)
self.assertRaises(OSError, socket.gethostbyaddr, addr)
for addr in [support.HOST, '10.0.0.1', '255.255.255.255']: for addr in [support.HOST, '10.0.0.1', '255.255.255.255']:
self.assertEqual(socket.gethostbyname(addr), addr) self.assertEqual(socket.gethostbyname(addr), addr)
...@@ -807,6 +811,21 @@ class GeneralModuleTests(unittest.TestCase): ...@@ -807,6 +811,21 @@ class GeneralModuleTests(unittest.TestCase):
for host in [support.HOST]: for host in [support.HOST]:
self.assertIn(host, socket.gethostbyaddr(host)[2]) self.assertIn(host, socket.gethostbyaddr(host)[2])
def test_host_resolution_bad_address(self):
# These are all malformed IP addresses and expected not to resolve to
# any result. But some ISPs, e.g. AWS, may successfully resolve these
# IPs.
explanation = (
"resolving an invalid IP address did not raise OSError; "
"can be caused by a broken DNS server"
)
for addr in ['0.1.1.~1', '1+.1.1.1', '::1q', '::1::2',
'1:1:1:1:1:1:1:1:1']:
with self.assertRaises(OSError):
socket.gethostbyname(addr)
with self.assertRaises(OSError, msg=explanation):
socket.gethostbyaddr(addr)
@unittest.skipUnless(hasattr(socket, 'sethostname'), "test needs socket.sethostname()") @unittest.skipUnless(hasattr(socket, 'sethostname'), "test needs socket.sethostname()")
@unittest.skipUnless(hasattr(socket, 'gethostname'), "test needs socket.gethostname()") @unittest.skipUnless(hasattr(socket, 'gethostname'), "test needs socket.gethostname()")
def test_sethostname(self): def test_sethostname(self):
...@@ -887,6 +906,7 @@ class GeneralModuleTests(unittest.TestCase): ...@@ -887,6 +906,7 @@ class GeneralModuleTests(unittest.TestCase):
self.assertEqual(swapped & mask, mask) self.assertEqual(swapped & mask, mask)
self.assertRaises(OverflowError, func, 1<<34) self.assertRaises(OverflowError, func, 1<<34)
@support.cpython_only
def testNtoHErrors(self): def testNtoHErrors(self):
good_values = [ 1, 2, 3, 1, 2, 3 ] good_values = [ 1, 2, 3, 1, 2, 3 ]
bad_values = [ -1, -2, -3, -1, -2, -3 ] bad_values = [ -1, -2, -3, -1, -2, -3 ]
...@@ -1480,7 +1500,8 @@ class GeneralModuleTests(unittest.TestCase): ...@@ -1480,7 +1500,8 @@ class GeneralModuleTests(unittest.TestCase):
# type and populates the socket object. # type and populates the socket object.
# #
# On Windows this trick won't work, so the test is skipped. # On Windows this trick won't work, so the test is skipped.
fd, _ = tempfile.mkstemp() fd, path = tempfile.mkstemp()
self.addCleanup(os.unlink, path)
with socket.socket(family=42424, type=13331, fileno=fd) as s: with socket.socket(family=42424, type=13331, fileno=fd) as s:
self.assertEqual(s.family, 42424) self.assertEqual(s.family, 42424)
self.assertEqual(s.type, 13331) self.assertEqual(s.type, 13331)
...@@ -4552,6 +4573,19 @@ class TestExceptions(unittest.TestCase): ...@@ -4552,6 +4573,19 @@ class TestExceptions(unittest.TestCase):
self.assertTrue(issubclass(socket.gaierror, OSError)) self.assertTrue(issubclass(socket.gaierror, OSError))
self.assertTrue(issubclass(socket.timeout, OSError)) self.assertTrue(issubclass(socket.timeout, OSError))
def test_setblocking_invalidfd(self):
# Regression test for issue #28471
sock0 = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
sock = socket.socket(
socket.AF_INET, socket.SOCK_STREAM, 0, sock0.fileno())
sock0.close()
self.addCleanup(sock.detach)
with self.assertRaises(OSError):
sock.setblocking(False)
@unittest.skipUnless(sys.platform == 'linux', 'Linux specific test') @unittest.skipUnless(sys.platform == 'linux', 'Linux specific test')
class TestLinuxAbstractNamespace(unittest.TestCase): class TestLinuxAbstractNamespace(unittest.TestCase):
...@@ -4617,7 +4651,7 @@ class TestUnixDomain(unittest.TestCase): ...@@ -4617,7 +4651,7 @@ class TestUnixDomain(unittest.TestCase):
def bind(self, sock, path): def bind(self, sock, path):
# Bind the socket # Bind the socket
try: try:
sock.bind(path) support.bind_unix_socket(sock, path)
except OSError as e: except OSError as e:
if str(e) == "AF_UNIX path too long": if str(e) == "AF_UNIX path too long":
self.skipTest( self.skipTest(
...@@ -4626,6 +4660,10 @@ class TestUnixDomain(unittest.TestCase): ...@@ -4626,6 +4660,10 @@ class TestUnixDomain(unittest.TestCase):
else: else:
raise raise
def testUnbound(self):
# Issue #30205
self.assertIn(self.sock.getsockname(), ('', None))
def testStrAddr(self): def testStrAddr(self):
# Test binding to and retrieving a normal string pathname. # Test binding to and retrieving a normal string pathname.
path = os.path.abspath(support.TESTFN) path = os.path.abspath(support.TESTFN)
...@@ -4755,9 +4793,13 @@ def isTipcAvailable(): ...@@ -4755,9 +4793,13 @@ def isTipcAvailable():
""" """
if not hasattr(socket, "AF_TIPC"): if not hasattr(socket, "AF_TIPC"):
return False return False
if not os.path.isfile("/proc/modules"): try:
f = open("/proc/modules")
except (FileNotFoundError, IsADirectoryError, PermissionError):
# It's ok if the file does not exist, is a directory or if we
# have not the permission to read it.
return False return False
with open("/proc/modules") as f: with f:
for line in f: for line in f:
if line.startswith("tipc "): if line.startswith("tipc "):
return True return True
...@@ -5442,7 +5484,7 @@ class LinuxKernelCryptoAPI(unittest.TestCase): ...@@ -5442,7 +5484,7 @@ class LinuxKernelCryptoAPI(unittest.TestCase):
self.assertEqual(len(dec), msglen * multiplier) self.assertEqual(len(dec), msglen * multiplier)
self.assertEqual(dec, msg * multiplier) self.assertEqual(dec, msg * multiplier)
@support.requires_linux_version(4, 3) # see test_aes_cbc @support.requires_linux_version(4, 9) # see issue29324
def test_aead_aes_gcm(self): def test_aead_aes_gcm(self):
key = bytes.fromhex('c939cc13397c1d37de6ae0e1cb7c423c') key = bytes.fromhex('c939cc13397c1d37de6ae0e1cb7c423c')
iv = bytes.fromhex('b3d8cc017cbb89b39e0f67e2') iv = bytes.fromhex('b3d8cc017cbb89b39e0f67e2')
...@@ -5465,8 +5507,7 @@ class LinuxKernelCryptoAPI(unittest.TestCase): ...@@ -5465,8 +5507,7 @@ class LinuxKernelCryptoAPI(unittest.TestCase):
op.sendmsg_afalg(op=socket.ALG_OP_ENCRYPT, iv=iv, op.sendmsg_afalg(op=socket.ALG_OP_ENCRYPT, iv=iv,
assoclen=assoclen, flags=socket.MSG_MORE) assoclen=assoclen, flags=socket.MSG_MORE)
op.sendall(assoc, socket.MSG_MORE) op.sendall(assoc, socket.MSG_MORE)
op.sendall(plain, socket.MSG_MORE) op.sendall(plain)
op.sendall(b'\x00' * taglen)
res = op.recv(assoclen + len(plain) + taglen) res = op.recv(assoclen + len(plain) + taglen)
self.assertEqual(expected_ct, res[assoclen:-taglen]) self.assertEqual(expected_ct, res[assoclen:-taglen])
self.assertEqual(expected_tag, res[-taglen:]) self.assertEqual(expected_tag, res[-taglen:])
...@@ -5474,7 +5515,7 @@ class LinuxKernelCryptoAPI(unittest.TestCase): ...@@ -5474,7 +5515,7 @@ class LinuxKernelCryptoAPI(unittest.TestCase):
# now with msg # now with msg
op, _ = algo.accept() op, _ = algo.accept()
with op: with op:
msg = assoc + plain + b'\x00' * taglen msg = assoc + plain
op.sendmsg_afalg([msg], op=socket.ALG_OP_ENCRYPT, iv=iv, op.sendmsg_afalg([msg], op=socket.ALG_OP_ENCRYPT, iv=iv,
assoclen=assoclen) assoclen=assoclen)
res = op.recv(assoclen + len(plain) + taglen) res = op.recv(assoclen + len(plain) + taglen)
...@@ -5485,7 +5526,7 @@ class LinuxKernelCryptoAPI(unittest.TestCase): ...@@ -5485,7 +5526,7 @@ class LinuxKernelCryptoAPI(unittest.TestCase):
pack_uint32 = struct.Struct('I').pack pack_uint32 = struct.Struct('I').pack
op, _ = algo.accept() op, _ = algo.accept()
with op: with op:
msg = assoc + plain + b'\x00' * taglen msg = assoc + plain
op.sendmsg( op.sendmsg(
[msg], [msg],
([socket.SOL_ALG, socket.ALG_SET_OP, pack_uint32(socket.ALG_OP_ENCRYPT)], ([socket.SOL_ALG, socket.ALG_SET_OP, pack_uint32(socket.ALG_OP_ENCRYPT)],
...@@ -5493,7 +5534,7 @@ class LinuxKernelCryptoAPI(unittest.TestCase): ...@@ -5493,7 +5534,7 @@ class LinuxKernelCryptoAPI(unittest.TestCase):
[socket.SOL_ALG, socket.ALG_SET_AEAD_ASSOCLEN, pack_uint32(assoclen)], [socket.SOL_ALG, socket.ALG_SET_AEAD_ASSOCLEN, pack_uint32(assoclen)],
) )
) )
res = op.recv(len(msg)) res = op.recv(len(msg) + taglen)
self.assertEqual(expected_ct, res[assoclen:-taglen]) self.assertEqual(expected_ct, res[assoclen:-taglen])
self.assertEqual(expected_tag, res[-taglen:]) self.assertEqual(expected_tag, res[-taglen:])
...@@ -5503,8 +5544,8 @@ class LinuxKernelCryptoAPI(unittest.TestCase): ...@@ -5503,8 +5544,8 @@ class LinuxKernelCryptoAPI(unittest.TestCase):
msg = assoc + expected_ct + expected_tag msg = assoc + expected_ct + expected_tag
op.sendmsg_afalg([msg], op=socket.ALG_OP_DECRYPT, iv=iv, op.sendmsg_afalg([msg], op=socket.ALG_OP_DECRYPT, iv=iv,
assoclen=assoclen) assoclen=assoclen)
res = op.recv(len(msg)) res = op.recv(len(msg) - taglen)
self.assertEqual(plain, res[assoclen:-taglen]) self.assertEqual(plain, res[assoclen:])
@support.requires_linux_version(4, 3) # see test_aes_cbc @support.requires_linux_version(4, 3) # see test_aes_cbc
def test_drbg_pr_sha256(self): def test_drbg_pr_sha256(self):
......
...@@ -18,6 +18,10 @@ import asyncore ...@@ -18,6 +18,10 @@ import asyncore
import weakref import weakref
import platform import platform
import functools import functools
try:
import ctypes
except ImportError:
ctypes = None
ssl = support.import_module("ssl") ssl = support.import_module("ssl")
...@@ -172,6 +176,13 @@ class BasicSocketTests(unittest.TestCase): ...@@ -172,6 +176,13 @@ class BasicSocketTests(unittest.TestCase):
ssl.OP_NO_COMPRESSION ssl.OP_NO_COMPRESSION
self.assertIn(ssl.HAS_SNI, {True, False}) self.assertIn(ssl.HAS_SNI, {True, False})
self.assertIn(ssl.HAS_ECDH, {True, False}) self.assertIn(ssl.HAS_ECDH, {True, False})
ssl.OP_NO_SSLv2
ssl.OP_NO_SSLv3
ssl.OP_NO_TLSv1
ssl.OP_NO_TLSv1_3
if ssl.OPENSSL_VERSION_INFO >= (1, 0, 1):
ssl.OP_NO_TLSv1_1
ssl.OP_NO_TLSv1_2
def test_str_for_enums(self): def test_str_for_enums(self):
# Make sure that the PROTOCOL_* constants have enum-like string # Make sure that the PROTOCOL_* constants have enum-like string
...@@ -1736,6 +1747,7 @@ class SimpleBackgroundTests(unittest.TestCase): ...@@ -1736,6 +1747,7 @@ class SimpleBackgroundTests(unittest.TestCase):
sslobj = ctx.wrap_bio(incoming, outgoing, False, 'localhost') sslobj = ctx.wrap_bio(incoming, outgoing, False, 'localhost')
self.assertIs(sslobj._sslobj.owner, sslobj) self.assertIs(sslobj._sslobj.owner, sslobj)
self.assertIsNone(sslobj.cipher()) self.assertIsNone(sslobj.cipher())
self.assertIsNone(sslobj.version())
self.assertIsNotNone(sslobj.shared_ciphers()) self.assertIsNotNone(sslobj.shared_ciphers())
self.assertRaises(ValueError, sslobj.getpeercert) self.assertRaises(ValueError, sslobj.getpeercert)
if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES: if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES:
...@@ -1743,6 +1755,7 @@ class SimpleBackgroundTests(unittest.TestCase): ...@@ -1743,6 +1755,7 @@ class SimpleBackgroundTests(unittest.TestCase):
self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake) self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake)
self.assertTrue(sslobj.cipher()) self.assertTrue(sslobj.cipher())
self.assertIsNotNone(sslobj.shared_ciphers()) self.assertIsNotNone(sslobj.shared_ciphers())
self.assertIsNotNone(sslobj.version())
self.assertTrue(sslobj.getpeercert()) self.assertTrue(sslobj.getpeercert())
if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES: if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES:
self.assertTrue(sslobj.get_channel_binding('tls-unique')) self.assertTrue(sslobj.get_channel_binding('tls-unique'))
...@@ -1793,34 +1806,6 @@ class NetworkedTests(unittest.TestCase): ...@@ -1793,34 +1806,6 @@ class NetworkedTests(unittest.TestCase):
_test_get_server_certificate(self, 'ipv6.google.com', 443) _test_get_server_certificate(self, 'ipv6.google.com', 443)
_test_get_server_certificate_fail(self, 'ipv6.google.com', 443) _test_get_server_certificate_fail(self, 'ipv6.google.com', 443)
def test_algorithms(self):
# Issue #8484: all algorithms should be available when verifying a
# certificate.
# SHA256 was added in OpenSSL 0.9.8
if ssl.OPENSSL_VERSION_INFO < (0, 9, 8, 0, 15):
self.skipTest("SHA256 not available on %r" % ssl.OPENSSL_VERSION)
# sha256.tbs-internet.com needs SNI to use the correct certificate
if not ssl.HAS_SNI:
self.skipTest("SNI needed for this test")
# https://sha2.hboeck.de/ was used until 2011-01-08 (no route to host)
remote = ("sha256.tbs-internet.com", 443)
sha256_cert = os.path.join(os.path.dirname(__file__), "sha256.pem")
with support.transient_internet("sha256.tbs-internet.com"):
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
ctx.verify_mode = ssl.CERT_REQUIRED
ctx.load_verify_locations(sha256_cert)
s = ctx.wrap_socket(socket.socket(socket.AF_INET),
server_hostname="sha256.tbs-internet.com")
try:
s.connect(remote)
if support.verbose:
sys.stdout.write("\nCipher with %r is %r\n" %
(remote, s.cipher()))
sys.stdout.write("Certificate is:\n%s\n" %
pprint.pformat(s.getpeercert()))
finally:
s.close()
def _test_get_server_certificate(test, host, port, cert=None): def _test_get_server_certificate(test, host, port, cert=None):
pem = ssl.get_server_certificate((host, port)) pem = ssl.get_server_certificate((host, port))
...@@ -1871,15 +1856,22 @@ if _have_threads: ...@@ -1871,15 +1856,22 @@ if _have_threads:
self.sock, server_side=True) self.sock, server_side=True)
self.server.selected_npn_protocols.append(self.sslconn.selected_npn_protocol()) self.server.selected_npn_protocols.append(self.sslconn.selected_npn_protocol())
self.server.selected_alpn_protocols.append(self.sslconn.selected_alpn_protocol()) self.server.selected_alpn_protocols.append(self.sslconn.selected_alpn_protocol())
except (ssl.SSLError, ConnectionResetError) as e: except (ssl.SSLError, ConnectionResetError, OSError) as e:
# We treat ConnectionResetError as though it were an # We treat ConnectionResetError as though it were an
# SSLError - OpenSSL on Ubuntu abruptly closes the # SSLError - OpenSSL on Ubuntu abruptly closes the
# connection when asked to use an unsupported protocol. # connection when asked to use an unsupported protocol.
# #
# OSError may occur with wrong protocols, e.g. both
# sides use PROTOCOL_TLS_SERVER.
#
# XXX Various errors can have happened here, for example # XXX Various errors can have happened here, for example
# a mismatching protocol version, an invalid certificate, # a mismatching protocol version, an invalid certificate,
# or a low-level bug. This should be made more discriminating. # or a low-level bug. This should be made more discriminating.
self.server.conn_errors.append(e) #
# bpo-31323: Store the exception as string to prevent
# a reference leak: server -> conn_errors -> exception
# -> traceback -> self (ConnectionHandler) -> server
self.server.conn_errors.append(str(e))
if self.server.chatty: if self.server.chatty:
handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n") handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
self.running = False self.running = False
...@@ -2065,7 +2057,7 @@ if _have_threads: ...@@ -2065,7 +2057,7 @@ if _have_threads:
class EchoServer (asyncore.dispatcher): class EchoServer (asyncore.dispatcher):
class ConnectionHandler (asyncore.dispatcher_with_send): class ConnectionHandler(asyncore.dispatcher_with_send):
def __init__(self, conn, certfile): def __init__(self, conn, certfile):
self.socket = test_wrap_socket(conn, server_side=True, self.socket = test_wrap_socket(conn, server_side=True,
...@@ -2156,6 +2148,8 @@ if _have_threads: ...@@ -2156,6 +2148,8 @@ if _have_threads:
self.join() self.join()
if support.verbose: if support.verbose:
sys.stdout.write(" cleanup: successfully joined.\n") sys.stdout.write(" cleanup: successfully joined.\n")
# make sure that ConnectionHandler is removed from socket_map
asyncore.close_all(ignore_all=True)
def start (self, flag=None): def start (self, flag=None):
self.flag = flag self.flag = flag
...@@ -2903,7 +2897,13 @@ if _have_threads: ...@@ -2903,7 +2897,13 @@ if _have_threads:
s.send(data) s.send(data)
buffer = bytearray(len(data)) buffer = bytearray(len(data))
self.assertEqual(s.read(-1, buffer), len(data)) self.assertEqual(s.read(-1, buffer), len(data))
self.assertEqual(buffer, data) self.assertEqual(buffer, data) # sendall accepts bytes-like objects
if ctypes is not None:
ubyte = ctypes.c_ubyte * len(data)
byteslike = ubyte.from_buffer_copy(data)
s.sendall(byteslike)
self.assertEqual(s.read(), data)
# Make sure sendmsg et al are disallowed to avoid # Make sure sendmsg et al are disallowed to avoid
# inadvertent disclosure of data and/or corruption # inadvertent disclosure of data and/or corruption
...@@ -3085,7 +3085,7 @@ if _have_threads: ...@@ -3085,7 +3085,7 @@ if _have_threads:
with context.wrap_socket(socket.socket()) as s: with context.wrap_socket(socket.socket()) as s:
with self.assertRaises(OSError): with self.assertRaises(OSError):
s.connect((HOST, server.port)) s.connect((HOST, server.port))
self.assertIn("no shared cipher", str(server.conn_errors[0])) self.assertIn("no shared cipher", server.conn_errors[0])
def test_version_basic(self): def test_version_basic(self):
""" """
...@@ -3102,12 +3102,33 @@ if _have_threads: ...@@ -3102,12 +3102,33 @@ if _have_threads:
self.assertEqual(s.version(), 'TLSv1') self.assertEqual(s.version(), 'TLSv1')
self.assertIs(s.version(), None) self.assertIs(s.version(), None)
@unittest.skipUnless(ssl.HAS_TLSv1_3,
"test requires TLSv1.3 enabled OpenSSL")
def test_tls1_3(self):
context = ssl.SSLContext(ssl.PROTOCOL_TLS)
context.load_cert_chain(CERTFILE)
# disable all but TLS 1.3
context.options |= (
ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1 | ssl.OP_NO_TLSv1_2
)
with ThreadedEchoServer(context=context) as server:
with context.wrap_socket(socket.socket()) as s:
s.connect((HOST, server.port))
self.assertIn(s.cipher()[0], [
'TLS13-AES-256-GCM-SHA384',
'TLS13-CHACHA20-POLY1305-SHA256',
'TLS13-AES-128-GCM-SHA256',
])
@unittest.skipUnless(ssl.HAS_ECDH, "test requires ECDH-enabled OpenSSL") @unittest.skipUnless(ssl.HAS_ECDH, "test requires ECDH-enabled OpenSSL")
def test_default_ecdh_curve(self): def test_default_ecdh_curve(self):
# Issue #21015: elliptic curve-based Diffie Hellman key exchange # Issue #21015: elliptic curve-based Diffie Hellman key exchange
# should be enabled by default on SSL contexts. # should be enabled by default on SSL contexts.
context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
context.load_cert_chain(CERTFILE) context.load_cert_chain(CERTFILE)
# TLSv1.3 defaults to PFS key agreement and no longer has KEA in
# cipher name.
context.options |= ssl.OP_NO_TLSv1_3
# Prior to OpenSSL 1.0.0, ECDH ciphers have to be enabled # Prior to OpenSSL 1.0.0, ECDH ciphers have to be enabled
# explicitly using the 'ECCdraft' cipher alias. Otherwise, # explicitly using the 'ECCdraft' cipher alias. Otherwise,
# our default cipher list should prefer ECDH-based ciphers # our default cipher list should prefer ECDH-based ciphers
...@@ -3256,8 +3277,9 @@ if _have_threads: ...@@ -3256,8 +3277,9 @@ if _have_threads:
except ssl.SSLError as e: except ssl.SSLError as e:
stats = e stats = e
if expected is None and IS_OPENSSL_1_1: if (expected is None and IS_OPENSSL_1_1
# OpenSSL 1.1.0 raises handshake error and ssl.OPENSSL_VERSION_INFO < (1, 1, 0, 6)):
# OpenSSL 1.1.0 to 1.1.0e raises handshake error
self.assertIsInstance(stats, ssl.SSLError) self.assertIsInstance(stats, ssl.SSLError)
else: else:
msg = "failed trying %s (s) and %s (c).\n" \ msg = "failed trying %s (s) and %s (c).\n" \
...@@ -3475,7 +3497,7 @@ if _have_threads: ...@@ -3475,7 +3497,7 @@ if _have_threads:
client_context.verify_mode = ssl.CERT_REQUIRED client_context.verify_mode = ssl.CERT_REQUIRED
client_context.load_verify_locations(SIGNING_CA) client_context.load_verify_locations(SIGNING_CA)
# first conncetion without session # first connection without session
stats = server_params_test(client_context, server_context) stats = server_params_test(client_context, server_context)
session = stats['session'] session = stats['session']
self.assertTrue(session.id) self.assertTrue(session.id)
...@@ -3535,6 +3557,10 @@ if _have_threads: ...@@ -3535,6 +3557,10 @@ if _have_threads:
context2.load_verify_locations(CERTFILE) context2.load_verify_locations(CERTFILE)
context2.load_cert_chain(CERTFILE) context2.load_cert_chain(CERTFILE)
# TODO: session reuse does not work with TLS 1.3
context.options |= ssl.OP_NO_TLSv1_3
context2.options |= ssl.OP_NO_TLSv1_3
server = ThreadedEchoServer(context=context, chatty=False) server = ThreadedEchoServer(context=context, chatty=False)
with server: with server:
with context.wrap_socket(socket.socket()) as s: with context.wrap_socket(socket.socket()) as s:
......
This diff is collapsed.
...@@ -170,6 +170,9 @@ class ThreadTests(BaseTestCase): ...@@ -170,6 +170,9 @@ class ThreadTests(BaseTestCase):
mutex.acquire() mutex.acquire()
self.assertIn(tid, threading._active) self.assertIn(tid, threading._active)
self.assertIsInstance(threading._active[tid], threading._DummyThread) self.assertIsInstance(threading._active[tid], threading._DummyThread)
#Issue 29376
self.assertTrue(threading._active[tid].is_alive())
self.assertRegex(repr(threading._active[tid]), '_DummyThread')
del threading._active[tid] del threading._active[tid]
# PyThreadState_SetAsyncExc() is a CPython-only gimmick, not (currently) # PyThreadState_SetAsyncExc() is a CPython-only gimmick, not (currently)
...@@ -462,18 +465,20 @@ class ThreadTests(BaseTestCase): ...@@ -462,18 +465,20 @@ class ThreadTests(BaseTestCase):
self.addCleanup(sys.setswitchinterval, old_interval) self.addCleanup(sys.setswitchinterval, old_interval)
# Make the bug more likely to manifest. # Make the bug more likely to manifest.
sys.setswitchinterval(1e-6) test.support.setswitchinterval(1e-6)
for i in range(20): for i in range(20):
t = threading.Thread(target=lambda: None) t = threading.Thread(target=lambda: None)
t.start() t.start()
self.addCleanup(t.join)
pid = os.fork() pid = os.fork()
if pid == 0: if pid == 0:
os._exit(1 if t.is_alive() else 0) os._exit(11 if t.is_alive() else 10)
else: else:
t.join()
pid, status = os.waitpid(pid, 0) pid, status = os.waitpid(pid, 0)
self.assertEqual(0, status) self.assertTrue(os.WIFEXITED(status))
self.assertEqual(10, os.WEXITSTATUS(status))
def test_main_thread(self): def test_main_thread(self):
main = threading.main_thread() main = threading.main_thread()
...@@ -570,6 +575,7 @@ class ThreadTests(BaseTestCase): ...@@ -570,6 +575,7 @@ class ThreadTests(BaseTestCase):
self.assertFalse(t.is_alive()) self.assertFalse(t.is_alive())
# And verify the thread disposed of _tstate_lock. # And verify the thread disposed of _tstate_lock.
self.assertIsNone(t._tstate_lock) self.assertIsNone(t._tstate_lock)
t.join()
def test_repr_stopped(self): def test_repr_stopped(self):
# Verify that "stopped" shows up in repr(Thread) appropriately. # Verify that "stopped" shows up in repr(Thread) appropriately.
...@@ -596,6 +602,7 @@ class ThreadTests(BaseTestCase): ...@@ -596,6 +602,7 @@ class ThreadTests(BaseTestCase):
break break
time.sleep(0.01) time.sleep(0.01)
self.assertIn(LOOKING_FOR, repr(t)) # we waited at least 5 seconds self.assertIn(LOOKING_FOR, repr(t)) # we waited at least 5 seconds
t.join()
def test_BoundedSemaphore_limit(self): def test_BoundedSemaphore_limit(self):
# BoundedSemaphore should raise ValueError if released too often. # BoundedSemaphore should raise ValueError if released too often.
...@@ -910,6 +917,7 @@ class ThreadingExceptionTests(BaseTestCase): ...@@ -910,6 +917,7 @@ class ThreadingExceptionTests(BaseTestCase):
thread = threading.Thread() thread = threading.Thread()
thread.start() thread.start()
self.assertRaises(RuntimeError, thread.start) self.assertRaises(RuntimeError, thread.start)
thread.join()
def test_joining_current_thread(self): def test_joining_current_thread(self):
current_thread = threading.current_thread() current_thread = threading.current_thread()
...@@ -923,6 +931,7 @@ class ThreadingExceptionTests(BaseTestCase): ...@@ -923,6 +931,7 @@ class ThreadingExceptionTests(BaseTestCase):
thread = threading.Thread() thread = threading.Thread()
thread.start() thread.start()
self.assertRaises(RuntimeError, setattr, thread, "daemon", True) self.assertRaises(RuntimeError, setattr, thread, "daemon", True)
thread.join()
def test_releasing_unacquired_lock(self): def test_releasing_unacquired_lock(self):
lock = threading.Lock() lock = threading.Lock()
...@@ -1061,6 +1070,8 @@ class ThreadingExceptionTests(BaseTestCase): ...@@ -1061,6 +1070,8 @@ class ThreadingExceptionTests(BaseTestCase):
thread.join() thread.join()
self.assertIsNotNone(thread.exc) self.assertIsNotNone(thread.exc)
self.assertIsInstance(thread.exc, RuntimeError) self.assertIsInstance(thread.exc, RuntimeError)
# explicitly break the reference cycle to not leak a dangling thread
thread.exc = None
class TimerTests(BaseTestCase): class TimerTests(BaseTestCase):
...@@ -1083,6 +1094,8 @@ class TimerTests(BaseTestCase): ...@@ -1083,6 +1094,8 @@ class TimerTests(BaseTestCase):
self.callback_event.wait() self.callback_event.wait()
self.assertEqual(len(self.callback_args), 2) self.assertEqual(len(self.callback_args), 2)
self.assertEqual(self.callback_args, [((), {}), ((), {})]) self.assertEqual(self.callback_args, [((), {}), ((), {})])
timer1.join()
timer2.join()
def _callback_spy(self, *args, **kwargs): def _callback_spy(self, *args, **kwargs):
self.callback_args.append((args[:], kwargs.copy())) self.callback_args.append((args[:], kwargs.copy()))
...@@ -1091,7 +1104,6 @@ class TimerTests(BaseTestCase): ...@@ -1091,7 +1104,6 @@ class TimerTests(BaseTestCase):
class LockTests(lock_tests.LockTests): class LockTests(lock_tests.LockTests):
locktype = staticmethod(threading.Lock) locktype = staticmethod(threading.Lock)
@unittest.skip("not on gevent") @unittest.skip("not on gevent")
def test_locked_repr(self): def test_locked_repr(self):
pass pass
...@@ -1112,6 +1124,7 @@ class EventTests(lock_tests.EventTests): ...@@ -1112,6 +1124,7 @@ class EventTests(lock_tests.EventTests):
@unittest.skip("not on gevent") @unittest.skip("not on gevent")
def test_reset_internal_locks(self): def test_reset_internal_locks(self):
# XXX: gevent: this appears to have gone away by 3.6.3
pass pass
class ConditionAsRLockTests(lock_tests.RLockTests): class ConditionAsRLockTests(lock_tests.RLockTests):
......
...@@ -484,12 +484,20 @@ if sys.version_info[0] == 3: ...@@ -484,12 +484,20 @@ if sys.version_info[0] == 3:
'test_subprocess.ProcessTestCase.test_io_buffered_by_default', 'test_subprocess.ProcessTestCase.test_io_buffered_by_default',
'test_subprocess.ProcessTestCase.test_io_unbuffered_works', 'test_subprocess.ProcessTestCase.test_io_unbuffered_works',
# 3.3 exposed the `endtime` argument to wait accidentally.
# It is documented as deprecated and not to be used since 3.4
# This test in 3.6.3 wants to use it though, and we don't have it.
'test_subprocess.ProcessTestCase.test_wait_endtime',
# These all want to inspect the string value of an exception raised # These all want to inspect the string value of an exception raised
# by the exec() call in the child. The _posixsubprocess module arranges # by the exec() call in the child. The _posixsubprocess module arranges
# for better exception handling and printing than we do. # for better exception handling and printing than we do.
'test_subprocess.POSIXProcessTestCase.test_exception_bad_args_0', 'test_subprocess.POSIXProcessTestCase.test_exception_bad_args_0',
'test_subprocess.POSIXProcessTestCase.test_exception_bad_executable', 'test_subprocess.POSIXProcessTestCase.test_exception_bad_executable',
'test_subprocess.POSIXProcessTestCase.test_exception_cwd', 'test_subprocess.POSIXProcessTestCase.test_exception_cwd',
# Relies on a 'fork_exec' attribute that we don't provide
'test_subprocess.POSIXProcessTestCase.test_exception_errpipe_bad_data',
'test_subprocess.POSIXProcessTestCase.test_exception_errpipe_normal',
# Python 3 fixed a bug if the stdio file descriptors were closed; # Python 3 fixed a bug if the stdio file descriptors were closed;
# we still have that bug # we still have that bug
...@@ -721,6 +729,18 @@ if sys.version_info[:2] >= (3, 5): ...@@ -721,6 +729,18 @@ if sys.version_info[:2] >= (3, 5):
# 'lock_tests.LockTests.lest_locked_repr', # 'lock_tests.LockTests.lest_locked_repr',
# 'lock_tests.LockTests.lest_repr', # 'lock_tests.LockTests.lest_repr',
# Added between 3.6.0 and 3.6.3, uses _testcapi and internals
# of the subprocess module.
'test_subprocess.POSIXProcessTestCase.test_stopped',
# This test opens a socket, creates a new socket with the same fileno,
# closes the original socket (and hence fileno) and then
# expects that the calling setblocking() on the duplicate socket
# will raise an error. Our implementation doesn't work that way because
# setblocking() doesn't actually touch the file descriptor.
# That's probably OK because this was a GIL state error in CPython
# see https://github.com/python/cpython/commit/fa22b29960b4e683f4e5d7e308f674df2620473c
'test_socket.TestExceptions.test_setblocking_invalidfd',
] ]
if os.environ.get('GEVENT_RESOLVER') == 'ares': if os.environ.get('GEVENT_RESOLVER') == 'ares':
......
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