Skip to content

Commit c9dc2bc

Browse files
miss-islingtonvstinner
andauthoredSep 8, 2023
[3.12] gh-109015: Add test.support.socket_helper.tcp_blackhole() (GH-109016) (#109041)
gh-109015: Add test.support.socket_helper.tcp_blackhole() (GH-109016) Skip test_asyncio, test_imaplib and test_socket tests if FreeBSD TCP blackhole is enabled (net.inet.tcp.blackhole=2). (cherry picked from commit a52a350) Co-authored-by: Victor Stinner <vstinner@python.org>
1 parent 579d782 commit c9dc2bc

File tree

7 files changed

+79
-0
lines changed

7 files changed

+79
-0
lines changed
 

Diff for: ‎Lib/test/support/socket_helper.py

+60
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import os.path
44
import socket
55
import sys
6+
import subprocess
67
import tempfile
78
import unittest
89

@@ -283,3 +284,62 @@ def create_unix_domain_name():
283284
"""
284285
return tempfile.mktemp(prefix="test_python_", suffix='.sock',
285286
dir=os.path.curdir)
287+
288+
289+
# consider that sysctl values should not change while tests are running
290+
_sysctl_cache = {}
291+
292+
def _get_sysctl(name):
293+
"""Get a sysctl value as an integer."""
294+
try:
295+
return _sysctl_cache[name]
296+
except KeyError:
297+
pass
298+
299+
# At least Linux and FreeBSD support the "-n" option
300+
cmd = ['sysctl', '-n', name]
301+
proc = subprocess.run(cmd,
302+
stdout=subprocess.PIPE,
303+
stderr=subprocess.STDOUT,
304+
text=True)
305+
if proc.returncode:
306+
support.print_warning(f'{' '.join(cmd)!r} command failed with '
307+
f'exit code {proc.returncode}')
308+
# cache the error to only log the warning once
309+
_sysctl_cache[name] = None
310+
return None
311+
output = proc.stdout
312+
313+
# Parse '0\n' to get '0'
314+
try:
315+
value = int(output.strip())
316+
except Exception as exc:
317+
support.print_warning(f'Failed to parse {' '.join(cmd)!r} '
318+
f'command output {output!r}: {exc!r}')
319+
# cache the error to only log the warning once
320+
_sysctl_cache[name] = None
321+
return None
322+
323+
_sysctl_cache[name] = value
324+
return value
325+
326+
327+
def tcp_blackhole():
328+
if not sys.platform.startswith('freebsd'):
329+
return False
330+
331+
# gh-109015: test if FreeBSD TCP blackhole is enabled
332+
value = _get_sysctl('net.inet.tcp.blackhole')
333+
if value is None:
334+
# don't skip if we fail to get the sysctl value
335+
return False
336+
return (value != 0)
337+
338+
339+
def skip_if_tcp_blackhole(test):
340+
"""Decorator skipping test if TCP blackhole is enabled."""
341+
skip_if = unittest.skipIf(
342+
tcp_blackhole(),
343+
"TCP blackhole is enabled (sysctl net.inet.tcp.blackhole)"
344+
)
345+
return skip_if(test)

Diff for: ‎Lib/test/test_asyncio/test_events.py

+3
Original file line numberDiff line numberDiff line change
@@ -671,6 +671,7 @@ def test_create_connection_local_addr(self):
671671
self.assertEqual(port, expected)
672672
tr.close()
673673

674+
@socket_helper.skip_if_tcp_blackhole
674675
def test_create_connection_local_addr_skip_different_family(self):
675676
# See https://github.com/python/cpython/issues/86508
676677
port1 = socket_helper.find_unused_port()
@@ -692,6 +693,7 @@ async def getaddrinfo(host, port, *args, **kwargs):
692693
with self.assertRaises(OSError):
693694
self.loop.run_until_complete(f)
694695

696+
@socket_helper.skip_if_tcp_blackhole
695697
def test_create_connection_local_addr_nomatch_family(self):
696698
# See https://github.com/python/cpython/issues/86508
697699
port1 = socket_helper.find_unused_port()
@@ -1271,6 +1273,7 @@ def connection_made(self, transport):
12711273

12721274
server.close()
12731275

1276+
@socket_helper.skip_if_tcp_blackhole
12741277
def test_server_close(self):
12751278
f = self.loop.create_server(MyProto, '0.0.0.0', 0)
12761279
server = self.loop.run_until_complete(f)

Diff for: ‎Lib/test/test_asyncio/test_sock_lowlevel.py

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
from test import support
1111
from test.support import socket_helper
1212

13+
if socket_helper.tcp_blackhole():
14+
raise unittest.SkipTest('Not relevant to ProactorEventLoop')
15+
16+
1317
def tearDownModule():
1418
asyncio.set_event_loop_policy(None)
1519

Diff for: ‎Lib/test/test_asyncio/test_sslproto.py

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import unittest
66
import weakref
77
from test import support
8+
from test.support import socket_helper
89
from unittest import mock
910
try:
1011
import ssl
@@ -350,6 +351,7 @@ async def client(addr):
350351
support.gc_collect()
351352
self.assertIsNone(client_context())
352353

354+
@socket_helper.skip_if_tcp_blackhole
353355
def test_start_tls_client_buf_proto_1(self):
354356
HELLO_MSG = b'1' * self.PAYLOAD_SIZE
355357

@@ -502,6 +504,7 @@ async def client(addr):
502504
asyncio.wait_for(client(srv.addr),
503505
timeout=support.SHORT_TIMEOUT))
504506

507+
@socket_helper.skip_if_tcp_blackhole
505508
def test_start_tls_server_1(self):
506509
HELLO_MSG = b'1' * self.PAYLOAD_SIZE
507510
ANSWER = b'answer'

Diff for: ‎Lib/test/test_imaplib.py

+1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ def test_that_Time2Internaldate_returns_a_result(self):
7474
for t in self.timevalues():
7575
imaplib.Time2Internaldate(t)
7676

77+
@socket_helper.skip_if_tcp_blackhole
7778
def test_imap4_host_default_value(self):
7879
# Check whether the IMAP4_PORT is truly unavailable.
7980
with socket.socket() as s:

Diff for: ‎Lib/test/test_socket.py

+2
Original file line numberDiff line numberDiff line change
@@ -5288,6 +5288,7 @@ def mocked_socket_module(self):
52885288
finally:
52895289
socket.socket = old_socket
52905290

5291+
@socket_helper.skip_if_tcp_blackhole
52915292
def test_connect(self):
52925293
port = socket_helper.find_unused_port()
52935294
cli = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@@ -5296,6 +5297,7 @@ def test_connect(self):
52965297
cli.connect((HOST, port))
52975298
self.assertEqual(cm.exception.errno, errno.ECONNREFUSED)
52985299

5300+
@socket_helper.skip_if_tcp_blackhole
52995301
def test_create_connection(self):
53005302
# Issue #9792: errors raised by create_connection() should have
53015303
# a proper errno attribute.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Fix test_asyncio, test_imaplib and test_socket tests on FreeBSD if the TCP
2+
blackhole is enabled (``sysctl net.inet.tcp.blackhole``). Skip the few tests
3+
which failed with ``ETIMEDOUT`` which such non standard configuration.
4+
Currently, the `FreeBSD GCP image enables TCP and UDP blackhole
5+
<https://reviews.freebsd.org/D41751>`_ (``sysctl net.inet.tcp.blackhole=2``
6+
and ``sysctl net.inet.udp.blackhole=1``). Patch by Victor Stinner.

0 commit comments

Comments
 (0)
Please sign in to comment.