blob: 0b82c9950a12f494663597b0761eb93957ee6ecb [file]
"""Build step class for running Python tests."""
import json
import logging
import os
from helpers import py_env_utils
from slave import base_step
_UNITTEST_RESULT_MARKER = '__CQ_UNITTEST_RESULTS_SUMMARY__:'
class PyTestStep(base_step.BaseStep):
"""Step for running python tests."""
def __init__(self,
project,
test_file_filter_regex,
timeout,
module_path_regex='.',
**kwargs):
"""Creates a PyTestStep instance.
Args:
project: Manifest project to look for tests inside of it.
test_file_filter_regex: File pattern for tests to be run.
timeout: Timeout for test run (in seconds).
module_path_regex: Regex to determine which modules to include.
**kwargs: Any additional args to pass to BaseStep.
"""
base_step.BaseStep.__init__(self, name='py_test', **kwargs)
self._project = project
self.test_file_filter_regex = test_file_filter_regex
self.module_path_regex = module_path_regex
self.timeout = timeout
def _execute_tests(self, venv_root): # pylint: disable=method-hidden
"""Execute the tests.
Args:
venv_root: Path to the python virtual env root to activate.
Returns:
Tuple: (review, passing) Where passing is a boolean if the tests
passed and review is the generated review message.
"""
test_runner = os.path.abspath(
os.path.join(self.get_cq_root(),
'scripts/helpers/py_test_runner.py'))
directory = os.path.join(
self._getcwd(), self.get_project_path(self._project))
test_results = os.path.join(self.get_tmp_dir(), 'test_review.json')
cmd = [test_runner,
'--test_dir', directory,
'--output', test_results,
'--test_file_filter_regex', self.test_file_filter_regex,
'--module_path_regex', self.module_path_regex,
'--timeout', str(self.timeout)]
env = {
'SHELL_EXE_BINARY_PATH': self.get_step_data('cast_shell_exe_path', ''),
}
returncode, stdout, stderr = py_env_utils.exec_within_virtual_env(
self, venv_root, cmd, env=env)
if returncode != 0:
logging.error('Failed to run tests: %s\n%s', stdout, stderr)
return {'message': 'Tests did not run properly', 'passing': False}
return self._parse_test_results(test_results)
def _parse_test_results(self, test_results_file):
with open(test_results_file) as f:
return json.load(f)
def run(self):
"""Runs python tests on the repository.
Sets a build property "review" with the output.
Returns:
True iff there were no test errors.
"""
venv_root = self.get_step_data('virtual_env_root')
try:
review = self._execute_tests(venv_root)
passing = review['passing']
if passing:
logging.info(review.get('message'))
else:
self.add_review(review)
except Exception as e: # pylint: disable=broad-except
logging.exception('Failure while executing tests.')
self.add_review({'message': 'Failed due to exception [{}].'.format(e)})
return False
return passing