Skip to content

Commit fa4885e

Browse files
author
MarcoFalke
committed
test: Remove polling loop from test_runner
1 parent fd813bf commit fa4885e

File tree

1 file changed

+46
-33
lines changed

1 file changed

+46
-33
lines changed

test/functional/test_runner.py

Lines changed: 46 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
import argparse
1616
from collections import deque
17+
from concurrent import futures
1718
import configparser
1819
import csv
1920
import 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

Comments
 (0)