Title: [213722] trunk/Tools
Revision
213722
Author
commit-qu...@webkit.org
Date
2017-03-10 11:24:47 -0800 (Fri, 10 Mar 2017)

Log Message

Add support for Bindings EWS
https://bugs.webkit.org/show_bug.cgi?id=169308

Patch by Srinivasan Vijayaraghavan <svijayaragha...@apple.com> on 2017-03-10
Reviewed by Alexey Proskuryakov.

* Scripts/webkitpy/common/config/ews.json: Add bindings-ews. Can test without building; should_build = False.
* Scripts/webkitpy/common/net/bindingstestresults.py:
(BindingsTestResults.__init__): Removed 'errors'.
(BindingsTestResults.results_from_string): Ditto.
(BindingsTestResults.is_subset): Ditto.
(BindingsTestResults.equals): Ditto.
(BindingsTestResults.all_passed): Ditto.
(BindingsTestResults.failing_tests): Ditto.
* Scripts/webkitpy/common/net/bindingstestresults_unittest.py:
(BindingsTestResultsTest.test_results_from_string): Removed 'errors'.
(BindingsTestResultsTest.test_results_from_string_success): Removed 'errors'.
* Scripts/webkitpy/tool/bot/earlywarningsystemtask.py:
(EarlyWarningSystemTask.__init__): Add should_build parameter.
(EarlyWarningSystemTask.run): Check should_build before calling self._build().
* Scripts/webkitpy/tool/bot/retrylogic_unittest.py: Renamed from Tools/Scripts/webkitpy/tool/bot/jscews_unittest.py.
(MockBindingsEarlyWarningSystem): Based of MockJSCEarlyWarningSystem. Mocked so we can provide test results.
(MockBindingsEarlyWarningSystem.__init__): Sets attributes.
(MockBindingsEarlyWarningSystem.test_results): Returns test results provided by us, instead of JSON output.
(BindingsEarlyWarningSystemTest): Class to test retry logic in below situations.
(BindingsEarlyWarningSystemTest._results_indicate_all_passed): False if None or or has failures, else True.
(BindingsEarlyWarningSystemTest._create_task):
(BindingsEarlyWarningSystemTest.test_success_case): Clean patch on clean tree.
(BindingsEarlyWarningSystemTest.test_test_failure): Red patch on clean tree.
(BindingsEarlyWarningSystemTest.test_fix): Clean patch on red tree.
(BindingsEarlyWarningSystemTest.test_ineffective_patch): Red patch on red tree.
(BindingsEarlyWarningSystemTest.test_partially_effective_patch): Red patch on redder tree.
(BindingsEarlyWarningSystemTest.test_different_test_failures_in_patch_and_tree): Red patch on red tree.
* Scripts/webkitpy/tool/bot/patchanalysistask.py:
(PatchAnalysisTask._build_and_test_without_patch): Don't build if should_build is False (eg. on Bindings EWS).
(PatchAnalysisTask._retry_bindings_tests): Retry logic for Bindings tests.
(PatchAnalysisTask._test_patch): If tests failed on Bindings EWS, and call _retry_bindings_tests.
* Scripts/webkitpy/tool/commands/earlywarningsystem.py:
(AbstractEarlyWarningSystem.begin_work_queue): Use BindingsTestResultsReader on Bindings EWS.
(AbstractEarlyWarningSystem._create_task): Pass should_build argument.
(AbstractEarlyWarningSystem.load_ews_classes): Add should_build argument (True by default).
* Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py:
(TestBindingsEWS): Bindings EWS class, derived from AbstractEarlyWarningSystem.
(AbstractEarlyWarningSystemTest.test_failing_bindings_tests_message): Unit test message posted to Bugzilla.
(EarlyWarningSystemTest._default_expected_logs): Not building on all ewses anymore; make build line optional.
(EarlyWarningSystemTest.test_ews_name): Add bindings-ews.
* Scripts/webkitpy/tool/steps/checkpatchrelevance.py:
(CheckPatchRelevance): Add bindings paths.
(CheckPatchRelevance._changes_are_relevant): Cleaner way to check if we should perform this step.
* Scripts/webkitpy/tool/steps/steps_unittest.py: Add unit tests for Bindings EWS patch relevance.
(test_patch_relevant_bindings): Test for patch relevant to bindings.
(test_patch_not_relevant_bindings): Test for patch not relevant to bindings.

Modified Paths

Added Paths

Removed Paths

Diff

Modified: trunk/Tools/ChangeLog (213721 => 213722)


--- trunk/Tools/ChangeLog	2017-03-10 19:15:23 UTC (rev 213721)
+++ trunk/Tools/ChangeLog	2017-03-10 19:24:47 UTC (rev 213722)
@@ -1,3 +1,57 @@
+2017-03-10  Srinivasan Vijayaraghavan  <svijayaragha...@apple.com>
+
+        Add support for Bindings EWS
+        https://bugs.webkit.org/show_bug.cgi?id=169308
+
+        Reviewed by Alexey Proskuryakov.
+
+        * Scripts/webkitpy/common/config/ews.json: Add bindings-ews. Can test without building; should_build = False.
+        * Scripts/webkitpy/common/net/bindingstestresults.py:
+        (BindingsTestResults.__init__): Removed 'errors'.
+        (BindingsTestResults.results_from_string): Ditto.
+        (BindingsTestResults.is_subset): Ditto.
+        (BindingsTestResults.equals): Ditto.
+        (BindingsTestResults.all_passed): Ditto.
+        (BindingsTestResults.failing_tests): Ditto.
+        * Scripts/webkitpy/common/net/bindingstestresults_unittest.py:
+        (BindingsTestResultsTest.test_results_from_string): Removed 'errors'.
+        (BindingsTestResultsTest.test_results_from_string_success): Removed 'errors'.
+        * Scripts/webkitpy/tool/bot/earlywarningsystemtask.py:
+        (EarlyWarningSystemTask.__init__): Add should_build parameter.
+        (EarlyWarningSystemTask.run): Check should_build before calling self._build().
+        * Scripts/webkitpy/tool/bot/retrylogic_unittest.py: Renamed from Tools/Scripts/webkitpy/tool/bot/jscews_unittest.py.
+        (MockBindingsEarlyWarningSystem): Based of MockJSCEarlyWarningSystem. Mocked so we can provide test results.
+        (MockBindingsEarlyWarningSystem.__init__): Sets attributes.
+        (MockBindingsEarlyWarningSystem.test_results): Returns test results provided by us, instead of JSON output.
+        (BindingsEarlyWarningSystemTest): Class to test retry logic in below situations.
+        (BindingsEarlyWarningSystemTest._results_indicate_all_passed): False if None or or has failures, else True.
+        (BindingsEarlyWarningSystemTest._create_task):
+        (BindingsEarlyWarningSystemTest.test_success_case): Clean patch on clean tree.
+        (BindingsEarlyWarningSystemTest.test_test_failure): Red patch on clean tree.
+        (BindingsEarlyWarningSystemTest.test_fix): Clean patch on red tree.
+        (BindingsEarlyWarningSystemTest.test_ineffective_patch): Red patch on red tree.
+        (BindingsEarlyWarningSystemTest.test_partially_effective_patch): Red patch on redder tree.
+        (BindingsEarlyWarningSystemTest.test_different_test_failures_in_patch_and_tree): Red patch on red tree.
+        * Scripts/webkitpy/tool/bot/patchanalysistask.py:
+        (PatchAnalysisTask._build_and_test_without_patch): Don't build if should_build is False (eg. on Bindings EWS).
+        (PatchAnalysisTask._retry_bindings_tests): Retry logic for Bindings tests.
+        (PatchAnalysisTask._test_patch): If tests failed on Bindings EWS, and call _retry_bindings_tests.
+        * Scripts/webkitpy/tool/commands/earlywarningsystem.py:
+        (AbstractEarlyWarningSystem.begin_work_queue): Use BindingsTestResultsReader on Bindings EWS.
+        (AbstractEarlyWarningSystem._create_task): Pass should_build argument.
+        (AbstractEarlyWarningSystem.load_ews_classes): Add should_build argument (True by default).
+        * Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py:
+        (TestBindingsEWS): Bindings EWS class, derived from AbstractEarlyWarningSystem.
+        (AbstractEarlyWarningSystemTest.test_failing_bindings_tests_message): Unit test message posted to Bugzilla.
+        (EarlyWarningSystemTest._default_expected_logs): Not building on all ewses anymore; make build line optional.
+        (EarlyWarningSystemTest.test_ews_name): Add bindings-ews.
+        * Scripts/webkitpy/tool/steps/checkpatchrelevance.py:
+        (CheckPatchRelevance): Add bindings paths.
+        (CheckPatchRelevance._changes_are_relevant): Cleaner way to check if we should perform this step.
+        * Scripts/webkitpy/tool/steps/steps_unittest.py: Add unit tests for Bindings EWS patch relevance.
+        (test_patch_relevant_bindings): Test for patch relevant to bindings.
+        (test_patch_not_relevant_bindings): Test for patch not relevant to bindings.
+
 2017-03-09  Simon Fraser  <simon.fra...@apple.com>
 
         [iOS WK2] Layer content blurry with nested perspective and transforms

Modified: trunk/Tools/Scripts/webkitpy/common/config/ews.json (213721 => 213722)


--- trunk/Tools/Scripts/webkitpy/common/config/ews.json	2017-03-10 19:15:23 UTC (rev 213721)
+++ trunk/Tools/Scripts/webkitpy/common/config/ews.json	2017-03-10 19:24:47 UTC (rev 213722)
@@ -51,5 +51,12 @@
         "name": "jsc-ews",
         "group": "jsc",
         "runTests": true
+    },
+    "Bindings EWS": {
+        "port": "mac",
+        "name": "bindings-ews",
+        "group": "bindings",
+        "runTests": true,
+        "shouldBuild": false
     }
 }

Modified: trunk/Tools/Scripts/webkitpy/common/net/bindingstestresults.py (213721 => 213722)


--- trunk/Tools/Scripts/webkitpy/common/net/bindingstestresults.py	2017-03-10 19:15:23 UTC (rev 213721)
+++ trunk/Tools/Scripts/webkitpy/common/net/bindingstestresults.py	2017-03-10 19:24:47 UTC (rev 213722)
@@ -28,12 +28,9 @@
 
 
 class BindingsTestResults(AbstractTestResults):
-    def __init__(self, failures, errors):
+    def __init__(self, failures):
         self._failures = failures
-        self._errors = errors
 
-        self._failing_test_names = failures + errors
-
     @classmethod
     def results_from_string(cls, string):
         parsed_results = cls.parse_json_string(string)
@@ -40,22 +37,22 @@
         if not parsed_results:
             return None
 
-        if 'failures' not in parsed_results or 'errors' not in parsed_results:
+        if 'failures' not in parsed_results:
             return None
 
-        return cls(parsed_results['failures'], parsed_results['errors'])
+        return cls(parsed_results['failures'])
 
     def is_subset(self, other):
-        return set(self._failures) <= set(other._failures) and set(self._errors) <= set(other._errors)
+        return set(self._failures) <= set(other._failures)
 
     def equals(self, other):
-        return set(self._failures) == set(other._failures) and set(self._errors) == set(other._errors)
+        return set(self._failures) == set(other._failures)
 
     def all_passed(self):
-        return not self._failures and not self._errors
+        return not self._failures
 
     def failing_tests(self):
-        return self._failing_test_names
+        return self._failures
 
     # No defined failure limit for bindings tests.
     def did_exceed_test_failure_limit(self):

Modified: trunk/Tools/Scripts/webkitpy/common/net/bindingstestresults_unittest.py (213721 => 213722)


--- trunk/Tools/Scripts/webkitpy/common/net/bindingstestresults_unittest.py	2017-03-10 19:15:23 UTC (rev 213721)
+++ trunk/Tools/Scripts/webkitpy/common/net/bindingstestresults_unittest.py	2017-03-10 19:24:47 UTC (rev 213722)
@@ -27,17 +27,15 @@
 
 class BindingsTestResultsTest(unittest.TestCase):
     def test_results_from_string(self):
-        incomplete_json_v1 = '{"failures": []}'
-        incomplete_json_v2 = '{"errors":[]}'
-        self.assertEqual(None, BindingsTestResults.results_from_string(incomplete_json_v1))
-        self.assertEqual(None, BindingsTestResults.results_from_string(incomplete_json_v2))
+        incomplete_json = '{"key2": []}'
+        self.assertEqual(None, BindingsTestResults.results_from_string(incomplete_json))
 
     def test_results_from_string_success(self):
-        no_failures_string = '{"failures": [], "errors":[]}'
-        no_failures_results = BindingsTestResults([], [])
+        no_failures_string = '{"failures": []}'
+        no_failures_results = BindingsTestResults([])
         self.assertTrue(no_failures_results.equals(BindingsTestResults.results_from_string(no_failures_string)))
         self.assertTrue(no_failures_results.all_passed())
 
-        test_string = '{"failures": ["failure1"], "errors": ["error1", "error2"]}'
-        test_results = BindingsTestResults(["failure1"], ["error1", "error2"])
+        test_string = '{"failures": ["failure1"]}'
+        test_results = BindingsTestResults(["failure1"])
         self.assertTrue(test_results.equals(BindingsTestResults.results_from_string(test_string)))

Modified: trunk/Tools/Scripts/webkitpy/tool/bot/earlywarningsystemtask.py (213721 => 213722)


--- trunk/Tools/Scripts/webkitpy/tool/bot/earlywarningsystemtask.py	2017-03-10 19:15:23 UTC (rev 213721)
+++ trunk/Tools/Scripts/webkitpy/tool/bot/earlywarningsystemtask.py	2017-03-10 19:24:47 UTC (rev 213722)
@@ -35,9 +35,10 @@
 
 
 class EarlyWarningSystemTask(PatchAnalysisTask):
-    def __init__(self, delegate, patch, should_run_tests=True):
+    def __init__(self, delegate, patch, should_run_tests=True, should_build=True):
         PatchAnalysisTask.__init__(self, delegate, patch)
         self._should_run_tests = should_run_tests
+        self._should_build = should_build
 
     def validate(self):
         self._patch = self._delegate.refetch_patch(self._patch)
@@ -61,10 +62,11 @@
             raise UnableToApplyPatch(self._patch)
         if not self._check_patch_relevance():
             raise PatchIsNotApplicable(self._patch)
-        if not self._build():
-            if not self._build_without_patch():
-                return False
-            return self.report_failure()
+        if self._should_build:
+            if not self._build():
+                if not self._build_without_patch():
+                    return False
+                return self.report_failure()
         if not self._should_run_tests:
             return True
         return self._test_patch()

Deleted: trunk/Tools/Scripts/webkitpy/tool/bot/jscews_unittest.py (213721 => 213722)


--- trunk/Tools/Scripts/webkitpy/tool/bot/jscews_unittest.py	2017-03-10 19:15:23 UTC (rev 213721)
+++ trunk/Tools/Scripts/webkitpy/tool/bot/jscews_unittest.py	2017-03-10 19:24:47 UTC (rev 213722)
@@ -1,218 +0,0 @@
-# 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:
-# 1.  Redistributions of source code must retain the above copyright
-#     notice, this list of conditions and the following disclaimer.
-# 2.  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.
-#
-# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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.
-
-import logging
-import unittest
-
-from webkitpy.common.net.jsctestresults import JSCTestResults
-from webkitpy.common.system.executive import ScriptError
-from webkitpy.tool.bot.patchanalysistask import *
-from webkitpy.tool.commands.earlywarningsystem import AbstractEarlyWarningSystem
-from webkitpy.tool.mocktool import MockTool
-
-_log = logging.getLogger(__name__)
-
-
-class MockPatchAnalysisTask(PatchAnalysisTask):
-    def __init__(self, delegate, patch, patches_passed_all_tests):
-        self._delegate = delegate
-        self._patch = patch
-        self._script_error = None
-        self._results_archive_from_patch_test_run = None
-        self._results_from_patch_test_run = None
-        self.error = None
-        self._patches_passed_all_tests = patches_passed_all_tests
-        self._test_run_count = 0
-        self.failure_status_id = 0
-
-    def _test(self):
-        self._test_run_count += 1
-
-        if self._patches_passed_all_tests.pop() == True:
-            return True
-        self._script_error = ScriptError('Regression test')
-        return False
-
-    def _build_and_test_without_patch(self):
-        self._test_run_count += 1
-        return True
-
-    def validate(self):
-        return True
-
-    def test_run_count(self):
-        return self._test_run_count
-
-
-# This is the delegate to be used with MockPatchAnalysisTask, above.
-class MockJSCEarlyWarningSystem(AbstractEarlyWarningSystem):
-    def __init__(self, first_test_results, second_test_results, clean_test_results):
-        AbstractEarlyWarningSystem.__init__(self)
-        self._group = 'jsc'
-        self._results_in_order = [clean_test_results, second_test_results, first_test_results]
-
-    def test_results(self):
-        return self._results_in_order.pop()
-
-
-class JSCEarlyWarningSystemTest(unittest.TestCase):
-    def _results_indicate_all_passed(self, results):
-        if results == None:
-            return False
-        return results.all_passed()
-
-    def _create_task(self, first_test_results, second_test_results, clean_test_results):
-        queue = MockJSCEarlyWarningSystem(first_test_results, second_test_results, clean_test_results)
-        tool = MockTool(log_executive=True)
-        patch = tool.bugs.fetch_attachment(10000)
-        patches_passed_all_tests = map(self._results_indicate_all_passed, [second_test_results, first_test_results])
-        return MockPatchAnalysisTask(queue, patch, patches_passed_all_tests)
-
-    def test_success_case(self):
-        first_test_results = JSCTestResults(True, [])
-        second_test_results = JSCTestResults(True, [])
-        clean_test_results = JSCTestResults(True, [])
-        task = self._create_task(first_test_results, second_test_results, clean_test_results)
-
-        return_value = task._test_patch()
-        self.assertEqual(task.test_run_count(), 1)
-        self.assertTrue(return_value)
-
-    def test_test_failure(self):
-        first_test_results = JSCTestResults(True, ['Fail.js'])
-        second_test_results = JSCTestResults(True, ['Fail.js'])
-        clean_test_results = JSCTestResults(True, [])
-        task = self._create_task(first_test_results, second_test_results, clean_test_results)
-
-        with self.assertRaises(ScriptError):
-            return_value = task._test_patch()
-        self.assertEqual(task.test_run_count(), 3)
-
-    def test_fix(self):
-        first_test_results = JSCTestResults(True, [])
-        second_test_results = JSCTestResults(True, [])
-        clean_test_results = JSCTestResults(True, ['Fail.js'])
-        task = self._create_task(first_test_results, second_test_results, clean_test_results)
-
-        return_value = task._test_patch()
-        self.assertEqual(task.test_run_count(), 1)
-        self.assertTrue(return_value)
-
-    def test_ineffective_patch(self):
-        first_test_results = JSCTestResults(False, ['failure1.js', 'failure2.js'])
-        second_test_results = JSCTestResults(False, ['failure1.js', 'failure2.js'])
-        clean_test_results = JSCTestResults(False, ['failure1.js', 'failure2.js'])
-        task = self._create_task(first_test_results, second_test_results, clean_test_results)
-
-        return_value = task._test_patch()
-        self.assertEqual(task.test_run_count(), 3)
-        self.assertTrue(return_value)
-
-    def test_partially_effective_patch(self):
-        first_test_results = JSCTestResults(True, ['failure2.js'])
-        second_test_results = JSCTestResults(True, ['failure2.js'])
-        clean_test_results = JSCTestResults(False, ['failure1.js', 'failure2.js'])
-        task = self._create_task(first_test_results, second_test_results, clean_test_results)
-
-        return_value = task._test_patch()
-        self.assertEqual(task.test_run_count(), 3)
-        self.assertTrue(return_value)
-
-    def test_different_test_failures_in_patch_and_tree(self):
-        first_test_results = JSCTestResults(False, [])
-        second_test_results = JSCTestResults(False, [])
-        clean_test_results = JSCTestResults(True, ['failure1.js', 'failure2.js'])
-        task = self._create_task(first_test_results, second_test_results, clean_test_results)
-
-        with self.assertRaises(ScriptError):
-            return_value = task._test_patch()
-        self.assertEqual(task.test_run_count(), 3)
-
-    def test_first_results_could_not_be_read(self):
-        first_test_results = None
-        second_test_results = JSCTestResults(True, [])
-        clean_test_results = JSCTestResults(True, [])
-        task = self._create_task(first_test_results, second_test_results, clean_test_results)
-
-        return_value = task._test_patch()
-        self.assertEqual(task.test_run_count(), 1)
-        self.assertFalse(return_value)
-
-    def test_second_results_could_not_be_read(self):
-        first_test_results = JSCTestResults(False, ['failure1.js', 'failure2.js'])
-        second_test_results = None
-        clean_test_results = JSCTestResults(True, [])
-        task = self._create_task(first_test_results, second_test_results, clean_test_results)
-
-        return_value = task._test_patch()
-        self.assertEqual(task.test_run_count(), 2)
-        self.assertFalse(return_value)
-
-    def test_clean_results_could_not_be_read(self):
-        first_test_results = JSCTestResults(True, ['failure2.js'])
-        second_test_results = JSCTestResults(True, ['failure2.js'])
-        clean_test_results = None
-        task = self._create_task(first_test_results, second_test_results, clean_test_results)
-
-        return_value = task._test_patch()
-        self.assertEqual(task.test_run_count(), 3)
-        self.assertFalse(return_value)
-
-    def test_flaky_results_on_clean_tree_pass(self):
-        first_test_results = JSCTestResults(True, ['failure2.js'])
-        second_test_results = JSCTestResults(True, [])
-        clean_test_results = JSCTestResults(True, [])
-        task = self._create_task(first_test_results, second_test_results, clean_test_results)
-
-        return_value = task._test_patch()
-        self.assertTrue(return_value)
-        self.assertEqual(task.test_run_count(), 2)
-
-    def test_flaky_results_on_clean_tree_pass_v2(self):
-        first_test_results = JSCTestResults(True, [])
-        second_test_results = JSCTestResults(True, ['failure2.js'])
-        clean_test_results = JSCTestResults(True, [])
-        task = self._create_task(first_test_results, second_test_results, clean_test_results)
-
-        return_value = task._test_patch()
-        self.assertTrue(return_value)
-        self.assertEqual(task.test_run_count(), 1)
-
-    def test_flaky_results_on_clean_tree_failure(self):
-        first_test_results = JSCTestResults(False, ['failure1.js', 'failure2.js'])
-        second_test_results = JSCTestResults(True, ['failure2.js'])
-        clean_test_results = JSCTestResults(True, [])
-        task = self._create_task(first_test_results, second_test_results, clean_test_results)
-
-        with self.assertRaises(ScriptError):
-            task._test_patch()
-        self.assertEqual(task.test_run_count(), 3)
-
-    def test_flaky_results_on_red_tree_pass(self):
-        first_test_results = JSCTestResults(True, ['failure1.js'])
-        second_test_results = JSCTestResults(True, ['failure1.js', 'failure2.js'])
-        clean_test_results = JSCTestResults(True, ['failure1.js'])
-        task = self._create_task(first_test_results, second_test_results, clean_test_results)
-
-        return_value = task._test_patch()
-        self.assertTrue(return_value)
-        self.assertEqual(task.test_run_count(), 3)

Modified: trunk/Tools/Scripts/webkitpy/tool/bot/patchanalysistask.py (213721 => 213722)


--- trunk/Tools/Scripts/webkitpy/tool/bot/patchanalysistask.py	2017-03-10 19:15:23 UTC (rev 213721)
+++ trunk/Tools/Scripts/webkitpy/tool/bot/patchanalysistask.py	2017-03-10 19:24:47 UTC (rev 213722)
@@ -186,12 +186,14 @@
             "build-and-test",
             "--force-clean",
             "--no-update",
-            "--build",
             "--test",
             "--non-interactive",
             "--build-style=%s" % self._delegate.build_style(),
         ]
 
+        if getattr(self._delegate, 'should_build', True):
+            args.append("--build")
+
         if hasattr(self._delegate, 'group'):
             args.append("--group=%s" % self._delegate.group())
 
@@ -235,6 +237,30 @@
         # also present without the patch, so we don't need to defer.
         return False
 
+    def _retry_bindings_tests(self):
+        first_results = self._delegate.test_results()
+        first_script_error = self._script_error
+        first_failure_status_id = self.failure_status_id
+        if first_results is None:
+            return False
+
+        # Some errors are not correctly reported by the run-bindings-tests script
+        # https://bugs.webkit.org/show_bug.cgi?id=169449
+        # In affected cases, add a message requesting to look at test output instead.
+        if not first_results._failures:
+            first_results._failures = ["Please see test output for results"]
+
+        self._build_and_test_without_patch()
+        clean_tree_results = self._delegate.test_results()
+        if clean_tree_results is None:
+            return False
+
+        if first_results.is_subset(clean_tree_results):
+            return True
+
+        self.failure_status_id = first_failure_status_id
+        return self.report_failure(None, first_results, first_script_error)
+
     # FIXME: Abstract out common parts of the retry logic.
     def _retry_jsc_tests(self):
         first_results = self._delegate.test_results()
@@ -338,6 +364,8 @@
 
         if hasattr(self._delegate, 'group') and self._delegate.group() == "jsc":
             return self._retry_jsc_tests()
+        elif hasattr(self._delegate, 'group') and self._delegate.group() == "bindings":
+            return self._retry_bindings_tests()
         else:
             return self._retry_layout_tests()
 

Copied: trunk/Tools/Scripts/webkitpy/tool/bot/retrylogic_unittest.py (from rev 213719, trunk/Tools/Scripts/webkitpy/tool/bot/jscews_unittest.py) (0 => 213722)


--- trunk/Tools/Scripts/webkitpy/tool/bot/retrylogic_unittest.py	                        (rev 0)
+++ trunk/Tools/Scripts/webkitpy/tool/bot/retrylogic_unittest.py	2017-03-10 19:24:47 UTC (rev 213722)
@@ -0,0 +1,297 @@
+# 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:
+# 1.  Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+# 2.  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.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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.
+
+import logging
+import unittest
+
+from webkitpy.common.net.bindingstestresults import BindingsTestResults
+from webkitpy.common.net.jsctestresults import JSCTestResults
+from webkitpy.common.system.executive import ScriptError
+from webkitpy.tool.bot.patchanalysistask import *
+from webkitpy.tool.commands.earlywarningsystem import AbstractEarlyWarningSystem
+from webkitpy.tool.mocktool import MockTool
+
+_log = logging.getLogger(__name__)
+
+
+class MockPatchAnalysisTask(PatchAnalysisTask):
+    def __init__(self, delegate, patch, patches_passed_all_tests):
+        self._delegate = delegate
+        self._patch = patch
+        self._script_error = None
+        self._results_archive_from_patch_test_run = None
+        self._results_from_patch_test_run = None
+        self.error = None
+        self._patches_passed_all_tests = patches_passed_all_tests
+        self._test_run_count = 0
+        self.failure_status_id = 0
+
+    def _test(self):
+        self._test_run_count += 1
+
+        if self._patches_passed_all_tests.pop() == True:
+            return True
+        self._script_error = ScriptError('Regression test')
+        return False
+
+    def _build_and_test_without_patch(self):
+        self._test_run_count += 1
+        return True
+
+    def validate(self):
+        return True
+
+    def test_run_count(self):
+        return self._test_run_count
+
+
+# This is the delegate to be used with MockPatchAnalysisTask, above.
+class MockJSCEarlyWarningSystem(AbstractEarlyWarningSystem):
+    def __init__(self, first_test_results, second_test_results, clean_test_results):
+        AbstractEarlyWarningSystem.__init__(self)
+        self._group = 'jsc'
+        self._results_in_order = [clean_test_results, second_test_results, first_test_results]
+
+    def test_results(self):
+        return self._results_in_order.pop()
+
+
+class JSCEarlyWarningSystemTest(unittest.TestCase):
+    def _results_indicate_all_passed(self, results):
+        if results == None:
+            return False
+        return results.all_passed()
+
+    def _create_task(self, first_test_results, second_test_results, clean_test_results):
+        queue = MockJSCEarlyWarningSystem(first_test_results, second_test_results, clean_test_results)
+        tool = MockTool(log_executive=True)
+        patch = tool.bugs.fetch_attachment(10000)
+        patches_passed_all_tests = map(self._results_indicate_all_passed, [second_test_results, first_test_results])
+        return MockPatchAnalysisTask(queue, patch, patches_passed_all_tests)
+
+    def test_success_case(self):
+        first_test_results = JSCTestResults(True, [])
+        second_test_results = JSCTestResults(True, [])
+        clean_test_results = JSCTestResults(True, [])
+        task = self._create_task(first_test_results, second_test_results, clean_test_results)
+
+        return_value = task._test_patch()
+        self.assertEqual(task.test_run_count(), 1)
+        self.assertTrue(return_value)
+
+    def test_test_failure(self):
+        first_test_results = JSCTestResults(True, ['Fail.js'])
+        second_test_results = JSCTestResults(True, ['Fail.js'])
+        clean_test_results = JSCTestResults(True, [])
+        task = self._create_task(first_test_results, second_test_results, clean_test_results)
+
+        with self.assertRaises(ScriptError):
+            return_value = task._test_patch()
+        self.assertEqual(task.test_run_count(), 3)
+
+    def test_fix(self):
+        first_test_results = JSCTestResults(True, [])
+        second_test_results = JSCTestResults(True, [])
+        clean_test_results = JSCTestResults(True, ['Fail.js'])
+        task = self._create_task(first_test_results, second_test_results, clean_test_results)
+
+        return_value = task._test_patch()
+        self.assertEqual(task.test_run_count(), 1)
+        self.assertTrue(return_value)
+
+    def test_ineffective_patch(self):
+        first_test_results = JSCTestResults(False, ['failure1.js', 'failure2.js'])
+        second_test_results = JSCTestResults(False, ['failure1.js', 'failure2.js'])
+        clean_test_results = JSCTestResults(False, ['failure1.js', 'failure2.js'])
+        task = self._create_task(first_test_results, second_test_results, clean_test_results)
+
+        return_value = task._test_patch()
+        self.assertEqual(task.test_run_count(), 3)
+        self.assertTrue(return_value)
+
+    def test_partially_effective_patch(self):
+        first_test_results = JSCTestResults(True, ['failure2.js'])
+        second_test_results = JSCTestResults(True, ['failure2.js'])
+        clean_test_results = JSCTestResults(False, ['failure1.js', 'failure2.js'])
+        task = self._create_task(first_test_results, second_test_results, clean_test_results)
+
+        return_value = task._test_patch()
+        self.assertEqual(task.test_run_count(), 3)
+        self.assertTrue(return_value)
+
+    def test_different_test_failures_in_patch_and_tree(self):
+        first_test_results = JSCTestResults(False, [])
+        second_test_results = JSCTestResults(False, [])
+        clean_test_results = JSCTestResults(True, ['failure1.js', 'failure2.js'])
+        task = self._create_task(first_test_results, second_test_results, clean_test_results)
+
+        with self.assertRaises(ScriptError):
+            return_value = task._test_patch()
+        self.assertEqual(task.test_run_count(), 3)
+
+    def test_first_results_could_not_be_read(self):
+        first_test_results = None
+        second_test_results = JSCTestResults(True, [])
+        clean_test_results = JSCTestResults(True, [])
+        task = self._create_task(first_test_results, second_test_results, clean_test_results)
+
+        return_value = task._test_patch()
+        self.assertEqual(task.test_run_count(), 1)
+        self.assertFalse(return_value)
+
+    def test_second_results_could_not_be_read(self):
+        first_test_results = JSCTestResults(False, ['failure1.js', 'failure2.js'])
+        second_test_results = None
+        clean_test_results = JSCTestResults(True, [])
+        task = self._create_task(first_test_results, second_test_results, clean_test_results)
+
+        return_value = task._test_patch()
+        self.assertEqual(task.test_run_count(), 2)
+        self.assertFalse(return_value)
+
+    def test_clean_results_could_not_be_read(self):
+        first_test_results = JSCTestResults(True, ['failure2.js'])
+        second_test_results = JSCTestResults(True, ['failure2.js'])
+        clean_test_results = None
+        task = self._create_task(first_test_results, second_test_results, clean_test_results)
+
+        return_value = task._test_patch()
+        self.assertEqual(task.test_run_count(), 3)
+        self.assertFalse(return_value)
+
+    def test_flaky_results_on_clean_tree_pass(self):
+        first_test_results = JSCTestResults(True, ['failure2.js'])
+        second_test_results = JSCTestResults(True, [])
+        clean_test_results = JSCTestResults(True, [])
+        task = self._create_task(first_test_results, second_test_results, clean_test_results)
+
+        return_value = task._test_patch()
+        self.assertTrue(return_value)
+        self.assertEqual(task.test_run_count(), 2)
+
+    def test_flaky_results_on_clean_tree_pass_v2(self):
+        first_test_results = JSCTestResults(True, [])
+        second_test_results = JSCTestResults(True, ['failure2.js'])
+        clean_test_results = JSCTestResults(True, [])
+        task = self._create_task(first_test_results, second_test_results, clean_test_results)
+
+        return_value = task._test_patch()
+        self.assertTrue(return_value)
+        self.assertEqual(task.test_run_count(), 1)
+
+    def test_flaky_results_on_clean_tree_failure(self):
+        first_test_results = JSCTestResults(False, ['failure1.js', 'failure2.js'])
+        second_test_results = JSCTestResults(True, ['failure2.js'])
+        clean_test_results = JSCTestResults(True, [])
+        task = self._create_task(first_test_results, second_test_results, clean_test_results)
+
+        with self.assertRaises(ScriptError):
+            task._test_patch()
+        self.assertEqual(task.test_run_count(), 3)
+
+    def test_flaky_results_on_red_tree_pass(self):
+        first_test_results = JSCTestResults(True, ['failure1.js'])
+        second_test_results = JSCTestResults(True, ['failure1.js', 'failure2.js'])
+        clean_test_results = JSCTestResults(True, ['failure1.js'])
+        task = self._create_task(first_test_results, second_test_results, clean_test_results)
+
+        return_value = task._test_patch()
+        self.assertTrue(return_value)
+        self.assertEqual(task.test_run_count(), 3)
+
+
+class MockBindingsEarlyWarningSystem(AbstractEarlyWarningSystem):
+    def __init__(self, first_test_results, clean_test_results):
+        AbstractEarlyWarningSystem.__init__(self)
+        self._group = 'bindings'
+        self._results_in_order = [clean_test_results, first_test_results]
+
+    def test_results(self):
+        return self._results_in_order.pop()
+
+
+class BindingsEarlyWarningSystemTest(unittest.TestCase):
+    def _results_indicate_all_passed(self, results):
+        if results == None:
+            return False
+        return results.all_passed()
+
+    def _create_task(self, first_test_results, clean_test_results):
+        queue = MockBindingsEarlyWarningSystem(first_test_results, clean_test_results)
+        tool = MockTool(log_executive=True)
+        patch = tool.bugs.fetch_attachment(10000)
+        patches_passed_all_tests = [self._results_indicate_all_passed(first_test_results)]
+        return MockPatchAnalysisTask(queue, patch, patches_passed_all_tests)
+
+    def test_success_case(self):
+        first_test_results = BindingsTestResults([])
+        clean_test_results = BindingsTestResults([])
+        task = self._create_task(first_test_results, clean_test_results)
+
+        return_value = task._test_patch()
+        self.assertEqual(task.test_run_count(), 1)
+        self.assertTrue(return_value)
+
+    def test_test_failure(self):
+        first_test_results = BindingsTestResults(['TestMapLike.idl'])
+        clean_test_results = BindingsTestResults([])
+        task = self._create_task(first_test_results, clean_test_results)
+
+        with self.assertRaises(ScriptError):
+            return_value = task._test_patch()
+        self.assertEqual(task.test_run_count(), 2)
+
+    def test_fix(self):
+        first_test_results = BindingsTestResults([])
+        clean_test_results = BindingsTestResults(['TestMapLike.idl'])
+        task = self._create_task(first_test_results, clean_test_results)
+
+        return_value = task._test_patch()
+        self.assertEqual(task.test_run_count(), 1)
+        self.assertTrue(return_value)
+
+    def test_ineffective_patch(self):
+        first_test_results = BindingsTestResults(['TestMapLike.idl'])
+        clean_test_results = BindingsTestResults(['TestMapLike.idl'])
+        task = self._create_task(first_test_results, clean_test_results)
+
+        return_value = task._test_patch()
+        self.assertEqual(task.test_run_count(), 2)
+        self.assertTrue(return_value)
+
+    def test_partially_effective_patch(self):
+        first_test_results = BindingsTestResults(['TestMapLike.idl'])
+        clean_test_results = BindingsTestResults(['TestMapLike.idl', 'TestNode.idl'])
+        task = self._create_task(first_test_results, clean_test_results)
+
+        return_value = task._test_patch()
+        self.assertEqual(task.test_run_count(), 2)
+        self.assertTrue(return_value)
+
+    def test_different_test_failures_in_patch_and_tree(self):
+        first_test_results = BindingsTestResults(['TestNode.idl'])
+        clean_test_results = BindingsTestResults(['TestMapLike.idl'])
+        task = self._create_task(first_test_results, clean_test_results)
+
+        with self.assertRaises(ScriptError):
+            return_value = task._test_patch()
+        self.assertEqual(task.test_run_count(), 2)

Modified: trunk/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py (213721 => 213722)


--- trunk/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py	2017-03-10 19:15:23 UTC (rev 213721)
+++ trunk/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py	2017-03-10 19:24:47 UTC (rev 213722)
@@ -37,6 +37,7 @@
 from webkitpy.common.system.filesystem import FileSystem
 from webkitpy.common.system.executive import ScriptError
 from webkitpy.tool.bot.earlywarningsystemtask import EarlyWarningSystemTask, EarlyWarningSystemTaskDelegate
+from webkitpy.tool.bot.bindingstestresultsreader import BindingsTestResultsReader
 from webkitpy.tool.bot.layouttestresultsreader import LayoutTestResultsReader
 from webkitpy.tool.bot.jsctestresultsreader import JSCTestResultsReader
 from webkitpy.tool.bot.patchanalysistask import UnableToApplyPatch, PatchIsNotValid, PatchIsNotApplicable
@@ -59,6 +60,8 @@
 
         if self.group() == "jsc":
             self._test_results_reader = JSCTestResultsReader(self._tool, self._port.jsc_results_directory())
+        elif self.group() == "bindings":
+            self._test_results_reader = BindingsTestResultsReader(self._tool, self._port.jsc_results_directory())
         else:
             self._test_results_reader = LayoutTestResultsReader(self._tool, self._port.results_directory(), self._log_directory())
 
@@ -88,7 +91,7 @@
 
     # This exists for mocking
     def _create_task(self, patch):
-        return EarlyWarningSystemTask(self, patch, self._options.run_tests)
+        return EarlyWarningSystemTask(self, patch, should_run_tests=self._options.run_tests, should_build=self.should_build)
 
     def review_patch(self, patch):
         task = self._create_task(patch)
@@ -174,5 +177,6 @@
                 'watchers': config.get('watchers', []),
                 'run_tests': config.get('runTests', cls.run_tests),
                 '_group': config.get('group', None),
+                'should_build': config.get('shouldBuild', True),
             }))
         return classes

Modified: trunk/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py (213721 => 213722)


--- trunk/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py	2017-03-10 19:15:23 UTC (rev 213721)
+++ trunk/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py	2017-03-10 19:24:47 UTC (rev 213722)
@@ -30,6 +30,7 @@
 from webkitpy.thirdparty.mock import Mock
 from webkitpy.common.host import Host
 from webkitpy.common.host_mock import MockHost
+from webkitpy.common.net.bindingstestresults import BindingsTestResults
 from webkitpy.common.net.jsctestresults import JSCTestResults
 from webkitpy.common.net.layouttestresults import LayoutTestResults
 from webkitpy.common.system.outputcapture import OutputCapture
@@ -56,6 +57,12 @@
     _group = "jsc"
 
 
+class TestBindingsEWS(AbstractEarlyWarningSystem):
+    port_name = "mac"
+    _build_style = None
+    _group = "bindings"
+
+
 class AbstractEarlyWarningSystemTest(QueuesTest):
     def _test_message(self, ews, results, message):
         ews.bind_to_tool(MockTool())
@@ -81,7 +88,13 @@
         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)
 
+
 class MockEarlyWarningSystemTaskForInconclusiveJSCResults(EarlyWarningSystemTask):
     def _test_patch(self):
         self._test()
@@ -104,6 +117,13 @@
             "build_style": ews.build_style(),
             "group": ews.group(),
         }
+
+        if ews.should_build:
+            build_line = "Running: webkit-patch --status-host=example.com build --no-clean --no-update --build-style=%(build_style)s --group=%(group)s --port=%(port)s%(architecture)s\n" % string_replacements
+        else:
+            build_line = ""
+        string_replacements['build_line'] = build_line
+
         if ews.run_tests:
             run_tests_line = "Running: 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\n" % string_replacements
         else:
@@ -123,8 +143,7 @@
 Running: webkit-patch --status-host=example.com update --port=%(port)s%(architecture)s
 Running: webkit-patch --status-host=example.com apply-attachment --no-update --non-interactive 10000 --port=%(port)s%(architecture)s
 Running: webkit-patch --status-host=example.com check-patch-relevance --group=%(group)s --port=%(port)s%(architecture)s
-Running: webkit-patch --status-host=example.com build --no-clean --no-update --build-style=%(build_style)s --group=%(group)s --port=%(port)s%(architecture)s
-%(run_tests_line)s%(result_lines)s""" % string_replacements,
+%(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",
         }
@@ -164,6 +183,7 @@
             'mac-wk2-ews',
             'mac-debug-ews',
             'mac-32bit-ews',
+            'bindings-ews',
             'jsc-ews',
         }
         classes = AbstractEarlyWarningSystem.load_ews_classes()

Modified: trunk/Tools/Scripts/webkitpy/tool/steps/checkpatchrelevance.py (213721 => 213722)


--- trunk/Tools/Scripts/webkitpy/tool/steps/checkpatchrelevance.py	2017-03-10 19:15:23 UTC (rev 213721)
+++ trunk/Tools/Scripts/webkitpy/tool/steps/checkpatchrelevance.py	2017-03-10 19:24:47 UTC (rev 213722)
@@ -37,6 +37,11 @@
             Options.group,
         ]
 
+    bindings_paths = [
+        "Source/WebCore",
+        "Tools",
+    ]
+
     jsc_paths = [
         "JSTests/",
         "Source/_javascript_Core/",
@@ -52,12 +57,13 @@
     ]
 
     group_to_paths_mapping = {
+        'bindings': bindings_paths,
         'jsc': jsc_paths,
     }
 
     def _changes_are_relevant(self, changed_files):
         # In the default case, all patches are relevant
-        if self._options.group != 'jsc':
+        if self._options.group not in self.group_to_paths_mapping:
             return True
 
         patterns = self.group_to_paths_mapping[self._options.group]

Modified: trunk/Tools/Scripts/webkitpy/tool/steps/steps_unittest.py (213721 => 213722)


--- trunk/Tools/Scripts/webkitpy/tool/steps/steps_unittest.py	2017-03-10 19:15:23 UTC (rev 213721)
+++ trunk/Tools/Scripts/webkitpy/tool/steps/steps_unittest.py	2017-03-10 19:24:47 UTC (rev 213722)
@@ -256,3 +256,29 @@
         expected_logs = """MOCK run_and_throw_if_fail: ['Tools/Scripts/run-bindings-tests', '--json-output=/tmp/bindings_test_results.json'], cwd=/mock-checkout
 """
         OutputCapture().assert_outputs(self, step.run, [{}], expected_logs=expected_logs)
+
+    def test_patch_relevant_bindings(self):
+        self.maxDiff = None
+        mock_options = self._step_options()
+        mock_options.group = "bindings"
+        tool = MockTool(log_executive=True)
+        tool.scm()._mockChangedFiles = ["Source/WebCore/features.json", "Source/ChangeLog"]
+        # FIXME: We shouldn't use a real port-object here, but there is too much to mock at the moment.
+        tool._deprecated_port = DeprecatedPort()
+        step = steps.CheckPatchRelevance(tool, mock_options)
+        expected_logs = """Checking relevance of patch
+"""
+        OutputCapture().assert_outputs(self, step.run, [{}], expected_logs=expected_logs)
+
+    def test_patch_not_relevant_bindings(self):
+        self.maxDiff = None
+        mock_options = self._step_options()
+        mock_options.group = "bindings"
+        tool = MockTool(log_executive=True)
+        tool.scm()._mockChangedFiles = ["Source/_javascript_Core/Makefile", "Source/ChangeLog"]
+        # FIXME: We shouldn't use a real port-object here, but there is too much to mock at the moment.
+        tool._deprecated_port = DeprecatedPort()
+        step = steps.CheckPatchRelevance(tool, mock_options)
+        expected_logs = """Checking relevance of patch
+This patch does not have relevant changes.
+"""
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to