1
1
import faulthandler
2
2
import json
3
- import os
3
+ import os . path
4
4
import queue
5
5
import shlex
6
6
import signal
17
17
from test .libregrtest .cmdline import Namespace
18
18
from test .libregrtest .main import Regrtest
19
19
from test .libregrtest .runtest import (
20
- runtest , is_failed , TestResult , Interrupted , Timeout , ChildError , PROGRESS_MIN_TIME )
20
+ runtest , is_failed , TestResult , Interrupted , Timeout , ChildError ,
21
+ PROGRESS_MIN_TIME , Passed , EnvChanged )
21
22
from test .libregrtest .setup import setup_tests
22
23
from test .libregrtest .utils import format_duration , print_warning
23
24
@@ -52,7 +53,7 @@ def parse_worker_args(worker_args) -> tuple[Namespace, str]:
52
53
return (ns , test_name )
53
54
54
55
55
- def run_test_in_subprocess (testname : str , ns : Namespace ) -> subprocess .Popen :
56
+ def run_test_in_subprocess (testname : str , ns : Namespace , tmp_dir : str ) -> subprocess .Popen :
56
57
ns_dict = vars (ns )
57
58
worker_args = (ns_dict , testname )
58
59
worker_args = json .dumps (worker_args )
@@ -66,10 +67,14 @@ def run_test_in_subprocess(testname: str, ns: Namespace) -> subprocess.Popen:
66
67
'-m' , 'test.regrtest' ,
67
68
'--worker-args' , worker_args ]
68
69
70
+ env = dict (os .environ )
71
+ env ['TMPDIR' ] = tmp_dir
72
+ env ['TEMPDIR' ] = tmp_dir
73
+
69
74
# Running the child from the same working directory as regrtest's original
70
75
# invocation ensures that TEMPDIR for the child is the same when
71
76
# sysconfig.is_python_build() is true. See issue 15300.
72
- kw = {}
77
+ kw = {'env' : env }
73
78
if USE_PROCESS_GROUP :
74
79
kw ['start_new_session' ] = True
75
80
return subprocess .Popen (cmd ,
@@ -206,12 +211,12 @@ def mp_result_error(
206
211
test_result .duration_sec = time .monotonic () - self .start_time
207
212
return MultiprocessResult (test_result , stdout , err_msg )
208
213
209
- def _run_process (self , test_name : str ) -> tuple [int , str , str ]:
214
+ def _run_process (self , test_name : str , tmp_dir : str ) -> tuple [int , str , str ]:
210
215
self .start_time = time .monotonic ()
211
216
212
217
self .current_test_name = test_name
213
218
try :
214
- popen = run_test_in_subprocess (test_name , self .ns )
219
+ popen = run_test_in_subprocess (test_name , self .ns , tmp_dir )
215
220
216
221
self ._killed = False
217
222
self ._popen = popen
@@ -266,7 +271,17 @@ def _run_process(self, test_name: str) -> tuple[int, str, str]:
266
271
self .current_test_name = None
267
272
268
273
def _runtest (self , test_name : str ) -> MultiprocessResult :
269
- retcode , stdout = self ._run_process (test_name )
274
+ # gh-93353: Check for leaked temporary files in the parent process,
275
+ # since the deletion of temporary files can happen late during
276
+ # Python finalization: too late for libregrtest.
277
+ tmp_dir = os .getcwd () + '_tmpdir'
278
+ tmp_dir = os .path .abspath (tmp_dir )
279
+ try :
280
+ os .mkdir (tmp_dir )
281
+ retcode , stdout = self ._run_process (test_name , tmp_dir )
282
+ finally :
283
+ tmp_files = os .listdir (tmp_dir )
284
+ os_helper .rmtree (tmp_dir )
270
285
271
286
if retcode is None :
272
287
return self .mp_result_error (Timeout (test_name ), stdout )
@@ -289,6 +304,14 @@ def _runtest(self, test_name: str) -> MultiprocessResult:
289
304
if err_msg is not None :
290
305
return self .mp_result_error (ChildError (test_name ), stdout , err_msg )
291
306
307
+ if tmp_files :
308
+ msg = (f'\n \n '
309
+ f'Warning -- Test leaked temporary files ({ len (tmp_files )} ): '
310
+ f'{ ", " .join (sorted (tmp_files ))} ' )
311
+ stdout += msg
312
+ if isinstance (result , Passed ):
313
+ result = EnvChanged .from_passed (result )
314
+
292
315
return MultiprocessResult (result , stdout , err_msg )
293
316
294
317
def run (self ) -> None :
0 commit comments