Skip to content

Commit

Permalink
bpo-38377: Add support.skip_if_broken_multiprocessing_synchronize() (p…
Browse files Browse the repository at this point in the history
…ythonGH-20944)

On Linux, skip tests using multiprocessing if the current user cannot
create a file in /dev/shm/ directory. Add the
skip_if_broken_multiprocessing_synchronize() function to the
test.support module.
  • Loading branch information
vstinner committed Jun 18, 2020
1 parent 2c2a4f3 commit ddbeb2f
Show file tree
Hide file tree
Showing 9 changed files with 48 additions and 12 deletions.
8 changes: 8 additions & 0 deletions Doc/library/test.rst
Original file line number Diff line number Diff line change
Expand Up @@ -919,6 +919,14 @@ The :mod:`test.support` module defines the following functions:

.. versionadded:: 3.6

.. function:: skip_if_broken_multiprocessing_synchronize()

Skip tests if the :mod:`multiprocessing.synchronize` module is missing, if
there is no available semaphore implementation, or if creating a lock raises
an :exc:`OSError`.

.. versionadded:: 3.10


The :mod:`test.support` module defines the following classes:

Expand Down
2 changes: 1 addition & 1 deletion Lib/test/_test_multiprocessing.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
# Skip tests if _multiprocessing wasn't built.
_multiprocessing = test.support.import_module('_multiprocessing')
# Skip tests if sem_open implementation is broken.
test.support.import_module('multiprocessing.synchronize')
support.skip_if_broken_multiprocessing_synchronize()
import threading

import multiprocessing.connection
Expand Down
22 changes: 22 additions & 0 deletions Lib/test/support/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1957,3 +1957,25 @@ def wait_process(pid, *, exitcode, timeout=None):
# sanity check: it should not fail in practice
if pid2 != pid:
raise AssertionError(f"pid {pid2} != pid {pid}")

def skip_if_broken_multiprocessing_synchronize():
"""
Skip tests if the multiprocessing.synchronize module is missing, if there
is no available semaphore implementation, or if creating a lock raises an
OSError.
"""

# Skip tests if the _multiprocessing extension is missing.
import_module('_multiprocessing')

# Skip tests if there is no available semaphore implementation:
# multiprocessing.synchronize requires _multiprocessing.SemLock.
synchronize = import_module('multiprocessing.synchronize')

try:
# bpo-38377: On Linux, creating a semaphore is the current user
# does not have the permission to create a file in /dev/shm.
# Create a semaphore to check permissions.
synchronize.Lock(ctx=None)
except OSError as exc:
raise unittest.SkipTest(f"broken multiprocessing SemLock: {exc!r}")
4 changes: 2 additions & 2 deletions Lib/test/test_asyncio/test_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -2673,10 +2673,10 @@ def tearDown(self):
if sys.platform != 'win32':

def test_get_event_loop_new_process(self):
# Issue bpo-32126: The multiprocessing module used by
# bpo-32126: The multiprocessing module used by
# ProcessPoolExecutor is not functional when the
# multiprocessing.synchronize module cannot be imported.
support.import_module('multiprocessing.synchronize')
support.skip_if_broken_multiprocessing_synchronize()

async def main():
pool = concurrent.futures.ProcessPoolExecutor()
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_concurrent_futures.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# Skip tests if _multiprocessing wasn't built.
support.import_module('_multiprocessing')
# Skip tests if sem_open implementation is broken.
support.import_module('multiprocessing.synchronize')
support.skip_if_broken_multiprocessing_synchronize()

from test.support import hashlib_helper
from test.support.script_helper import assert_python_ok
Expand Down
8 changes: 4 additions & 4 deletions Lib/test/test_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -3630,9 +3630,9 @@ def test_handle_called_with_queue_queue(self, mock_handle):

@patch.object(logging.handlers.QueueListener, 'handle')
def test_handle_called_with_mp_queue(self, mock_handle):
# Issue 28668: The multiprocessing (mp) module is not functional
# bpo-28668: The multiprocessing (mp) module is not functional
# when the mp.synchronize module cannot be imported.
support.import_module('multiprocessing.synchronize')
support.skip_if_broken_multiprocessing_synchronize()
for i in range(self.repeat):
log_queue = multiprocessing.Queue()
self.setup_and_log(log_queue, '%s_%s' % (self.id(), i))
Expand All @@ -3656,9 +3656,9 @@ def test_no_messages_in_queue_after_stop(self):
indicates that messages were not registered on the queue until
_after_ the QueueListener stopped.
"""
# Issue 28668: The multiprocessing (mp) module is not functional
# bpo-28668: The multiprocessing (mp) module is not functional
# when the mp.synchronize module cannot be imported.
support.import_module('multiprocessing.synchronize')
support.skip_if_broken_multiprocessing_synchronize()
for i in range(self.repeat):
queue = multiprocessing.Queue()
self.setup_and_log(queue, '%s_%s' %(self.id(), i))
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_multiprocessing_main_handling.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
AVAILABLE_START_METHODS = set(multiprocessing.get_all_start_methods())

# Issue #22332: Skip tests if sem_open implementation is broken.
support.import_module('multiprocessing.synchronize')
support.skip_if_broken_multiprocessing_synchronize()

verbose = support.verbose

Expand Down
8 changes: 5 additions & 3 deletions Lib/test/test_venv.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
import tempfile
from test.support import (captured_stdout, captured_stderr, requires_zlib,
can_symlink, EnvironmentVarGuard, rmtree,
import_module)
import_module,
skip_if_broken_multiprocessing_synchronize)
import unittest
import venv
from unittest.mock import patch
Expand Down Expand Up @@ -357,10 +358,11 @@ def test_multiprocessing(self):
"""
Test that the multiprocessing is able to spawn.
"""
# Issue bpo-36342: Instantiation of a Pool object imports the
# bpo-36342: Instantiation of a Pool object imports the
# multiprocessing.synchronize module. Skip the test if this module
# cannot be imported.
import_module('multiprocessing.synchronize')
skip_if_broken_multiprocessing_synchronize()

rmtree(self.env_dir)
self.run_with_capture(venv.create, self.env_dir)
envpy = os.path.join(os.path.realpath(self.env_dir),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
On Linux, skip tests using multiprocessing if the current user cannot create
a file in ``/dev/shm/`` directory. Add the
:func:`~test.support.skip_if_broken_multiprocessing_synchronize` function to
the :mod:`test.support` module.

0 comments on commit ddbeb2f

Please sign in to comment.