1414
1515import argparse
1616from collections import deque
17+ from concurrent import futures
1718import configparser
1819import csv
1920import datetime
@@ -703,15 +704,15 @@ class TestHandler:
703704 """
704705 Trigger the test scripts passed in via the list.
705706 """
706-
707707 def __init__ (self , * , num_tests_parallel , tests_dir , tmpdir , test_list , flags , use_term_control ):
708708 assert num_tests_parallel >= 1
709+ self .executor = futures .ThreadPoolExecutor (max_workers = num_tests_parallel )
709710 self .num_jobs = num_tests_parallel
710711 self .tests_dir = tests_dir
711712 self .tmpdir = tmpdir
712713 self .test_list = test_list
713714 self .flags = flags
714- self .jobs = []
715+ self .jobs = {}
715716 self .use_term_control = use_term_control
716717
717718 def done (self ):
@@ -728,47 +729,59 @@ def get_next(self):
728729 test_argv = test .split ()
729730 testdir = "{}/{}_{}" .format (self .tmpdir , re .sub (".py$" , "" , test_argv [0 ]), portseed )
730731 tmpdir_arg = ["--tmpdir={}" .format (testdir )]
731- self .jobs .append ((test ,
732- time .time (),
733- subprocess .Popen ([sys .executable , self .tests_dir + test_argv [0 ]] + test_argv [1 :] + self .flags + portseed_arg + tmpdir_arg ,
734- text = True ,
735- stdout = log_stdout ,
736- stderr = log_stderr ),
737- testdir ,
738- log_stdout ,
739- log_stderr ))
732+
733+ def proc_wait (task ):
734+ task [2 ].wait ()
735+ return task
736+
737+ task = [
738+ test ,
739+ time .time (),
740+ subprocess .Popen (
741+ [sys .executable , self .tests_dir + test_argv [0 ]] + test_argv [1 :] + self .flags + portseed_arg + tmpdir_arg ,
742+ text = True ,
743+ stdout = log_stdout ,
744+ stderr = log_stderr ,
745+ ),
746+ testdir ,
747+ log_stdout ,
748+ log_stderr ,
749+ ]
750+ fut = self .executor .submit (proc_wait , task )
751+ self .jobs [fut ] = test
740752 if not self .jobs :
741753 raise IndexError ('pop from empty list' )
742754
743755 # Print remaining running jobs when all jobs have been started.
744756 if not self .test_list :
745- print ("Remaining jobs: [{}]" .format (", " .join (j [ 0 ] for j in self .jobs )))
757+ print ("Remaining jobs: [{}]" .format (", " .join (sorted ( self .jobs . values ()) )))
746758
747759 dot_count = 0
748760 while True :
749761 # Return all procs that have finished, if any. Otherwise sleep until there is one.
750- time .sleep (.5 )
762+ procs = futures .wait (self .jobs .keys (), timeout = .5 , return_when = futures .FIRST_COMPLETED )
763+ self .jobs = {fut : self .jobs [fut ] for fut in procs .not_done }
751764 ret = []
752- for job in self . jobs :
753- (name , start_time , proc , testdir , log_out , log_err ) = job
754- if proc . poll () is not None :
755- log_out .seek (0 ), log_err .seek (0 )
756- [stdout , stderr ] = [log_file .read ().decode ('utf-8' ) for log_file in (log_out , log_err )]
757- log_out .close (), log_err .close ()
758- skip_reason = None
759- if proc .returncode == TEST_EXIT_PASSED and stderr == "" :
760- status = "Passed"
761- elif proc .returncode == TEST_EXIT_SKIPPED :
762- status = "Skipped"
763- skip_reason = re .search (r"Test Skipped: (.*)" , stdout ).group (1 )
764- else :
765- status = "Failed"
766- self . jobs . remove ( job )
767- if self .use_term_control :
768- clearline = '\r ' + (' ' * dot_count ) + '\r '
769- print (clearline , end = '' , flush = True )
770- dot_count = 0
771- ret .append ((TestResult (name , status , int (time .time () - start_time )), testdir , stdout , stderr , skip_reason ))
765+ for job in procs . done :
766+ (name , start_time , proc , testdir , log_out , log_err ) = job . result ()
767+
768+ log_out .seek (0 ), log_err .seek (0 )
769+ [stdout , stderr ] = [log_file .read ().decode ('utf-8' ) for log_file in (log_out , log_err )]
770+ log_out .close (), log_err .close ()
771+ skip_reason = None
772+ if proc .returncode == TEST_EXIT_PASSED and stderr == "" :
773+ status = "Passed"
774+ elif proc .returncode == TEST_EXIT_SKIPPED :
775+ status = "Skipped"
776+ skip_reason = re .search (r"Test Skipped: (.*)" , stdout ).group (1 )
777+ else :
778+ status = "Failed"
779+
780+ if self .use_term_control :
781+ clearline = '\r ' + (' ' * dot_count ) + '\r '
782+ print (clearline , end = '' , flush = True )
783+ dot_count = 0
784+ ret .append ((TestResult (name , status , int (time .time () - start_time )), testdir , stdout , stderr , skip_reason ))
772785 if ret :
773786 return ret
774787 if self .use_term_control :
0 commit comments