blob: c047a6a2c9c8b4d86cea01e428bcba4a0b8f62d2 [file]
"""Run a unittest with a sanitizer.
The key feature of this step is that this step will only be marked as failed
if the sanitizer detects an issue. If a test fails for another reason, then
this step is not considered to have failed.
Available sanitizers are: asan, msan, tsan, and ubsan.
"""
from __future__ import absolute_import
import os
from helpers import sanitizer_utils
from slave.step import shell_step
class SanitizerUnitTestShellStep(shell_step.ShellStep):
"""Unit test step running with a sanitizer ."""
def __init__(self, sanitizer=None, **kwargs):
"""Constructor."""
assert sanitizer in ['asan', 'msan', 'tsan', 'ubsan']
properties_handler = sanitizer_utils.get_sanitizer_to_comments_for(
sanitizer)
shell_step.ShellStep.__init__(
self, properties_handler=properties_handler, **kwargs)
self._sanitizer = sanitizer
self._unittest_prefix_filter = 'cast_'
if 'unittest_prefix_filter' in kwargs:
self._unittest_prefix_filter = kwargs['unittest_prefix_filter']
symbolizer = os.path.relpath(
os.path.join(
self.get_project_path('chromium/src'),
'third_party/llvm-build/Release+Asserts/bin/llvm-symbolizer'),
self.directory)
suppression_dir = os.path.relpath(
os.path.join(
self.get_project_path('chromecast/internal'), 'build/sanitizers'),
self.directory)
asan_options = ('detect_leaks=1 '
'detect_odr_violation=0 '
'symbolize=1 '
'external_symbolizer_path={}'.format(symbolizer))
lsan_options = ('suppressions={}/lsan_suppressions'.format(suppression_dir))
tsan_options = ('external_symbolizer_path={} '
'suppressions={}/tsan_suppressions').format(symbolizer,
suppression_dir)
ubsan_options = ('external_symbolizer_path={}'.format(symbolizer))
self._sanitizer_env = {
'ASAN_OPTIONS': asan_options,
'LSAN_OPTIONS': lsan_options,
'MSAN_SYMBOLIZER_PATH': symbolizer,
'TSAN_OPTIONS': tsan_options,
'UBSAN_OPTIONS': ubsan_options,
}
@property
def validator(self):
# Non-cast unittests (i.e. upstream Chromium tests) are not MSAN clean, so
# do not block on them until upstream MSAN bots are stabilized.
# (crbug/658452)
if not self._name.startswith(self._unittest_prefix_filter):
return lambda *args: True
return sanitizer_utils.get_validator_for(self._sanitizer)
def get_commands(self):
"""Returns which commands to be run. Can be overridden by a subclass.
Returns:
List of ShellCommand objects to execute.
"""
assert isinstance(self._command, list)
return [self.ShellCommand(
self._command,
validator=self.validator,
cwd=self.directory,
env=self._sanitizer_env)]