blob: 0ff2ad87f852ee0fb8dbd5427006a2bd3363f53c [file] [log] [blame]
# Copyright 2016 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import json
import optparse
from webkitpy.common.net.buildbot import Build
from webkitpy.common.net.git_cl import GitCL
from webkitpy.common.checkout.git_mock import MockGit
from webkitpy.common.net.layout_test_results import LayoutTestResults
from webkitpy.common.system.log_testing import LoggingTestCase
from webkitpy.layout_tests.builder_list import BuilderList
from webkitpy.tool.commands.rebaseline_cl import RebaselineCL
from webkitpy.tool.commands.rebaseline_unittest import BaseTestCase
class RebaselineCLTest(BaseTestCase, LoggingTestCase):
command_constructor = RebaselineCL
def setUp(self):
BaseTestCase.setUp(self)
LoggingTestCase.setUp(self)
builds = [
Build('MOCK Try Win', 5000),
Build('MOCK Try Mac', 4000),
Build('MOCK Try Linux', 6000),
]
git_cl = GitCL(self.tool)
git_cl.get_issue_number = lambda: '11112222'
git_cl.latest_try_jobs = lambda _: builds
self.command.git_cl = lambda: git_cl
git = MockGit(filesystem=self.tool.filesystem, executive=self.tool.executive)
git.changed_files = lambda **_: [
'third_party/WebKit/LayoutTests/fast/dom/prototype-inheritance.html',
'third_party/WebKit/LayoutTests/fast/dom/prototype-taco.html',
]
self.tool.git = lambda: git
self.tool.builders = BuilderList({
'MOCK Try Win': {
'port_name': 'test-win-win7',
'specifiers': ['Win7', 'Release'],
'is_try_builder': True,
},
'MOCK Try Linux': {
'port_name': 'test-linux-trusty',
'specifiers': ['Trusty', 'Release'],
'is_try_builder': True,
},
'MOCK Try Mac': {
'port_name': 'test-mac-mac10.11',
'specifiers': ['Mac10.11', 'Release'],
'is_try_builder': True,
},
})
layout_test_results = LayoutTestResults({
'tests': {
'fast': {
'dom': {
'prototype-inheritance.html': {
'expected': 'PASS',
'actual': 'TEXT',
'is_unexpected': True,
},
'prototype-banana.html': {
'expected': 'FAIL',
'actual': 'PASS',
'is_unexpected': True,
},
'prototype-taco.html': {
'expected': 'PASS',
'actual': 'PASS TEXT',
'is_unexpected': True,
},
'prototype-chocolate.html': {
'expected': 'FAIL',
'actual': 'IMAGE+TEXT'
},
'prototype-crashy.html': {
'expected': 'PASS',
'actual': 'CRASH',
'is_unexpected': True,
},
'prototype-newtest.html': {
'expected': 'PASS',
'actual': 'MISSING',
'is_unexpected': True,
'is_missing_text': True,
},
'prototype-slowtest.html': {
'expected': 'SLOW',
'actual': 'TEXT',
'is_unexpected': True,
},
}
},
'svg': {
'dynamic-updates': {
'SVGFEDropShadowElement-dom-stdDeviation-attr.html': {
'expected': 'PASS',
'actual': 'IMAGE',
'has_stderr': True,
'is_unexpected': True,
}
}
}
}
})
for build in builds:
self.tool.buildbot.set_results(build, layout_test_results)
self.tool.buildbot.set_retry_sumary_json(build, json.dumps({
'failures': [
'fast/dom/prototype-inheritance.html',
'fast/dom/prototype-newtest.html',
'fast/dom/prototype-slowtest.html',
'fast/dom/prototype-taco.html',
'svg/dynamic-updates/SVGFEDropShadowElement-dom-stdDeviation-attr.html',
],
'ignored': [],
}))
# Write to the mock filesystem so that these tests are considered to exist.
tests = [
'fast/dom/prototype-taco.html',
'fast/dom/prototype-inheritance.html',
'fast/dom/prototype-newtest.html',
'svg/dynamic-updates/SVGFEDropShadowElement-dom-stdDeviation-attr.html',
]
for test in tests:
self._write(self.mac_port.host.filesystem.join(self.mac_port.layout_tests_dir(), test), 'contents')
def tearDown(self):
BaseTestCase.tearDown(self)
LoggingTestCase.tearDown(self)
@staticmethod
def command_options(**kwargs):
options = {
'only_changed_tests': False,
'dry_run': False,
'optimize': True,
'results_directory': None,
'verbose': False,
'trigger_jobs': False,
}
options.update(kwargs)
return optparse.Values(dict(**options))
def test_execute_with_issue_number_given(self):
return_code = self.command.execute(self.command_options(), [], self.tool)
self.assertEqual(return_code, 0)
self.assertLog([
'INFO: Rebaselining fast/dom/prototype-inheritance.html\n',
'INFO: Rebaselining fast/dom/prototype-newtest.html\n',
'INFO: Rebaselining fast/dom/prototype-slowtest.html\n',
'INFO: Rebaselining fast/dom/prototype-taco.html\n',
'INFO: Rebaselining svg/dynamic-updates/SVGFEDropShadowElement-dom-stdDeviation-attr.html\n',
])
def test_execute_with_no_issue_number(self):
git_cl = GitCL(self.tool)
git_cl.get_issue_number = lambda: 'None'
self.command.git_cl = lambda: git_cl
return_code = self.command.execute(self.command_options(), [], self.tool)
self.assertEqual(return_code, 1)
self.assertLog(['ERROR: No issue number for current branch.\n'])
def test_execute_with_issue_number_from_branch(self):
return_code = self.command.execute(self.command_options(), [], self.tool)
self.assertEqual(return_code, 0)
self.assertLog([
'INFO: Rebaselining fast/dom/prototype-inheritance.html\n',
'INFO: Rebaselining fast/dom/prototype-newtest.html\n',
'INFO: Rebaselining fast/dom/prototype-slowtest.html\n',
'INFO: Rebaselining fast/dom/prototype-taco.html\n',
'INFO: Rebaselining svg/dynamic-updates/SVGFEDropShadowElement-dom-stdDeviation-attr.html\n',
])
def test_execute_with_only_changed_tests_option(self):
return_code = self.command.execute(self.command_options(only_changed_tests=True), [], self.tool)
self.assertEqual(return_code, 0)
# svg/dynamic-updates/SVGFEDropShadowElement-dom-stdDeviation-attr.html
# is in the list of failed tests, but not in the list of files modified
# in the given CL; it should be included because all_tests is set to True.
self.assertLog([
'INFO: Rebaselining fast/dom/prototype-inheritance.html\n',
'INFO: Rebaselining fast/dom/prototype-taco.html\n',
])
def test_execute_with_flaky_test_that_fails_on_retry(self):
# In this example, the --only-changed-tests flag is not given, but
# svg/dynamic-updates/SVGFEDropShadowElement-dom-stdDeviation-attr.html
# failed both with and without the patch in the try job, so it is not
# rebaselined.
builds = [
Build('MOCK Try Win', 5000),
Build('MOCK Try Mac', 4000),
Build('MOCK Try Linux', 6000),
]
for build in builds:
self.tool.buildbot.set_retry_sumary_json(build, json.dumps({
'failures': [
'fast/dom/prototype-taco.html',
'fast/dom/prototype-inheritance.html',
],
'ignored': ['svg/dynamic-updates/SVGFEDropShadowElement-dom-stdDeviation-attr.html'],
}))
return_code = self.command.execute(self.command_options(), [], self.tool)
self.assertEqual(return_code, 0)
self.assertLog([
'INFO: Rebaselining fast/dom/prototype-inheritance.html\n',
'INFO: Rebaselining fast/dom/prototype-taco.html\n',
])
def test_execute_with_no_retry_summary_downloaded(self):
# In this example, the --only-changed-tests flag is not given, but
# svg/dynamic-updates/SVGFEDropShadowElement-dom-stdDeviation-attr.html
# failed both with and without the patch in the try job, so it is not
# rebaselined.
self.tool.buildbot.set_retry_sumary_json(Build('MOCK Try Win', 5000), None)
return_code = self.command.execute(self.command_options(), [], self.tool)
self.assertEqual(return_code, 0)
self.assertLog([
'WARNING: No retry summary available for build Build(builder_name=\'MOCK Try Win\', build_number=5000).\n',
'INFO: Rebaselining fast/dom/prototype-inheritance.html\n',
'INFO: Rebaselining fast/dom/prototype-newtest.html\n',
'INFO: Rebaselining fast/dom/prototype-slowtest.html\n',
'INFO: Rebaselining fast/dom/prototype-taco.html\n',
'INFO: Rebaselining svg/dynamic-updates/SVGFEDropShadowElement-dom-stdDeviation-attr.html\n',
])
def test_execute_with_trigger_jobs_option(self):
builds = [
Build('MOCK Try Win', 5000),
Build('MOCK Try Mac', 4000),
]
git_cl = GitCL(self.tool)
git_cl.get_issue_number = lambda: '11112222'
git_cl.latest_try_jobs = lambda _: builds
self.command.git_cl = lambda: git_cl
return_code = self.command.execute(self.command_options(trigger_jobs=True), [], self.tool)
self.assertEqual(return_code, 1)
self.assertLog([
'INFO: Triggering try jobs for:\n',
'INFO: MOCK Try Linux\n',
'INFO: Please re-run webkit-patch rebaseline-cl once all pending try jobs have finished.\n',
])
self.assertEqual(
self.tool.executive.calls,
[
[
'python',
'/mock-checkout/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/manifest',
'--work',
'--tests-root',
'/mock-checkout/third_party/WebKit/LayoutTests/external/wpt'
],
['git', 'cl', 'try', '-m', 'tryserver.blink', '-b', 'MOCK Try Linux']
])
def test_rebaseline_calls(self):
"""Tests the list of commands that are invoked when rebaseline is called."""
# First write test contents to the mock filesystem so that
# fast/dom/prototype-taco.html is considered a real test to rebaseline.
port = self.tool.port_factory.get('test-win-win7')
self._write(
port.host.filesystem.join(port.layout_tests_dir(), 'fast/dom/prototype-taco.html'),
'test contents')
self.command.rebaseline(
self.command_options(),
{'fast/dom/prototype-taco.html': {Build('MOCK Try Win', 5000): ['txt', 'png']}})
self.assertEqual(
self.tool.executive.calls,
[
[['python', 'echo', 'copy-existing-baselines-internal', '--suffixes', 'txt',
'--builder', 'MOCK Try Win', '--test', 'fast/dom/prototype-taco.html']],
[['python', 'echo', 'rebaseline-test-internal', '--suffixes', 'txt',
'--builder', 'MOCK Try Win', '--test', 'fast/dom/prototype-taco.html', '--build-number', '5000']],
[['python', 'echo', 'optimize-baselines', '--suffixes', 'txt', 'fast/dom/prototype-taco.html']]
])
def test_trigger_builds(self):
# The trigger_builds method just uses git cl to trigger jobs for the given builders.
self.command.trigger_builds(['MOCK Try Linux', 'MOCK Try Win'])
self.assertEqual(
self.tool.executive.calls,
[['git', 'cl', 'try', '-m', 'tryserver.blink', '-b', 'MOCK Try Linux', '-b', 'MOCK Try Win']])
self.assertLog([
'INFO: Triggering try jobs for:\n',
'INFO: MOCK Try Linux\n',
'INFO: MOCK Try Win\n',
])
def test_builders_with_pending_builds(self):
# A build number of None implies that a job has been started but not finished yet.
self.assertEqual(
self.command.builders_with_pending_builds([Build('MOCK Try Linux', None), Build('MOCK Try Win', 123)]),
{'MOCK Try Linux'})
def test_bails_when_one_build_is_missing_results(self):
self.tool.buildbot.set_results(Build('MOCK Try Win', 5000), None)
return_code = self.command.execute(self.command_options(), [], self.tool)
self.assertEqual(return_code, 1)
self.assertLog([
'ERROR: Failed to fetch results from '
'"https://storage.googleapis.com/chromium-layout-test-archives/MOCK_Try_Win/5000/layout-test-results".\n'
'Try starting a new job for MOCK Try Win by running :\n'
' git cl try -b MOCK Try Win\n'
])
def test_bails_when_there_are_unstaged_baselines(self):
git = self.tool.git()
git.unstaged_changes = lambda: {'third_party/WebKit/LayoutTests/my-test-expected.txt': '?'}
return_code = self.command.execute(self.command_options(), [], self.tool)
self.assertEqual(return_code, 1)
self.assertLog([
'ERROR: Aborting: there are unstaged baselines:\n',
'ERROR: /mock-checkout/third_party/WebKit/LayoutTests/my-test-expected.txt\n',
])