From bfed38ae4f4da548b3a1b88c4c5e5752f8a21910 Mon Sep 17 00:00:00 2001 From: Michael Aigner Date: Mon, 22 Mar 2021 23:51:52 +0100 Subject: [PATCH 1/3] add gtest_output support --- gtest_parallel.py | 64 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/gtest_parallel.py b/gtest_parallel.py index 6e2351f..d8e6838 100755 --- a/gtest_parallel.py +++ b/gtest_parallel.py @@ -412,6 +412,55 @@ def add_stats(stats, task, idx): def flush(self): self.out.flush_transient_output() +def join_gtest_output_files(files, output_filename): + '''join given files into a single one''' + from xml.dom import minidom + + base_file = files[0] + del files[0] + doc = minidom.parse(base_file) + testsuites_root = doc.getElementsByTagName("testsuites")[0] + + def sum_tags(base, other): + for k in base.attributes.keys(): + v = base.attributes[k] + if k in ["tests", "failures", "disabled", "errors"]: + base.attributes[k].value = str(int(v.value) + int(other.attributes[k].value)) + elif k == "time": + base.attributes[k].value = str(round(float(v.value) + float(other.attributes[k].value), 3)) + + def add_testsuite(ts): + tag = "testsuite" + other = ts.getElementsByTagName(tag)[0] + for s in doc.getElementsByTagName(tag): + if s.attributes['name'].value == other.attributes['name'].value: + sum_tags(s, other) + for tc in other.getElementsByTagName("testcase"): + s.appendChild(tc) + break + else: + testsuites_root.appendChild(other) + + for f in files: + tmp_doc = minidom.parse(f) + sum_tags( + doc.getElementsByTagName("testsuites")[0], + tmp_doc.getElementsByTagName("testsuites")[0] + ) + add_testsuite(tmp_doc) + + xmlstr = doc.toprettyxml(indent=" ") + # remove empty lines from pretty print + lines = [] + for line in xmlstr.replace("\r", "").split("\n"): + l = line.rstrip() + if l: + lines.append(l) + xmlstr = "\n".join(lines) + + with open(output_filename, 'w', encoding='utf8') as f: + f.write(xmlstr) + class CollectTestResults(object): def __init__(self, json_dump_filepath): @@ -729,6 +778,8 @@ def default_options_parser(): parser.add_option('--serialize_test_cases', action='store_true', default=False, help='Do not run tests from the same test ' 'case in parallel.') + parser.add_option('--gtest_output', type='string', default=None, + help="Save the results to a file") return parser @@ -806,6 +857,17 @@ def main(): options.retry_failed, options.repeat + 1) tasks = find_tests(binaries, additional_args, options, times) + gtest_output_files = [] + if options.gtest_output: + if not options.gtest_output.startswith("xml:"): + raise Exception("only xml is supported as gtest_output format") + for task in tasks: + (gtest_output_handle, gtest_output_file) = tempfile.mkstemp(prefix='gtest_parallel_out_', + suffix=".xml") + os.close(gtest_output_handle) + gtest_output_files.append(gtest_output_file) + task.gtest_output = gtest_output_file + task.test_command += ["--gtest_output=xml:{}".format(task.gtest_output)] logger.log_tasks(len(tasks)) execute_tasks(tasks, options.workers, task_manager, timeout, options.serialize_test_cases) @@ -833,6 +895,8 @@ def main(): times.write_to_file(save_file) if test_results: test_results.dump_to_file_and_close() + if options.gtest_output: + join_gtest_output_files(gtest_output_files, options.gtest_output[4:]) if sigint_handler.got_sigint(): return -signal.SIGINT From b14817ffe3ff36802d04bd7cb1e1be219789b5d7 Mon Sep 17 00:00:00 2001 From: Michael Aigner Date: Tue, 23 Mar 2021 08:49:38 +0100 Subject: [PATCH 2/3] add parser.error instead of exceptions --- gtest_parallel.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/gtest_parallel.py b/gtest_parallel.py index d8e6838..d764864 100755 --- a/gtest_parallel.py +++ b/gtest_parallel.py @@ -779,7 +779,7 @@ def default_options_parser(): default=False, help='Do not run tests from the same test ' 'case in parallel.') parser.add_option('--gtest_output', type='string', default=None, - help="Save the results to a file") + help="Save the results to a file. Needs to start with 'xml:'") return parser @@ -859,8 +859,10 @@ def main(): tasks = find_tests(binaries, additional_args, options, times) gtest_output_files = [] if options.gtest_output: + if options.repeat != 1: + parser.error("gtest_output only works with repeat times 1") if not options.gtest_output.startswith("xml:"): - raise Exception("only xml is supported as gtest_output format") + parser.error("only xml is supported as gtest_output format") for task in tasks: (gtest_output_handle, gtest_output_file) = tempfile.mkstemp(prefix='gtest_parallel_out_', suffix=".xml") From b4e78484b766e5c35e0fe5302f6aea1474b31909 Mon Sep 17 00:00:00 2001 From: Michael Aigner Date: Fri, 23 Sep 2022 21:52:36 +0200 Subject: [PATCH 3/3] skip empty test files --- gtest_parallel.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gtest_parallel.py b/gtest_parallel.py index aa19483..4496cfa 100755 --- a/gtest_parallel.py +++ b/gtest_parallel.py @@ -440,6 +440,8 @@ def join_gtest_output_files(files, output_filename): '''join given files into a single one''' from xml.dom import minidom + files = [f for f in files if os.path.exists(f) and os.path.getsize(f) > 0] + base_file = files[0] del files[0] doc = minidom.parse(base_file)