blob: 07dd39df8679a873fc46b5a7acc50d606e3a2385 [file] [log] [blame]
# Copyright (C) 2009 Google Inc. All rights reserved.
# Copyright (C) 2017 Apple Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from webkitpy.thirdparty.mock import Mock
from webkitpy.common.host import Host
from webkitpy.common.host_mock import MockHost
from webkitpy.common.net.generictestresults import BindingsTestResults
from webkitpy.common.net.generictestresults import WebkitpyTestResults
from webkitpy.common.net.jsctestresults import JSCTestResults
from webkitpy.common.net.layouttestresults import LayoutTestResults
from webkitpy.common.system.outputcapture import OutputCapture
from webkitpy.layout_tests.models import test_results
from webkitpy.layout_tests.models import test_failures
from webkitpy.port.factory import PortFactory
from webkitpy.tool.bot.queueengine import QueueEngine
from webkitpy.tool.commands.earlywarningsystem import *
from webkitpy.tool.commands.queues import PatchProcessingQueue
from webkitpy.tool.commands.queuestest import QueuesTest
from webkitpy.tool.mocktool import MockTool, MockOptions
# Needed to define port_name, used in AbstractEarlyWarningSystem.__init__
class TestEWS(AbstractEarlyWarningSystem):
port_name = "win" # Needs to be a port which port/factory understands.
_build_style = None
_group = None
class TestJSCEWS(AbstractEarlyWarningSystem):
port_name = "mac" # Needs to be a port which port/factory understands.
_build_style = None
_group = "jsc"
class TestBindingsEWS(AbstractEarlyWarningSystem):
port_name = "mac"
_build_style = None
_group = "bindings"
class TestWebkitpyEWS(AbstractEarlyWarningSystem):
port_name = "mac"
_build_style = None
_group = "webkitpy"
class AbstractEarlyWarningSystemTest(QueuesTest):
def _test_message(self, ews, results, message):
ews.bind_to_tool(MockTool())
ews.host = MockHost()
ews._options = MockOptions(port=None, confirm=False)
OutputCapture().assert_outputs(self, ews.begin_work_queue, expected_logs=self._default_begin_work_queue_logs(ews.name))
task = Mock()
task.results_from_patch_test_run = results
patch = ews._tool.bugs.fetch_attachment(10000)
self.assertMultiLineEqual(ews._failing_tests_message(task, patch), message)
def test_failing_tests_message(self):
ews = TestEWS()
results = lambda a: LayoutTestResults([test_results.TestResult("foo.html", failures=[test_failures.FailureTextMismatch()]),
test_results.TestResult("bar.html", failures=[test_failures.FailureTextMismatch()])],
did_exceed_test_failure_limit=False)
message = "New failing tests:\nfoo.html\nbar.html"
self._test_message(ews, results, message)
def test_failing_jsc_tests_message(self):
ews = TestJSCEWS()
results = lambda a: JSCTestResults(False, ["es6.yaml/es6/typed_arrays_Int8Array.js.default", "es6.yaml/es6/typed_arrays_Uint8Array.js.default"])
message = "New failing tests:\nes6.yaml/es6/typed_arrays_Int8Array.js.default\nes6.yaml/es6/typed_arrays_Uint8Array.js.default\napiTests"
self._test_message(ews, results, message)
def test_failing_bindings_tests_message(self):
ews = TestBindingsEWS()
results = lambda a: BindingsTestResults(["(JS) TestMapLike.idl", "(JS) TestNode.idl"])
message = "New failing tests:\n(JS) TestMapLike.idl\n(JS) TestNode.idl"
self._test_message(ews, results, message)
def test_failing_webkitpy_tests_message(self):
ews = TestWebkitpyEWS()
results = lambda a: WebkitpyTestResults(["webkitpy.tool.commands.earlywarningsystem_unittest.EarlyWarningSystemTest.test_ews_name"])
message = "New failing tests:\nwebkitpy.tool.commands.earlywarningsystem_unittest.EarlyWarningSystemTest.test_ews_name"
self._test_message(ews, results, message)
class MockEarlyWarningSystemTaskForInconclusiveJSCResults(EarlyWarningSystemTask):
def _test_patch(self):
self._test()
results = self._delegate.test_results()
return bool(results)
class MockAbstractEarlyWarningSystemForInconclusiveJSCResults(AbstractEarlyWarningSystem):
def _create_task(self, patch):
task = MockEarlyWarningSystemTaskForInconclusiveJSCResults(self, patch, self._options.run_tests)
return task
class EarlyWarningSystemTest(QueuesTest):
def _default_expected_logs(self, ews, conclusive, work_item, will_fetch_from_status_server=False):
string_replacements = {
"name": ews.name,
"port": ews.port_name,
"architecture": " --architecture=%s" % ews.architecture if ews.architecture else "",
"build_style": ews.build_style(),
"group": ews.group(),
'patch_id': work_item.id() if work_item else QueuesTest.mock_work_item.id(),
}
if will_fetch_from_status_server:
status_server_fetch_line = 'MOCK: fetch_attachment: %(patch_id)s\n' % string_replacements
else:
status_server_fetch_line = ''
string_replacements['status_server_fetch_line'] = status_server_fetch_line
if ews.should_build:
build_line = "%(status_server_fetch_line)sRunning: webkit-patch --status-host=example.com build --no-clean --no-update --build-style=%(build_style)s --group=%(group)s --port=%(port)s%(architecture)s\nMOCK: update_status: %(name)s Built patch\n" % string_replacements
else:
build_line = ""
string_replacements['build_line'] = build_line
if ews.run_tests:
run_tests_line = "%(status_server_fetch_line)sRunning: webkit-patch --status-host=example.com build-and-test --no-clean --no-update --test --non-interactive --build-style=%(build_style)s --group=%(group)s --port=%(port)s%(architecture)s\nMOCK: update_status: %(name)s Passed tests\n" % string_replacements
else:
run_tests_line = ""
string_replacements['run_tests_line'] = run_tests_line
if conclusive:
result_lines = "MOCK: update_status: %(name)s Pass\nMOCK: release_work_item: %(name)s %(patch_id)s\n" % string_replacements
else:
result_lines = "MOCK: release_lock: %(name)s %(patch_id)s\n" % string_replacements
string_replacements['result_lines'] = result_lines
expected_logs = {
"begin_work_queue": self._default_begin_work_queue_logs(ews.name),
"process_work_item": """MOCK: update_status: %(name)s Started processing patch
%(status_server_fetch_line)sRunning: webkit-patch --status-host=example.com clean --port=%(port)s%(architecture)s
MOCK: update_status: %(name)s Cleaned working directory
%(status_server_fetch_line)sRunning: webkit-patch --status-host=example.com update --port=%(port)s%(architecture)s
MOCK: update_status: %(name)s Updated working directory
%(status_server_fetch_line)sRunning: webkit-patch --status-host=example.com apply-attachment --no-update --non-interactive %(patch_id)s --port=%(port)s%(architecture)s
MOCK: update_status: %(name)s Applied patch
%(status_server_fetch_line)sRunning: webkit-patch --status-host=example.com check-patch-relevance --quiet --group=%(group)s --port=%(port)s%(architecture)s
MOCK: update_status: %(name)s Checked relevance of patch
%(build_line)s%(run_tests_line)s%(result_lines)s""" % string_replacements,
"handle_unexpected_error": "Mock error message\n",
"handle_script_error": "ScriptError error message\n\nMOCK output\n",
}
return expected_logs
def _test_ews(self, ews, results_are_conclusive=True, use_security_sensitive_patch=False):
ews.bind_to_tool(MockTool())
ews.host = MockHost()
options = Mock()
options.port = None
options.run_tests = ews.run_tests
work_item = MockTool().bugs.fetch_attachment(10008) if use_security_sensitive_patch else None
self.assert_queue_outputs(ews, work_item=work_item, expected_logs=self._default_expected_logs(ews, results_are_conclusive, work_item, will_fetch_from_status_server=bool(use_security_sensitive_patch)), options=options)
def test_ewses(self):
classes = AbstractEarlyWarningSystem.load_ews_classes()
self.assertTrue(classes)
self.maxDiff = None
for ews_class in classes:
self._test_ews(ews_class())
def test_ewses_with_security_sensitive_patch(self):
classes = AbstractEarlyWarningSystem.load_ews_classes()
self.assertTrue(classes)
self.maxDiff = None
for ews_class in classes:
self._test_ews(ews_class(), use_security_sensitive_patch=True)
def test_inconclusive_jsc_test_results(self):
classes = MockAbstractEarlyWarningSystemForInconclusiveJSCResults.load_ews_classes()
self.assertTrue(classes)
self.maxDiff = None
test_classes = filter(lambda x: x.run_tests and x.group == "jsc", classes)
for ews_class in test_classes:
self._test_ews(ews_class(), False)
def test_ews_name(self):
# These are the names EWS's infrastructure expects, check that they work
expected_names = {
'bindings-ews',
'gtk-wk2-ews',
'ios-ews',
'ios-sim-ews',
'jsc-ews',
'jsc-i386-ews',
'jsc-mips-ews',
'jsc-armv7-ews',
'mac-debug-ews',
'mac-ews',
'mac-wk2-ews',
'webkitpy-ews',
'win-ews',
'wpe-ews',
'wincairo-ews',
}
classes = AbstractEarlyWarningSystem.load_ews_classes()
names = {cls.name for cls in classes}
missing_names = expected_names - names
unexpected_names = names - expected_names
if missing_names:
raise AssertionError("'{}' is not a valid EWS command but is used by EWS's infrastructure".format(missing_names.pop()))
if unexpected_names:
raise AssertionError("'{}' is a valid EWS command but is not used by EWS's infrastructure".format(unexpected_names.pop()))