Commit 1ba34078 authored by Brian Sheedy's avatar Brian Sheedy Committed by Commit Bot

Hide flaky RenderTests on trybots

Adds an ignore:1 to the JSON uploaded to Gold from the Android
RenderTests if we are running on a trybot and it is not the final
retry attempt. This is to counter flaky tests causing unrelated CLs to
receive comments from Gold when the test causes their CL to produce a
new image. With this change, CLs will only receive a comment if a
test fails consistently.

Bug: skia:10787
Change-Id: I827de961e49a357f1755d6931b89468e27bebac6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2446717Reviewed-by: default avatarTibor Goldschwendt <tiborg@chromium.org>
Commit-Queue: Brian Sheedy <bsheedy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#814807}
parent 43001197
...@@ -100,6 +100,7 @@ class LocalDeviceEnvironment(environment.Environment): ...@@ -100,6 +100,7 @@ class LocalDeviceEnvironment(environment.Environment):
def __init__(self, args, output_manager, _error_func): def __init__(self, args, output_manager, _error_func):
super(LocalDeviceEnvironment, self).__init__(output_manager) super(LocalDeviceEnvironment, self).__init__(output_manager)
self._current_try = 0
self._denylist = (device_denylist.Denylist(args.denylist_file) self._denylist = (device_denylist.Denylist(args.denylist_file)
if args.denylist_file else None) if args.denylist_file else None)
self._device_serials = args.test_devices self._device_serials = args.test_devices
...@@ -188,6 +189,13 @@ class LocalDeviceEnvironment(environment.Environment): ...@@ -188,6 +189,13 @@ class LocalDeviceEnvironment(environment.Environment):
self.parallel_devices.pMap(prepare_device) self.parallel_devices.pMap(prepare_device)
@property
def current_try(self):
return self._current_try
def IncrementCurrentTry(self):
self._current_try += 1
@property @property
def denylist(self): def denylist(self):
return self._denylist return self._denylist
......
...@@ -1037,6 +1037,10 @@ class LocalDeviceInstrumentationTestRun( ...@@ -1037,6 +1037,10 @@ class LocalDeviceInstrumentationTestRun(
# that implies that we aren't actively maintaining baselines for the # that implies that we aren't actively maintaining baselines for the
# test. This helps prevent unrelated CLs from getting comments posted to # test. This helps prevent unrelated CLs from getting comments posted to
# them. # them.
# Additionally, add the ignore if we're running on a trybot and this is
# not our final retry attempt in order to prevent unrelated CLs from
# getting spammed if a test is flaky.
optional_keys = {}
with open(json_path) as infile: with open(json_path) as infile:
# All the key/value pairs in the JSON file are strings, so convert # All the key/value pairs in the JSON file are strings, so convert
# to a bool. # to a bool.
...@@ -1044,13 +1048,20 @@ class LocalDeviceInstrumentationTestRun( ...@@ -1044,13 +1048,20 @@ class LocalDeviceInstrumentationTestRun(
fail_on_unsupported = json_dict.get('fail_on_unsupported_configs', fail_on_unsupported = json_dict.get('fail_on_unsupported_configs',
'false') 'false')
fail_on_unsupported = fail_on_unsupported.lower() == 'true' fail_on_unsupported = fail_on_unsupported.lower() == 'true'
should_hide_failure = ( running_on_unsupported = (
device.build_version_sdk not in RENDER_TEST_MODEL_SDK_CONFIGS.get( device.build_version_sdk not in RENDER_TEST_MODEL_SDK_CONFIGS.get(
device.product_model, []) and not fail_on_unsupported) device.product_model, []) and not fail_on_unsupported)
# TODO(skbug.com/10787): Remove the ignore on non-final retry once we
# fully switch over to using the Gerrit plugin for surfacing Gold
# information since it does not spam people with emails due to automated
# comments.
not_final_retry = self._env.current_try + 1 != self._env.max_tries
tryjob_but_not_final_retry =\
not_final_retry and gold_properties.IsTryjobRun()
should_hide_failure =\
running_on_unsupported or tryjob_but_not_final_retry
if should_hide_failure: if should_hide_failure:
json_dict['ignore'] = '1' optional_keys['ignore'] = '1'
with open(json_path, 'w') as outfile:
json.dump(json_dict, outfile)
gold_session = self._skia_gold_session_manager.GetSkiaGoldSession( gold_session = self._skia_gold_session_manager.GetSkiaGoldSession(
keys_input=json_path) keys_input=json_path)
...@@ -1060,7 +1071,8 @@ class LocalDeviceInstrumentationTestRun( ...@@ -1060,7 +1071,8 @@ class LocalDeviceInstrumentationTestRun(
name=render_name, name=render_name,
png_file=image_path, png_file=image_path,
output_manager=self._env.output_manager, output_manager=self._env.output_manager,
use_luci=use_luci) use_luci=use_luci,
optional_keys=optional_keys)
except Exception as e: # pylint: disable=broad-except except Exception as e: # pylint: disable=broad-except
_FailTestIfNecessary(results) _FailTestIfNecessary(results)
_AppendToLog(results, 'Skia Gold comparison raised exception: %s' % e) _AppendToLog(results, 'Skia Gold comparison raised exception: %s' % e)
......
...@@ -135,8 +135,8 @@ class LocalDeviceTestRun(test_run.TestRun): ...@@ -135,8 +135,8 @@ class LocalDeviceTestRun(test_run.TestRun):
try: try:
with signal_handler.AddSignalHandler(signal.SIGTERM, stop_tests): with signal_handler.AddSignalHandler(signal.SIGTERM, stop_tests):
tries = 0 while self._env.current_try < self._env.max_tries and tests:
while tries < self._env.max_tries and tests: tries = self._env.current_try
grouped_tests = self._GroupTests(tests) grouped_tests = self._GroupTests(tests)
logging.info('STARTING TRY #%d/%d', tries + 1, self._env.max_tries) logging.info('STARTING TRY #%d/%d', tries + 1, self._env.max_tries)
if tries > 0 and self._env.recover_devices: if tries > 0 and self._env.recover_devices:
...@@ -189,7 +189,7 @@ class LocalDeviceTestRun(test_run.TestRun): ...@@ -189,7 +189,7 @@ class LocalDeviceTestRun(test_run.TestRun):
log=_SIGTERM_TEST_LOG)) log=_SIGTERM_TEST_LOG))
raise raise
tries += 1 self._env.IncrementCurrentTry()
tests = self._GetTestsToRetry(tests, try_results) tests = self._GetTestsToRetry(tests, try_results)
logging.info('FINISHED TRY #%d/%d', tries, self._env.max_tries) logging.info('FINISHED TRY #%d/%d', tries, self._env.max_tries)
......
...@@ -20,7 +20,8 @@ class OutputManagerlessSkiaGoldSession(skia_gold_session.SkiaGoldSession): ...@@ -20,7 +20,8 @@ class OutputManagerlessSkiaGoldSession(skia_gold_session.SkiaGoldSession):
png_file, png_file,
output_manager=True, output_manager=True,
inexact_matching_args=None, inexact_matching_args=None,
use_luci=True): use_luci=True,
optional_keys=None):
# Passing True for the output manager is a bit of a hack, as we don't # Passing True for the output manager is a bit of a hack, as we don't
# actually need an output manager and just need to get past the truthy # actually need an output manager and just need to get past the truthy
# check. # check.
...@@ -29,7 +30,8 @@ class OutputManagerlessSkiaGoldSession(skia_gold_session.SkiaGoldSession): ...@@ -29,7 +30,8 @@ class OutputManagerlessSkiaGoldSession(skia_gold_session.SkiaGoldSession):
png_file=png_file, png_file=png_file,
output_manager=output_manager, output_manager=output_manager,
inexact_matching_args=inexact_matching_args, inexact_matching_args=inexact_matching_args,
use_luci=use_luci) use_luci=use_luci,
optional_keys=optional_keys)
def _CreateDiffOutputDir(self): def _CreateDiffOutputDir(self):
# We intentionally don't clean this up and don't put it in self._working_dir # We intentionally don't clean this up and don't put it in self._working_dir
......
...@@ -82,7 +82,8 @@ class SkiaGoldSession(object): ...@@ -82,7 +82,8 @@ class SkiaGoldSession(object):
png_file, png_file,
output_manager, output_manager,
inexact_matching_args=None, inexact_matching_args=None,
use_luci=True): use_luci=True,
optional_keys=None):
"""Helper method to run all steps to compare a produced image. """Helper method to run all steps to compare a produced image.
Handles authentication, itnitialization, comparison, and, if necessary, Handles authentication, itnitialization, comparison, and, if necessary,
...@@ -101,6 +102,10 @@ class SkiaGoldSession(object): ...@@ -101,6 +102,10 @@ class SkiaGoldSession(object):
use_luci: If true, authentication will use the service account provided by use_luci: If true, authentication will use the service account provided by
the LUCI context. If false, will attempt to use whatever is set up in the LUCI context. If false, will attempt to use whatever is set up in
gsutil, which is only supported for local runs. gsutil, which is only supported for local runs.
optional_keys: A dict containing optional key/value pairs to pass to Gold
for this comparison. Optional keys are keys unrelated to the
configuration the image was produced on, e.g. a comment or whether
Gold should treat the image as ignored.
Returns: Returns:
A tuple (status, error). |status| is a value from A tuple (status, error). |status| is a value from
...@@ -118,7 +123,8 @@ class SkiaGoldSession(object): ...@@ -118,7 +123,8 @@ class SkiaGoldSession(object):
compare_rc, compare_stdout = self.Compare( compare_rc, compare_stdout = self.Compare(
name=name, name=name,
png_file=png_file, png_file=png_file,
inexact_matching_args=inexact_matching_args) inexact_matching_args=inexact_matching_args,
optional_keys=optional_keys)
if not compare_rc: if not compare_rc:
return self.StatusCodes.SUCCESS, None return self.StatusCodes.SUCCESS, None
...@@ -227,7 +233,11 @@ class SkiaGoldSession(object): ...@@ -227,7 +233,11 @@ class SkiaGoldSession(object):
self._initialized = True self._initialized = True
return rc, stdout return rc, stdout
def Compare(self, name, png_file, inexact_matching_args=None): def Compare(self,
name,
png_file,
inexact_matching_args=None,
optional_keys=None):
"""Compares the given image to images known to Gold. """Compares the given image to images known to Gold.
Triage links can later be retrieved using GetTriageLinks(). Triage links can later be retrieved using GetTriageLinks().
...@@ -238,6 +248,10 @@ class SkiaGoldSession(object): ...@@ -238,6 +248,10 @@ class SkiaGoldSession(object):
inexact_matching_args: A list of strings containing extra command line inexact_matching_args: A list of strings containing extra command line
arguments to pass to Gold for inexact matching. Can be omitted to use arguments to pass to Gold for inexact matching. Can be omitted to use
exact matching. exact matching.
optional_keys: A dict containing optional key/value pairs to pass to Gold
for this comparison. Optional keys are keys unrelated to the
configuration the image was produced on, e.g. a comment or whether
Gold should treat the image as ignored.
Returns: Returns:
A tuple (return_code, output). |return_code| is the return code of the A tuple (return_code, output). |return_code| is the return code of the
...@@ -267,6 +281,13 @@ class SkiaGoldSession(object): ...@@ -267,6 +281,13 @@ class SkiaGoldSession(object):
inexact_matching_args) inexact_matching_args)
compare_cmd.extend(inexact_matching_args) compare_cmd.extend(inexact_matching_args)
optional_keys = optional_keys or {}
for k, v in optional_keys.iteritems():
compare_cmd.extend([
'--add-test-optional-key',
'%s:%s' % (k, v),
])
self._ClearTriageLinkFile() self._ClearTriageLinkFile()
rc, stdout = self._RunCmdForRcAndOutput(compare_cmd) rc, stdout = self._RunCmdForRcAndOutput(compare_cmd)
......
...@@ -164,7 +164,37 @@ class SkiaGoldSessionRunComparisonTest(fake_filesystem_unittest.TestCase): ...@@ -164,7 +164,37 @@ class SkiaGoldSessionRunComparisonTest(fake_filesystem_unittest.TestCase):
self.assertEqual(diff_mock.call_count, 0) self.assertEqual(diff_mock.call_count, 0)
compare_mock.assert_called_with(name=None, compare_mock.assert_called_with(name=None,
png_file=mock.ANY, png_file=mock.ANY,
inexact_matching_args=['--inexact']) inexact_matching_args=['--inexact'],
optional_keys=None)
@mock.patch.object(skia_gold_session.SkiaGoldSession, 'Diff')
@mock.patch.object(skia_gold_session.SkiaGoldSession, 'Compare')
@mock.patch.object(skia_gold_session.SkiaGoldSession, 'Initialize')
@mock.patch.object(skia_gold_session.SkiaGoldSession, 'Authenticate')
def test_compareOptionalKeys(self, auth_mock, init_mock, compare_mock,
diff_mock):
auth_mock.return_value = (0, None)
init_mock.return_value = (0, None)
compare_mock.return_value = (0, None)
diff_mock.return_value = (0, None)
args = createSkiaGoldArgs(local_pixel_tests=False)
sgp = skia_gold_properties.SkiaGoldProperties(args)
session = skia_gold_session.SkiaGoldSession(self._working_dir, sgp,
self._json_keys, None, None)
status, _ = session.RunComparison(None,
None,
None,
optional_keys={'foo': 'bar'})
self.assertEqual(status,
skia_gold_session.SkiaGoldSession.StatusCodes.SUCCESS)
self.assertEqual(auth_mock.call_count, 1)
self.assertEqual(init_mock.call_count, 1)
self.assertEqual(compare_mock.call_count, 1)
self.assertEqual(diff_mock.call_count, 0)
compare_mock.assert_called_with(name=None,
png_file=mock.ANY,
inexact_matching_args=None,
optional_keys={'foo': 'bar'})
@mock.patch.object(skia_gold_session.SkiaGoldSession, 'Diff') @mock.patch.object(skia_gold_session.SkiaGoldSession, 'Diff')
@mock.patch.object(skia_gold_session.SkiaGoldSession, 'Compare') @mock.patch.object(skia_gold_session.SkiaGoldSession, 'Compare')
...@@ -655,6 +685,17 @@ class SkiaGoldSessionCompareTest(fake_filesystem_unittest.TestCase): ...@@ -655,6 +685,17 @@ class SkiaGoldSessionCompareTest(fake_filesystem_unittest.TestCase):
self.assertIn('Failed to read', self.assertIn('Failed to read',
comparison_result.triage_link_omission_reason) comparison_result.triage_link_omission_reason)
@mock.patch.object(skia_gold_session.SkiaGoldSession, '_RunCmdForRcAndOutput')
def test_optionalKeysPassedToGoldctl(self, cmd_mock):
cmd_mock.return_value = (None, None)
args = createSkiaGoldArgs(git_revision='a', local_pixel_tests=True)
sgp = skia_gold_properties.SkiaGoldProperties(args)
session = skia_gold_session.SkiaGoldSession(self._working_dir, sgp,
self._json_keys, None, None)
session.Compare(None, None, optional_keys={'foo': 'bar'})
assertArgWith(self, cmd_mock.call_args[0][0], '--add-test-optional-key',
'foo:bar')
class SkiaGoldSessionDiffTest(fake_filesystem_unittest.TestCase): class SkiaGoldSessionDiffTest(fake_filesystem_unittest.TestCase):
"""Tests the functionality of SkiaGoldSession.Diff.""" """Tests the functionality of SkiaGoldSession.Diff."""
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment