Enable real test discovery in build_test_suites

Enable test discovery to actually affect build targets in build_test_suites.py (only when the flags are enabled. On failure of test discovery or if the flags are off instead fall back to the previous optimizations.

Change-Id: I6937dd0c5096884095d0770bc53b6399233cefc2
Test: atest build_test_suites_test
Bug: 378926009
This commit is contained in:
Luca Farsi 2024-11-22 00:09:47 +00:00 committed by Julien Desprez
parent 62035d9c96
commit 26c0d8a4e7
2 changed files with 83 additions and 22 deletions

View file

@ -33,6 +33,7 @@ import test_discovery_agent
REQUIRED_ENV_VARS = frozenset(['TARGET_PRODUCT', 'TARGET_RELEASE', 'TOP', 'DIST_DIR'])
SOONG_UI_EXE_REL_PATH = 'build/soong/soong_ui.bash'
LOG_PATH = 'logs/build_test_suites.log'
REQUIRED_BUILD_TARGETS = frozenset(['dist'])
class Error(Exception):
@ -73,34 +74,46 @@ class BuildPlanner:
build_targets = set()
packaging_commands_getters = []
test_discovery_zip_regexes = set()
optimization_rationale = ''
try:
# Do not use these regexes for now, only run this to collect data on what
# would be optimized.
test_discovery_zip_regexes = self._get_test_discovery_zip_regexes()
logging.info(f'Discovered test discovery regexes: {test_discovery_zip_regexes}')
except test_discovery_agent.TestDiscoveryError as e:
optimization_rationale = e.message
logging.warning(f'Unable to perform test discovery: {optimization_rationale}')
for target in self.args.extra_targets:
if optimization_rationale:
get_metrics_agent().report_unoptimized_target(target, optimization_rationale)
else:
# In order to roll optimizations out differently between test suites and
# device builds, we have separate flags.
if (
'test_suites_zip_test_discovery'
in self.build_context.enabled_build_features
and not self.args.device_build
) or (
'device_zip_test_discovery'
in self.build_context.enabled_build_features
and self.args.device_build
):
preliminary_build_targets = self._collect_preliminary_build_targets()
else:
preliminary_build_targets = self._legacy_collect_preliminary_build_targets()
# Keep reporting metrics when test discovery is disabled.
# To be removed once test discovery is fully rolled out.
optimization_rationale = ''
test_discovery_zip_regexes = set()
try:
test_discovery_zip_regexes = self._get_test_discovery_zip_regexes()
logging.info(f'Discovered test discovery regexes: {test_discovery_zip_regexes}')
except test_discovery_agent.TestDiscoveryError as e:
optimization_rationale = e.message
logging.warning(f'Unable to perform test discovery: {optimization_rationale}')
for target in self.args.extra_targets:
if optimization_rationale:
get_metrics_agent().report_unoptimized_target(target, optimization_rationale)
continue
try:
regex = r'\b(%s)\b' % re.escape(target)
regex = r'\b(%s.*)\b' % re.escape(target)
if any(re.search(regex, opt) for opt in test_discovery_zip_regexes):
get_metrics_agent().report_unoptimized_target(target, 'Test artifact used.')
else:
get_metrics_agent().report_optimized_target(target)
continue
get_metrics_agent().report_optimized_target(target)
except Exception as e:
logging.error(f'unable to parse test discovery output: {repr(e)}')
if self._unused_target_exclusion_enabled(
target
) and not self.build_context.build_target_used(target):
continue
for target in preliminary_build_targets:
target_optimizer_getter = self.target_optimizations.get(target, None)
if not target_optimizer_getter:
build_targets.add(target)
@ -116,6 +129,51 @@ class BuildPlanner:
return BuildPlan(build_targets, packaging_commands_getters)
def _collect_preliminary_build_targets(self):
build_targets = set()
try:
test_discovery_zip_regexes = self._get_test_discovery_zip_regexes()
logging.info(f'Discovered test discovery regexes: {test_discovery_zip_regexes}')
except test_discovery_agent.TestDiscoveryError as e:
optimization_rationale = e.message
logging.warning(f'Unable to perform test discovery: {optimization_rationale}')
for target in self.args.extra_targets:
get_metrics_agent().report_unoptimized_target(target, optimization_rationale)
return self._legacy_collect_preliminary_build_targets()
for target in self.args.extra_targets:
if target in REQUIRED_BUILD_TARGETS:
build_targets.add(target)
continue
regex = r'\b(%s.*)\b' % re.escape(target)
for opt in test_discovery_zip_regexes:
try:
if re.search(regex, opt):
get_metrics_agent().report_unoptimized_target(target, 'Test artifact used.')
build_targets.add(target)
continue
get_metrics_agent().report_optimized_target(target)
except Exception as e:
# In case of exception report as unoptimized
build_targets.add(target)
get_metrics_agent().report_unoptimized_target(target, f'Error in parsing test discovery output for {target}: {repr(e)}')
logging.error(f'unable to parse test discovery output: {repr(e)}')
return build_targets
def _legacy_collect_preliminary_build_targets(self):
build_targets = set()
for target in self.args.extra_targets:
if self._unused_target_exclusion_enabled(
target
) and not self.build_context.build_target_used(target):
continue
build_targets.add(target)
return build_targets
def _unused_target_exclusion_enabled(self, target: str) -> bool:
return (
f'{target}_unused_exclusion'

View file

@ -120,6 +120,9 @@ class BuildTestSuitesTest(fake_filesystem_unittest.TestCase):
self.soong_ui_dir = self.fake_top.joinpath('build/soong')
self.soong_ui_dir.mkdir(parents=True, exist_ok=True)
self.logs_dir = self.fake_top.joinpath('dist/logs')
self.logs_dir.mkdir(parents=True, exist_ok=True)
self.soong_ui = self.soong_ui_dir.joinpath('soong_ui.bash')
self.soong_ui.touch()