From ca503852a9b7a4f040f10e18d9938fdc7be471c2 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 6 Sep 2023 02:39:41 +0200 Subject: [PATCH 1/2] gh-91960: Add FreeBSD build and test using Cirrus-CI Cirrus-CI is a hosted CI service that supports FreeBSD, Linux, macOS, and Winodws. Add a .cirrus.yml to provide CI coverage on pull requests for FreeBSD 12.4 and 13.2. Co-Authored-By: Ed Maste --- .cirrus.yml | 13 +++++++++++++ .../2023-09-05-21-42-54.gh-issue-91960.abClTs.rst | 1 + 2 files changed, 14 insertions(+) create mode 100644 .cirrus.yml create mode 100644 Misc/NEWS.d/next/Tests/2023-09-05-21-42-54.gh-issue-91960.abClTs.rst diff --git a/.cirrus.yml b/.cirrus.yml new file mode 100644 index 00000000000000..48bf41bd2b37ec --- /dev/null +++ b/.cirrus.yml @@ -0,0 +1,13 @@ +freebsd_task: + freebsd_instance: + matrix: + - image: freebsd-13-2-release-amd64 + build_script: + - mkdir build + - cd build + - ../configure + - make -j$(sysctl -n hw.ncpu) + test_script: + - cd build + # dtrace fails to build on FreeBSD - see gh-73263 + - make buildbottest TESTOPTS="-j2 -u-network -x test_dtrace" diff --git a/Misc/NEWS.d/next/Tests/2023-09-05-21-42-54.gh-issue-91960.abClTs.rst b/Misc/NEWS.d/next/Tests/2023-09-05-21-42-54.gh-issue-91960.abClTs.rst new file mode 100644 index 00000000000000..f63e0874499193 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-09-05-21-42-54.gh-issue-91960.abClTs.rst @@ -0,0 +1 @@ +FreeBSD 13.2 CI coverage for pull requests is now provided by Cirrus-CI (a hosted CI service that supports Linux, macOS, Windows, and FreeBSD). From 72ee1f37493bf00eb16654b5ee4e9582a0eb8d1b Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 6 Sep 2023 02:35:17 +0200 Subject: [PATCH 2/2] gh-91960: Add test.support.socket_helper.tcp_blackhole() Skip tests in test_asyncio and test_imaplib, test_socket if FreeBSD TCP blackhole is enabled. --- .cirrus.yml | 3 +- Lib/test/support/socket_helper.py | 50 +++++++++++++++++++++ Lib/test/test_asyncio/test_events.py | 1 + Lib/test/test_asyncio/test_sock_lowlevel.py | 5 +++ Lib/test/test_asyncio/test_sslproto.py | 3 ++ Lib/test/test_imaplib.py | 1 + Lib/test/test_socket.py | 2 + 7 files changed, 64 insertions(+), 1 deletion(-) diff --git a/.cirrus.yml b/.cirrus.yml index 48bf41bd2b37ec..bbfd5eb477ba39 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -7,7 +7,8 @@ freebsd_task: - cd build - ../configure - make -j$(sysctl -n hw.ncpu) + - make pythoninfo test_script: - cd build # dtrace fails to build on FreeBSD - see gh-73263 - - make buildbottest TESTOPTS="-j2 -u-network -x test_dtrace" + - make buildbottest TESTOPTS="-j0 -u-network -x test_dtrace" diff --git a/Lib/test/support/socket_helper.py b/Lib/test/support/socket_helper.py index 45f6d65c355dd4..9d23dc5f32031e 100644 --- a/Lib/test/support/socket_helper.py +++ b/Lib/test/support/socket_helper.py @@ -3,6 +3,7 @@ import os.path import socket import sys +import subprocess import tempfile import unittest @@ -277,3 +278,52 @@ def create_unix_domain_name(): """ return tempfile.mktemp(prefix="test_python_", suffix='.sock', dir=os.path.curdir) + + +# consider that sysctl values should not change while tests are running +_sysctl_cache = {} + +def _get_sysctl(name): + """Get a sysctl value as an integer.""" + try: + return _sysctl_cache[name] + except KeyError: + pass + + cmd = ['sysctl', name] + proc = subprocess.run(cmd, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True) + if proc.returncode: + return None + # Parse 'net.inet.tcp.blackhole: 0\n' to get '0' + value = proc.stdout.rstrip().split(': ')[-1] + try: + value = int(value) + except ValueError: + return None + + _sysctl_cache[name] = value + return value + + +def tcp_blackhole(): + if not sys.platform.startswith('freebsd'): + return False + + # gh-91960: test if FreeBSD TCP blackhost is enabled + value = _get_sysctl('net.inet.tcp.blackhole') + if value is None: + # don't skip if we fail to get the sysctl value + return False + return (value != 0) + + +def skip_if_tcp_blackhole(test): + """Decorator for tests requiring a functional bind() for unix sockets.""" + skip_if = unittest.skipIf( + tcp_blackhole(), + "TCP blackhost is enabled (sysctl net.inet.tcp.blackhole)" + ) + return skip_if(test) diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py index b9069056c3a436..aebbd4ff183db2 100644 --- a/Lib/test/test_asyncio/test_events.py +++ b/Lib/test/test_asyncio/test_events.py @@ -1271,6 +1271,7 @@ def connection_made(self, transport): server.close() + @socket_helper.skip_if_tcp_blackhole def test_server_close(self): f = self.loop.create_server(MyProto, '0.0.0.0', 0) server = self.loop.run_until_complete(f) diff --git a/Lib/test/test_asyncio/test_sock_lowlevel.py b/Lib/test/test_asyncio/test_sock_lowlevel.py index b829fd4cc69fff..9346469238cfad 100644 --- a/Lib/test/test_asyncio/test_sock_lowlevel.py +++ b/Lib/test/test_asyncio/test_sock_lowlevel.py @@ -10,6 +10,11 @@ from test import support from test.support import socket_helper +if socket_helper.tcp_blackhole(): + raise unittest.SkipTest('Not relevant to ProactorEventLoop') + + + def tearDownModule(): asyncio.set_event_loop_policy(None) diff --git a/Lib/test/test_asyncio/test_sslproto.py b/Lib/test/test_asyncio/test_sslproto.py index 52a45f1c7c6e96..37d015339761c6 100644 --- a/Lib/test/test_asyncio/test_sslproto.py +++ b/Lib/test/test_asyncio/test_sslproto.py @@ -5,6 +5,7 @@ import unittest import weakref from test import support +from test.support import socket_helper from unittest import mock try: import ssl @@ -350,6 +351,7 @@ async def client(addr): support.gc_collect() self.assertIsNone(client_context()) + @socket_helper.skip_if_tcp_blackhole def test_start_tls_client_buf_proto_1(self): HELLO_MSG = b'1' * self.PAYLOAD_SIZE @@ -502,6 +504,7 @@ async def client(addr): asyncio.wait_for(client(srv.addr), timeout=support.SHORT_TIMEOUT)) + @socket_helper.skip_if_tcp_blackhole def test_start_tls_server_1(self): HELLO_MSG = b'1' * self.PAYLOAD_SIZE ANSWER = b'answer' diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index 89cdca499f92a9..a1eaf2169fe227 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -74,6 +74,7 @@ def test_that_Time2Internaldate_returns_a_result(self): for t in self.timevalues(): imaplib.Time2Internaldate(t) + @socket_helper.skip_if_tcp_blackhole def test_imap4_host_default_value(self): # Check whether the IMAP4_PORT is truly unavailable. with socket.socket() as s: diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 0eaf64257c3b81..f35618e0281e70 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -5288,6 +5288,7 @@ def mocked_socket_module(self): finally: socket.socket = old_socket + @socket_helper.skip_if_tcp_blackhole def test_connect(self): port = socket_helper.find_unused_port() cli = socket.socket(socket.AF_INET, socket.SOCK_STREAM) @@ -5296,6 +5297,7 @@ def test_connect(self): cli.connect((HOST, port)) self.assertEqual(cm.exception.errno, errno.ECONNREFUSED) + @socket_helper.skip_if_tcp_blackhole def test_create_connection(self): # Issue #9792: errors raised by create_connection() should have # a proper errno attribute.