| """Recipe for running python tests against the given build.""" |
| import logging |
| import os |
| from pathlib import Path |
| from typing import Dict, List, Union |
| |
| from slave import base_recipe |
| from slave.step import py_env_setup_step |
| from slave.step import py_test_step |
| |
| |
| LOGGER = logging.getLogger(__name__) |
| DEFAULT_UNIT_TEST_TIMEOUT_SECONDS = 300 |
| DEFAULT_INTEGRATION_TEST_TIMEOUT_SECONDS = 3600 |
| DEFAULT_E2E_TEST_TIMEOUT_SECONDS = 3600 |
| UNIT_TEST_REGEX_SUFFIX = r'.*_test\.py$' |
| INTEGRATION_TEST_REGEX_SUFFIX = r'.*_test_integration\.py$' |
| E2E_TEST_REGEX_SUFFIX = r'.*_test_case.py$' |
| PY3_EXCLUDED_PATH = [ |
| 'cq/buildbot-masters', |
| 'cq/scripts/master', |
| ] |
| |
| |
| BUILD_CONFIGS = { |
| 'py_unittest_builder_masters': { |
| 'project': 'builder/masters', |
| 'py_requirements_path': 'requirements_buildbot.txt', |
| 'py_requirements_project': 'builder/masters', |
| 'py_packages_mirror_dir': 'python_packages', |
| 'test_file_filter_regex': UNIT_TEST_REGEX_SUFFIX, |
| 'test_timeout_seconds': DEFAULT_UNIT_TEST_TIMEOUT_SECONDS, |
| }, |
| 'py_unittest_builder_scripts': { |
| 'project': 'builder/scripts', |
| 'test_file_filter_regex': UNIT_TEST_REGEX_SUFFIX, |
| 'test_timeout_seconds': DEFAULT_UNIT_TEST_TIMEOUT_SECONDS, |
| }, |
| 'py3_unittest_continuous_tests': { |
| 'project': 'continuous-tests', |
| 'py_requirements_path': 'cq/requirements_recipe3.txt', |
| 'py_requirements_project': 'continuous-tests', |
| 'py_packages_mirror_dir': 'python_packages', |
| 'test_file_filter_regex': UNIT_TEST_REGEX_SUFFIX, |
| 'test_timeout_seconds': DEFAULT_UNIT_TEST_TIMEOUT_SECONDS * 2, |
| 'module_path_regex': '^((?!{}).)*$'.format('|'.join(PY3_EXCLUDED_PATH)), |
| 'py3': True, |
| }, |
| 'py_unittest_test': { |
| 'project': 'test', |
| 'test_file_filter_regex': UNIT_TEST_REGEX_SUFFIX, |
| 'test_timeout_seconds': DEFAULT_UNIT_TEST_TIMEOUT_SECONDS, |
| }, |
| 'py3_unittest_test': { |
| 'project': 'test', |
| 'test_file_filter_regex': UNIT_TEST_REGEX_SUFFIX, |
| 'test_timeout_seconds': DEFAULT_UNIT_TEST_TIMEOUT_SECONDS * 2, |
| 'py3': True, |
| 'py_requirements_path': os.path.join('lab_system', 'requirements3.txt'), |
| }, |
| 'py_unittest_chromecast_internal': { |
| 'project': 'chromecast/internal', |
| 'py_requirements_path': os.path.join('lab_system', 'requirements3.txt'), |
| 'py3': True, |
| # The gunittest runner filters use full, absolute file paths, |
| # and will search into the nested git projects within |
| # chromecast/internal. To avoid finding unwanted test modules, include |
| # a 'chromecast/internal' prefix and only search specific directories. |
| 'test_file_filter_regex': |
| (r'cast/internal/(build|tools|android/build)/' + |
| UNIT_TEST_REGEX_SUFFIX), |
| 'test_timeout_seconds': DEFAULT_UNIT_TEST_TIMEOUT_SECONDS, |
| }, |
| 'py_integration_test_chromecast_internal': { |
| 'project': 'chromecast/internal', |
| 'py_requirements_path': os.path.join('lab_system', 'requirements3.txt'), |
| 'py3': True, |
| # The gunittest runner filters use full, absolute file paths, |
| # and will search into the nested git projects within |
| # chromecast/internal. To avoid finding unwanted test modules, include |
| # a 'chromecast/internal' prefix and only search specific directories. |
| 'test_file_filter_regex': |
| (r'cast/internal/(build|tools|android/build)/' + |
| INTEGRATION_TEST_REGEX_SUFFIX), |
| 'test_timeout_seconds': DEFAULT_INTEGRATION_TEST_TIMEOUT_SECONDS, |
| }, |
| } |
| Config = Dict[str, Union[str, int]] |
| |
| def GetValidBuildNames(): |
| return list(BUILD_CONFIGS.keys()) |
| |
| |
| def CreateRecipe(build_name: str, **kwargs): |
| """Builds a recipe object.""" |
| if build_name in BUILD_CONFIGS: |
| return PyTestRecipe( |
| config=BUILD_CONFIGS[build_name], |
| **kwargs) |
| raise base_recipe.BuildNameNotSupportedError(build_name) |
| |
| |
| class PyTestRecipe(base_recipe.BaseRecipe): |
| """Recipe to run python tests on a repository.""" |
| |
| def __init__(self, |
| config: Config, |
| **kwargs): |
| super().__init__(**kwargs) |
| self._config = config |
| LOGGER.info("Eureka root when creatini PyTestRecipe: %s", self._eureka_root) |
| |
| def get_steps(self): |
| requirements_project = self._config.get('py_requirements_project', 'test') |
| requirements_path = self._config.get( |
| 'py_requirements_path', os.path.join('lab_system', 'requirements.txt')) |
| python_packages_dir = self._config.get( |
| 'py_packages_mirror_dir', 'team-catatester/python_packages') |
| test_file_filter_regex = self._config.get( |
| 'test_file_filter_regex', UNIT_TEST_REGEX_SUFFIX) |
| test_timeout_seconds = self._config.get( |
| 'test_timeout_seconds', DEFAULT_UNIT_TEST_TIMEOUT_SECONDS) |
| test_py3 = self._config.get('py3', False) |
| module_path_regex = self._config.get('module_path_regex', '.') |
| LOGGER.info("Eureka root when creating additional import paths: %s", self._eureka_root) |
| additional_import_paths = [ |
| self._eureka_root / path for path |
| in ( |
| 'builder/masters', |
| 'builder/masters/src', |
| 'chromium/src/third_party/catapult/telemetry', |
| 'chromium/src/chromecast/internal', |
| 'chromium/src/chromecast/tools', |
| 'continuous-tests', |
| 'continuous-tests/cq/scripts', |
| 'test', |
| 'testing/external/autotest', |
| 'testing/external/chromite', |
| 'testing/sprockets', |
| )] |
| return [ |
| py_env_setup_step.PyEnvSetupStep( |
| additional_import_paths=additional_import_paths, |
| local_packages_dir=python_packages_dir, |
| py3=test_py3, |
| requirements_path=requirements_path, |
| requirements_project=requirements_project, |
| **self._step_kwargs), |
| py_test_step.PyTestStep( |
| project=self._config.get('project'), |
| test_file_filter_regex=test_file_filter_regex, |
| timeout=test_timeout_seconds, |
| module_path_regex=module_path_regex, |
| **self._step_kwargs) |
| ] |