Skip to content

Commit

Permalink
[Android Test] Send whether random app crashed to resultdb
Browse files Browse the repository at this point in the history
This CL propagates "whether a random app crashed during the test
execution and showed a system dialog" to resultdb.
test_runner.py propagates this via the 'failure_reason' field in the
test_result proto.

BUG=1107896

Change-Id: Idf6ae89c02216fee11ec5b7ae9fa112679bcaed0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3010217
Reviewed-by: Andrew Grieve <agrieve@chromium.org>
Reviewed-by: Haiyang Pan <hypan@google.com>
Commit-Queue: Peter Kotwicz <pkotwicz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#907297}
  • Loading branch information
pkotwicz authored and Chromium LUCI CQ committed Jul 30, 2021
1 parent 815e90b commit f6f7ef2
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 9 deletions.
15 changes: 14 additions & 1 deletion build/android/pylib/base/base_test_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def GetTypes():
class BaseTestResult(object):
"""Base class for a single test result."""

def __init__(self, name, test_type, duration=0, log=''):
def __init__(self, name, test_type, duration=0, log='', failure_reason=None):
"""Construct a BaseTestResult.
Args:
Expand All @@ -51,6 +51,7 @@ def __init__(self, name, test_type, duration=0, log=''):
self._test_type = test_type
self._duration = duration
self._log = log
self._failure_reason = failure_reason
self._links = {}

def __str__(self):
Expand Down Expand Up @@ -101,6 +102,18 @@ def GetLog(self):
"""Get the test log."""
return self._log

def SetFailureReason(self, failure_reason):
"""Set the reason the test failed."""
self._failure_reason = failure_reason

def GetFailureReason(self):
"""Get the reason the test failed.
Returns None if the test did not fail or if the reason the test failed is
unknown.
"""
return self._failure_reason

def SetLink(self, name, link_url):
"""Set link with test result data."""
self._links[name] = link_url
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -803,11 +803,18 @@ def stop_chrome_proxy():
for r in results:
if r.GetType() == base_test_result.ResultType.UNKNOWN:
r.SetType(base_test_result.ResultType.CRASH)
if (crashed_packages and len(results) == 1
and results[0].GetType() != base_test_result.ResultType.PASS):
elif (crashed_packages and len(results) == 1
and results[0].GetType() != base_test_result.ResultType.PASS):
# Add log message and set failure reason if:
# 1) The app crash was likely not caused by the test.
# AND
# 2) The app crash possibly caused the test to fail.
# Crashes of the package under test are assumed to be the test's fault.
_AppendToLogForResult(
results[0], 'OS displayed error dialogs for {}'.format(
', '.join(crashed_packages)))
results[0].SetFailureReason('{} Crashed'.format(
','.join(crashed_packages)))
except device_errors.CommandTimeoutError:
logging.warning('timed out when detecting/dismissing error dialogs')
# Attach screenshot to the test to help with debugging the dialog boxes.
Expand Down
11 changes: 7 additions & 4 deletions build/android/test_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -935,10 +935,13 @@ def json_writer():
match.group(1)) if match else None
# Some tests put in non utf-8 char as part of the test
# which breaks uploads, so need to decode and re-encode.
result_sink_client.Post(
r.GetName(), r.GetType(), r.GetDuration(),
r.GetLog().decode('utf-8', 'replace').encode('utf-8'),
test_file_name)
result_sink_client.Post(r.GetName(),
r.GetType(),
r.GetDuration(),
r.GetLog().decode(
'utf-8', 'replace').encode('utf-8'),
test_file_name,
failure_reason=r.GetFailureReason())

@contextlib.contextmanager
def upload_logcats_file():
Expand Down
14 changes: 12 additions & 2 deletions build/util/lib/results/result_sink.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,14 @@ def __init__(self, context):
'Authorization': 'ResultSink %s' % context['auth_token'],
}

def Post(self, test_id, status, duration, test_log, test_file,
artifacts=None):
def Post(self,
test_id,
status,
duration,
test_log,
test_file,
artifacts=None,
failure_reason=None):
"""Uploads the test result to the ResultSink server.
This assumes that the rdb stream has been called already and that
Expand All @@ -72,6 +78,8 @@ def Post(self, test_id, status, duration, test_log, test_file,
test_log: A string representing the test's output.
test_file: A string representing the file location of the test.
artifacts: An optional dict of artifacts to attach to the test.
failure_reason: An optional string with the reason why the test failed.
Should be None if the test did not fail.
Returns:
N/A
Expand Down Expand Up @@ -108,6 +116,8 @@ def Post(self, test_id, status, duration, test_log, test_file,
tr['summaryHtml'] = '<text-artifact artifact-id="Test Log" />'
if artifacts:
tr['artifacts'] = artifacts
if failure_reason:
tr['failureReason']['primaryErrorMessage'] = failure_reason

if duration is not None:
# Duration must be formatted to avoid scientific notation in case
Expand Down

0 comments on commit f6f7ef2

Please sign in to comment.