From 22e032a2ec8180a1a88784bf89fdd1398972a4ea Mon Sep 17 00:00:00 2001 From: Anselm Kruis Date: Sun, 9 Apr 2017 22:03:49 +0200 Subject: [PATCH 1/7] bpo-30028: make test.support.temp_cwd() fork-safe Improve the context manager test.support.temp_cwd() to not remove the temporary directory, if a forked child terminates. --- Lib/test/support/__init__.py | 4 +++- Lib/test/test_regrtest.py | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 6658ece735cfe9..46796e788743cd 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -960,10 +960,12 @@ def temp_dir(path=None, quiet=False): warnings.warn(f'tests may fail, unable to create ' f'temporary directory {path!r}: {exc}', RuntimeWarning, stacklevel=3) + if dir_created: + pid = os.getpid() try: yield path finally: - if dir_created: + if dir_created and pid == os.getpid(): rmtree(path) @contextlib.contextmanager diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py index 0bd62985d9c21d..908ab2c7506cfc 100644 --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -821,5 +821,20 @@ def test_crashed(self): randomize=True) +class TempCwdTestCase(unittest.TestCase): + @unittest.skipUnless(hasattr(os, "fork"), "test requires os.fork") + def test_forked_child(self): + import sys + with support.temp_cwd() as cwd: + pid = os.fork() + if pid != 0: + # parent + os.waitpid(pid, 0) + self.assertTrue(os.path.isdir(cwd), "directory was removed "+cwd) + if pid == 0: + # terminate the child in order to not confuse the test runner + os._exit(0) + + if __name__ == '__main__': unittest.main() From 7b96cf72703eab2932158cbb3ec1dc0757e60134 Mon Sep 17 00:00:00 2001 From: Anselm Kruis Date: Mon, 10 Apr 2017 10:00:14 +0200 Subject: [PATCH 2/7] Update test_regrtest.py Remove an unused "import sys". --- Lib/test/test_regrtest.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py index 908ab2c7506cfc..287576619e17e2 100644 --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -824,7 +824,6 @@ def test_crashed(self): class TempCwdTestCase(unittest.TestCase): @unittest.skipUnless(hasattr(os, "fork"), "test requires os.fork") def test_forked_child(self): - import sys with support.temp_cwd() as cwd: pid = os.fork() if pid != 0: From 9ca966554cab0decb4b555701148fef5be2b3875 Mon Sep 17 00:00:00 2001 From: Anselm Kruis Date: Mon, 10 Apr 2017 10:49:47 +0200 Subject: [PATCH 3/7] bpo-30028: Add comments, move the test to test_support.py Added an explanatory comment and moved the test to test_support.py. I also modified the test to be in line with the other tests of temp_cwd. --- Lib/test/support/__init__.py | 2 ++ Lib/test/test_regrtest.py | 14 -------------- Lib/test/test_support.py | 14 ++++++++++++++ 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 46796e788743cd..ed3738d949f56f 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -965,6 +965,8 @@ def temp_dir(path=None, quiet=False): try: yield path finally: + # In case the process forks, let only the parent remove the + # directory. The child has a diffent process id. (bpo-30028) if dir_created and pid == os.getpid(): rmtree(path) diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py index 287576619e17e2..0bd62985d9c21d 100644 --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -821,19 +821,5 @@ def test_crashed(self): randomize=True) -class TempCwdTestCase(unittest.TestCase): - @unittest.skipUnless(hasattr(os, "fork"), "test requires os.fork") - def test_forked_child(self): - with support.temp_cwd() as cwd: - pid = os.fork() - if pid != 0: - # parent - os.waitpid(pid, 0) - self.assertTrue(os.path.isdir(cwd), "directory was removed "+cwd) - if pid == 0: - # terminate the child in order to not confuse the test runner - os._exit(0) - - if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py index 0dbe02eeb388b6..e3a25dfe391084 100644 --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -161,6 +161,20 @@ def test_temp_dir__existing_dir__quiet_true(self): f'temporary directory {path!r}: '), warn) + @unittest.skipUnless(hasattr(os, "fork"), "test requires os.fork") + def test_temp_dir__forked_child(self): + """Test that a forked child process does not remove the directory.""" + with support.temp_cwd() as temp_path: + pid = os.fork() + if pid != 0: + # parent process + os.waitpid(pid, 0) # wait for the child to terminate + # make sure that temp_path is still present + self.assertTrue(os.path.isdir(temp_path)) + if pid == 0: + # terminate the child in order to not confuse the test runner + os._exit(0) + # Tests for change_cwd() def test_change_cwd(self): From 1a0364d4bf0427df69f0e560664ab80e7389ac86 Mon Sep 17 00:00:00 2001 From: Anselm Kruis Date: Mon, 10 Apr 2017 11:55:17 +0200 Subject: [PATCH 4/7] bpo-30028: Run the fork test as an external script. --- Lib/test/test_support.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py index e3a25dfe391084..b7710beda33708 100644 --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -7,7 +7,9 @@ import socket import tempfile import errno +import textwrap from test import support +from test.support import script_helper TESTFN = support.TESTFN @@ -164,16 +166,18 @@ def test_temp_dir__existing_dir__quiet_true(self): @unittest.skipUnless(hasattr(os, "fork"), "test requires os.fork") def test_temp_dir__forked_child(self): """Test that a forked child process does not remove the directory.""" - with support.temp_cwd() as temp_path: - pid = os.fork() - if pid != 0: - # parent process - os.waitpid(pid, 0) # wait for the child to terminate - # make sure that temp_path is still present - self.assertTrue(os.path.isdir(temp_path)) - if pid == 0: - # terminate the child in order to not confuse the test runner - os._exit(0) + # Run the test as an external script, because it uses fork. + script_helper.assert_python_ok("-c", textwrap.dedent(""" + import os + from test import support + with support.temp_cwd() as temp_path: + pid = os.fork() + if pid != 0: + # parent process + os.waitpid(pid, 0) # wait for the child to terminate + # make sure that temp_path is still present + assert os.path.isdir(temp_path), "Child removed temp_path." + """)) # Tests for change_cwd() From 0f480d95bffc511e4f73221ab5127394aa3a6ad9 Mon Sep 17 00:00:00 2001 From: Anselm Kruis Date: Sat, 15 Apr 2017 14:38:52 +0200 Subject: [PATCH 5/7] bpo-30028: replace assert by if ...: raise AssertionError An assert might removed depending on Python options. --- Lib/test/test_support.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py index b7710beda33708..a71e32d7436915 100644 --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -176,7 +176,8 @@ def test_temp_dir__forked_child(self): # parent process os.waitpid(pid, 0) # wait for the child to terminate # make sure that temp_path is still present - assert os.path.isdir(temp_path), "Child removed temp_path." + if not os.path.isdir(temp_path): + raise AssertionError("Child removed temp_path.") """)) # Tests for change_cwd() From 8cebac881d4689f2f7ed8e2dfda823298d8da4f9 Mon Sep 17 00:00:00 2001 From: Anselm Kruis Date: Sat, 22 Apr 2017 23:10:19 +0100 Subject: [PATCH 6/7] bpo-30028: improve the test case - better comments - make sure, that the child exits successfully --- Lib/test/test_support.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py index a71e32d7436915..cceb2360fb80df 100644 --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -166,6 +166,7 @@ def test_temp_dir__existing_dir__quiet_true(self): @unittest.skipUnless(hasattr(os, "fork"), "test requires os.fork") def test_temp_dir__forked_child(self): """Test that a forked child process does not remove the directory.""" + # See bpo-30028 for details. # Run the test as an external script, because it uses fork. script_helper.assert_python_ok("-c", textwrap.dedent(""" import os @@ -173,9 +174,18 @@ def test_temp_dir__forked_child(self): with support.temp_cwd() as temp_path: pid = os.fork() if pid != 0: - # parent process - os.waitpid(pid, 0) # wait for the child to terminate - # make sure that temp_path is still present + # parent process (child has pid == 0) + + # wait for the child to terminate + (pid, status) = os.waitpid(pid, 0) + if status != 0: + raise AssertionError(f"Child process failed with exit " + f"status indication 0x{status:x}.") + + # Make sure that temp_path is still present. When the child + # process leaves the 'temp_cwd'-context, the __exit__()- + # method of the context must not remove the temporary + # directory. if not os.path.isdir(temp_path): raise AssertionError("Child removed temp_path.") """)) From ee34a5b025742c0ac188e82bdc6fb6c90699ac50 Mon Sep 17 00:00:00 2001 From: Anselm Kruis Date: Thu, 22 Feb 2018 15:44:23 +0100 Subject: [PATCH 7/7] bpo-30028: Add name to Misc/ACKS Proposed by Serhiy Storchaka. --- Misc/ACKS | 1 + 1 file changed, 1 insertion(+) diff --git a/Misc/ACKS b/Misc/ACKS index b15b20e6c1c02f..4e43581869b2bc 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -856,6 +856,7 @@ Pedro Kroger Hannu Krosing Andrej Krpic Ivan Krstić +Anselm Kruis Steven Kryskalla Andrew Kuchling Dave Kuhlman pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy