blob: ead9c01fbcba1ba5df518da1b4e8ecbc04fe817c [file]
from __future__ import absolute_import
import os
import pathlib
import re
import collections
from slave import base_step
from slave.step import code_coverage_step
BUILD_VARIANT = 'eng'
TARGET_PRODUCT = 'sirocco_x86_64'
BUILD_ITEM = 'sirocco_virtual_device_deps'
UNIT_TESTS = [
'ap-wireless_unittest',
'ap-infra_unittests',
'ap-daemons_unittest',
]
_MAKE_ERROR_PATTERN = (
r'^(?P<filename>[^:]+):(?P<linenum>\d+):(?P<column>\d+): '
'error: (?P<err_msg>.*)$',
r'^(?P<filename>[^\-]+)-(?P<linenum>\d+): error: (?P<err_msg>.*)$',
)
_GTEST_ERROR_TEST_NAME_PATTERN = re.compile(r'^\[. FAILED. \] (\S+\.\S+)$',
re.MULTILINE)
def make_error_to_comments(stderr, directory):
"""
parse stderr with regex error pattern and return comments dict
Args:
stderr (str): logs from stderr
Return:
(dict) comments: {
"filename":
{ "linenum": <int>,
"message": <str> error message,
}
}
"""
comments = collections.defaultdict(list)
for line in stderr.splitlines():
match = [m for m in [
re.match(err_pat, line) for err_pat in _MAKE_ERROR_PATTERN
] if m is not None]
if match:
match = match[0]
filename = match.group('filename')
if directory and filename.startswith(directory):
filename = filename[len(directory) + len(os.path.sep):]
linenum = int(match.group('linenum'))
comments[filename].append({'line': linenum, 'message': line})
return comments
class MakeCleanSim(base_step.BaseStep):
def __init__(self, **kwargs):
base_step.BaseStep.__init__(self,
name='make clean sirocco_x86_64',
halt_on_failure=True,
**kwargs)
def run(self):
command = [
'make',
'TARGET_PRODUCT={}'.format(TARGET_PRODUCT),
'TARGET_BUILD_VARIANT={}'.format(BUILD_VARIANT),
'clean'
]
returncode, _, stderr = self.exec_subprocess(command)
if returncode != 0:
comment = make_error_to_comments(stderr, '')
self.add_review({
'comments': comment
})
return False
return True
class BuildSimulatorStep(base_step.BaseStep):
def __init__(self, code_coverage=False, **kwargs):
self._code_coverage = code_coverage
base_step.BaseStep.__init__(self,
name='build x86_64 sirocco_x86_64',
halt_on_failure=True,
**kwargs)
def run(self):
command = [
'make',
'-j{}'.format(self.get_num_jobs()),
'TARGET_PRODUCT={}'.format(TARGET_PRODUCT),
'TARGET_BUILD_VARIANT={}'.format(BUILD_VARIANT)
]
command += self.build_accelerator.make_flags
command += [BUILD_ITEM]
returncode, _, stderr = self.exec_subprocess(command)
if returncode != 0:
comment = make_error_to_comments(stderr, '')
self.add_review({
'comments': comment
})
return False
return True
class BuildUnitTestsStep(base_step.BaseStep):
def __init__(self, code_coverage=False, **kwargs):
self._code_coverage = code_coverage
super().__init__(name='build unittests sirocco_x86_64',
halt_on_failure=True,
**kwargs)
def run(self):
command = [
'make',
'-j{}'.format(self.get_num_jobs()),
'TARGET_PRODUCT={}'.format(TARGET_PRODUCT),
'TARGET_BUILD_VARIANT={}'.format(BUILD_VARIANT),
]
if self._code_coverage:
command.append('COMMAND_LINE_GN_ARGS=\''
'use_clang_coverage=true is_component_build=false\''
)
if self.build_accelerator.make_flags:
command.extend(self.build_accelerator.make_flags)
command.append('sirocco_virtual_unittests')
returncode, _, stderr = self.exec_subprocess(command)
if returncode:
comment = make_error_to_comments(stderr, '')
self.add_review({
'comments': comment
})
return False
test_list = UNIT_TESTS.copy()
self.add_step_data(code_coverage_step.STEP_DATA_TEST_LIST, test_list)
return True
class RunUnitTestsStep(base_step.BaseStep):
def __init__(self, test_env=None, build_out_dir=None, **kwargs):
self._test_env = test_env
self._build_out_dir = build_out_dir
super().__init__(name='run unittests sirocco_x86_64',
halt_on_failure=True,
**kwargs)
def run(self):
# Use to run all tests, then if any failed we fail this step
errors = []
for test in UNIT_TESTS:
returncode, stdout, _ = self.exec_subprocess(
[f'{self._build_out_dir}/{test}'],
cwd='chromium/src',
env=self._test_env
)
if returncode:
gtest_failures = re.findall(_GTEST_ERROR_TEST_NAME_PATTERN, stdout)
if gtest_failures:
errors.extend(
[f'{test_case} from {test}' for test_case in gtest_failures]
)
else:
errors.append(f'Test execution error for {test}')
if errors:
error_msg = '\n'.join(errors)
self.add_review({
'message': f'{len(errors)} failure(s) from unit tests:\n{error_msg}',
})
return False
return True
class CreateSimTarStep(base_step.BaseStep):
def __init__(self, **kwargs):
self._eurekaroot = kwargs['eureka_root']
base_step.BaseStep.__init__(self,
name='tar-ing sim artifacts',
halt_on_failure=True,
**kwargs)
def run(self):
dockerignore = os.path.join(self._eurekaroot,
'vendor/x86_64_simulator/sirocco_x86_64/products',
'Dockerfile.dockerignore')
include_files = []
exclude_files = []
try:
with open(dockerignore) as f:
# Skip * on first line that excludes everything
for line in f.readlines()[1:]:
line = line.replace('\\', '') # Strip escaped + characters
if line.startswith('!'):
paths = self._eurekaroot.glob(line[1:].rstrip())
include_files.extend(
[str(path.relative_to(self._eurekaroot)) for path in paths])
else:
path = line.rstrip()
exclude_files.append(path)
except OSError:
# Ignore missing file here for tests
# tar would fail because the archive is empty
pass
tar_filename = '{}.tar.gz'.format(TARGET_PRODUCT)
command = ['tar']
command += ['-C', str(self._eurekaroot)]
command += [f'--exclude={file}' for file in exclude_files]
command += [
'-czf',
os.path.join(self.get_gcs_dir(), tar_filename),
]
command += include_files
returncode, _, stderr = self.exec_subprocess(command)
if returncode != 0:
comment = f'tar-ing failed: {stderr}'
self.add_review({
'message': comment
})
return False
self.set_build_property('ota_files', [tar_filename])
return True