Skip to content

Commit

Permalink
Update te 3.12.2 tests and test 3.12.2 on GHA.
Browse files Browse the repository at this point in the history
  • Loading branch information
jamadden committed Feb 13, 2024
1 parent a4911f9 commit 50dd5a1
Show file tree
Hide file tree
Showing 15 changed files with 264 additions and 60 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Expand Up @@ -89,7 +89,7 @@ jobs:
# for example to force a specific patch release, don't forget to change conditions!
# XXX: We could probably make this easier on ourself by adding a specific
# key to the matrix in the version we care about and checking for that matrix key.
python-version: ["3.12.1", "pypy-3.10-v7.3.12", 3.8, 3.9, '3.10', '3.11.8']
python-version: ["3.12.2", "pypy-3.10-v7.3.15", 3.8, 3.9, '3.10', '3.11.8']
os: [macos-latest, ubuntu-latest]
exclude:
# The bulk of the testing is on Linux and Windows (appveyor).
Expand All @@ -103,7 +103,7 @@ jobs:
# - os: macos-latest
# python-version: 3.10
- os: macos-latest
python-version: "pypy-3.10-v7.3.12"
python-version: "pypy-3.10-v7.3.15"

steps:
- name: checkout
Expand Down Expand Up @@ -267,7 +267,7 @@ jobs:
# it's sufficient to run the full suite on the current version
# and oldest version.
- name: "Tests: subproccess and FileObjectThread"
if: startsWith(runner.os, 'Linux') || (startsWith(runner.os, 'Mac') && matrix.python-version == '3.12.1')
if: startsWith(runner.os, 'Linux') || (startsWith(runner.os, 'Mac') && matrix.python-version == '3.12.2')
# Now, the non-default threaded file object.
# In the past, we included all test files that had a reference to 'subprocess'' somewhere in their
# text. The monkey-patched stdlib tests were specifically included here.
Expand Down
8 changes: 7 additions & 1 deletion docs/changes/2020.bugfix
Expand Up @@ -7,4 +7,10 @@ Other updates for compatibility with the standard library include:
- ``SSLSocket.recv_into`` and ``SSLSocket.read`` no longer require the
buffer to implement ``len`` and now work with buffers whose size is
not 1.
- gh-108310: Fix CVE-2023-40217: Check for & avoid the ssl pre-close flaw.
- gh-108310: Fix CVE-2023-40217: Check for & avoid the ssl pre-close
flaw.

Other changes:

- Drop ``setuptools`` to a soft test dependency.
- Drop support for very old versions of CFFI.
3 changes: 0 additions & 3 deletions setup.py
Expand Up @@ -418,9 +418,6 @@ def run_setup(ext_modules):

# leak checks. previously we had a hand-rolled version.
'objgraph',

# We still have some places we like to test with pkg_resources
'setuptools',
],
},
# It's always safe to pass the CFFI keyword, even if
Expand Down
18 changes: 18 additions & 0 deletions src/gevent/testing/testcase.py
Expand Up @@ -296,6 +296,24 @@ def setUp(self):
self.close_on_teardown = []
self.addCleanup(self._tearDownCloseOnTearDown)

def _callTestMethod(self, method):
# 3.12 started raising a stupid warning about returning
# non-None from ``test_...()`` being deprecated. Since the
# test framework never cares about the return value anyway,
# this is an utterly pointless annoyance. Override the method
# that raises that deprecation. (Are the maintainers planning
# to make the return value _mean_ something someday? That's
# the only valid reason for them to do this. Answer: No, no
# they're not. They're just trying to protect people from
# writing broken tests that accidentally turn into generators
# or something. Which...if people don't notice their tests
# aren't working...well. Now, perhaps this got worse in the
# era of asyncio where *everything* is a generator. But that's
# not our problem; we have better ways of dealing with the
# shortcomings of asyncio, namely, don't use it.
# https://bugs.python.org/issue41322)
method()

def tearDown(self):
if getattr(self, 'skipTearDown', False):
del self.close_on_teardown[:]
Expand Down
3 changes: 1 addition & 2 deletions src/gevent/testing/testrunner.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
from __future__ import print_function, absolute_import, division
# -*- coding: utf-8 -*-

import re
import sys
Expand Down
6 changes: 5 additions & 1 deletion src/gevent/tests/test__monkey_ssl_warning.py
Expand Up @@ -12,7 +12,11 @@ def test_with_pkg_resources(self):
# as is done for namespace packages, imports ssl,
# leading to an unwanted SSL warning.
# This is a deprecated API though.
__import__('pkg_resources')
with warnings.catch_warnings():
try:
__import__('pkg_resources')
except ImportError:
self.skipTest('Uses pkg_resources (setuptools) which is not installed')

from gevent import monkey

Expand Down
13 changes: 0 additions & 13 deletions src/gevent/tests/test__signal.py
Expand Up @@ -2,14 +2,6 @@
import signal
import gevent.testing as greentest
import gevent
import pkg_resources

try:
cffi_version = pkg_resources.get_distribution('cffi').parsed_version
except Exception: # pylint:disable=broad-except
# No cffi installed. Shouldn't happen to gevent standard tests,
# but maybe some downstream distributor removed it.
cffi_version = None

class Expected(Exception):
pass
Expand Down Expand Up @@ -52,11 +44,6 @@ def test():
finally:
sig.cancel()


@greentest.skipIf((greentest.PY3
and greentest.CFFI_BACKEND
and cffi_version < pkg_resources.parse_version('1.11.3')),
"https://bitbucket.org/cffi/cffi/issues/352/systemerror-returned-a-result-with-an")
@greentest.ignores_leakcheck
def test_reload(self):
# The site module tries to set attributes
Expand Down
16 changes: 14 additions & 2 deletions src/greentest/3.12/test_httplib.py
Expand Up @@ -1546,18 +1546,22 @@ def test_readline(self):
resp = self.resp
self._verify_readline(self.resp.readline, self.lines_expected)

def _verify_readline(self, readline, expected):
def test_readline_without_limit(self):
self._verify_readline(self.resp.readline, self.lines_expected, limit=-1)

def _verify_readline(self, readline, expected, limit=5):
all = []
while True:
# short readlines
line = readline(5)
line = readline(limit)
if line and line != b"foo":
if len(line) < 5:
self.assertTrue(line.endswith(b"\n"))
all.append(line)
if not line:
break
self.assertEqual(b"".join(all), expected)
self.assertTrue(self.resp.isclosed())

def test_read1(self):
resp = self.resp
Expand All @@ -1577,6 +1581,7 @@ def test_read1_unbounded(self):
break
all.append(data)
self.assertEqual(b"".join(all), self.lines_expected)
self.assertTrue(resp.isclosed())

def test_read1_bounded(self):
resp = self.resp
Expand All @@ -1588,15 +1593,22 @@ def test_read1_bounded(self):
self.assertLessEqual(len(data), 10)
all.append(data)
self.assertEqual(b"".join(all), self.lines_expected)
self.assertTrue(resp.isclosed())

def test_read1_0(self):
self.assertEqual(self.resp.read1(0), b"")
self.assertFalse(self.resp.isclosed())

def test_peek_0(self):
p = self.resp.peek(0)
self.assertLessEqual(0, len(p))


class ExtendedReadTestContentLengthKnown(ExtendedReadTest):
_header, _body = ExtendedReadTest.lines.split('\r\n\r\n', 1)
lines = _header + f'\r\nContent-Length: {len(_body)}\r\n\r\n' + _body


class ExtendedReadTestChunked(ExtendedReadTest):
"""
Test peek(), read1(), readline() in chunked mode
Expand Down
5 changes: 2 additions & 3 deletions src/greentest/3.12/test_interpreters.py
Expand Up @@ -1054,7 +1054,6 @@ def test_recv_nowait_default(self):
self.assertEqual(obj5, b'eggs')
self.assertIs(obj6, default)

# gevent: This was missing, making it unlike
# ALL OTHER TESTS.
if __name__ == '__main__':

if __name__ == "__main__":
unittest.main()
27 changes: 27 additions & 0 deletions src/greentest/3.12/test_signal.py
@@ -1,5 +1,6 @@
import enum
import errno
import functools
import inspect
import os
import random
Expand Down Expand Up @@ -76,6 +77,9 @@ class PosixTests(unittest.TestCase):
def trivial_signal_handler(self, *args):
pass

def create_handler_with_partial(self, argument):
return functools.partial(self.trivial_signal_handler, argument)

def test_out_of_range_signal_number_raises_error(self):
self.assertRaises(ValueError, signal.getsignal, 4242)

Expand All @@ -96,6 +100,28 @@ def test_getsignal(self):
signal.signal(signal.SIGHUP, hup)
self.assertEqual(signal.getsignal(signal.SIGHUP), hup)

def test_no_repr_is_called_on_signal_handler(self):
# See https://github.com/python/cpython/issues/112559.

class MyArgument:
def __init__(self):
self.repr_count = 0

def __repr__(self):
self.repr_count += 1
return super().__repr__()

argument = MyArgument()
self.assertEqual(0, argument.repr_count)

handler = self.create_handler_with_partial(argument)
hup = signal.signal(signal.SIGHUP, handler)
self.assertIsInstance(hup, signal.Handlers)
self.assertEqual(signal.getsignal(signal.SIGHUP), handler)
signal.signal(signal.SIGHUP, hup)
self.assertEqual(signal.getsignal(signal.SIGHUP), hup)
self.assertEqual(0, argument.repr_count)

def test_strsignal(self):
self.assertIn("Interrupt", signal.strsignal(signal.SIGINT))
self.assertIn("Terminated", signal.strsignal(signal.SIGTERM))
Expand Down Expand Up @@ -1318,6 +1344,7 @@ def handler(signum, frame):
# Python handler
self.assertEqual(len(sigs), N, "Some signals were lost")

@unittest.skipIf(sys.platform == "darwin", "crashes due to system bug (FB13453490)")
@unittest.skipUnless(hasattr(signal, "SIGUSR1"),
"test needs SIGUSR1")
@threading_helper.requires_working_threading()
Expand Down
13 changes: 13 additions & 0 deletions src/greentest/3.12/test_socket.py
Expand Up @@ -1082,7 +1082,20 @@ def testInterfaceNameIndex(self):
'socket.if_indextoname() not available.')
def testInvalidInterfaceIndexToName(self):
self.assertRaises(OSError, socket.if_indextoname, 0)
self.assertRaises(OverflowError, socket.if_indextoname, -1)
self.assertRaises(OverflowError, socket.if_indextoname, 2**1000)
self.assertRaises(TypeError, socket.if_indextoname, '_DEADBEEF')
if hasattr(socket, 'if_nameindex'):
indices = dict(socket.if_nameindex())
for index in indices:
index2 = index + 2**32
if index2 not in indices:
with self.assertRaises((OverflowError, OSError)):
socket.if_indextoname(index2)
for index in 2**32-1, 2**64-1:
if index not in indices:
with self.assertRaises((OverflowError, OSError)):
socket.if_indextoname(index)

@unittest.skipUnless(hasattr(socket, 'if_nametoindex'),
'socket.if_nametoindex() not available.')
Expand Down
34 changes: 24 additions & 10 deletions src/greentest/3.12/test_ssl.py
Expand Up @@ -2206,14 +2206,15 @@ def _test_get_server_certificate(test, host, port, cert=None):
sys.stdout.write("\nVerified certificate for %s:%s is\n%s\n" % (host, port ,pem))

def _test_get_server_certificate_fail(test, host, port):
try:
pem = ssl.get_server_certificate((host, port), ca_certs=CERTFILE)
except ssl.SSLError as x:
#should fail
if support.verbose:
sys.stdout.write("%s\n" % x)
else:
test.fail("Got server certificate %s for %s:%s!" % (pem, host, port))
with warnings_helper.check_no_resource_warning(test):
try:
pem = ssl.get_server_certificate((host, port), ca_certs=CERTFILE)
except ssl.SSLError as x:
#should fail
if support.verbose:
sys.stdout.write("%s\n" % x)
else:
test.fail("Got server certificate %s for %s:%s!" % (pem, host, port))


from test.ssl_servers import make_https_server
Expand Down Expand Up @@ -3026,6 +3027,16 @@ def test_check_hostname_idn(self):
server_hostname="python.example.org") as s:
with self.assertRaises(ssl.CertificateError):
s.connect((HOST, server.port))
with ThreadedEchoServer(context=server_context, chatty=True) as server:
with warnings_helper.check_no_resource_warning(self):
with self.assertRaises(UnicodeError):
context.wrap_socket(socket.socket(),
server_hostname='.pythontest.net')
with ThreadedEchoServer(context=server_context, chatty=True) as server:
with warnings_helper.check_no_resource_warning(self):
with self.assertRaises(UnicodeDecodeError):
context.wrap_socket(socket.socket(),
server_hostname=b'k\xf6nig.idn.pythontest.net')

def test_wrong_cert_tls12(self):
"""Connecting when the server rejects the client's certificate
Expand Down Expand Up @@ -4761,6 +4772,7 @@ def run(self):
def non_linux_skip_if_other_okay_error(self, err):
if sys.platform == "linux":
return # Expect the full test setup to always work on Linux.

if (isinstance(err, ConnectionResetError) or
(isinstance(err, OSError) and err.errno == errno.EINVAL) or
re.search('wrong.version.number', getattr(err, "reason", ""), re.I)):
Expand Down Expand Up @@ -4882,7 +4894,8 @@ def call_after_accept(conn_to_client):
self.assertIsNone(wrap_error.library, msg="attr must exist")
finally:
# gh-108342: Explicitly break the reference cycle
wrap_error = None
with warnings_helper.check_no_resource_warning(self):
wrap_error = None
server = None

def test_https_client_non_tls_response_ignored(self):
Expand Down Expand Up @@ -4931,7 +4944,8 @@ def call_after_accept(conn_to_client):
# socket; that fails if the connection is broken. It may seem pointless
# to test this. It serves as an illustration of something that we never
# want to happen... properly not happening.
with self.assertRaises(OSError):
with warnings_helper.check_no_resource_warning(self), \
self.assertRaises(OSError):
connection.request("HEAD", "/test", headers={"Host": "localhost"})
response = connection.getresponse()

Expand Down

0 comments on commit 50dd5a1

Please sign in to comment.