summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Heimes <christian@python.org>2022-01-16 21:52:43 (GMT)
committerGitHub <noreply@github.com>2022-01-16 21:52:43 (GMT)
commit91e33ac3d08a1c6004c469da2c0e2a97b5bdc53c (patch)
tree93e1ad6d692a706bd319b6c705642487499f4965
parent5cd9a162cd02a3d0f1b0a182d80feeb17439e84f (diff)
downloadcpython-91e33ac3d08a1c6004c469da2c0e2a97b5bdc53c.zip
cpython-91e33ac3d08a1c6004c469da2c0e2a97b5bdc53c.tar.gz
cpython-91e33ac3d08a1c6004c469da2c0e2a97b5bdc53c.tar.bz2
bpo-40280: Add requires_fork test helper (GH-30622)
-rw-r--r--Lib/test/support/__init__.py14
-rw-r--r--Lib/test/test_fork1.py4
-rw-r--r--Lib/test/test_random.py2
-rw-r--r--Lib/test/test_support.py3
-rw-r--r--Lib/test/test_sysconfig.py2
-rw-r--r--Lib/test/test_tempfile.py3
-rw-r--r--Lib/test/test_thread.py2
-rw-r--r--Lib/test/test_threading.py18
-rwxr-xr-xLib/test/test_uuid.py2
-rw-r--r--Misc/NEWS.d/next/Tests/2022-01-16-14-11-57.bpo-40280.fNnFfx.rst2
10 files changed, 34 insertions, 18 deletions
diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
index f8faa41..ca903d3 100644
--- a/Lib/test/support/__init__.py
+++ b/Lib/test/support/__init__.py
@@ -39,12 +39,13 @@ __all__ = [
"requires_gzip", "requires_bz2", "requires_lzma",
"bigmemtest", "bigaddrspacetest", "cpython_only", "get_attribute",
"requires_IEEE_754", "requires_zlib",
+ "has_fork_support", "requires_fork",
"anticipate_failure", "load_package_tests", "detect_api_mismatch",
"check__all__", "skip_if_buggy_ucrt_strfptime",
"check_disallow_instantiation",
# sys
- "is_jython", "is_android", "check_impl_detail", "unix_shell",
- "setswitchinterval",
+ "is_jython", "is_android", "is_emscripten",
+ "check_impl_detail", "unix_shell", "setswitchinterval",
# network
"open_urlresource",
# processes
@@ -466,6 +467,15 @@ if sys.platform not in ('win32', 'vxworks'):
else:
unix_shell = None
+# wasm32-emscripten is POSIX-like but does not provide a
+# working fork() or subprocess API.
+is_emscripten = sys.platform == "emscripten"
+
+has_fork_support = hasattr(os, "fork") and not is_emscripten
+
+def requires_fork():
+ return unittest.skipUnless(has_fork_support, "requires working os.fork()")
+
# Define the URL of a dedicated HTTP server for the network tests.
# The URL must use clear-text HTTP: no redirection to encrypted HTTPS.
TEST_HTTP_URL = "http://www.pythontest.net"
diff --git a/Lib/test/test_fork1.py b/Lib/test/test_fork1.py
index a2f7cfe..a6523bb 100644
--- a/Lib/test/test_fork1.py
+++ b/Lib/test/test_fork1.py
@@ -14,7 +14,9 @@ from test import support
# Skip test if fork does not exist.
-support.get_attribute(os, 'fork')
+if not support.has_fork_support:
+ raise unittest.SkipTest("test module requires working os.fork")
+
class ForkTest(ForkWait):
def test_threaded_import_lock_fork(self):
diff --git a/Lib/test/test_random.py b/Lib/test/test_random.py
index b80aeca..f980c5b 100644
--- a/Lib/test/test_random.py
+++ b/Lib/test/test_random.py
@@ -1293,7 +1293,7 @@ class TestModule(unittest.TestCase):
# tests validity but not completeness of the __all__ list
self.assertTrue(set(random.__all__) <= set(dir(random)))
- @unittest.skipUnless(hasattr(os, "fork"), "fork() required")
+ @test.support.requires_fork()
def test_after_fork(self):
# Test the global Random instance gets reseeded in child
r, w = os.pipe()
diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py
index d5a1d44..4dac7f6 100644
--- a/Lib/test/test_support.py
+++ b/Lib/test/test_support.py
@@ -198,7 +198,7 @@ class TestSupport(unittest.TestCase):
f'temporary directory {path!r}: '),
warn)
- @unittest.skipUnless(hasattr(os, "fork"), "test requires os.fork")
+ @support.requires_fork()
def test_temp_dir__forked_child(self):
"""Test that a forked child process does not remove the directory."""
# See bpo-30028 for details.
@@ -447,6 +447,7 @@ class TestSupport(unittest.TestCase):
@unittest.skipUnless(hasattr(os, 'waitpid') and hasattr(os, 'WNOHANG'),
'need os.waitpid() and os.WNOHANG')
+ @support.requires_fork()
def test_reap_children(self):
# Make sure that there is no other pending child process
support.reap_children()
diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py
index 506266d..6fbb80d 100644
--- a/Lib/test/test_sysconfig.py
+++ b/Lib/test/test_sysconfig.py
@@ -412,6 +412,8 @@ class TestSysConfig(unittest.TestCase):
'EXT_SUFFIX required for this test')
def test_EXT_SUFFIX_in_vars(self):
import _imp
+ if not _imp.extension_suffixes():
+ self.skipTest("stub loader has no suffixes")
vars = sysconfig.get_config_vars()
self.assertIsNotNone(vars['SO'])
self.assertEqual(vars['SO'], vars['EXT_SUFFIX'])
diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py
index 2b0ec46..25fddae 100644
--- a/Lib/test/test_tempfile.py
+++ b/Lib/test/test_tempfile.py
@@ -198,8 +198,7 @@ class TestRandomNameSequence(BaseTestCase):
if i == 20:
break
- @unittest.skipUnless(hasattr(os, 'fork'),
- "os.fork is required for this test")
+ @support.requires_fork()
def test_process_awareness(self):
# ensure that the random source differs between
# child and parent.
diff --git a/Lib/test/test_thread.py b/Lib/test/test_thread.py
index 4ae8a83..d55fb73 100644
--- a/Lib/test/test_thread.py
+++ b/Lib/test/test_thread.py
@@ -224,7 +224,7 @@ class TestForkInThread(unittest.TestCase):
def setUp(self):
self.read_fd, self.write_fd = os.pipe()
- @unittest.skipUnless(hasattr(os, 'fork'), 'need os.fork')
+ @support.requires_fork()
@threading_helper.reap_threads
def test_forkinthread(self):
pid = None
diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py
index a8f3c13..f03a642 100644
--- a/Lib/test/test_threading.py
+++ b/Lib/test/test_threading.py
@@ -505,7 +505,7 @@ class ThreadTests(BaseTestCase):
t = threading.Thread(daemon=True)
self.assertTrue(t.daemon)
- @unittest.skipUnless(hasattr(os, 'fork'), 'needs os.fork()')
+ @support.requires_fork()
def test_fork_at_exit(self):
# bpo-42350: Calling os.fork() after threading._shutdown() must
# not log an error.
@@ -533,7 +533,7 @@ class ThreadTests(BaseTestCase):
self.assertEqual(out, b'')
self.assertEqual(err.rstrip(), b'child process ok')
- @unittest.skipUnless(hasattr(os, 'fork'), 'test needs fork()')
+ @support.requires_fork()
def test_dummy_thread_after_fork(self):
# Issue #14308: a dummy thread in the active list doesn't mess up
# the after-fork mechanism.
@@ -560,7 +560,7 @@ class ThreadTests(BaseTestCase):
self.assertEqual(out, b'')
self.assertEqual(err, b'')
- @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()")
+ @support.requires_fork()
def test_is_alive_after_fork(self):
# Try hard to trigger #18418: is_alive() could sometimes be True on
# threads that vanished after a fork.
@@ -594,7 +594,7 @@ class ThreadTests(BaseTestCase):
th.start()
th.join()
- @unittest.skipUnless(hasattr(os, 'fork'), "test needs os.fork()")
+ @support.requires_fork()
@unittest.skipUnless(hasattr(os, 'waitpid'), "test needs os.waitpid()")
def test_main_thread_after_fork(self):
code = """if 1:
@@ -616,7 +616,7 @@ class ThreadTests(BaseTestCase):
self.assertEqual(data, "MainThread\nTrue\nTrue\n")
@unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug")
- @unittest.skipUnless(hasattr(os, 'fork'), "test needs os.fork()")
+ @support.requires_fork()
@unittest.skipUnless(hasattr(os, 'waitpid'), "test needs os.waitpid()")
def test_main_thread_after_fork_from_nonmain_thread(self):
code = """if 1:
@@ -993,7 +993,7 @@ class ThreadJoinOnShutdown(BaseTestCase):
"""
self._run_and_join(script)
- @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()")
+ @support.requires_fork()
@unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug")
def test_2_join_in_forked_process(self):
# Like the test above, but from a forked interpreter
@@ -1014,7 +1014,7 @@ class ThreadJoinOnShutdown(BaseTestCase):
"""
self._run_and_join(script)
- @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()")
+ @support.requires_fork()
@unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug")
def test_3_join_in_forked_from_thread(self):
# Like the test above, but fork() was called from a worker thread
@@ -1085,7 +1085,7 @@ class ThreadJoinOnShutdown(BaseTestCase):
rc, out, err = assert_python_ok('-c', script)
self.assertFalse(err)
- @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()")
+ @support.requires_fork()
@unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug")
def test_reinit_tls_after_fork(self):
# Issue #13817: fork() would deadlock in a multithreaded program with
@@ -1109,7 +1109,7 @@ class ThreadJoinOnShutdown(BaseTestCase):
for t in threads:
t.join()
- @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()")
+ @support.requires_fork()
def test_clear_threads_states_after_fork(self):
# Issue #17094: check that threads states are cleared after fork()
diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py
index 3f56192..411eec0 100755
--- a/Lib/test/test_uuid.py
+++ b/Lib/test/test_uuid.py
@@ -647,7 +647,7 @@ class BaseTestUUID:
equal(u, self.uuid.UUID(v))
equal(str(u), v)
- @unittest.skipUnless(hasattr(os, 'fork'), 'need os.fork')
+ @support.requires_fork()
def testIssue8621(self):
# On at least some versions of OSX self.uuid.uuid4 generates
# the same sequence of UUIDs in the parent and any
diff --git a/Misc/NEWS.d/next/Tests/2022-01-16-14-11-57.bpo-40280.fNnFfx.rst b/Misc/NEWS.d/next/Tests/2022-01-16-14-11-57.bpo-40280.fNnFfx.rst
new file mode 100644
index 0000000..2d66db1
--- /dev/null
+++ b/Misc/NEWS.d/next/Tests/2022-01-16-14-11-57.bpo-40280.fNnFfx.rst
@@ -0,0 +1,2 @@
+Add :func:`test.support.requires_fork` decorators to mark tests that require
+a working :func:`os.fork`.