|
3 | 3 | import os.path
|
4 | 4 | import socket
|
5 | 5 | import sys
|
| 6 | +import subprocess |
6 | 7 | import tempfile
|
7 | 8 | import unittest
|
8 | 9 |
|
@@ -283,3 +284,62 @@ def create_unix_domain_name():
|
283 | 284 | """
|
284 | 285 | return tempfile.mktemp(prefix="test_python_", suffix='.sock',
|
285 | 286 | 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) |
0 commit comments