-
-
Notifications
You must be signed in to change notification settings - Fork 30.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[3.11] gh-108416: Mark slow but not CPU bound test methods with requi…
- Loading branch information
1 parent
4e5fd6d
commit cf19e8e
Showing
18 changed files
with
316 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
import threading | ||
import time | ||
import weakref | ||
from concurrent import futures | ||
from test import support | ||
|
||
|
||
def mul(x, y): | ||
return x * y | ||
|
||
def capture(*args, **kwargs): | ||
return args, kwargs | ||
|
||
|
||
class MyObject(object): | ||
def my_method(self): | ||
pass | ||
|
||
|
||
def make_dummy_object(_): | ||
return MyObject() | ||
|
||
|
||
class ExecutorTest: | ||
# Executor.shutdown() and context manager usage is tested by | ||
# ExecutorShutdownTest. | ||
def test_submit(self): | ||
future = self.executor.submit(pow, 2, 8) | ||
self.assertEqual(256, future.result()) | ||
|
||
def test_submit_keyword(self): | ||
future = self.executor.submit(mul, 2, y=8) | ||
self.assertEqual(16, future.result()) | ||
future = self.executor.submit(capture, 1, self=2, fn=3) | ||
self.assertEqual(future.result(), ((1,), {'self': 2, 'fn': 3})) | ||
with self.assertRaises(TypeError): | ||
self.executor.submit(fn=capture, arg=1) | ||
with self.assertRaises(TypeError): | ||
self.executor.submit(arg=1) | ||
|
||
def test_map(self): | ||
self.assertEqual( | ||
list(self.executor.map(pow, range(10), range(10))), | ||
list(map(pow, range(10), range(10)))) | ||
|
||
self.assertEqual( | ||
list(self.executor.map(pow, range(10), range(10), chunksize=3)), | ||
list(map(pow, range(10), range(10)))) | ||
|
||
def test_map_exception(self): | ||
i = self.executor.map(divmod, [1, 1, 1, 1], [2, 3, 0, 5]) | ||
self.assertEqual(i.__next__(), (0, 1)) | ||
self.assertEqual(i.__next__(), (0, 1)) | ||
self.assertRaises(ZeroDivisionError, i.__next__) | ||
|
||
@support.requires_resource('walltime') | ||
def test_map_timeout(self): | ||
results = [] | ||
try: | ||
for i in self.executor.map(time.sleep, | ||
[0, 0, 6], | ||
timeout=5): | ||
results.append(i) | ||
except futures.TimeoutError: | ||
pass | ||
else: | ||
self.fail('expected TimeoutError') | ||
|
||
self.assertEqual([None, None], results) | ||
|
||
def test_shutdown_race_issue12456(self): | ||
# Issue #12456: race condition at shutdown where trying to post a | ||
# sentinel in the call queue blocks (the queue is full while processes | ||
# have exited). | ||
self.executor.map(str, [2] * (self.worker_count + 1)) | ||
self.executor.shutdown() | ||
|
||
@support.cpython_only | ||
def test_no_stale_references(self): | ||
# Issue #16284: check that the executors don't unnecessarily hang onto | ||
# references. | ||
my_object = MyObject() | ||
my_object_collected = threading.Event() | ||
my_object_callback = weakref.ref( | ||
my_object, lambda obj: my_object_collected.set()) | ||
# Deliberately discarding the future. | ||
self.executor.submit(my_object.my_method) | ||
del my_object | ||
|
||
collected = my_object_collected.wait(timeout=support.SHORT_TIMEOUT) | ||
self.assertTrue(collected, | ||
"Stale reference not collected within timeout.") | ||
|
||
def test_max_workers_negative(self): | ||
for number in (0, -1): | ||
with self.assertRaisesRegex(ValueError, | ||
"max_workers must be greater " | ||
"than 0"): | ||
self.executor_type(max_workers=number) | ||
|
||
def test_free_reference(self): | ||
# Issue #14406: Result iterator should not keep an internal | ||
# reference to result objects. | ||
for obj in self.executor.map(make_dummy_object, range(10)): | ||
wr = weakref.ref(obj) | ||
del obj | ||
support.gc_collect() # For PyPy or other GCs. | ||
self.assertIsNone(wr()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
import sys | ||
import threading | ||
import time | ||
import unittest | ||
from concurrent import futures | ||
from test import support | ||
|
||
from .util import ( | ||
CANCELLED_FUTURE, CANCELLED_AND_NOTIFIED_FUTURE, EXCEPTION_FUTURE, | ||
SUCCESSFUL_FUTURE, | ||
create_executor_tests, setup_module, | ||
BaseTestCase, ThreadPoolMixin, | ||
ProcessPoolForkMixin, ProcessPoolForkserverMixin, ProcessPoolSpawnMixin) | ||
|
||
|
||
def mul(x, y): | ||
return x * y | ||
|
||
def sleep_and_raise(t): | ||
time.sleep(t) | ||
raise Exception('this is an exception') | ||
|
||
|
||
class WaitTests: | ||
def test_20369(self): | ||
# See https://bugs.python.org/issue20369 | ||
future = self.executor.submit(time.sleep, 1.5) | ||
done, not_done = futures.wait([future, future], | ||
return_when=futures.ALL_COMPLETED) | ||
self.assertEqual({future}, done) | ||
self.assertEqual(set(), not_done) | ||
|
||
|
||
def test_first_completed(self): | ||
future1 = self.executor.submit(mul, 21, 2) | ||
future2 = self.executor.submit(time.sleep, 1.5) | ||
|
||
done, not_done = futures.wait( | ||
[CANCELLED_FUTURE, future1, future2], | ||
return_when=futures.FIRST_COMPLETED) | ||
|
||
self.assertEqual(set([future1]), done) | ||
self.assertEqual(set([CANCELLED_FUTURE, future2]), not_done) | ||
|
||
def test_first_completed_some_already_completed(self): | ||
future1 = self.executor.submit(time.sleep, 1.5) | ||
|
||
finished, pending = futures.wait( | ||
[CANCELLED_AND_NOTIFIED_FUTURE, SUCCESSFUL_FUTURE, future1], | ||
return_when=futures.FIRST_COMPLETED) | ||
|
||
self.assertEqual( | ||
set([CANCELLED_AND_NOTIFIED_FUTURE, SUCCESSFUL_FUTURE]), | ||
finished) | ||
self.assertEqual(set([future1]), pending) | ||
|
||
@support.requires_resource('walltime') | ||
def test_first_exception(self): | ||
future1 = self.executor.submit(mul, 2, 21) | ||
future2 = self.executor.submit(sleep_and_raise, 1.5) | ||
future3 = self.executor.submit(time.sleep, 3) | ||
|
||
finished, pending = futures.wait( | ||
[future1, future2, future3], | ||
return_when=futures.FIRST_EXCEPTION) | ||
|
||
self.assertEqual(set([future1, future2]), finished) | ||
self.assertEqual(set([future3]), pending) | ||
|
||
def test_first_exception_some_already_complete(self): | ||
future1 = self.executor.submit(divmod, 21, 0) | ||
future2 = self.executor.submit(time.sleep, 1.5) | ||
|
||
finished, pending = futures.wait( | ||
[SUCCESSFUL_FUTURE, | ||
CANCELLED_FUTURE, | ||
CANCELLED_AND_NOTIFIED_FUTURE, | ||
future1, future2], | ||
return_when=futures.FIRST_EXCEPTION) | ||
|
||
self.assertEqual(set([SUCCESSFUL_FUTURE, | ||
CANCELLED_AND_NOTIFIED_FUTURE, | ||
future1]), finished) | ||
self.assertEqual(set([CANCELLED_FUTURE, future2]), pending) | ||
|
||
def test_first_exception_one_already_failed(self): | ||
future1 = self.executor.submit(time.sleep, 2) | ||
|
||
finished, pending = futures.wait( | ||
[EXCEPTION_FUTURE, future1], | ||
return_when=futures.FIRST_EXCEPTION) | ||
|
||
self.assertEqual(set([EXCEPTION_FUTURE]), finished) | ||
self.assertEqual(set([future1]), pending) | ||
|
||
def test_all_completed(self): | ||
future1 = self.executor.submit(divmod, 2, 0) | ||
future2 = self.executor.submit(mul, 2, 21) | ||
|
||
finished, pending = futures.wait( | ||
[SUCCESSFUL_FUTURE, | ||
CANCELLED_AND_NOTIFIED_FUTURE, | ||
EXCEPTION_FUTURE, | ||
future1, | ||
future2], | ||
return_when=futures.ALL_COMPLETED) | ||
|
||
self.assertEqual(set([SUCCESSFUL_FUTURE, | ||
CANCELLED_AND_NOTIFIED_FUTURE, | ||
EXCEPTION_FUTURE, | ||
future1, | ||
future2]), finished) | ||
self.assertEqual(set(), pending) | ||
|
||
@support.requires_resource('walltime') | ||
def test_timeout(self): | ||
future1 = self.executor.submit(mul, 6, 7) | ||
future2 = self.executor.submit(time.sleep, 6) | ||
|
||
finished, pending = futures.wait( | ||
[CANCELLED_AND_NOTIFIED_FUTURE, | ||
EXCEPTION_FUTURE, | ||
SUCCESSFUL_FUTURE, | ||
future1, future2], | ||
timeout=5, | ||
return_when=futures.ALL_COMPLETED) | ||
|
||
self.assertEqual(set([CANCELLED_AND_NOTIFIED_FUTURE, | ||
EXCEPTION_FUTURE, | ||
SUCCESSFUL_FUTURE, | ||
future1]), finished) | ||
self.assertEqual(set([future2]), pending) | ||
|
||
|
||
class ThreadPoolWaitTests(ThreadPoolMixin, WaitTests, BaseTestCase): | ||
|
||
def test_pending_calls_race(self): | ||
# Issue #14406: multi-threaded race condition when waiting on all | ||
# futures. | ||
event = threading.Event() | ||
def future_func(): | ||
event.wait() | ||
oldswitchinterval = sys.getswitchinterval() | ||
sys.setswitchinterval(1e-6) | ||
try: | ||
fs = {self.executor.submit(future_func) for i in range(100)} | ||
event.set() | ||
futures.wait(fs, return_when=futures.ALL_COMPLETED) | ||
finally: | ||
sys.setswitchinterval(oldswitchinterval) | ||
|
||
|
||
create_executor_tests(globals(), WaitTests, | ||
executor_mixins=(ProcessPoolForkMixin, | ||
ProcessPoolForkserverMixin, | ||
ProcessPoolSpawnMixin)) | ||
|
||
|
||
def setUpModule(): | ||
setup_module() | ||
|
||
|
||
if __name__ == "__main__": | ||
unittest.main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.