Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 26c0d8a4 authored by Luca Farsi's avatar Luca Farsi Committed by Julien Desprez
Browse files

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
parent 62035d9c
Loading
Loading
Loading
Loading
+80 −22
Original line number Diff line number Diff line
@@ -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()
    # 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:
      # 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:
          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:
            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'
+3 −0
Original line number Diff line number Diff line
@@ -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()