Skip to content

Commit 24c6258

Browse files
authored
bpo-38614: Add timeout constants to test.support (GH-16964)
Add timeout constants to test.support: * LOOPBACK_TIMEOUT * INTERNET_TIMEOUT * SHORT_TIMEOUT * LONG_TIMEOUT
1 parent 865c3b2 commit 24c6258

File tree

6 files changed

+145
-26
lines changed

6 files changed

+145
-26
lines changed

Doc/library/test.rst

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,67 @@ The :mod:`test.support` module defines the following constants:
287287
Set to a filename containing the :data:`FS_NONASCII` character.
288288

289289

290+
.. data:: LOOPBACK_TIMEOUT
291+
292+
Timeout in seconds for tests using a network server listening on the network
293+
local loopback interface like ``127.0.0.1``.
294+
295+
The timeout is long enough to prevent test failure: it takes into account
296+
that the client and the server can run in different threads or even
297+
different processes.
298+
299+
The timeout should be long enough for :meth:`~socket.socket.connect`,
300+
:meth:`~socket.socket.recv` and :meth:`~socket.socket.send` methods of
301+
:class:`socket.socket`.
302+
303+
Its default value is 5 seconds.
304+
305+
See also :data:`INTERNET_TIMEOUT`.
306+
307+
308+
.. data:: INTERNET_TIMEOUT
309+
310+
Timeout in seconds for network requests going to the Internet.
311+
312+
The timeout is short enough to prevent a test to wait for too long if the
313+
Internet request is blocked for whatever reason.
314+
315+
Usually, a timeout using :data:`INTERNET_TIMEOUT` should not mark a test as
316+
failed, but skip the test instead: see
317+
:func:`~test.support.transient_internet`.
318+
319+
Its default value is 1 minute.
320+
321+
See also :data:`LOOPBACK_TIMEOUT`.
322+
323+
324+
.. data:: SHORT_TIMEOUT
325+
326+
Timeout in seconds to mark a test as failed if the test takes "too long".
327+
328+
The timeout value depends on the regrtest ``--timeout`` command line option.
329+
330+
If a test using :data:`SHORT_TIMEOUT` starts to fail randomly on slow
331+
buildbots, use :data:`LONG_TIMEOUT` instead.
332+
333+
Its default value is 30 seconds.
334+
335+
336+
.. data:: LONG_TIMEOUT
337+
338+
Timeout in seconds to detect when a test hangs.
339+
340+
It is long enough to reduce the risk of test failure on the slowest Python
341+
buildbots. It should not be used to mark a test as failed if the test takes
342+
"too long". The timeout value depends on the regrtest ``--timeout`` command
343+
line option.
344+
345+
Its default value is 5 minutes.
346+
347+
See also :data:`LOOPBACK_TIMEOUT`, :data:`INTERNET_TIMEOUT` and
348+
:data:`SHORT_TIMEOUT`.
349+
350+
290351
.. data:: IPV6_ENABLED
291352

292353
Set to ``True`` if IPV6 is enabled on this host, ``False`` otherwise.

Lib/test/_test_multiprocessing.py

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,6 @@
6666
except ImportError:
6767
msvcrt = None
6868

69-
#
70-
#
71-
#
72-
73-
# Timeout to wait until a process completes
74-
TIMEOUT = 60.0 # seconds
7569

7670
def latin(s):
7771
return s.encode('latin')
@@ -86,7 +80,7 @@ def close_queue(queue):
8680
def join_process(process):
8781
# Since multiprocessing.Process has the same API than threading.Thread
8882
# (join() and is_alive(), the support function can be reused
89-
support.join_thread(process, timeout=TIMEOUT)
83+
support.join_thread(process)
9084

9185

9286
if os.name == "posix":
@@ -1128,7 +1122,7 @@ def __reduce__(self):
11281122
q = self.Queue()
11291123
q.put(NotSerializable())
11301124
q.put(True)
1131-
self.assertTrue(q.get(timeout=TIMEOUT))
1125+
self.assertTrue(q.get(timeout=support.LONG_TIMEOUT))
11321126
close_queue(q)
11331127

11341128
with test.support.captured_stderr():
@@ -1531,7 +1525,7 @@ def test_waitfor_timeout(self):
15311525
args=(cond, state, success, sem))
15321526
p.daemon = True
15331527
p.start()
1534-
self.assertTrue(sem.acquire(timeout=TIMEOUT))
1528+
self.assertTrue(sem.acquire(timeout=support.LONG_TIMEOUT))
15351529

15361530
# Only increment 3 times, so state == 4 is never reached.
15371531
for i in range(3):
@@ -3388,7 +3382,7 @@ class _TestPicklingConnections(BaseTestCase):
33883382
@classmethod
33893383
def tearDownClass(cls):
33903384
from multiprocessing import resource_sharer
3391-
resource_sharer.stop(timeout=TIMEOUT)
3385+
resource_sharer.stop(timeout=support.LONG_TIMEOUT)
33923386

33933387
@classmethod
33943388
def _listener(cls, conn, families):
@@ -4033,7 +4027,7 @@ def test_shared_memory_cleaned_after_process_termination(self):
40334027
p.terminate()
40344028
p.wait()
40354029

4036-
deadline = time.monotonic() + 60
4030+
deadline = time.monotonic() + support.LONG_TIMEOUT
40374031
t = 0.1
40384032
while time.monotonic() < deadline:
40394033
time.sleep(t)
@@ -5040,7 +5034,7 @@ def create_and_register_resource(rtype):
50405034
p.terminate()
50415035
p.wait()
50425036

5043-
deadline = time.monotonic() + 60
5037+
deadline = time.monotonic() + support.LONG_TIMEOUT
50445038
while time.monotonic() < deadline:
50455039
time.sleep(.5)
50465040
try:

Lib/test/libregrtest/setup.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,17 @@ def _test_audit_hook(name, args):
8181

8282
setup_unraisable_hook()
8383

84+
if ns.timeout is not None:
85+
# For a slow buildbot worker, increase SHORT_TIMEOUT and LONG_TIMEOUT
86+
support.SHORT_TIMEOUT = max(support.SHORT_TIMEOUT, ns.timeout / 40)
87+
support.LONG_TIMEOUT = max(support.LONG_TIMEOUT, ns.timeout / 4)
88+
89+
# If --timeout is short: reduce timeouts
90+
support.LOOPBACK_TIMEOUT = min(support.LOOPBACK_TIMEOUT, ns.timeout)
91+
support.INTERNET_TIMEOUT = min(support.INTERNET_TIMEOUT, ns.timeout)
92+
support.SHORT_TIMEOUT = min(support.SHORT_TIMEOUT, ns.timeout)
93+
support.LONG_TIMEOUT = min(support.LONG_TIMEOUT, ns.timeout)
94+
8495

8596
def suppress_msvcrt_asserts(verbose):
8697
try:

Lib/test/support/__init__.py

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,53 @@
119119
"run_with_locale", "swap_item",
120120
"swap_attr", "Matcher", "set_memlimit", "SuppressCrashReport", "sortdict",
121121
"run_with_tz", "PGO", "missing_compiler_executable", "fd_count",
122-
"ALWAYS_EQ", "NEVER_EQ", "LARGEST", "SMALLEST"
122+
"ALWAYS_EQ", "NEVER_EQ", "LARGEST", "SMALLEST",
123+
"LOOPBACK_TIMEOUT", "INTERNET_TIMEOUT", "SHORT_TIMEOUT", "LONG_TIMEOUT",
123124
]
124125

126+
127+
# Timeout in seconds for tests using a network server listening on the network
128+
# local loopback interface like 127.0.0.1.
129+
#
130+
# The timeout is long enough to prevent test failure: it takes into account
131+
# that the client and the server can run in different threads or even different
132+
# processes.
133+
#
134+
# The timeout should be long enough for connect(), recv() and send() methods
135+
# of socket.socket.
136+
LOOPBACK_TIMEOUT = 5.0
137+
if sys.platform == 'win32' and platform.machine() == 'ARM':
138+
# bpo-37553: test_socket.SendfileUsingSendTest is taking longer than 2
139+
# seconds on Windows ARM32 buildbot
140+
LOOPBACK_TIMEOUT = 10
141+
142+
# Timeout in seconds for network requests going to the Internet. The timeout is
143+
# short enough to prevent a test to wait for too long if the Internet request
144+
# is blocked for whatever reason.
145+
#
146+
# Usually, a timeout using INTERNET_TIMEOUT should not mark a test as failed,
147+
# but skip the test instead: see transient_internet().
148+
INTERNET_TIMEOUT = 60.0
149+
150+
# Timeout in seconds to mark a test as failed if the test takes "too long".
151+
#
152+
# The timeout value depends on the regrtest --timeout command line option.
153+
#
154+
# If a test using SHORT_TIMEOUT starts to fail randomly on slow buildbots, use
155+
# LONG_TIMEOUT instead.
156+
SHORT_TIMEOUT = 30.0
157+
158+
# Timeout in seconds to detect when a test hangs.
159+
#
160+
# It is long enough to reduce the risk of test failure on the slowest Python
161+
# buildbots. It should not be used to mark a test as failed if the test takes
162+
# "too long". The timeout value depends on the regrtest --timeout command line
163+
# option.
164+
LONG_TIMEOUT = 5 * 60.0
165+
166+
_NOT_SET = object()
167+
168+
125169
class Error(Exception):
126170
"""Base class for regression test exceptions."""
127171

@@ -1231,7 +1275,7 @@ def check_valid_file(fn):
12311275
opener = urllib.request.build_opener()
12321276
if gzip:
12331277
opener.addheaders.append(('Accept-Encoding', 'gzip'))
1234-
f = opener.open(url, timeout=15)
1278+
f = opener.open(url, timeout=INTERNET_TIMEOUT)
12351279
if gzip and f.headers.get('Content-Encoding') == 'gzip':
12361280
f = gzip.GzipFile(fileobj=f)
12371281
try:
@@ -1542,9 +1586,12 @@ def get_socket_conn_refused_errs():
15421586

15431587

15441588
@contextlib.contextmanager
1545-
def transient_internet(resource_name, *, timeout=30.0, errnos=()):
1589+
def transient_internet(resource_name, *, timeout=_NOT_SET, errnos=()):
15461590
"""Return a context manager that raises ResourceDenied when various issues
15471591
with the Internet connection manifest themselves as exceptions."""
1592+
if timeout is _NOT_SET:
1593+
timeout = INTERNET_TIMEOUT
1594+
15481595
default_errnos = [
15491596
('ECONNREFUSED', 111),
15501597
('ECONNRESET', 104),
@@ -2264,7 +2311,7 @@ def decorator(*args):
22642311

22652312

22662313
@contextlib.contextmanager
2267-
def wait_threads_exit(timeout=60.0):
2314+
def wait_threads_exit(timeout=None):
22682315
"""
22692316
bpo-31234: Context manager to wait until all threads created in the with
22702317
statement exit.
@@ -2278,6 +2325,8 @@ def wait_threads_exit(timeout=60.0):
22782325
which doesn't allow to wait for thread exit, whereas thread.Thread has a
22792326
join() method.
22802327
"""
2328+
if timeout is None:
2329+
timeout = SHORT_TIMEOUT
22812330
old_count = _thread._count()
22822331
try:
22832332
yield
@@ -2298,10 +2347,12 @@ def wait_threads_exit(timeout=60.0):
22982347
gc_collect()
22992348

23002349

2301-
def join_thread(thread, timeout=30.0):
2350+
def join_thread(thread, timeout=None):
23022351
"""Join a thread. Raise an AssertionError if the thread is still alive
23032352
after timeout seconds.
23042353
"""
2354+
if timeout is None:
2355+
timeout = SHORT_TIMEOUT
23052356
thread.join(timeout)
23062357
if thread.is_alive():
23072358
msg = f"failed to join the thread in {timeout:.1f} seconds"

Lib/test/test_socket.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
HOST = support.HOST
3838
# test unicode string and carriage return
3939
MSG = 'Michael Gilfix was here\u1234\r\n'.encode('utf-8')
40-
MAIN_TIMEOUT = 60.0
4140

4241
VSOCKPORT = 1234
4342
AIX = platform.system() == "AIX"
@@ -2527,7 +2526,7 @@ class SendrecvmsgBase(ThreadSafeCleanupTestCase):
25272526

25282527
# Time in seconds to wait before considering a test failed, or
25292528
# None for no timeout. Not all tests actually set a timeout.
2530-
fail_timeout = 3.0
2529+
fail_timeout = support.LOOPBACK_TIMEOUT
25312530

25322531
def setUp(self):
25332532
self.misc_event = threading.Event()
@@ -4320,7 +4319,7 @@ def setUp(self):
43204319
self.addCleanup(signal.signal, signal.SIGALRM, orig_alrm_handler)
43214320

43224321
# Timeout for socket operations
4323-
timeout = 4.0
4322+
timeout = support.LOOPBACK_TIMEOUT
43244323

43254324
# Provide setAlarm() method to schedule delivery of SIGALRM after
43264325
# given number of seconds, or cancel it if zero, and an
@@ -4610,7 +4609,7 @@ def testAccept(self):
46104609

46114610
self.event.set()
46124611

4613-
read, write, err = select.select([self.serv], [], [], MAIN_TIMEOUT)
4612+
read, write, err = select.select([self.serv], [], [], support.LONG_TIMEOUT)
46144613
if self.serv not in read:
46154614
self.fail("Error trying to do accept after select.")
46164615

@@ -4638,7 +4637,7 @@ def testRecv(self):
46384637

46394638
self.event.set()
46404639

4641-
read, write, err = select.select([conn], [], [], MAIN_TIMEOUT)
4640+
read, write, err = select.select([conn], [], [], support.LONG_TIMEOUT)
46424641
if conn not in read:
46434642
self.fail("Error during select call to non-blocking socket.")
46444643

@@ -5838,8 +5837,7 @@ class SendfileUsingSendTest(ThreadedTCPSocketTest):
58385837
FILESIZE = (10 * 1024 * 1024) # 10 MiB
58395838
BUFSIZE = 8192
58405839
FILEDATA = b""
5841-
# bpo-37553: This is taking longer than 2 seconds on Windows ARM32 buildbot
5842-
TIMEOUT = 10 if sys.platform == 'win32' and platform.machine() == 'ARM' else 2
5840+
TIMEOUT = support.LOOPBACK_TIMEOUT
58435841

58445842
@classmethod
58455843
def setUpClass(cls):
@@ -5865,7 +5863,7 @@ def tearDownClass(cls):
58655863
support.unlink(support.TESTFN)
58665864

58675865
def accept_conn(self):
5868-
self.serv.settimeout(MAIN_TIMEOUT)
5866+
self.serv.settimeout(support.LONG_TIMEOUT)
58695867
conn, addr = self.serv.accept()
58705868
conn.settimeout(self.TIMEOUT)
58715869
self.addCleanup(conn.close)
@@ -6369,7 +6367,7 @@ def test_dualstack_ipv6_family(self):
63696367

63706368

63716369
class CreateServerFunctionalTest(unittest.TestCase):
6372-
timeout = 3
6370+
timeout = support.LOOPBACK_TIMEOUT
63736371

63746372
def setUp(self):
63756373
self.thread = None
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Add timeout constants to :mod:`test.support`:
2+
:data:`~test.support.LOOPBACK_TIMEOUT`,
3+
:data:`~test.support.INTERNET_TIMEOUT`, :data:`~test.support.SHORT_TIMEOUT`
4+
and :data:`~test.support.LONG_TIMEOUT`.

0 commit comments

Comments
 (0)