Skip to content

Commit

Permalink
pythongh-109015: Add test.support.socket_helper.tcp_blackhole() (pyth…
Browse files Browse the repository at this point in the history
…on#109016)

Skip test_asyncio, test_imaplib and test_socket tests if FreeBSD TCP
blackhole is enabled (net.inet.tcp.blackhole=2).
  • Loading branch information
vstinner committed Sep 6, 2023
1 parent 60a9eea commit a52a350
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 0 deletions.
60 changes: 60 additions & 0 deletions Lib/test/support/socket_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import os.path
import socket
import sys
import subprocess
import tempfile
import unittest

Expand Down Expand Up @@ -277,3 +278,62 @@ 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

# At least Linux and FreeBSD support the "-n" option
cmd = ['sysctl', '-n', name]
proc = subprocess.run(cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True)
if proc.returncode:
support.print_warning(f'{' '.join(cmd)!r} command failed with '
f'exit code {proc.returncode}')
# cache the error to only log the warning once
_sysctl_cache[name] = None
return None
output = proc.stdout

# Parse '0\n' to get '0'
try:
value = int(output.strip())
except Exception as exc:
support.print_warning(f'Failed to parse {' '.join(cmd)!r} '
f'command output {output!r}: {exc!r}')
# cache the error to only log the warning once
_sysctl_cache[name] = None
return None

_sysctl_cache[name] = value
return value


def tcp_blackhole():
if not sys.platform.startswith('freebsd'):
return False

# gh-109015: test if FreeBSD TCP blackhole 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 skipping test if TCP blackhole is enabled."""
skip_if = unittest.skipIf(
tcp_blackhole(),
"TCP blackhole is enabled (sysctl net.inet.tcp.blackhole)"
)
return skip_if(test)
3 changes: 3 additions & 0 deletions Lib/test/test_asyncio/test_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,7 @@ def test_create_connection_local_addr(self):
self.assertEqual(port, expected)
tr.close()

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

@socket_helper.skip_if_tcp_blackhole
def test_create_connection_local_addr_nomatch_family(self):
# See https://github.com/python/cpython/issues/86508
port1 = socket_helper.find_unused_port()
Expand Down Expand Up @@ -1271,6 +1273,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)
Expand Down
4 changes: 4 additions & 0 deletions Lib/test/test_asyncio/test_sock_lowlevel.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
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)

Expand Down
3 changes: 3 additions & 0 deletions Lib/test/test_asyncio/test_sslproto.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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'
Expand Down
1 change: 1 addition & 0 deletions Lib/test/test_imaplib.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 2 additions & 0 deletions Lib/test/test_socket.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Fix test_asyncio, test_imaplib and test_socket tests on FreeBSD if the TCP
blackhole is enabled (``sysctl net.inet.tcp.blackhole``). Skip the few tests
which failed with ``ETIMEDOUT`` which such non standard configuration.
Currently, the `FreeBSD GCP image enables TCP and UDP blackhole
<https://reviews.freebsd.org/D41751>`_ (``sysctl net.inet.tcp.blackhole=2``
and ``sysctl net.inet.udp.blackhole=1``). Patch by Victor Stinner.

0 comments on commit a52a350

Please sign in to comment.