From caec6ee52b6b7ca84a6b4ce0eb2425ea7ad562d2 Mon Sep 17 00:00:00 2001 From: Alex Franchuk Date: Thu, 18 Jun 2026 16:03:08 +0000 Subject: [PATCH] Bug 1992915 - Run one process per test suite in rungtests.py r=jmaher Differential Revision: https://phabricator.services.mozilla.com/D255020 --- testing/gtest/rungtests.py | 92 +++++++++++++++++++++++------------- testing/testsuite-targets.mk | 1 + 2 files changed, 60 insertions(+), 33 deletions(-) diff --git a/testing/gtest/rungtests.py b/testing/gtest/rungtests.py index 142252f1ced9..3e717b807dc5 100644 --- a/testing/gtest/rungtests.py +++ b/testing/gtest/rungtests.py @@ -5,6 +5,7 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. import argparse +import functools import json import os import pathlib @@ -17,6 +18,7 @@ import mozprocess from mozfile import load_source from mozlog import commandline from mozrunner.utils import get_stack_fixer_function +from suites import get_gtest_suites, suite_filters HERE = os.path.abspath(os.path.dirname(__file__)) @@ -65,9 +67,10 @@ class GTests: utility_path=None, enable_inc_origin_init=False, filter_set=None, + combine_suites=False, ): """ - Run a single C++ unit test program. + Run a C++ unit test program. Arguments: * prog: The path to the test program to run. @@ -79,8 +82,10 @@ class GTests: * utility_path: A path to a directory containing utility programs. currently used to locate a stack fixer to provide symbols symbols for assertion stacks. + * combine_suites: Run one program with all suites, rather than running + each suite as a separate program invocation. - Return True if the program exits with a zero status, False otherwise. + Return True if the program(s) exit with a zero status, False otherwise. """ self.xre_path = xre_path env = self.build_environment(enable_inc_origin_init, filter_set) @@ -95,8 +100,6 @@ class GTests: if utility_path: stack_fixer = get_stack_fixer_function(utility_path, symbols_path) - GTests.run_gtest.timed_out = False - def output_line_handler(proc, line): if stack_fixer: print(stack_fixer(line)) @@ -108,29 +111,53 @@ class GTests: data = json.loads(match.group(1)) perfherder_data.append(data) - def proc_timeout_handler(proc): - GTests.run_gtest.timed_out = True - log.error("gtest | timed out after %d seconds" % self.gtest_timeout_value()) - mozcrash.kill_and_get_minidump(proc.pid, cwd, utility_path) + args = [prog, "-unittest", "--gtest_death_test_style=threadsafe"] - def output_timeout_handler(proc): - GTests.run_gtest.timed_out = True - log.error( - "gtest | timed out after %d seconds without output" - % GTests.TEST_PROC_NO_OUTPUT_TIMEOUT + def run_test_process(test_name, env): + def timeout_handler(timeout, context, proc): + timeout_handler.timed_out = True + log.error(f"{test_name} | timed out after {timeout} seconds{context}") + mozcrash.kill_and_get_minidump(proc.pid, cwd, utility_path) + + timeout_handler.timed_out = False + + proc = mozprocess.run_and_wait( + args, + cwd=cwd, + env=env, + output_line_handler=output_line_handler, + timeout=self.gtest_timeout_value(), + timeout_handler=functools.partial( + timeout_handler, self.gtest_timeout_value(), "" + ), + output_timeout=GTests.TEST_PROC_NO_OUTPUT_TIMEOUT, + output_timeout_handler=functools.partial( + timeout_handler, + GTests.TEST_PROC_NO_OUTPUT_TIMEOUT, + " without output", + ), ) - mozcrash.kill_and_get_minidump(proc.pid, cwd, utility_path) + returncode = proc.returncode - proc = mozprocess.run_and_wait( - [prog, "-unittest", "--gtest_death_test_style=threadsafe"], - cwd=cwd, - env=env, - output_line_handler=output_line_handler, - timeout=self.gtest_timeout_value(), - timeout_handler=proc_timeout_handler, - output_timeout=GTests.TEST_PROC_NO_OUTPUT_TIMEOUT, - output_timeout_handler=output_timeout_handler, - ) + log.info(f"{test_name} | process wait complete, returncode={returncode}") + if mozcrash.check_for_crashes(cwd, symbols_path, test_name=test_name): + # mozcrash will output the log failure line for us. + return False + if timeout_handler.timed_out: + return False + result = returncode == 0 + if not result: + log.error(f"{test_name} | test failed with return code {returncode}") + return result + + if combine_suites: + result = run_test_process("gtest", env) + else: + suites = get_gtest_suites(args, cwd, env) + result = all( + run_test_process(f"gtest.{filt.suite}", filt(env)) + for filt in suite_filters(suites) + ) if perfherder_data and "MOZ_AUTOMATION" in os.environ: upload_dir = pathlib.Path(os.getenv("MOZ_UPLOAD_DIR")) @@ -146,15 +173,6 @@ class GTests: with out_path.open("w", encoding="utf-8") as f: json.dump(data, f) - log.info("gtest | process wait complete, returncode=%s" % proc.returncode) - if mozcrash.check_for_crashes(cwd, symbols_path, test_name="gtest"): - # mozcrash will output the log failure line for us. - return False - if GTests.run_gtest.timed_out: - return False - result = proc.returncode == 0 - if not result: - log.error("gtest | test failed with return code %d" % proc.returncode) return result def build_core_environment(self, env={}): @@ -296,6 +314,13 @@ class gtestOptions(argparse.ArgumentParser): default=None, help="predefined gtest filter", ) + self.add_argument( + "--combine-suites", + action="store_true", + dest="combine_suites", + default=False, + help="test all suites in one program invocation", + ) self.add_argument("args", nargs=argparse.REMAINDER) @@ -339,6 +364,7 @@ def main(): utility_path=options.utility_path, enable_inc_origin_init=options.enable_inc_origin_init, filter_set=options.filter_set, + combine_suites=options.combine_suites, ) except Exception as e: log.error(str(e)) diff --git a/testing/testsuite-targets.mk b/testing/testsuite-targets.mk index 115265875af5..1310d7b489c0 100644 --- a/testing/testsuite-targets.mk +++ b/testing/testsuite-targets.mk @@ -216,6 +216,7 @@ endif cp $(topsrcdir)/testing/gtest/gtest_filter_sets.yml $(PKG_STAGE)/gtest cp $(topsrcdir)/testing/gtest/rungtests.py $(PKG_STAGE)/gtest cp $(topsrcdir)/testing/gtest/remotegtests.py $(PKG_STAGE)/gtest + cp $(topsrcdir)/testing/gtest/suites.py $(PKG_STAGE)/gtest cp $(topsrcdir)/testing/gtest/mach_test_package_commands.py $(PKG_STAGE)/gtest cp $(DIST)/bin/dependentlibs.list.gtest $(PKG_STAGE)/gtest cp $(DEPTH)/mozinfo.json $(PKG_STAGE)/gtest