From 036a6bbfed1fc93b969d058cbbd19548f7e387fd Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 27 Jun 2019 00:34:30 +0200 Subject: [PATCH] [WIP] bpo-37421: regrtest detects if a test leaks temporary files --- Lib/test/libregrtest/main.py | 39 +++++++++++++++++++------------- Lib/test/libregrtest/save_env.py | 13 +++++++++++ 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/Lib/test/libregrtest/main.py b/Lib/test/libregrtest/main.py index e2274254fdb89c..c3fa1a07cd79b1 100644 --- a/Lib/test/libregrtest/main.py +++ b/Lib/test/libregrtest/main.py @@ -83,7 +83,7 @@ def __init__(self): # misc self.win_load_tracker = None - self.tmp_dir = None + self.directory = None self.worker_test_name = None def get_executed(self): @@ -191,7 +191,7 @@ def find_tests(self, tests): self.tests = tests if self.ns.single: - self.next_single_filename = os.path.join(self.tmp_dir, 'pynexttest') + self.next_single_filename = os.path.join(self.directory, 'pynexttest') try: with open(self.next_single_filename, 'r') as fp: next_test = fp.read().strip() @@ -551,28 +551,28 @@ def save_xml_result(self): def set_temp_dir(self): if self.ns.tempdir: - self.tmp_dir = self.ns.tempdir + self.directory = self.ns.tempdir - if not self.tmp_dir: + if not self.directory: # When tests are run from the Python build directory, it is best practice # to keep the test files in a subfolder. This eases the cleanup of leftover # files using the "make distclean" command. if sysconfig.is_python_build(): - self.tmp_dir = sysconfig.get_config_var('abs_builddir') - if self.tmp_dir is None: + self.directory = sysconfig.get_config_var('abs_builddir') + if self.directory is None: # bpo-30284: On Windows, only srcdir is available. Using # abs_builddir mostly matters on UNIX when building Python # out of the source tree, especially when the source tree # is read only. - self.tmp_dir = sysconfig.get_config_var('srcdir') - self.tmp_dir = os.path.join(self.tmp_dir, 'build') + self.directory = sysconfig.get_config_var('srcdir') + self.directory = os.path.join(self.directory, 'build') else: - self.tmp_dir = tempfile.gettempdir() + self.directory = tempfile.gettempdir() - self.tmp_dir = os.path.abspath(self.tmp_dir) + self.directory = os.path.abspath(self.directory) - def create_temp_dir(self): - os.makedirs(self.tmp_dir, exist_ok=True) + def create_test_dir(self): + os.makedirs(self.directory, exist_ok=True) # Define a writable temp dir that will be used as cwd while running # the tests. The name of the dir includes the pid to allow parallel @@ -582,14 +582,14 @@ def create_temp_dir(self): test_cwd = 'test_python_worker_{}'.format(pid) else: test_cwd = 'test_python_{}'.format(pid) - test_cwd = os.path.join(self.tmp_dir, test_cwd) + test_cwd = os.path.join(self.directory, test_cwd) return test_cwd def cleanup(self): import glob - path = os.path.join(self.tmp_dir, 'test_python_*') - print("Cleanup %s directory" % self.tmp_dir) + path = os.path.join(self.directory, 'test_python_*') + print("Cleanup %s directory" % self.directory) for name in glob.glob(path): if os.path.isdir(name): print("Remove directory: %s" % name) @@ -607,13 +607,20 @@ def main(self, tests=None, **kwargs): self.cleanup() sys.exit(0) - test_cwd = self.create_temp_dir() + test_cwd = self.create_test_dir() # Run the tests in a context manager that temporarily changes the CWD # to a temporary and writable directory. If it's not possible to # create or change the CWD, the original CWD will be used. # The original CWD is available from support.SAVEDCWD. with support.temp_cwd(test_cwd, quiet=True): + tmpdir = os.path.join(test_cwd, 'tmpdir') + os.mkdir(tmpdir) + + os.environ['TMPDIR'] = tmpdir + os.environ['TEMPDIR'] = tmpdir + support.TMPDIR = tmpdir + # When using multiprocessing, worker processes will use test_cwd # as their parent temporary directory. So when the main process # exit, it removes also subdirectories of worker processes. diff --git a/Lib/test/libregrtest/save_env.py b/Lib/test/libregrtest/save_env.py index e7c27a698b06a0..16958383d8cbae 100644 --- a/Lib/test/libregrtest/save_env.py +++ b/Lib/test/libregrtest/save_env.py @@ -46,6 +46,7 @@ def __init__(self, testname, verbose=0, quiet=False, *, pgo=False): self.verbose = verbose self.quiet = quiet self.pgo = pgo + self.tmpdir = support.TMPDIR # To add things to save and restore, add a name XXX to the resources list # and add corresponding get_XXX/restore_XXX functions. get_XXX should @@ -70,6 +71,7 @@ def __init__(self, testname, verbose=0, quiet=False, *, pgo=False): 'shutil_archive_formats', 'shutil_unpack_formats', 'asyncio.events._event_loop_policy', 'urllib.requests._url_tempfiles', 'urllib.requests._opener', + 'tmpdir', ) def get_urllib_requests__url_tempfiles(self): @@ -248,6 +250,17 @@ def restore_files(self, saved_value): elif os.path.isdir(fn): support.rmtree(fn) + def get_tmpdir(self): + return sorted(fn + ('/' if os.path.isdir(fn) else '') + for fn in os.listdir(self.tmpdir)) + def restore_tmpdir(self, saved_value): + fn = support.TESTFN + if fn not in saved_value and (fn + '/') not in saved_value: + if os.path.isfile(fn): + support.unlink(fn) + elif os.path.isdir(fn): + support.rmtree(fn) + _lc = [getattr(locale, lc) for lc in dir(locale) if lc.startswith('LC_')] def get_locale(self):