Skip to content

Commit cf19e8e

Browse files
[3.11] gh-108416: Mark slow but not CPU bound test methods with requires_resource('walltime') (GH-108480) (GH-108924)
(cherry picked from commit 1e0d627)
1 parent 4e5fd6d commit cf19e8e

18 files changed

+316
-3
lines changed

Lib/test/_test_multiprocessing.py

+3
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,7 @@ def test_close(self):
674674

675675
close_queue(q)
676676

677+
@support.requires_resource('walltime')
677678
def test_many_processes(self):
678679
if self.TYPE == 'threads':
679680
self.skipTest('test not appropriate for {}'.format(self.TYPE))
@@ -4919,6 +4920,7 @@ def test_wait_slow(self):
49194920
def test_wait_socket_slow(self):
49204921
self.test_wait_socket(True)
49214922

4923+
@support.requires_resource('walltime')
49224924
def test_wait_timeout(self):
49234925
from multiprocessing.connection import wait
49244926

@@ -4947,6 +4949,7 @@ def signal_and_sleep(cls, sem, period):
49474949
sem.release()
49484950
time.sleep(period)
49494951

4952+
@support.requires_resource('walltime')
49504953
def test_wait_integer(self):
49514954
from multiprocessing.connection import wait
49524955

Lib/test/libregrtest/cmdline.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@
107107
108108
cpu - Used for certain CPU-heavy tests.
109109
110+
walltime - Long running but not CPU-bound tests.
111+
110112
subprocess Run all tests for the subprocess module.
111113
112114
urlfetch - It is okay to download files required on testing.
@@ -129,7 +131,7 @@
129131

130132

131133
ALL_RESOURCES = ('audio', 'curses', 'largefile', 'network',
132-
'decimal', 'cpu', 'subprocess', 'urlfetch', 'gui')
134+
'decimal', 'cpu', 'subprocess', 'urlfetch', 'gui', 'walltime')
133135

134136
# Other resources excluded from --use=all:
135137
#
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import threading
2+
import time
3+
import weakref
4+
from concurrent import futures
5+
from test import support
6+
7+
8+
def mul(x, y):
9+
return x * y
10+
11+
def capture(*args, **kwargs):
12+
return args, kwargs
13+
14+
15+
class MyObject(object):
16+
def my_method(self):
17+
pass
18+
19+
20+
def make_dummy_object(_):
21+
return MyObject()
22+
23+
24+
class ExecutorTest:
25+
# Executor.shutdown() and context manager usage is tested by
26+
# ExecutorShutdownTest.
27+
def test_submit(self):
28+
future = self.executor.submit(pow, 2, 8)
29+
self.assertEqual(256, future.result())
30+
31+
def test_submit_keyword(self):
32+
future = self.executor.submit(mul, 2, y=8)
33+
self.assertEqual(16, future.result())
34+
future = self.executor.submit(capture, 1, self=2, fn=3)
35+
self.assertEqual(future.result(), ((1,), {'self': 2, 'fn': 3}))
36+
with self.assertRaises(TypeError):
37+
self.executor.submit(fn=capture, arg=1)
38+
with self.assertRaises(TypeError):
39+
self.executor.submit(arg=1)
40+
41+
def test_map(self):
42+
self.assertEqual(
43+
list(self.executor.map(pow, range(10), range(10))),
44+
list(map(pow, range(10), range(10))))
45+
46+
self.assertEqual(
47+
list(self.executor.map(pow, range(10), range(10), chunksize=3)),
48+
list(map(pow, range(10), range(10))))
49+
50+
def test_map_exception(self):
51+
i = self.executor.map(divmod, [1, 1, 1, 1], [2, 3, 0, 5])
52+
self.assertEqual(i.__next__(), (0, 1))
53+
self.assertEqual(i.__next__(), (0, 1))
54+
self.assertRaises(ZeroDivisionError, i.__next__)
55+
56+
@support.requires_resource('walltime')
57+
def test_map_timeout(self):
58+
results = []
59+
try:
60+
for i in self.executor.map(time.sleep,
61+
[0, 0, 6],
62+
timeout=5):
63+
results.append(i)
64+
except futures.TimeoutError:
65+
pass
66+
else:
67+
self.fail('expected TimeoutError')
68+
69+
self.assertEqual([None, None], results)
70+
71+
def test_shutdown_race_issue12456(self):
72+
# Issue #12456: race condition at shutdown where trying to post a
73+
# sentinel in the call queue blocks (the queue is full while processes
74+
# have exited).
75+
self.executor.map(str, [2] * (self.worker_count + 1))
76+
self.executor.shutdown()
77+
78+
@support.cpython_only
79+
def test_no_stale_references(self):
80+
# Issue #16284: check that the executors don't unnecessarily hang onto
81+
# references.
82+
my_object = MyObject()
83+
my_object_collected = threading.Event()
84+
my_object_callback = weakref.ref(
85+
my_object, lambda obj: my_object_collected.set())
86+
# Deliberately discarding the future.
87+
self.executor.submit(my_object.my_method)
88+
del my_object
89+
90+
collected = my_object_collected.wait(timeout=support.SHORT_TIMEOUT)
91+
self.assertTrue(collected,
92+
"Stale reference not collected within timeout.")
93+
94+
def test_max_workers_negative(self):
95+
for number in (0, -1):
96+
with self.assertRaisesRegex(ValueError,
97+
"max_workers must be greater "
98+
"than 0"):
99+
self.executor_type(max_workers=number)
100+
101+
def test_free_reference(self):
102+
# Issue #14406: Result iterator should not keep an internal
103+
# reference to result objects.
104+
for obj in self.executor.map(make_dummy_object, range(10)):
105+
wr = weakref.ref(obj)
106+
del obj
107+
support.gc_collect() # For PyPy or other GCs.
108+
self.assertIsNone(wr())
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
import sys
2+
import threading
3+
import time
4+
import unittest
5+
from concurrent import futures
6+
from test import support
7+
8+
from .util import (
9+
CANCELLED_FUTURE, CANCELLED_AND_NOTIFIED_FUTURE, EXCEPTION_FUTURE,
10+
SUCCESSFUL_FUTURE,
11+
create_executor_tests, setup_module,
12+
BaseTestCase, ThreadPoolMixin,
13+
ProcessPoolForkMixin, ProcessPoolForkserverMixin, ProcessPoolSpawnMixin)
14+
15+
16+
def mul(x, y):
17+
return x * y
18+
19+
def sleep_and_raise(t):
20+
time.sleep(t)
21+
raise Exception('this is an exception')
22+
23+
24+
class WaitTests:
25+
def test_20369(self):
26+
# See https://bugs.python.org/issue20369
27+
future = self.executor.submit(time.sleep, 1.5)
28+
done, not_done = futures.wait([future, future],
29+
return_when=futures.ALL_COMPLETED)
30+
self.assertEqual({future}, done)
31+
self.assertEqual(set(), not_done)
32+
33+
34+
def test_first_completed(self):
35+
future1 = self.executor.submit(mul, 21, 2)
36+
future2 = self.executor.submit(time.sleep, 1.5)
37+
38+
done, not_done = futures.wait(
39+
[CANCELLED_FUTURE, future1, future2],
40+
return_when=futures.FIRST_COMPLETED)
41+
42+
self.assertEqual(set([future1]), done)
43+
self.assertEqual(set([CANCELLED_FUTURE, future2]), not_done)
44+
45+
def test_first_completed_some_already_completed(self):
46+
future1 = self.executor.submit(time.sleep, 1.5)
47+
48+
finished, pending = futures.wait(
49+
[CANCELLED_AND_NOTIFIED_FUTURE, SUCCESSFUL_FUTURE, future1],
50+
return_when=futures.FIRST_COMPLETED)
51+
52+
self.assertEqual(
53+
set([CANCELLED_AND_NOTIFIED_FUTURE, SUCCESSFUL_FUTURE]),
54+
finished)
55+
self.assertEqual(set([future1]), pending)
56+
57+
@support.requires_resource('walltime')
58+
def test_first_exception(self):
59+
future1 = self.executor.submit(mul, 2, 21)
60+
future2 = self.executor.submit(sleep_and_raise, 1.5)
61+
future3 = self.executor.submit(time.sleep, 3)
62+
63+
finished, pending = futures.wait(
64+
[future1, future2, future3],
65+
return_when=futures.FIRST_EXCEPTION)
66+
67+
self.assertEqual(set([future1, future2]), finished)
68+
self.assertEqual(set([future3]), pending)
69+
70+
def test_first_exception_some_already_complete(self):
71+
future1 = self.executor.submit(divmod, 21, 0)
72+
future2 = self.executor.submit(time.sleep, 1.5)
73+
74+
finished, pending = futures.wait(
75+
[SUCCESSFUL_FUTURE,
76+
CANCELLED_FUTURE,
77+
CANCELLED_AND_NOTIFIED_FUTURE,
78+
future1, future2],
79+
return_when=futures.FIRST_EXCEPTION)
80+
81+
self.assertEqual(set([SUCCESSFUL_FUTURE,
82+
CANCELLED_AND_NOTIFIED_FUTURE,
83+
future1]), finished)
84+
self.assertEqual(set([CANCELLED_FUTURE, future2]), pending)
85+
86+
def test_first_exception_one_already_failed(self):
87+
future1 = self.executor.submit(time.sleep, 2)
88+
89+
finished, pending = futures.wait(
90+
[EXCEPTION_FUTURE, future1],
91+
return_when=futures.FIRST_EXCEPTION)
92+
93+
self.assertEqual(set([EXCEPTION_FUTURE]), finished)
94+
self.assertEqual(set([future1]), pending)
95+
96+
def test_all_completed(self):
97+
future1 = self.executor.submit(divmod, 2, 0)
98+
future2 = self.executor.submit(mul, 2, 21)
99+
100+
finished, pending = futures.wait(
101+
[SUCCESSFUL_FUTURE,
102+
CANCELLED_AND_NOTIFIED_FUTURE,
103+
EXCEPTION_FUTURE,
104+
future1,
105+
future2],
106+
return_when=futures.ALL_COMPLETED)
107+
108+
self.assertEqual(set([SUCCESSFUL_FUTURE,
109+
CANCELLED_AND_NOTIFIED_FUTURE,
110+
EXCEPTION_FUTURE,
111+
future1,
112+
future2]), finished)
113+
self.assertEqual(set(), pending)
114+
115+
@support.requires_resource('walltime')
116+
def test_timeout(self):
117+
future1 = self.executor.submit(mul, 6, 7)
118+
future2 = self.executor.submit(time.sleep, 6)
119+
120+
finished, pending = futures.wait(
121+
[CANCELLED_AND_NOTIFIED_FUTURE,
122+
EXCEPTION_FUTURE,
123+
SUCCESSFUL_FUTURE,
124+
future1, future2],
125+
timeout=5,
126+
return_when=futures.ALL_COMPLETED)
127+
128+
self.assertEqual(set([CANCELLED_AND_NOTIFIED_FUTURE,
129+
EXCEPTION_FUTURE,
130+
SUCCESSFUL_FUTURE,
131+
future1]), finished)
132+
self.assertEqual(set([future2]), pending)
133+
134+
135+
class ThreadPoolWaitTests(ThreadPoolMixin, WaitTests, BaseTestCase):
136+
137+
def test_pending_calls_race(self):
138+
# Issue #14406: multi-threaded race condition when waiting on all
139+
# futures.
140+
event = threading.Event()
141+
def future_func():
142+
event.wait()
143+
oldswitchinterval = sys.getswitchinterval()
144+
sys.setswitchinterval(1e-6)
145+
try:
146+
fs = {self.executor.submit(future_func) for i in range(100)}
147+
event.set()
148+
futures.wait(fs, return_when=futures.ALL_COMPLETED)
149+
finally:
150+
sys.setswitchinterval(oldswitchinterval)
151+
152+
153+
create_executor_tests(globals(), WaitTests,
154+
executor_mixins=(ProcessPoolForkMixin,
155+
ProcessPoolForkserverMixin,
156+
ProcessPoolSpawnMixin))
157+
158+
159+
def setUpModule():
160+
setup_module()
161+
162+
163+
if __name__ == "__main__":
164+
unittest.main()

Lib/test/test_eintr.py

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
class EINTRTests(unittest.TestCase):
1010

1111
@unittest.skipUnless(hasattr(signal, "setitimer"), "requires setitimer()")
12+
@support.requires_resource('walltime')
1213
def test_all(self):
1314
# Run the tester in a sub-process, to make sure there is only one
1415
# thread (for reliable signal delivery).

Lib/test/test_faulthandler.py

+1
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,7 @@ def test_dump_traceback_later_fd(self):
676676
with tempfile.TemporaryFile('wb+') as fp:
677677
self.check_dump_traceback_later(fd=fp.fileno())
678678

679+
@support.requires_resource('walltime')
679680
def test_dump_traceback_later_twice(self):
680681
self.check_dump_traceback_later(loops=2)
681682

Lib/test/test_httplib.py

+1
Original file line numberDiff line numberDiff line change
@@ -1911,6 +1911,7 @@ def test_networked_good_cert(self):
19111911
h.close()
19121912
self.assertIn('nginx', server_string)
19131913

1914+
@support.requires_resource('walltime')
19141915
def test_networked_bad_cert(self):
19151916
# We feed a "CA" cert that is unrelated to the server's cert
19161917
import ssl

Lib/test/test_imaplib.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import socket
1212

1313
from test.support import (verbose,
14-
run_with_tz, run_with_locale, cpython_only,
14+
run_with_tz, run_with_locale, cpython_only, requires_resource,
1515
requires_working_socket)
1616
from test.support import hashlib_helper
1717
from test.support import threading_helper
@@ -459,6 +459,7 @@ def test_simple_with_statement(self):
459459
with self.imap_class(*server.server_address):
460460
pass
461461

462+
@requires_resource('walltime')
462463
def test_imaplib_timeout_test(self):
463464
_, server = self._setup(SimpleIMAPHandler)
464465
addr = server.server_address[1]
@@ -552,6 +553,7 @@ class NewIMAPSSLTests(NewIMAPTestsMixin, unittest.TestCase):
552553
imap_class = IMAP4_SSL
553554
server_class = SecureTCPServer
554555

556+
@requires_resource('walltime')
555557
def test_ssl_raises(self):
556558
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
557559
self.assertEqual(ssl_context.verify_mode, ssl.CERT_REQUIRED)
@@ -566,6 +568,7 @@ def test_ssl_raises(self):
566568
ssl_context=ssl_context)
567569
client.shutdown()
568570

571+
@requires_resource('walltime')
569572
def test_ssl_verified(self):
570573
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
571574
ssl_context.load_verify_locations(CAFILE)

0 commit comments

Comments
 (0)