| Differences between
and this patch
- a/Tools/ChangeLog +129 lines
Lines 1-3 a/Tools/ChangeLog_sec1
1
2017-02-09  Srinivasan Vijayaraghavan  <svijayaraghavan@apple.com>
2
3
        EWS should run JavaScriptCore tests
4
        https://bugs.webkit.org/show_bug.cgi?id=162458
5
6
        Reviewed by NOBODY (OOPS!).
7
8
        * QueueStatusServer/config/queues.py: Add jsc-ews queue
9
        * QueueStatusServer/model/queuestatus.py:
10
        (QueueStatus.did_skip): Returns whether patch was skipped, based on status.
11
        * QueueStatusServer/handlers/statusbubble.py:
12
        (StatusBubble._should_show_bubble_for): Add logic to hide jsc-ews bubble if the patch does not touch jsc.
13
        * Scripts/webkitpy/common/checkout/scm/scm_mock.py:
14
        (MockSCM.__init__): Add _mockChangedFiles variable.
15
        (MockSCM.changed_files): Change to use _mockChangedFiles variables.
16
        * Scripts/webkitpy/common/config/ews.json: Add config info for JSC EWS.
17
        * Scripts/webkitpy/common/config/ports.py: Add support for JSC EWS in Mac Port.
18
        (DeprecatedPort.build_jsc_command): Added - command to build JSC only (quicker than building all of WebKit).
19
        (DeprecatedPort.run_javascriptcore_tests_command): Allow JSC EWS to only run JSC tests.
20
        (MacPort.run_webkit_tests_command): Check for JSC.
21
        * Scripts/webkitpy/common/config/ports_mock.py:
22
        (MockPort.run_javascriptcore_tests_command): Add build_style argument.
23
        * Scripts/webkitpy/common/config/ports_unittest.py:
24
        (DeprecatedPortTest.test_mac_port): Add unit tests for build-jsc shell command.
25
        * Scripts/webkitpy/common/net/jsctestresults.py: Added.
26
        (JSCTestResults): Added.
27
        (JSCTestResults.intersection): Return a JSCTestResults object with failures common to both input objects.
28
        (JSCTestResults.results_from_string): Use json library to parse results.
29
        (JSCTestResults.__init__): Initialize members.
30
        (JSCTestResults.equals): This enables unit testing.
31
        (JSCTestResults.is_subset): Checks if one set of failures is a subset of another.
32
        (JSCTestResults.all_passed): Getter.
33
        (JSCTestResults.failing_test_results): Getter. Some of these exist for interopability reasons.
34
        (JSCTestResults.test_results): Getter.
35
        (JSCTestResults.failing_tests): Getter.
36
        (JSCTestResults.did_exceed_test_failure_limit): Getter.
37
        * Scripts/webkitpy/common/net/jsctestresults_unittest.py: Added.
38
        (JSCTestResultsTest): Class to test JSCTestResults.
39
        (JSCTestResultsTest.test_results_from_string): Tests parsing.
40
        (JSCTestResultsTest.test_intersection_api_tests): Unit test for intersection() class method.
41
        (JSCTestResultsTest.test_intersection_stress_tests): Unit test for intersection() class method.
42
        (JSCTestResultsTest.test_intersection_general_case): Unit test for intersection() class method.
43
        * Scripts/webkitpy/tool/bot/earlywarningsystemtask.py:
44
        (EarlyWarningSystemTask.run): Add check_patch_relevance step.
45
        * Scripts/webkitpy/tool/bot/jscews_unittest.py: Added.
46
        (MockPatchAnalysisTask): Mocked-out version of PatchAnalysisTask that doesn't run commands.
47
        (MockPatchAnalysisTask.__init__): Sets attributes.
48
        (MockPatchAnalysisTask._test): Override to not run command.
49
        (MockPatchAnalysisTask._build_and_test_without_patch): Override to not run command.
50
        (MockPatchAnalysisTask.validate): Assume mocked patch is valid for purposes of testing retry logic.
51
        (MockPatchAnalysisTask.test_run_count): Specific to the mocked version, to test retry logic.
52
        (MockJSCEarlyWarningSystem): Mocked-out version of AbstarctEarlyWarningSystem so we can provide test results.
53
        (MockJSCEarlyWarningSystem.__init__): Sets attributes, also sets group to jsc.
54
        (MockJSCEarlyWarningSystem.test_results): Returns test results provided by us, instead of using a JSON reader.
55
        (JSCEarlyWarningSystemTest): Class to test retry logic in below situations.
56
        (JSCEarlyWarningSystemTest._create_task): Helper function to abstract out common code.
57
        (JSCEarlyWarningSystemTest._results_indicate_all_passed): False if input is None or has failures, else True.
58
        (JSCEarlyWarningSystemTest.test_success_case): Clean patch on clean tree.
59
        (JSCEarlyWarningSystemTest.test_test_failure): Failed patch on clean tree.
60
        (JSCEarlyWarningSystemTest.test_fix): Patch that fixes all tree redness.
61
        (JSCEarlyWarningSystemTest.test_ineffective_patch): Patch that has same failures as tree.
62
        (JSCEarlyWarningSystemTest.test_partially_effective_patch): Patch fixes some failures but adds no new failures.
63
        (JSCEarlyWarningSystemTest.test_different_test_failures_in_patch_and_tree): Patch has some failures not in tree.
64
        (JSCEarlyWarningSystemTest.test_first_results_could_not_be_read): Patch results not readable.
65
        (JSCEarlyWarningSystemTest.test_second_results_could_not_be_read): Patch results not readable on second run.
66
        (JSCEarlyWarningSystemTest.test_clean_results_could_not_be_read): Results from clean tree not readable.
67
        (JSCEarlyWarningSystemTest.test_flaky_results_on_clean_tree_pass): Patch has one flake and no failures.
68
        (JSCEarlyWarningSystemTest.test_flaky_results_on_clean_tree_pass_v2): Patch has one flake and no failures.
69
        (JSCEarlyWarningSystemTest.test_flaky_results_on_clean_tree_failure): Patch has flakes and failed tests.
70
        (JSCEarlyWarningSystemTest.test_flaky_results_on_red_tree_pass): Patch has same failures as tree, plus a flake.
71
        * Scripts/webkitpy/tool/bot/jsctestresultsreader.py: Added.
72
        (JSCTestResultsReader): Reads results file.
73
        (JSCTestResultsReader.__init__): Sets attributes.
74
        (JSCTestResultsReader._read_file_contents): Reads file.
75
        (JSCTestResultsReader._create_jsc_test_results): Creates a JSCTestResults object.
76
        (JSCTestResultsReader.results): Invokes _create_jsc_test_results to return a JSCTestResults object.
77
        * Scripts/webkitpy/tool/bot/patchanalysistask.py:
78
        (PatchIsNotApplicable): Exception for when patch doesn't have relevant changes.
79
        (PatchAnalysisTask._check_patch_relevance): Added.
80
        (PatchAnalysisTask._build): Check for JSC.
81
        (PatchAnalysisTask._build_without_patch): Check for JSC.
82
        (PatchAnalysisTask._test): Check for JSC.
83
        (PatchAnalysisTask._build_and_test_without_patch): Check for JSC.
84
        (PatchAnalysisTask._retry_jsc_tests): Retry logic for JSC EWS.
85
        (PatchAnalysisTask._retry_layout_tests): Retry logic for layout tests EWS.
86
        (PatchAnalysisTask._test_patch): Add retry logic for JSC.
87
        * Scripts/webkitpy/tool/commands/download.py:
88
        (CheckPatchRelevance): Add check-patch-relevance command.
89
        * Scripts/webkitpy/tool/commands/earlywarningsystem.py:
90
        (AbstractEarlyWarningSystem._create_task): Abstract out to enable mocking.
91
        (AbstractEarlyWarningSystem.begin_work_queue): Use JSCTestResultsReader not LayoutTestResultsReader in JSC EWS.
92
        (AbstractEarlyWarningSystem.review_patch): Handle PatchIsApplicable
93
        (AbstractEarlyWarningSystem.test_results): _layout_test_results_reader -> _test_results_reader.
94
        (AbstractEarlyWarningSystem.archive_last_test_results): _layout_test_results_reader -> _test_results_reader.
95
        (AbstractEarlyWarningSystem.group): This attribute determines the type of EWS (eg. JSC).
96
        (AbstractEarlyWarningSystem.load_ews_classes): Add _group, and make classes of type cls to enable mocking.
97
        * Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py:
98
        (TestEWS): Sample layout test EWS class used for unit testing.
99
        (TestJSCEWS): Sample JSC EWS class used for unit testing.
100
        (AbstractEarlyWarningSystemTest.test_failing_tests_message.TestEWS): Add _group.
101
        (AbstractEarlyWarningSystemTest.test_failing_jsc_tests_message.TestEWS): Added test for jsc failures message.
102
        (AbstractEarlyWarningSystemTest): Add _group variable.
103
        (EarlyWarningSystemTest._default_expected_logs): Add check-patch-relevance step, inconclusive logs, and group.
104
        (EarlyWarningSystemTest._test_ews): Add logs_are_conclusive option to pass through to default_expected_logs().
105
        (EarlyWarningSystemTest.test_inconclusive_test_results): Test not removing patch from queue if not conclusive.
106
        (MockAbstractEarlyWarningSystem): Added.
107
        (MockAbstractEarlyWarningSystem.test_results): Simulates inconclusive results.
108
        (MockAbstractEarlyWarningSystem._create_task): Use MockEarlyWarningSystemTask (not EarlyWarningSystemTask).
109
        (MockEarlyWarningSystemTask): Added.
110
        (MockEarlyWarningSystemTask._test_patch): Simulates running tests but not getting a conclusive result.
111
        * Scripts/webkitpy/tool/steps/__init__.py: Add CheckPatchRelevance import.
112
        * Scripts/webkitpy/tool/steps/build.py:
113
        (Build.options): Check for JSC.
114
        (Build.build): Check for JSC.
115
        (Build.run): Check for JSC.
116
        * Scripts/webkitpy/tool/steps/checkpatchrelevance.py: Added.
117
        (CheckPatchRelevance): Added.
118
        (CheckPatchRelevance._does_contain_change_in_paths): Abstract function to perform regex matching.
119
        (CheckPatchRelevance.run): Check if changed files in patch belong in certain folders.
120
        * Scripts/webkitpy/tool/steps/options.py:
121
        (Options): Add --group command line option.
122
        * Scripts/webkitpy/tool/steps/runtests.py:
123
        (RunTests.options): Add group.
124
        (RunTests.run): Check for JSC.
125
        (RunTests._run_webkit_tests): Check for JSC.
126
        (RunTests): Add _group attribute.
127
        (RunTests._run_javascriptcore_tests): New.
128
        * Scripts/webkitpy/tool/steps/steps_unittest.py: Unit tests.
129
1
2017-02-10  Joseph Pecoraro  <pecoraro@apple.com>
130
2017-02-10  Joseph Pecoraro  <pecoraro@apple.com>
2
131
3
        [Resource Timing] Enable Resource Timing by default in Tests
132
        [Resource Timing] Enable Resource Timing by default in Tests
- a/Tools/QueueStatusServer/config/messages.py +2 lines
Lines 1-4 a/Tools/QueueStatusServer/config/messages.py_sec1
1
# Copyright (C) 2013 Google Inc. All rights reserved.
1
# Copyright (C) 2013 Google Inc. All rights reserved.
2
# Copyright (C) 2017 Apple Inc. All rights reserved.
2
#
3
#
3
# Redistribution and use in source and binary forms, with or without
4
# Redistribution and use in source and binary forms, with or without
4
# modification, are permitted provided that the following conditions are
5
# modification, are permitted provided that the following conditions are
Lines 27-32 a/Tools/QueueStatusServer/config/messages.py_sec2
27
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29
29
# These must be in sync with webkit-patch's AbstractQueue.
30
# These must be in sync with webkit-patch's AbstractQueue.
31
skip_status = "Skip"
30
pass_status = "Pass"
32
pass_status = "Pass"
31
fail_status = "Fail"
33
fail_status = "Fail"
32
error_status = "Error"
34
error_status = "Error"
- a/Tools/QueueStatusServer/config/queues.py -1 / +2 lines
Lines 1-4 a/Tools/QueueStatusServer/config/queues.py_sec1
1
# Copyright (C) 2014 Apple Inc. All rights reserved.
1
# Copyright (C) 2014, 2017 Apple Inc. All rights reserved.
2
# Copyright (C) 2013 Google Inc. All rights reserved.
2
# Copyright (C) 2013 Google Inc. All rights reserved.
3
#
3
#
4
# Redistribution and use in source and binary forms, with or without
4
# Redistribution and use in source and binary forms, with or without
Lines 36-41 all_queue_names = [ a/Tools/QueueStatusServer/config/queues.py_sec2
36
    "gtk-wk2-ews",
36
    "gtk-wk2-ews",
37
    "ios-ews",
37
    "ios-ews",
38
    "ios-sim-ews",
38
    "ios-sim-ews",
39
    "jsc-ews",
39
    "mac-ews",
40
    "mac-ews",
40
    "mac-wk2-ews",
41
    "mac-wk2-ews",
41
    "mac-debug-ews",
42
    "mac-debug-ews",
- a/Tools/QueueStatusServer/handlers/statusbubble.py -3 / +9 lines
Lines 1-4 a/Tools/QueueStatusServer/handlers/statusbubble.py_sec1
1
# Copyright (C) 2009 Google Inc. All rights reserved.
1
# Copyright (C) 2009 Google Inc. All rights reserved.
2
# Copyright (C) 2017 Apple Inc. All rights reserved.
2
#
3
#
3
# Redistribution and use in source and binary forms, with or without
4
# Redistribution and use in source and binary forms, with or without
4
# modification, are permitted provided that the following conditions are
5
# modification, are permitted provided that the following conditions are
Lines 182-192 class StatusBubble(webapp.RequestHandler): a/Tools/QueueStatusServer/handlers/statusbubble.py_sec2
182
        return bubble
183
        return bubble
183
184
184
    def _should_show_bubble_for(self, attachment, queue):
185
    def _should_show_bubble_for(self, attachment, queue):
185
         # Any pending queue is shown.
186
        # Any pending queue is shown.
186
        if attachment.position_in_queue(queue):
187
        if attachment.position_in_queue(queue):
187
            return True
188
            return True
188
        # EWS queues are also shown when complete.
189
189
        return bool(queue.is_ews() and attachment.status_for_queue(queue))
190
        # EWS queues that weren't skipped are also shown when complete.
191
        if not queue.is_ews():
192
            return False
193
194
        status = attachment.status_for_queue(queue)
195
        return bool(status and not status.did_skip())
190
196
191
    def _build_bubbles_for_attachment(self, attachment):
197
    def _build_bubbles_for_attachment(self, attachment):
192
        show_submit_to_ews = True
198
        show_submit_to_ews = True
- a/Tools/QueueStatusServer/model/queuestatus.py +4 lines
Lines 1-4 a/Tools/QueueStatusServer/model/queuestatus.py_sec1
1
# Copyright (C) 2013 Google Inc. All rights reserved.
1
# Copyright (C) 2013 Google Inc. All rights reserved.
2
# Copyright (C) 2017 Apple Inc. All rights reserved.
2
#
3
#
3
# Redistribution and use in source and binary forms, with or without
4
# Redistribution and use in source and binary forms, with or without
4
# modification, are permitted provided that the following conditions are
5
# modification, are permitted provided that the following conditions are
Lines 40-42 class QueueStatus(db.Model, QueuePropertyMixin): a/Tools/QueueStatusServer/model/queuestatus.py_sec2
40
    message = db.StringProperty(multiline=True)
41
    message = db.StringProperty(multiline=True)
41
    date = db.DateTimeProperty(auto_now_add=True)
42
    date = db.DateTimeProperty(auto_now_add=True)
42
    results_file = db.BlobProperty()
43
    results_file = db.BlobProperty()
44
45
    def did_skip(self):
46
        return self.message.startswith(messages.skip_status)
- a/Tools/Scripts/webkitpy/common/checkout/scm/scm_mock.py -1 / +3 lines
Lines 1-4 a/Tools/Scripts/webkitpy/common/checkout/scm/scm_mock.py_sec1
1
# Copyright (C) 2011 Google Inc. All rights reserved.
1
# Copyright (C) 2011 Google Inc. All rights reserved.
2
# Copyright (C) 2017 Apple Inc. All rights reserved.
2
#
3
#
3
# Redistribution and use in source and binary forms, with or without
4
# Redistribution and use in source and binary forms, with or without
4
# modification, are permitted provided that the following conditions are
5
# modification, are permitted provided that the following conditions are
Lines 37-42 class MockSCM(object): a/Tools/Scripts/webkitpy/common/checkout/scm/scm_mock.py_sec2
37
        self.added_paths = set()
38
        self.added_paths = set()
38
        self._filesystem = filesystem or MockFileSystem()
39
        self._filesystem = filesystem or MockFileSystem()
39
        self._executive = executive or MockExecutive()
40
        self._executive = executive or MockExecutive()
41
        self._mockChangedFiles = ["MockFile1"]
40
42
41
    def add(self, destination_path):
43
    def add(self, destination_path):
42
        self.add_list([destination_path])
44
        self.add_list([destination_path])
Lines 71-77 class MockSCM(object): a/Tools/Scripts/webkitpy/common/checkout/scm/scm_mock.py_sec3
71
        return self._filesystem.join(self.checkout_root, *comps)
73
        return self._filesystem.join(self.checkout_root, *comps)
72
74
73
    def changed_files(self, git_commit=None):
75
    def changed_files(self, git_commit=None):
74
        return ["MockFile1"]
76
        return self._mockChangedFiles
75
77
76
    def changed_files_for_revision(self, revision):
78
    def changed_files_for_revision(self, revision):
77
        return ["MockFile1"]
79
        return ["MockFile1"]
- a/Tools/Scripts/webkitpy/common/config/ews.json +6 lines
Lines 50-54 a/Tools/Scripts/webkitpy/common/config/ews.json_sec1
50
        "port": "mac",
50
        "port": "mac",
51
        "name": "mac-32bit-ews",
51
        "name": "mac-32bit-ews",
52
        "architecture": "i386"
52
        "architecture": "i386"
53
    },
54
    "JSC EWS": {
55
        "port": "mac",
56
        "name": "jsc-ews",
57
        "group": "jsc",
58
        "runTests": true
53
    }
59
    }
54
}
60
}
- a/Tools/Scripts/webkitpy/common/config/ports.py -4 / +20 lines
Lines 1-6 a/Tools/Scripts/webkitpy/common/config/ports.py_sec1
1
# Copyright (C) 2009, Google Inc. All rights reserved.
1
# Copyright (C) 2009, Google Inc. All rights reserved.
2
# Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies).
2
# Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies).
3
# Copyright (C) 2015 Apple Inc. All rights reserved.
3
# Copyright (C) 2015, 2017 Apple Inc. All rights reserved.
4
#
4
#
5
# Redistribution and use in source and binary forms, with or without
5
# Redistribution and use in source and binary forms, with or without
6
# modification, are permitted provided that the following conditions are
6
# modification, are permitted provided that the following conditions are
Lines 103-110 class DeprecatedPort(object): a/Tools/Scripts/webkitpy/common/config/ports.py_sec2
103
            command.append("--release")
103
            command.append("--release")
104
        return command
104
        return command
105
105
106
    def run_javascriptcore_tests_command(self):
106
    def build_jsc_command(self, build_style=None):
107
        return self.script_shell_command("run-javascriptcore-tests")
107
        command = self.script_shell_command("build-jsc")
108
        if build_style == "debug":
109
            command.append("--debug")
110
        if build_style == "release":
111
            command.append("--release")
112
        return command
113
114
    def run_javascriptcore_tests_command(self, build_style=None):
115
        command = self.script_shell_command("run-javascriptcore-tests")
116
        command.append("--no-fail-fast")
117
        command.append("--json-output=jsc_test_results.json")
118
        if (build_style == "debug"):
119
            command.append("--debug")
120
        return command
108
121
109
    def run_webkit_tests_command(self, build_style=None):
122
    def run_webkit_tests_command(self, build_style=None):
110
        command = self.script_shell_command("run-webkit-tests")
123
        command = self.script_shell_command("run-webkit-tests")
Lines 150-156 class IOSSimulatorWK2Port(DeprecatedPort): a/Tools/Scripts/webkitpy/common/config/ports.py_sec3
150
class MacPort(DeprecatedPort):
163
class MacPort(DeprecatedPort):
151
    port_flag_name = "mac"
164
    port_flag_name = "mac"
152
165
153
    def run_webkit_tests_command(self, build_style=None):
166
    def run_webkit_tests_command(self, build_style=None, test_suite=None):
167
        if test_suite == "jsc":
168
            return super(MacPort, self).run_javascriptcore_tests_command(build_style)
169
154
        command = super(MacPort, self).run_webkit_tests_command(build_style)
170
        command = super(MacPort, self).run_webkit_tests_command(build_style)
155
        command.append("--dump-render-tree")
171
        command.append("--dump-render-tree")
156
        return command
172
        return command
- a/Tools/Scripts/webkitpy/common/config/ports_mock.py -1 / +2 lines
Lines 1-4 a/Tools/Scripts/webkitpy/common/config/ports_mock.py_sec1
1
# Copyright (C) 2011 Google Inc. All rights reserved.
1
# Copyright (C) 2011 Google Inc. All rights reserved.
2
# Copyright (C) 2017 Apple Inc. All rights reserved.
2
#
3
#
3
# Redistribution and use in source and binary forms, with or without
4
# Redistribution and use in source and binary forms, with or without
4
# modification, are permitted provided that the following conditions are
5
# modification, are permitted provided that the following conditions are
Lines 49-55 class MockPort(object): a/Tools/Scripts/webkitpy/common/config/ports_mock.py_sec2
49
    def run_perl_unittests_command(self):
50
    def run_perl_unittests_command(self):
50
        return ['mock-test-webkitperl']
51
        return ['mock-test-webkitperl']
51
52
52
    def run_javascriptcore_tests_command(self):
53
    def run_javascriptcore_tests_command(self, build_style=None):
53
        return ['mock-run-javacriptcore-tests']
54
        return ['mock-run-javacriptcore-tests']
54
55
55
    def run_webkit_tests_command(self, build_style=None):
56
    def run_webkit_tests_command(self, build_style=None):
- a/Tools/Scripts/webkitpy/common/config/ports_unittest.py +5 lines
Lines 1-4 a/Tools/Scripts/webkitpy/common/config/ports_unittest.py_sec1
1
# Copyright (c) 2009, Google Inc. All rights reserved.
1
# Copyright (c) 2009, Google Inc. All rights reserved.
2
# Copyright (C) 2017 Apple Inc. All rights reserved.
2
#
3
#
3
# Redistribution and use in source and binary forms, with or without
4
# Redistribution and use in source and binary forms, with or without
4
# modification, are permitted provided that the following conditions are
5
# modification, are permitted provided that the following conditions are
Lines 39-44 class DeprecatedPortTest(unittest.TestCase): a/Tools/Scripts/webkitpy/common/config/ports_unittest.py_sec2
39
        self.assertEqual(MacPort().build_webkit_command(build_style="debug"), DeprecatedPort().script_shell_command("build-webkit") + ["--debug"])
40
        self.assertEqual(MacPort().build_webkit_command(build_style="debug"), DeprecatedPort().script_shell_command("build-webkit") + ["--debug"])
40
        self.assertEqual(MacPort().build_webkit_command(build_style="release"), DeprecatedPort().script_shell_command("build-webkit") + ["--release"])
41
        self.assertEqual(MacPort().build_webkit_command(build_style="release"), DeprecatedPort().script_shell_command("build-webkit") + ["--release"])
41
42
43
        self.assertEqual(MacPort().build_jsc_command(), DeprecatedPort().script_shell_command("build-jsc"))
44
        self.assertEqual(MacPort().build_jsc_command(build_style="release"), DeprecatedPort().script_shell_command("build-jsc") + ["--release"])
45
        self.assertEqual(MacPort().build_jsc_command(build_style="debug"), DeprecatedPort().script_shell_command("build-jsc") + ["--debug"])
46
42
    def test_gtk_wk2_port(self):
47
    def test_gtk_wk2_port(self):
43
        self.assertEqual(GtkWK2Port().flag(), "--port=gtk-wk2")
48
        self.assertEqual(GtkWK2Port().flag(), "--port=gtk-wk2")
44
        self.assertEqual(GtkWK2Port().run_webkit_tests_command(), DeprecatedPort().script_shell_command("run-webkit-tests") + ["--gtk"])
49
        self.assertEqual(GtkWK2Port().run_webkit_tests_command(), DeprecatedPort().script_shell_command("run-webkit-tests") + ["--gtk"])
- a/Tools/Scripts/webkitpy/common/net/jsctestresults.py +81 lines
Line 0 a/Tools/Scripts/webkitpy/common/net/jsctestresults.py_sec1
1
# Copyright (C) 2017 Apple Inc. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or without
4
# modification, are permitted provided that the following conditions
5
# are met:
6
# 1.  Redistributions of source code must retain the above copyright
7
#     notice, this list of conditions and the following disclaimer.
8
# 2.  Redistributions in binary form must reproduce the above copyright
9
#     notice, this list of conditions and the following disclaimer in the
10
#     documentation and/or other materials provided with the distribution.
11
#
12
# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
13
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15
# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
16
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
18
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
19
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
20
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
21
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22
23
import json
24
import logging
25
26
_log = logging.getLogger(__name__)
27
28
29
class JSCTestResults(object):
30
    def __init__(self, all_api_tests_passed, stress_test_failures):
31
        self.all_api_tests_passed = all_api_tests_passed
32
        self.stress_test_failures = stress_test_failures
33
34
        self.results = stress_test_failures[:]
35
        if not self.all_api_tests_passed:
36
            self.results.append("apiTests")
37
38
    @classmethod
39
    def intersection(cls, first, second):
40
        intersection_api_tests_passed = first.all_api_tests_passed or second.all_api_tests_passed
41
        intersection_stress_test_failures = list(set(first.stress_test_failures) & set(second.stress_test_failures))
42
        return cls(intersection_api_tests_passed, intersection_stress_test_failures)
43
44
    @classmethod
45
    def results_from_string(cls, string):
46
        if not string:
47
            return None
48
49
        try:
50
            parsed_results = json.loads(string)
51
        except ValueError:
52
            _log.error("Invalid JSON results")
53
            return None
54
55
        if 'allApiTestsPassed' not in parsed_results or 'stressTestFailures' not in parsed_results:
56
            return None
57
58
        return cls(parsed_results['allApiTestsPassed'], parsed_results['stressTestFailures'])
59
60
    def equals(self, other):
61
        return (self.all_api_tests_passed == other.all_api_tests_passed and
62
               set(self.stress_test_failures) == set(other.stress_test_failures))
63
64
    def is_subset(self, other):
65
        return set(self.results) <= set(other.results)
66
67
    def all_passed(self):
68
        return self.all_api_tests_passed and not self.stress_test_failures
69
70
    def failing_test_results(self):
71
        return self.results
72
73
    def test_results(self):
74
        return self.results
75
76
    def failing_tests(self):
77
        return self.results
78
79
    # No defined failure limit for JSC.
80
    def did_exceed_test_failure_limit(self):
81
        return False
- a/Tools/Scripts/webkitpy/common/net/jsctestresults_unittest.py +75 lines
Line 0 a/Tools/Scripts/webkitpy/common/net/jsctestresults_unittest.py_sec1
1
# Copyright (C) 2017 Apple Inc. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or without
4
# modification, are permitted provided that the following conditions
5
# are met:
6
# 1.  Redistributions of source code must retain the above copyright
7
#     notice, this list of conditions and the following disclaimer.
8
# 2.  Redistributions in binary form must reproduce the above copyright
9
#     notice, this list of conditions and the following disclaimer in the
10
#     documentation and/or other materials provided with the distribution.
11
#
12
# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
13
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15
# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
16
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
18
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
19
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
20
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
21
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22
23
import unittest
24
25
from webkitpy.common.net.jsctestresults import JSCTestResults
26
27
28
class JSCTestResultsTest(unittest.TestCase):
29
    def test_results_from_string(self):
30
        none_item = None
31
        empty_json = ""
32
        invalid_json = '{"allApiTestsPassed":'
33
        incomplete_json_v1 = '{"allApiTestsPassed": true}'
34
        incomplete_json_v2 = '{"stressTestFailures":[]}'
35
        self.assertEqual(None, JSCTestResults.results_from_string(none_item))
36
        self.assertEqual(None, JSCTestResults.results_from_string(empty_json))
37
        self.assertEqual(None, JSCTestResults.results_from_string(invalid_json))
38
        self.assertEqual(None, JSCTestResults.results_from_string(incomplete_json_v1))
39
        self.assertEqual(None, JSCTestResults.results_from_string(incomplete_json_v2))
40
41
        no_failures_string = '{"allApiTestsPassed": true, "stressTestFailures":[]}'
42
        no_failures_results = JSCTestResults(True, [])
43
        self.assertTrue(no_failures_results.equals(JSCTestResults.results_from_string(no_failures_string)))
44
45
        api_test_failures_string = '{"allApiTestsPassed": false, "stressTestFailures":[]}'
46
        api_test_failures_results = JSCTestResults(False, [])
47
        self.assertTrue(api_test_failures_results.equals(JSCTestResults.results_from_string(api_test_failures_string)))
48
49
        many_failures_string = '{"allApiTestsPassed": false, "stressTestFailures":["es6.yaml/es6/typed_arrays_Int16Array.js.default", "es6.yaml/es6/typed_arrays_Int8Array.js.default"]}'
50
        many_failures_results = JSCTestResults(False, ["es6.yaml/es6/typed_arrays_Int16Array.js.default", "es6.yaml/es6/typed_arrays_Int8Array.js.default"])
51
        self.assertTrue(many_failures_results.equals(JSCTestResults.results_from_string(many_failures_string)))
52
53
        self.assertFalse(no_failures_results == api_test_failures_results)
54
        self.assertFalse(api_test_failures_results == many_failures_results)
55
56
    def test_intersection_api_tests(self):
57
        results1 = JSCTestResults(False, [])
58
        results2 = JSCTestResults(True, [])
59
60
        expected_intersection = JSCTestResults(True, [])
61
        self.assertTrue(expected_intersection.equals(JSCTestResults.intersection(results1, results2)))
62
63
    def test_intersection_stress_tests(self):
64
        results1 = JSCTestResults(True, ['failure1', 'failure2'])
65
        results2 = JSCTestResults(True, ['failure1', 'failure3'])
66
67
        expected_intersection = JSCTestResults(True, ['failure1'])
68
        self.assertTrue(expected_intersection.equals(JSCTestResults.intersection(results1, results2)))
69
70
    def test_intersection_general_case(self):
71
        results1 = JSCTestResults(True, ['failure1', 'failure2'])
72
        results2 = JSCTestResults(False, ['failure1'])
73
74
        expected_intersection = JSCTestResults(True, ['failure1'])
75
        self.assertTrue(expected_intersection.equals(JSCTestResults.intersection(results1, results2)))
- a/Tools/Scripts/webkitpy/tool/bot/earlywarningsystemtask.py -1 / +4 lines
Lines 1-4 a/Tools/Scripts/webkitpy/tool/bot/earlywarningsystemtask.py_sec1
1
# Copyright (c) 2011 Google Inc. All rights reserved.
1
# Copyright (c) 2011 Google Inc. All rights reserved.
2
# Copyright (C) 2017 Apple Inc. All rights reserved.
2
#
3
#
3
# Redistribution and use in source and binary forms, with or without
4
# Redistribution and use in source and binary forms, with or without
4
# modification, are permitted provided that the following conditions are
5
# modification, are permitted provided that the following conditions are
Lines 26-32 a/Tools/Scripts/webkitpy/tool/bot/earlywarningsystemtask.py_sec2
26
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29
29
from webkitpy.tool.bot.patchanalysistask import PatchAnalysisTask, PatchAnalysisTaskDelegate, UnableToApplyPatch, PatchIsNotValid
30
from webkitpy.tool.bot.patchanalysistask import PatchAnalysisTask, PatchAnalysisTaskDelegate, UnableToApplyPatch, PatchIsNotValid, PatchIsNotApplicable
30
31
31
32
32
class EarlyWarningSystemTaskDelegate(PatchAnalysisTaskDelegate):
33
class EarlyWarningSystemTaskDelegate(PatchAnalysisTaskDelegate):
Lines 58-63 class EarlyWarningSystemTask(PatchAnalysisTask): a/Tools/Scripts/webkitpy/tool/bot/earlywarningsystemtask.py_sec3
58
            return False
59
            return False
59
        if not self._apply():
60
        if not self._apply():
60
            raise UnableToApplyPatch(self._patch)
61
            raise UnableToApplyPatch(self._patch)
62
        if not self._check_patch_relevance():
63
            raise PatchIsNotApplicable(self._patch)
61
        if not self._build():
64
        if not self._build():
62
            if not self._build_without_patch():
65
            if not self._build_without_patch():
63
                return False
66
                return False
- a/Tools/Scripts/webkitpy/tool/bot/jscews_unittest.py +218 lines
Line 0 a/Tools/Scripts/webkitpy/tool/bot/jscews_unittest.py_sec1
1
# Copyright (C) 2017 Apple Inc. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or without
4
# modification, are permitted provided that the following conditions
5
# are met:
6
# 1.  Redistributions of source code must retain the above copyright
7
#     notice, this list of conditions and the following disclaimer.
8
# 2.  Redistributions in binary form must reproduce the above copyright
9
#     notice, this list of conditions and the following disclaimer in the
10
#     documentation and/or other materials provided with the distribution.
11
#
12
# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
13
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15
# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
16
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
18
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
19
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
20
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
21
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22
23
import logging
24
import unittest
25
26
from webkitpy.common.net.jsctestresults import JSCTestResults
27
from webkitpy.common.system.executive import ScriptError
28
from webkitpy.tool.bot.patchanalysistask import *
29
from webkitpy.tool.commands.earlywarningsystem import AbstractEarlyWarningSystem
30
from webkitpy.tool.mocktool import MockTool
31
32
_log = logging.getLogger(__name__)
33
34
35
class MockPatchAnalysisTask(PatchAnalysisTask):
36
    def __init__(self, delegate, patch, patches_passed_all_tests):
37
        self._delegate = delegate
38
        self._patch = patch
39
        self._script_error = None
40
        self._results_archive_from_patch_test_run = None
41
        self._results_from_patch_test_run = None
42
        self.error = None
43
        self._patches_passed_all_tests = patches_passed_all_tests
44
        self._test_run_count = 0
45
        self.failure_status_id = 0
46
47
    def _test(self):
48
        self._test_run_count += 1
49
50
        if self._patches_passed_all_tests.pop() == True:
51
            return True
52
        self._script_error = ScriptError("Regression test")
53
        return False
54
55
    def _build_and_test_without_patch(self):
56
        self._test_run_count += 1
57
        return True
58
59
    def validate(self):
60
        return True
61
62
    def test_run_count(self):
63
        return self._test_run_count
64
65
66
# This is the delegate to be used with MockPatchAnalysisTask, above.
67
class MockJSCEarlyWarningSystem(AbstractEarlyWarningSystem):
68
    def __init__(self, first_test_results, second_test_results, clean_test_results):
69
        AbstractEarlyWarningSystem.__init__(self)
70
        self._group = "jsc"
71
        self._results_in_order = [clean_test_results, second_test_results, first_test_results]
72
73
    def test_results(self):
74
        return self._results_in_order.pop()
75
76
77
class JSCEarlyWarningSystemTest(unittest.TestCase):
78
    def _results_indicate_all_passed(self, results):
79
        if results == None:
80
            return False
81
        return results.all_passed()
82
83
    def _create_task(self, first_test_results, second_test_results, clean_test_results):
84
        queue = MockJSCEarlyWarningSystem(first_test_results, second_test_results, clean_test_results)
85
        tool = MockTool(log_executive=True)
86
        patch = tool.bugs.fetch_attachment(10000)
87
        patches_passed_all_tests = map(self._results_indicate_all_passed, [second_test_results, first_test_results])
88
        return MockPatchAnalysisTask(queue, patch, patches_passed_all_tests)
89
90
    def test_success_case(self):
91
        first_test_results = JSCTestResults(True, [])
92
        second_test_results = JSCTestResults(True, [])
93
        clean_test_results = JSCTestResults(True, [])
94
        task = self._create_task(first_test_results, second_test_results, clean_test_results)
95
96
        return_value = task._test_patch()
97
        self.assertEqual(task.test_run_count(), 1)
98
        self.assertTrue(return_value)
99
100
    def test_test_failure(self):
101
        first_test_results = JSCTestResults(True, ['Fail.js'])
102
        second_test_results = JSCTestResults(True, ['Fail.js'])
103
        clean_test_results = JSCTestResults(True, [])
104
        task = self._create_task(first_test_results, second_test_results, clean_test_results)
105
106
        with self.assertRaises(ScriptError):
107
            return_value = task._test_patch()
108
        self.assertEqual(task.test_run_count(), 3)
109
110
    def test_fix(self):
111
        first_test_results = JSCTestResults(True, [])
112
        second_test_results = JSCTestResults(True, [])
113
        clean_test_results = JSCTestResults(True, ['Fail.js'])
114
        task = self._create_task(first_test_results, second_test_results, clean_test_results)
115
116
        return_value = task._test_patch()
117
        self.assertEqual(task.test_run_count(), 1)
118
        self.assertTrue(return_value)
119
120
    def test_ineffective_patch(self):
121
        first_test_results = JSCTestResults(False, ['failure1.js', 'failure2.js'])
122
        second_test_results = JSCTestResults(False, ['failure1.js', 'failure2.js'])
123
        clean_test_results = JSCTestResults(False, ['failure1.js', 'failure2.js'])
124
        task = self._create_task(first_test_results, second_test_results, clean_test_results)
125
126
        return_value = task._test_patch()
127
        self.assertEqual(task.test_run_count(), 3)
128
        self.assertTrue(return_value)
129
130
    def test_partially_effective_patch(self):
131
        first_test_results = JSCTestResults(True, ['failure2.js'])
132
        second_test_results = JSCTestResults(True, ['failure2.js'])
133
        clean_test_results = JSCTestResults(False, ['failure1.js', 'failure2.js'])
134
        task = self._create_task(first_test_results, second_test_results, clean_test_results)
135
136
        return_value = task._test_patch()
137
        self.assertEqual(task.test_run_count(), 3)
138
        self.assertTrue(return_value)
139
140
    def test_different_test_failures_in_patch_and_tree(self):
141
        first_test_results = JSCTestResults(False, [])
142
        second_test_results = JSCTestResults(False, [])
143
        clean_test_results = JSCTestResults(True, ['failure1.js', 'failure2.js'])
144
        task = self._create_task(first_test_results, second_test_results, clean_test_results)
145
146
        with self.assertRaises(ScriptError):
147
            return_value = task._test_patch()
148
        self.assertEqual(task.test_run_count(), 3)
149
150
    def test_first_results_could_not_be_read(self):
151
        first_test_results = None
152
        second_test_results = JSCTestResults(True, [])
153
        clean_test_results = JSCTestResults(True, [])
154
        task = self._create_task(first_test_results, second_test_results, clean_test_results)
155
156
        return_value = task._test_patch()
157
        self.assertEqual(task.test_run_count(), 1)
158
        self.assertFalse(return_value)
159
160
    def test_second_results_could_not_be_read(self):
161
        first_test_results = JSCTestResults(False, ['failure1.js', 'failure2.js'])
162
        second_test_results = None
163
        clean_test_results = JSCTestResults(True, [])
164
        task = self._create_task(first_test_results, second_test_results, clean_test_results)
165
166
        return_value = task._test_patch()
167
        self.assertEqual(task.test_run_count(), 2)
168
        self.assertFalse(return_value)
169
170
    def test_clean_results_could_not_be_read(self):
171
        first_test_results = JSCTestResults(True, ['failure2.js'])
172
        second_test_results = JSCTestResults(True, ['failure2.js'])
173
        clean_test_results = None
174
        task = self._create_task(first_test_results, second_test_results, clean_test_results)
175
176
        return_value = task._test_patch()
177
        self.assertEqual(task.test_run_count(), 3)
178
        self.assertFalse(return_value)
179
180
    def test_flaky_results_on_clean_tree_pass(self):
181
        first_test_results = JSCTestResults(True, ['failure2.js'])
182
        second_test_results = JSCTestResults(True, [])
183
        clean_test_results = JSCTestResults(True, [])
184
        task = self._create_task(first_test_results, second_test_results, clean_test_results)
185
186
        return_value = task._test_patch()
187
        self.assertTrue(return_value)
188
        self.assertEqual(task.test_run_count(), 2)
189
190
    def test_flaky_results_on_clean_tree_pass_v2(self):
191
        first_test_results = JSCTestResults(True, [])
192
        second_test_results = JSCTestResults(True, ['failure2.js'])
193
        clean_test_results = JSCTestResults(True, [])
194
        task = self._create_task(first_test_results, second_test_results, clean_test_results)
195
196
        return_value = task._test_patch()
197
        self.assertTrue(return_value)
198
        self.assertEqual(task.test_run_count(), 1)
199
200
    def test_flaky_results_on_clean_tree_failure(self):
201
        first_test_results = JSCTestResults(False, ['failure1.js', 'failure2.js'])
202
        second_test_results = JSCTestResults(True, ['failure2.js'])
203
        clean_test_results = JSCTestResults(True, [])
204
        task = self._create_task(first_test_results, second_test_results, clean_test_results)
205
206
        with self.assertRaises(ScriptError):
207
            task._test_patch()
208
        self.assertEqual(task.test_run_count(), 3)
209
210
    def test_flaky_results_on_red_tree_pass(self):
211
        first_test_results = JSCTestResults(True, ['failure1.js'])
212
        second_test_results = JSCTestResults(True, ['failure1.js', 'failure2.js'])
213
        clean_test_results = JSCTestResults(True, ['failure1.js'])
214
        task = self._create_task(first_test_results, second_test_results, clean_test_results)
215
216
        return_value = task._test_patch()
217
        self.assertTrue(return_value)
218
        self.assertEqual(task.test_run_count(), 3)
- a/Tools/Scripts/webkitpy/tool/bot/jsctestresultsreader.py +47 lines
Line 0 a/Tools/Scripts/webkitpy/tool/bot/jsctestresultsreader.py_sec1
1
# Copyright (C) 2017 Apple Inc. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or without
4
# modification, are permitted provided that the following conditions
5
# are met:
6
# 1.  Redistributions of source code must retain the above copyright
7
#     notice, this list of conditions and the following disclaimer.
8
# 2.  Redistributions in binary form must reproduce the above copyright
9
#     notice, this list of conditions and the following disclaimer in the
10
#     documentation and/or other materials provided with the distribution.
11
#
12
# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
13
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15
# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
16
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
18
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
19
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
20
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
21
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22
23
import logging
24
25
from webkitpy.common.net.jsctestresults import JSCTestResults
26
27
_log = logging.getLogger(__name__)
28
29
30
class JSCTestResultsReader(object):
31
    def __init__(self, host, results_directory):
32
        self._host = host
33
        self._results_directory = results_directory
34
35
    def _read_file_contents(self, path):
36
        try:
37
            return self._host.filesystem.read_text_file(path)
38
        except (IOError, KeyError):  # File does not exist or can't be read.
39
            return None
40
41
    def _create_jsc_test_results(self):
42
        results_path = self._host.filesystem.join(self._results_directory, "jsc_test_results.json")
43
        contents = self._read_file_contents(results_path)
44
        return JSCTestResults.results_from_string(contents)
45
46
    def results(self):
47
        return self._create_jsc_test_results()
- a/Tools/Scripts/webkitpy/tool/bot/patchanalysistask.py -21 / +88 lines
Lines 1-4 a/Tools/Scripts/webkitpy/tool/bot/patchanalysistask.py_sec1
1
# Copyright (c) 2010 Google Inc. All rights reserved.
1
# Copyright (c) 2010 Google Inc. All rights reserved.
2
# Copyright (C) 2017 Apple Inc. All rights reserved.
2
#
3
#
3
# Redistribution and use in source and binary forms, with or without
4
# Redistribution and use in source and binary forms, with or without
4
# modification, are permitted provided that the following conditions are
5
# modification, are permitted provided that the following conditions are
Lines 28-33 a/Tools/Scripts/webkitpy/tool/bot/patchanalysistask.py_sec2
28
29
29
from webkitpy.common.system.executive import ScriptError
30
from webkitpy.common.system.executive import ScriptError
30
from webkitpy.common.net.layouttestresults import LayoutTestResults
31
from webkitpy.common.net.layouttestresults import LayoutTestResults
32
from webkitpy.common.net.jsctestresults import JSCTestResults
31
33
32
34
33
class UnableToApplyPatch(Exception):
35
class UnableToApplyPatch(Exception):
Lines 43-48 class PatchIsNotValid(Exception): a/Tools/Scripts/webkitpy/tool/bot/patchanalysistask.py_sec3
43
        self.failure_message = failure_message
45
        self.failure_message = failure_message
44
46
45
47
48
class PatchIsNotApplicable(Exception):
49
    def __init__(self, patch):
50
        Exception.__init__(self)
51
        self.patch = patch
52
46
class PatchAnalysisTaskDelegate(object):
53
class PatchAnalysisTaskDelegate(object):
47
    def parent_command(self):
54
    def parent_command(self):
48
        raise NotImplementedError("subclasses must implement")
55
        raise NotImplementedError("subclasses must implement")
Lines 122-149 class PatchAnalysisTask(object): a/Tools/Scripts/webkitpy/tool/bot/patchanalysistask.py_sec4
122
        "Applied patch",
129
        "Applied patch",
123
        "Patch does not apply")
130
        "Patch does not apply")
124
131
132
    def _check_patch_relevance(self):
133
        args = [
134
            "check-patch-relevance",
135
        ]
136
137
        if hasattr(self._delegate, 'group'):
138
            args.append("--group=%s" % self._delegate.group())
139
140
        return self._run_command(args, "Checked relevance of patch", "Patch was not relevant")
141
125
    def _build(self):
142
    def _build(self):
126
        return self._run_command([
143
        args = [
127
            "build",
144
            "build",
128
            "--no-clean",
145
            "--no-clean",
129
            "--no-update",
146
            "--no-update",
130
            "--build-style=%s" % self._delegate.build_style(),
147
            "--build-style=%s" % self._delegate.build_style(),
131
        ],
148
        ]
132
        "Built patch",
149
133
        "Patch does not build")
150
        if hasattr(self._delegate, 'group'):
151
            args.append("--group=%s" % self._delegate.group())
152
153
        return self._run_command(args, "Built patch", "Patch does not build")
134
154
135
    def _build_without_patch(self):
155
    def _build_without_patch(self):
136
        return self._run_command([
156
        args = [
137
            "build",
157
            "build",
138
            "--force-clean",
158
            "--force-clean",
139
            "--no-update",
159
            "--no-update",
140
            "--build-style=%s" % self._delegate.build_style(),
160
            "--build-style=%s" % self._delegate.build_style(),
141
        ],
161
        ]
142
        "Able to build without patch",
162
143
        "Unable to build without patch")
163
        if hasattr(self._delegate, 'group'):
164
            args.append("--group=%s" % self._delegate.group())
165
166
        return self._run_command(args, "Able to build without patch", "Unable to build without patch")
144
167
145
    def _test(self):
168
    def _test(self):
146
        return self._run_command([
169
        args = [
147
            "build-and-test",
170
            "build-and-test",
148
            "--no-clean",
171
            "--no-clean",
149
            "--no-update",
172
            "--no-update",
Lines 151-162 class PatchAnalysisTask(object): a/Tools/Scripts/webkitpy/tool/bot/patchanalysistask.py_sec5
151
            "--test",
174
            "--test",
152
            "--non-interactive",
175
            "--non-interactive",
153
            "--build-style=%s" % self._delegate.build_style(),
176
            "--build-style=%s" % self._delegate.build_style(),
154
        ],
177
        ]
155
        "Passed tests",
178
156
        "Patch does not pass tests")
179
        if hasattr(self._delegate, 'group'):
180
            args.append("--group=%s" % self._delegate.group())
181
182
        return self._run_command(args, "Passed tests", "Patch does not pass tests")
157
183
158
    def _build_and_test_without_patch(self):
184
    def _build_and_test_without_patch(self):
159
        return self._run_command([
185
        args = [
160
            "build-and-test",
186
            "build-and-test",
161
            "--force-clean",
187
            "--force-clean",
162
            "--no-update",
188
            "--no-update",
Lines 164-172 class PatchAnalysisTask(object): a/Tools/Scripts/webkitpy/tool/bot/patchanalysistask.py_sec6
164
            "--test",
190
            "--test",
165
            "--non-interactive",
191
            "--non-interactive",
166
            "--build-style=%s" % self._delegate.build_style(),
192
            "--build-style=%s" % self._delegate.build_style(),
167
        ],
193
        ]
168
        "Able to pass tests without patch",
194
169
        "Unable to pass tests without patch (tree is red?)")
195
        if hasattr(self._delegate, 'group'):
196
            args.append("--group=%s" % self._delegate.group())
197
198
        return self._run_command(args, "Able to pass tests without patch", "Unable to pass tests without patch (tree is red?)")
170
199
171
    def _land(self):
200
    def _land(self):
172
        # Unclear if this should pass --quiet or not.  If --parent-command always does the reporting, then it should.
201
        # Unclear if this should pass --quiet or not.  If --parent-command always does the reporting, then it should.
Lines 206-215 class PatchAnalysisTask(object): a/Tools/Scripts/webkitpy/tool/bot/patchanalysistask.py_sec7
206
        # also present without the patch, so we don't need to defer.
235
        # also present without the patch, so we don't need to defer.
207
        return False
236
        return False
208
237
209
    def _test_patch(self):
238
    # FIXME: Abstract out common parts of the retry logic.
239
    def _retry_jsc_tests(self):
240
        first_results = self._delegate.test_results()
241
        first_script_error = self._script_error
242
        first_failure_status_id = self.failure_status_id
243
        if first_results is None:
244
            return False
245
210
        if self._test():
246
        if self._test():
211
            return True
247
            return True
248
        second_results = self._delegate.test_results()
249
        second_script_error = self._script_error
250
        if second_results is None:
251
            return False
252
253
        consistent_results = JSCTestResults.intersection(first_results, second_results)
254
255
        self._build_and_test_without_patch()
256
        clean_tree_results = self._delegate.test_results()
257
        if clean_tree_results is None:
258
            return False
259
260
        if consistent_results.is_subset(clean_tree_results):
261
            return True
262
263
        self.failure_status_id = first_failure_status_id
264
        return self.report_failure(None, consistent_results, first_script_error)
212
265
266
    def _retry_layout_tests(self):
213
        # Note: archive_last_test_results deletes the results directory, making these calls order-sensitve.
267
        # Note: archive_last_test_results deletes the results directory, making these calls order-sensitve.
214
        # We could remove this dependency by building the test_results from the archive.
268
        # We could remove this dependency by building the test_results from the archive.
215
        first_results = self._delegate.test_results()
269
        first_results = self._delegate.test_results()
Lines 240-250 class PatchAnalysisTask(object): a/Tools/Scripts/webkitpy/tool/bot/patchanalysistask.py_sec8
240
            return self.report_failure(first_results_archive, first_results, first_script_error)
294
            return self.report_failure(first_results_archive, first_results, first_script_error)
241
295
242
        if second_results.did_exceed_test_failure_limit():
296
        if second_results.did_exceed_test_failure_limit():
243
            self._should_defer_patch_or_throw(first_results.failing_test_results(), first_results_archive, first_script_error, first_failure_status_id)
297
            self._should_defer_patch_or_throw(first_results.failing_test_results(), first_results_archive,
298
                                              first_script_error, first_failure_status_id)
244
            return False
299
            return False
245
300
246
        if first_results.did_exceed_test_failure_limit():
301
        if first_results.did_exceed_test_failure_limit():
247
            self._should_defer_patch_or_throw(second_results.failing_test_results(), second_results_archive, second_script_error, second_failure_status_id)
302
            self._should_defer_patch_or_throw(second_results.failing_test_results(), second_results_archive,
303
                                              second_script_error, second_failure_status_id)
248
            return False
304
            return False
249
305
250
        if self._results_failed_different_tests(first_results, second_results):
306
        if self._results_failed_different_tests(first_results, second_results):
Lines 259-272 class PatchAnalysisTask(object): a/Tools/Scripts/webkitpy/tool/bot/patchanalysistask.py_sec9
259
315
260
            tests_that_consistently_failed = first_failing_results_set.intersection(second_failing_results_set)
316
            tests_that_consistently_failed = first_failing_results_set.intersection(second_failing_results_set)
261
            if tests_that_consistently_failed:
317
            if tests_that_consistently_failed:
262
                if self._should_defer_patch_or_throw(tests_that_consistently_failed, first_results_archive, first_script_error, first_failure_status_id):
318
                if self._should_defer_patch_or_throw(tests_that_consistently_failed, first_results_archive,
319
                                                     first_script_error, first_failure_status_id):
263
                    return False  # Defer patch
320
                    return False  # Defer patch
264
321
265
            # At this point we know that at least one test flaked, but no consistent failures
322
            # At this point we know that at least one test flaked, but no consistent failures
266
            # were introduced. This is a bit of a grey-zone.
323
            # were introduced. This is a bit of a grey-zone.
267
            return False  # Defer patch
324
            return False  # Defer patch
268
325
269
        if self._should_defer_patch_or_throw(first_results.failing_test_results(), first_results_archive, first_script_error, first_failure_status_id):
326
        if self._should_defer_patch_or_throw(first_results.failing_test_results(), first_results_archive,
327
                                             first_script_error, first_failure_status_id):
270
            return False  # Defer patch
328
            return False  # Defer patch
271
329
272
        # At this point, we know that the first and second runs had the exact same failures,
330
        # At this point, we know that the first and second runs had the exact same failures,
Lines 274-279 class PatchAnalysisTask(object): a/Tools/Scripts/webkitpy/tool/bot/patchanalysistask.py_sec10
274
        # that the patch is good.
332
        # that the patch is good.
275
        return True
333
        return True
276
334
335
    def _test_patch(self):
336
        if self._test():
337
            return True
338
339
        if hasattr(self._delegate, 'group') and self._delegate.group() == "jsc":
340
            return self._retry_jsc_tests()
341
        else:
342
            return self._retry_layout_tests()
343
277
    def results_archive_from_patch_test_run(self, patch):
344
    def results_archive_from_patch_test_run(self, patch):
278
        assert(self._patch.id() == patch.id())  # PatchAnalysisTask is not currently re-useable.
345
        assert(self._patch.id() == patch.id())  # PatchAnalysisTask is not currently re-useable.
279
        return self._results_archive_from_patch_test_run
346
        return self._results_archive_from_patch_test_run
- a/Tools/Scripts/webkitpy/tool/commands/download.py -1 / +9 lines
Lines 1-5 a/Tools/Scripts/webkitpy/tool/commands/download.py_sec1
1
# Copyright (c) 2009, 2011 Google Inc. All rights reserved.
1
# Copyright (c) 2009, 2011 Google Inc. All rights reserved.
2
# Copyright (c) 2009 Apple Inc. All rights reserved.
2
# Copyright (c) 2009, 2017 Apple Inc. All rights reserved.
3
#
3
#
4
# Redistribution and use in source and binary forms, with or without
4
# Redistribution and use in source and binary forms, with or without
5
# modification, are permitted provided that the following conditions are
5
# modification, are permitted provided that the following conditions are
Lines 87-92 class BuildAndTest(AbstractSequencedCommand): a/Tools/Scripts/webkitpy/tool/commands/download.py_sec2
87
    ]
87
    ]
88
88
89
89
90
class CheckPatchRelevance(AbstractSequencedCommand):
91
    name = "check-patch-relevance"
92
    help_text = "Check if this patch needs to be tested"
93
    steps = [
94
        steps.CheckPatchRelevance,
95
    ]
96
97
90
class Land(AbstractSequencedCommand):
98
class Land(AbstractSequencedCommand):
91
    name = "land"
99
    name = "land"
92
    help_text = "Land the current working directory diff and updates the associated bug if any"
100
    help_text = "Land the current working directory diff and updates the associated bug if any"
- a/Tools/Scripts/webkitpy/tool/commands/download_unittest.py +1 lines
Lines 89-94 class DownloadCommandsTest(CommandsTest): a/Tools/Scripts/webkitpy/tool/commands/download_unittest.py_sec1
89
        options.update = True
89
        options.update = True
90
        options.architecture = 'MOCK ARCH'
90
        options.architecture = 'MOCK ARCH'
91
        options.iterate_on_new_tests = 0
91
        options.iterate_on_new_tests = 0
92
        options.group = None
92
        return options
93
        return options
93
94
94
    def test_build(self):
95
    def test_build(self):
- a/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py -6 / +25 lines
Lines 1-4 a/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py_sec1
1
# Copyright (c) 2009 Google Inc. All rights reserved.
1
# Copyright (c) 2009 Google Inc. All rights reserved.
2
# Copyright (c) 2017 Apple Inc. All rights reserved.
2
#
3
#
3
# Redistribution and use in source and binary forms, with or without
4
# Redistribution and use in source and binary forms, with or without
4
# modification, are permitted provided that the following conditions are
5
# modification, are permitted provided that the following conditions are
Lines 28-33 a/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py_sec2
28
29
29
import json
30
import json
30
import logging
31
import logging
32
import os
31
from optparse import make_option
33
from optparse import make_option
32
34
33
from webkitpy.common.config.committers import CommitterList
35
from webkitpy.common.config.committers import CommitterList
Lines 36-42 from webkitpy.common.system.filesystem import FileSystem a/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py_sec3
36
from webkitpy.common.system.executive import ScriptError
38
from webkitpy.common.system.executive import ScriptError
37
from webkitpy.tool.bot.earlywarningsystemtask import EarlyWarningSystemTask, EarlyWarningSystemTaskDelegate
39
from webkitpy.tool.bot.earlywarningsystemtask import EarlyWarningSystemTask, EarlyWarningSystemTaskDelegate
38
from webkitpy.tool.bot.layouttestresultsreader import LayoutTestResultsReader
40
from webkitpy.tool.bot.layouttestresultsreader import LayoutTestResultsReader
39
from webkitpy.tool.bot.patchanalysistask import UnableToApplyPatch, PatchIsNotValid
41
from webkitpy.tool.bot.jsctestresultsreader import JSCTestResultsReader
42
from webkitpy.tool.bot.patchanalysistask import UnableToApplyPatch, PatchIsNotValid, PatchIsNotApplicable
40
from webkitpy.tool.bot.queueengine import QueueEngine
43
from webkitpy.tool.bot.queueengine import QueueEngine
41
from webkitpy.tool.commands.queues import AbstractReviewQueue
44
from webkitpy.tool.commands.queues import AbstractReviewQueue
42
45
Lines 53-59 class AbstractEarlyWarningSystem(AbstractReviewQueue, EarlyWarningSystemTaskDele a/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py_sec4
53
56
54
    def begin_work_queue(self):
57
    def begin_work_queue(self):
55
        AbstractReviewQueue.begin_work_queue(self)
58
        AbstractReviewQueue.begin_work_queue(self)
56
        self._layout_test_results_reader = LayoutTestResultsReader(self._tool, self._port.results_directory(), self._log_directory())
59
60
        if self.group() == "jsc":
61
            jsc_results_directory = os.path.dirname(os.path.dirname(os.path.dirname(self._port.results_directory())))
62
            self._test_results_reader = JSCTestResultsReader(self._tool, jsc_results_directory)
63
        else:
64
            self._test_results_reader = LayoutTestResultsReader(self._tool, self._port.results_directory(), self._log_directory())
57
65
58
    def _failing_tests_message(self, task, patch):
66
    def _failing_tests_message(self, task, patch):
59
        results = task.results_from_patch_test_run(patch)
67
        results = task.results_from_patch_test_run(patch)
Lines 79-86 class AbstractEarlyWarningSystem(AbstractReviewQueue, EarlyWarningSystemTaskDele a/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py_sec5
79
            tool.bugs.add_cc_to_bug(patch.bug_id(), self.watchers)
87
            tool.bugs.add_cc_to_bug(patch.bug_id(), self.watchers)
80
        tool.bugs.set_flag_on_attachment(patch.id(), "commit-queue", "-", message)
88
        tool.bugs.set_flag_on_attachment(patch.id(), "commit-queue", "-", message)
81
89
90
    # This exists for mocking
91
    def _create_task(self, patch):
92
        return EarlyWarningSystemTask(self, patch, self._options.run_tests)
93
82
    def review_patch(self, patch):
94
    def review_patch(self, patch):
83
        task = EarlyWarningSystemTask(self, patch, self._options.run_tests)
95
        task = self._create_task(patch)
84
        try:
96
        try:
85
            succeeded = task.run()
97
            succeeded = task.run()
86
            if not succeeded:
98
            if not succeeded:
Lines 93-98 class AbstractEarlyWarningSystem(AbstractReviewQueue, EarlyWarningSystemTaskDele a/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py_sec6
93
        except UnableToApplyPatch, e:
105
        except UnableToApplyPatch, e:
94
            self._did_error(patch, "%s unable to apply patch." % self.name)
106
            self._did_error(patch, "%s unable to apply patch." % self.name)
95
            return False
107
            return False
108
        except PatchIsNotApplicable, e:
109
            self._did_skip(patch, "Patch not applicable to %s." % self.name)
110
            return False
96
        except ScriptError, e:
111
        except ScriptError, e:
97
            self._post_reject_message_on_bug(self._tool, patch, task.failure_status_id, self._failing_tests_message(task, patch))
112
            self._post_reject_message_on_bug(self._tool, patch, task.failure_status_id, self._failing_tests_message(task, patch))
98
            results_archive = task.results_archive_from_patch_test_run(patch)
113
            results_archive = task.results_archive_from_patch_test_run(patch)
Lines 117-130 class AbstractEarlyWarningSystem(AbstractReviewQueue, EarlyWarningSystemTaskDele a/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py_sec7
117
        return self._update_status(message, patch=patch, results_file=failure_log)
132
        return self._update_status(message, patch=patch, results_file=failure_log)
118
133
119
    def test_results(self):
134
    def test_results(self):
120
        return self._layout_test_results_reader.results()
135
        return self._test_results_reader.results()
121
136
122
    def archive_last_test_results(self, patch):
137
    def archive_last_test_results(self, patch):
123
        return self._layout_test_results_reader.archive(patch)
138
        return self._test_results_reader.archive(patch)
124
139
125
    def build_style(self):
140
    def build_style(self):
126
        return self._build_style
141
        return self._build_style
127
142
143
    def group(self):
144
        return self._group
145
128
    def refetch_patch(self, patch):
146
    def refetch_patch(self, patch):
129
        return self._tool.bugs.fetch_attachment(patch.id())
147
        return self._tool.bugs.fetch_attachment(patch.id())
130
148
Lines 149-160 class AbstractEarlyWarningSystem(AbstractReviewQueue, EarlyWarningSystemTaskDele a/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py_sec8
149
167
150
        classes = []
168
        classes = []
151
        for name, config in ewses.iteritems():
169
        for name, config in ewses.iteritems():
152
            classes.append(type(name.encode('utf-8').translate(None, ' -'), (AbstractEarlyWarningSystem,), {
170
            classes.append(type(name.encode('utf-8').translate(None, ' -'), (cls,), {
153
                'name': config.get('name', config['port'] + '-ews'),
171
                'name': config.get('name', config['port'] + '-ews'),
154
                'port_name': config['port'],
172
                'port_name': config['port'],
155
                'architecture': config.get('architecture', None),
173
                'architecture': config.get('architecture', None),
156
                '_build_style': config.get('style', "release"),
174
                '_build_style': config.get('style', "release"),
157
                'watchers': config.get('watchers', []),
175
                'watchers': config.get('watchers', []),
158
                'run_tests': config.get('runTests', cls.run_tests),
176
                'run_tests': config.get('runTests', cls.run_tests),
177
                '_group': config.get('group', None),
159
            }))
178
            }))
160
        return classes
179
        return classes
- a/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py -19 / +70 lines
Lines 1-4 a/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py_sec1
1
# Copyright (C) 2009 Google Inc. All rights reserved.
1
# Copyright (C) 2009 Google Inc. All rights reserved.
2
# Copyright (C) 2017 Apple Inc. All rights reserved.
2
#
3
#
3
# Redistribution and use in source and binary forms, with or without
4
# Redistribution and use in source and binary forms, with or without
4
# modification, are permitted provided that the following conditions are
5
# modification, are permitted provided that the following conditions are
Lines 29-34 a/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py_sec2
29
from webkitpy.thirdparty.mock import Mock
30
from webkitpy.thirdparty.mock import Mock
30
from webkitpy.common.host import Host
31
from webkitpy.common.host import Host
31
from webkitpy.common.host_mock import MockHost
32
from webkitpy.common.host_mock import MockHost
33
from webkitpy.common.net.jsctestresults import JSCTestResults
32
from webkitpy.common.net.layouttestresults import LayoutTestResults
34
from webkitpy.common.net.layouttestresults import LayoutTestResults
33
from webkitpy.common.system.outputcapture import OutputCapture
35
from webkitpy.common.system.outputcapture import OutputCapture
34
from webkitpy.layout_tests.models import test_results
36
from webkitpy.layout_tests.models import test_results
Lines 41-102 from webkitpy.tool.commands.queuestest import QueuesTest a/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py_sec3
41
from webkitpy.tool.mocktool import MockTool, MockOptions
43
from webkitpy.tool.mocktool import MockTool, MockOptions
42
44
43
45
44
class AbstractEarlyWarningSystemTest(QueuesTest):
46
# Needed to define port_name, used in AbstractEarlyWarningSystem.__init__
45
    def test_failing_tests_message(self):
47
class TestEWS(AbstractEarlyWarningSystem):
46
        # Needed to define port_name, used in AbstractEarlyWarningSystem.__init__
48
    port_name = "win"  # Needs to be a port which port/factory understands.
47
        class TestEWS(AbstractEarlyWarningSystem):
49
    _build_style = None
48
            port_name = "win"  # Needs to be a port which port/factory understands.
50
    _group = None
49
            _build_style = None
50
51
51
        ews = TestEWS()
52
53
class TestJSCEWS(AbstractEarlyWarningSystem):
54
    port_name = "mac"  # Needs to be a port which port/factory understands.
55
    _build_style = None
56
    _group = "jsc"
57
58
59
class AbstractEarlyWarningSystemTest(QueuesTest):
60
    def _test_message(self, ews, results, message):
52
        ews.bind_to_tool(MockTool())
61
        ews.bind_to_tool(MockTool())
53
        ews.host = MockHost()
62
        ews.host = MockHost()
54
        ews._options = MockOptions(port=None, confirm=False)
63
        ews._options = MockOptions(port=None, confirm=False)
55
        OutputCapture().assert_outputs(self, ews.begin_work_queue, expected_logs=self._default_begin_work_queue_logs(ews.name))
64
        OutputCapture().assert_outputs(self, ews.begin_work_queue, expected_logs=self._default_begin_work_queue_logs(ews.name))
56
        task = Mock()
65
        task = Mock()
57
        task.results_from_patch_test_run = lambda a: LayoutTestResults([test_results.TestResult("foo.html", failures=[test_failures.FailureTextMismatch()]),
66
        task.results_from_patch_test_run = results
58
                                                                          test_results.TestResult("bar.html", failures=[test_failures.FailureTextMismatch()])],
59
                                                                          did_exceed_test_failure_limit=False)
60
        patch = ews._tool.bugs.fetch_attachment(10000)
67
        patch = ews._tool.bugs.fetch_attachment(10000)
61
        self.assertMultiLineEqual(ews._failing_tests_message(task, patch), "New failing tests:\nfoo.html\nbar.html")
68
        self.assertMultiLineEqual(ews._failing_tests_message(task, patch), message)
69
70
    def test_failing_tests_message(self):
71
        ews = TestEWS()
72
        results = lambda a: LayoutTestResults([test_results.TestResult("foo.html", failures=[test_failures.FailureTextMismatch()]),
73
                                                test_results.TestResult("bar.html", failures=[test_failures.FailureTextMismatch()])],
74
                                                did_exceed_test_failure_limit=False)
75
        message = "New failing tests:\nfoo.html\nbar.html"
76
        self._test_message(ews, results, message)
77
78
    def test_failing_jsc_tests_message(self):
79
        ews = TestJSCEWS()
80
        results = lambda a: JSCTestResults(False, ["es6.yaml/es6/typed_arrays_Int8Array.js.default", "es6.yaml/es6/typed_arrays_Uint8Array.js.default"])
81
        message = "New failing tests:\nes6.yaml/es6/typed_arrays_Int8Array.js.default\nes6.yaml/es6/typed_arrays_Uint8Array.js.default\napiTests"
82
        self._test_message(ews, results, message)
83
84
85
class MockEarlyWarningSystemTaskForInconclusiveResults(EarlyWarningSystemTask):
86
    def _test_patch(self):
87
        self._test()
88
        return False
89
90
91
class MockAbstractEarlyWarningSystemForInconclusiveResults(AbstractEarlyWarningSystem):
92
    def test_results(self):
93
        return None
94
95
    def _create_task(self, patch):
96
        task = MockEarlyWarningSystemTaskForInconclusiveResults(self, patch, self._options.run_tests)
97
        return task
62
98
63
99
64
class EarlyWarningSystemTest(QueuesTest):
100
class EarlyWarningSystemTest(QueuesTest):
65
    def _default_expected_logs(self, ews):
101
    def _default_expected_logs(self, ews, conclusive):
66
        string_replacements = {
102
        string_replacements = {
67
            "name": ews.name,
103
            "name": ews.name,
68
            "port": ews.port_name,
104
            "port": ews.port_name,
69
            "architecture": " --architecture=%s" % ews.architecture if ews.architecture else "",
105
            "architecture": " --architecture=%s" % ews.architecture if ews.architecture else "",
70
            "build_style": ews.build_style(),
106
            "build_style": ews.build_style(),
107
            "group": ews.group(),
71
        }
108
        }
72
        if ews.run_tests:
109
        if ews.run_tests:
73
            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 --port=%(port)s%(architecture)s\n" % string_replacements
110
            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
74
        else:
111
        else:
75
            run_tests_line = ""
112
            run_tests_line = ""
76
        string_replacements['run_tests_line'] = run_tests_line
113
        string_replacements['run_tests_line'] = run_tests_line
77
114
115
        if conclusive:
116
            result_lines = "MOCK: update_status: %(name)s Pass\nMOCK: release_work_item: %(name)s 10000\n" % string_replacements
117
        else:
118
            result_lines = "MOCK: release_lock: %(name)s 10000\n" % string_replacements
119
        string_replacements['result_lines'] = result_lines
120
78
        expected_logs = {
121
        expected_logs = {
79
            "begin_work_queue": self._default_begin_work_queue_logs(ews.name),
122
            "begin_work_queue": self._default_begin_work_queue_logs(ews.name),
80
            "process_work_item": """MOCK: update_status: %(name)s Started processing patch
123
            "process_work_item": """MOCK: update_status: %(name)s Started processing patch
81
Running: webkit-patch --status-host=example.com clean --port=%(port)s%(architecture)s
124
Running: webkit-patch --status-host=example.com clean --port=%(port)s%(architecture)s
82
Running: webkit-patch --status-host=example.com update --port=%(port)s%(architecture)s
125
Running: webkit-patch --status-host=example.com update --port=%(port)s%(architecture)s
83
Running: webkit-patch --status-host=example.com apply-attachment --no-update --non-interactive 10000 --port=%(port)s%(architecture)s
126
Running: webkit-patch --status-host=example.com apply-attachment --no-update --non-interactive 10000 --port=%(port)s%(architecture)s
84
Running: webkit-patch --status-host=example.com build --no-clean --no-update --build-style=%(build_style)s --port=%(port)s%(architecture)s
127
Running: webkit-patch --status-host=example.com check-patch-relevance --group=%(group)s --port=%(port)s%(architecture)s
85
%(run_tests_line)sMOCK: update_status: %(name)s Pass
128
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
86
MOCK: release_work_item: %(name)s 10000
129
%(run_tests_line)s%(result_lines)s""" % string_replacements,
87
""" % string_replacements,
88
            "handle_unexpected_error": "Mock error message\n",
130
            "handle_unexpected_error": "Mock error message\n",
89
            "handle_script_error": "ScriptError error message\n\nMOCK output\n",
131
            "handle_script_error": "ScriptError error message\n\nMOCK output\n",
90
        }
132
        }
91
        return expected_logs
133
        return expected_logs
92
134
93
    def _test_ews(self, ews):
135
    def _test_ews(self, ews, results_are_conclusive=True):
94
        ews.bind_to_tool(MockTool())
136
        ews.bind_to_tool(MockTool())
95
        ews.host = MockHost()
137
        ews.host = MockHost()
96
        options = Mock()
138
        options = Mock()
97
        options.port = None
139
        options.port = None
98
        options.run_tests = ews.run_tests
140
        options.run_tests = ews.run_tests
99
        self.assert_queue_outputs(ews, expected_logs=self._default_expected_logs(ews), options=options)
141
        self.assert_queue_outputs(ews, expected_logs=self._default_expected_logs(ews, results_are_conclusive), options=options)
100
142
101
    def test_ewses(self):
143
    def test_ewses(self):
102
        classes = AbstractEarlyWarningSystem.load_ews_classes()
144
        classes = AbstractEarlyWarningSystem.load_ews_classes()
Lines 104-106 MOCK: release_work_item: %(name)s 10000 a/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py_sec4
104
        self.maxDiff = None
146
        self.maxDiff = None
105
        for ews_class in classes:
147
        for ews_class in classes:
106
            self._test_ews(ews_class())
148
            self._test_ews(ews_class())
149
150
    # This must use the Mock EWS classes defined above
151
    def test_inconclusive_test_results(self):
152
        classes = MockAbstractEarlyWarningSystemForInconclusiveResults.load_ews_classes()
153
        self.assertTrue(classes)
154
        self.maxDiff = None
155
        test_classes = filter(lambda x: x.run_tests, classes)
156
        for ews_class in test_classes:
157
            self._test_ews(ews_class(), False)
- a/Tools/Scripts/webkitpy/tool/commands/queues.py -1 / +7 lines
Lines 1-5 a/Tools/Scripts/webkitpy/tool/commands/queues.py_sec1
1
# Copyright (c) 2009 Google Inc. All rights reserved.
1
# Copyright (c) 2009 Google Inc. All rights reserved.
2
# Copyright (c) 2009 Apple Inc. All rights reserved.
2
# Copyright (c) 2009, 2017 Apple Inc. All rights reserved.
3
#
3
#
4
# Redistribution and use in source and binary forms, with or without
4
# Redistribution and use in source and binary forms, with or without
5
# modification, are permitted provided that the following conditions are
5
# modification, are permitted provided that the following conditions are
Lines 62-67 class AbstractQueue(Command, QueueEngineDelegate): a/Tools/Scripts/webkitpy/tool/commands/queues.py_sec2
62
    watchers = [
62
    watchers = [
63
    ]
63
    ]
64
64
65
    _skip_status = "Skip"
65
    _pass_status = "Pass"
66
    _pass_status = "Pass"
66
    _fail_status = "Fail"
67
    _fail_status = "Fail"
67
    _error_status = "Error"
68
    _error_status = "Error"
Lines 244-249 class AbstractPatchQueue(AbstractQueue): a/Tools/Scripts/webkitpy/tool/commands/queues.py_sec3
244
        self._update_status(message, patch)
245
        self._update_status(message, patch)
245
        self._release_work_item(patch)
246
        self._release_work_item(patch)
246
247
248
    def _did_skip(self, patch, reason):
249
        message = "%s: %s" % (self._skip_status, reason)
250
        self._update_status(message, patch)
251
        self._release_work_item(patch)
252
247
    def _unlock_patch(self, patch):
253
    def _unlock_patch(self, patch):
248
        self._tool.status_server.release_lock(self.name, patch)
254
        self._tool.status_server.release_lock(self.name, patch)
249
255
- a/Tools/Scripts/webkitpy/tool/steps/__init__.py +2 lines
Lines 1-4 a/Tools/Scripts/webkitpy/tool/steps/__init__.py_sec1
1
# Copyright (C) 2010 Google Inc. All rights reserved.
1
# Copyright (C) 2010 Google Inc. All rights reserved.
2
# Copyright (C) 2017 Apple Inc. All rights reserved.
2
#
3
#
3
# Redistribution and use in source and binary forms, with or without
4
# Redistribution and use in source and binary forms, with or without
4
# modification, are permitted provided that the following conditions are
5
# modification, are permitted provided that the following conditions are
Lines 33-38 from webkitpy.tool.steps.applypatchwithlocalcommit import ApplyPatchWithLocalCom a/Tools/Scripts/webkitpy/tool/steps/__init__.py_sec2
33
from webkitpy.tool.steps.applywatchlist import ApplyWatchList
34
from webkitpy.tool.steps.applywatchlist import ApplyWatchList
34
from webkitpy.tool.steps.attachtobug import AttachToBug
35
from webkitpy.tool.steps.attachtobug import AttachToBug
35
from webkitpy.tool.steps.build import Build
36
from webkitpy.tool.steps.build import Build
37
from webkitpy.tool.steps.checkpatchrelevance import CheckPatchRelevance
36
from webkitpy.tool.steps.checkstyle import CheckStyle
38
from webkitpy.tool.steps.checkstyle import CheckStyle
37
from webkitpy.tool.steps.cleanworkingdirectory import CleanWorkingDirectory
39
from webkitpy.tool.steps.cleanworkingdirectory import CleanWorkingDirectory
38
from webkitpy.tool.steps.closebug import CloseBug
40
from webkitpy.tool.steps.closebug import CloseBug
- a/Tools/Scripts/webkitpy/tool/steps/build.py -7 / +15 lines
Lines 1-4 a/Tools/Scripts/webkitpy/tool/steps/build.py_sec1
1
# Copyright (C) 2010 Google Inc. All rights reserved.
1
# Copyright (C) 2010 Google Inc. All rights reserved.
2
# Copyright (C) 2017 Apple Inc. All rights reserved.
2
#
3
#
3
# Redistribution and use in source and binary forms, with or without
4
# Redistribution and use in source and binary forms, with or without
4
# modification, are permitted provided that the following conditions are
5
# modification, are permitted provided that the following conditions are
Lines 41-68 class Build(AbstractStep): a/Tools/Scripts/webkitpy/tool/steps/build.py_sec2
41
            Options.build,
42
            Options.build,
42
            Options.quiet,
43
            Options.quiet,
43
            Options.build_style,
44
            Options.build_style,
45
            Options.group,
44
        ]
46
        ]
45
47
46
    def build(self, build_style):
48
    def build(self, build_style, group):
47
        environment = self._tool.copy_current_environment()
49
        environment = self._tool.copy_current_environment()
48
        environment.disable_gcc_smartquotes()
50
        environment.disable_gcc_smartquotes()
49
        environment.disable_jhbuild_VT100_output()
51
        environment.disable_jhbuild_VT100_output()
50
        env = environment.to_dictionary()
52
        env = environment.to_dictionary()
51
53
52
        build_webkit_command = self._tool.deprecated_port().build_webkit_command(build_style=build_style)
54
        if group == "jsc":
55
            build_command = self._tool.deprecated_port().build_jsc_command(build_style=build_style)
56
        else:
57
            build_command = self._tool.deprecated_port().build_webkit_command(build_style=build_style)
53
58
54
        if self._options.architecture:
59
        if self._options.architecture:
55
            build_webkit_command += ['ARCHS=%s' % self._options.architecture]
60
            build_command += ['ARCHS=%s' % self._options.architecture]
56
61
57
        self._tool.executive.run_and_throw_if_fail(build_webkit_command, self._options.quiet,
62
        self._tool.executive.run_and_throw_if_fail(build_command, self._options.quiet,
58
            cwd=self._tool.scm().checkout_root, env=env)
63
            cwd=self._tool.scm().checkout_root, env=env)
59
64
60
    def run(self, state):
65
    def run(self, state):
61
        if not self._options.build:
66
        if not self._options.build:
62
            return
67
            return
63
        _log.info("Building WebKit")
68
        _log.info("Building WebKit")
69
70
        group = self._options.group
71
64
        if self._options.build_style == "both":
72
        if self._options.build_style == "both":
65
            self.build("debug")
73
            self.build("debug", group)
66
            self.build("release")
74
            self.build("release", group)
67
        else:
75
        else:
68
            self.build(self._options.build_style)
76
            self.build(self._options.build_style, group)
- a/Tools/Scripts/webkitpy/tool/steps/checkpatchrelevance.py +75 lines
Line 0 a/Tools/Scripts/webkitpy/tool/steps/checkpatchrelevance.py_sec1
1
# Copyright (C) 2017 Apple Inc. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or without
4
# modification, are permitted provided that the following conditions
5
# are met:
6
# 1.  Redistributions of source code must retain the above copyright
7
#     notice, this list of conditions and the following disclaimer.
8
# 2.  Redistributions in binary form must reproduce the above copyright
9
#     notice, this list of conditions and the following disclaimer in the
10
#     documentation and/or other materials provided with the distribution.
11
#
12
# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
13
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15
# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
16
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
18
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
19
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
20
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
21
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22
23
import logging
24
import re
25
26
from webkitpy.common.system.executive import ScriptError
27
from webkitpy.tool.steps.abstractstep import AbstractStep
28
from webkitpy.tool.steps.options import Options
29
30
_log = logging.getLogger(__name__)
31
32
33
class CheckPatchRelevance(AbstractStep):
34
    @classmethod
35
    def options(cls):
36
        return AbstractStep.options() + [
37
            Options.group,
38
        ]
39
40
    jsc_paths = [
41
        "JSTests/",
42
        "Source/JavaScriptCore/",
43
        "Source/WTF/"
44
        "Source/bmalloc/",
45
    ]
46
47
    group_to_paths_mapping = {
48
        'jsc': jsc_paths,
49
    }
50
51
    def _changes_are_relevant(self, changed_files):
52
        # In the default case, all patches are relevant
53
        if self._options.group is None:
54
            return True
55
56
        patterns = self.group_to_paths_mapping[self._options.group]
57
58
        for changed_file in changed_files:
59
            for pattern in patterns:
60
                if re.search(pattern, changed_file, re.IGNORECASE):
61
                    return True
62
63
        return False
64
65
    def run(self, state):
66
        _log.info("Checking relevance of patch")
67
68
        change_list = self._tool.scm().changed_files()
69
70
        if self._changes_are_relevant(change_list):
71
            _log.info("This patch has relevant changes.")
72
            return True
73
74
        _log.info("This patch does not have relevant changes.")
75
        raise ScriptError(message="This patch does not have relevant changes.")
- a/Tools/Scripts/webkitpy/tool/steps/options.py +2 lines
Lines 1-4 a/Tools/Scripts/webkitpy/tool/steps/options.py_sec1
1
# Copyright (C) 2010 Google Inc. All rights reserved.
1
# Copyright (C) 2010 Google Inc. All rights reserved.
2
# Copyright (C) 2017 Apple Inc. All rights reserved.
2
#
3
#
3
# Redistribution and use in source and binary forms, with or without
4
# Redistribution and use in source and binary forms, with or without
4
# modification, are permitted provided that the following conditions are
5
# modification, are permitted provided that the following conditions are
Lines 46-51 class Options(object): a/Tools/Scripts/webkitpy/tool/steps/options.py_sec2
46
    email = make_option("--email", action="store", type="string", dest="email", help="Email address to use in ChangeLogs.")
47
    email = make_option("--email", action="store", type="string", dest="email", help="Email address to use in ChangeLogs.")
47
    force_clean = make_option("--force-clean", action="store_true", dest="force_clean", default=False, help="Clean working directory before applying patches (removes local changes and commits)")
48
    force_clean = make_option("--force-clean", action="store_true", dest="force_clean", default=False, help="Clean working directory before applying patches (removes local changes and commits)")
48
    git_commit = make_option("-g", "--git-commit", action="store", dest="git_commit", help="Operate on a local commit. If a range, the commits are squashed into one. <ref>.... includes the working copy changes. UPSTREAM can be used for the upstream/tracking branch.")
49
    git_commit = make_option("-g", "--git-commit", action="store", dest="git_commit", help="Operate on a local commit. If a range, the commits are squashed into one. <ref>.... includes the working copy changes. UPSTREAM can be used for the upstream/tracking branch.")
50
    group = make_option("--group", action="store", dest="group", default=None, help="")
49
    local_commit = make_option("--local-commit", action="store_true", dest="local_commit", default=False, help="Make a local commit for each applied patch")
51
    local_commit = make_option("--local-commit", action="store_true", dest="local_commit", default=False, help="Make a local commit for each applied patch")
50
    non_interactive = make_option("--non-interactive", action="store_true", dest="non_interactive", default=False, help="Never prompt the user, fail as fast as possible.")
52
    non_interactive = make_option("--non-interactive", action="store_true", dest="non_interactive", default=False, help="Never prompt the user, fail as fast as possible.")
51
    obsolete_patches = make_option("--no-obsolete", action="store_false", dest="obsolete_patches", default=True, help="Do not obsolete old patches before posting this one.")
53
    obsolete_patches = make_option("--no-obsolete", action="store_false", dest="obsolete_patches", default=True, help="Do not obsolete old patches before posting this one.")
- a/Tools/Scripts/webkitpy/tool/steps/runtests.py +10 lines
Lines 1-4 a/Tools/Scripts/webkitpy/tool/steps/runtests.py_sec1
1
# Copyright (C) 2010 Google Inc. All rights reserved.
1
# Copyright (C) 2010 Google Inc. All rights reserved.
2
# Copyright (C) 2017 Apple Inc. All rights reserved.
2
#
3
#
3
# Redistribution and use in source and binary forms, with or without
4
# Redistribution and use in source and binary forms, with or without
4
# modification, are permitted provided that the following conditions are
5
# modification, are permitted provided that the following conditions are
Lines 53-61 class RunTests(AbstractStep): a/Tools/Scripts/webkitpy/tool/steps/runtests.py_sec2
53
            Options.iterate_on_new_tests,
54
            Options.iterate_on_new_tests,
54
            Options.non_interactive,
55
            Options.non_interactive,
55
            Options.quiet,
56
            Options.quiet,
57
            Options.group,
56
        ]
58
        ]
57
59
58
    def run(self, state):
60
    def run(self, state):
61
        if self._options.group == "jsc":
62
            self._run_javascriptcore_tests()
63
            return
64
59
        if self._options.iterate_on_new_tests:
65
        if self._options.iterate_on_new_tests:
60
            _log.info("Running run-webkit-tests on new tests")
66
            _log.info("Running run-webkit-tests on new tests")
61
            self._run_webkit_tests(self._options.iterate_on_new_tests)
67
            self._run_webkit_tests(self._options.iterate_on_new_tests)
Lines 143-145 class RunTests(AbstractStep): a/Tools/Scripts/webkitpy/tool/steps/runtests.py_sec3
143
            args.append("--iterations=%d" % iterate_on_new_tests)
149
            args.append("--iterations=%d" % iterate_on_new_tests)
144
150
145
        self._tool.executive.run_and_throw_if_fail(args, cwd=self._tool.scm().checkout_root)
151
        self._tool.executive.run_and_throw_if_fail(args, cwd=self._tool.scm().checkout_root)
152
153
    def _run_javascriptcore_tests(self):
154
        args = self._tool.deprecated_port().run_javascriptcore_tests_command(self._options.build_style)
155
        self._tool.executive.run_and_throw_if_fail(args, cwd=self._tool.scm().checkout_root)
- a/Tools/Scripts/webkitpy/tool/steps/runtests_unittest.py -1 / +1 lines
Lines 40-46 class RunTestsTest(unittest.TestCase): a/Tools/Scripts/webkitpy/tool/steps/runtests_unittest.py_sec1
40
        tool = MockTool(log_executive=True)
40
        tool = MockTool(log_executive=True)
41
        tool._deprecated_port.run_python_unittests_command = lambda: None
41
        tool._deprecated_port.run_python_unittests_command = lambda: None
42
        tool._deprecated_port.run_perl_unittests_command = lambda: None
42
        tool._deprecated_port.run_perl_unittests_command = lambda: None
43
        step = RunTests(tool, MockOptions(test=True, non_interactive=True, quiet=False, build_style="release", iterate_on_new_tests=0))
43
        step = RunTests(tool, MockOptions(test=True, non_interactive=True, quiet=False, build_style="release", iterate_on_new_tests=0, group=None))
44
44
45
        if sys.platform != "cygwin":
45
        if sys.platform != "cygwin":
46
            expected_logs = """Running bindings generation tests
46
            expected_logs = """Running bindings generation tests
- a/Tools/Scripts/webkitpy/tool/steps/steps_unittest.py -2 / +106 lines
Lines 1-4 a/Tools/Scripts/webkitpy/tool/steps/steps_unittest.py_sec1
1
# Copyright (C) 2010 Google Inc. All rights reserved.
1
# Copyright (C) 2010 Google Inc. All rights reserved.
2
# Copyright (C) 2017 Apple Inc. All rights reserved.
2
#
3
#
3
# Redistribution and use in source and binary forms, with or without
4
# Redistribution and use in source and binary forms, with or without
4
# modification, are permitted provided that the following conditions are
5
# modification, are permitted provided that the following conditions are
Lines 28-33 a/Tools/Scripts/webkitpy/tool/steps/steps_unittest.py_sec2
28
29
29
import unittest
30
import unittest
30
31
32
from webkitpy.common.system.executive import ScriptError
31
from webkitpy.common.system.outputcapture import OutputCapture
33
from webkitpy.common.system.outputcapture import OutputCapture
32
from webkitpy.common.config.ports import DeprecatedPort
34
from webkitpy.common.config.ports import DeprecatedPort
33
from webkitpy.tool.mocktool import MockOptions, MockTool
35
from webkitpy.tool.mocktool import MockOptions, MockTool
Lines 38-43 from webkitpy.tool import steps a/Tools/Scripts/webkitpy/tool/steps/steps_unittest.py_sec3
38
class StepsTest(unittest.TestCase):
40
class StepsTest(unittest.TestCase):
39
    def _step_options(self):
41
    def _step_options(self):
40
        options = MockOptions()
42
        options = MockOptions()
43
        options.group = None
41
        options.non_interactive = True
44
        options.non_interactive = True
42
        options.port = 'MOCK port'
45
        options.port = 'MOCK port'
43
        options.quiet = True
46
        options.quiet = True
Lines 111-117 MOCK run_and_throw_if_fail: ['Tools/Scripts/test-webkitpy'], cwd=/mock-checkout a/Tools/Scripts/webkitpy/tool/steps/steps_unittest.py_sec4
111
Running Perl unit tests
114
Running Perl unit tests
112
MOCK run_and_throw_if_fail: ['Tools/Scripts/test-webkitperl'], cwd=/mock-checkout
115
MOCK run_and_throw_if_fail: ['Tools/Scripts/test-webkitperl'], cwd=/mock-checkout
113
Running JavaScriptCore tests
116
Running JavaScriptCore tests
114
MOCK run_and_throw_if_fail: ['Tools/Scripts/run-javascriptcore-tests'], cwd=/mock-checkout
117
MOCK run_and_throw_if_fail: ['Tools/Scripts/run-javascriptcore-tests', '--no-fail-fast', '--json-output=jsc_test_results.json'], cwd=/mock-checkout
115
Running bindings generation tests
118
Running bindings generation tests
116
MOCK run_and_throw_if_fail: ['Tools/Scripts/run-bindings-tests'], cwd=/mock-checkout
119
MOCK run_and_throw_if_fail: ['Tools/Scripts/run-bindings-tests'], cwd=/mock-checkout
117
Running run-webkit-tests
120
Running run-webkit-tests
Lines 133-142 MOCK run_and_throw_if_fail: ['Tools/Scripts/test-webkitpy'], cwd=/mock-checkout a/Tools/Scripts/webkitpy/tool/steps/steps_unittest.py_sec5
133
Running Perl unit tests
136
Running Perl unit tests
134
MOCK run_and_throw_if_fail: ['Tools/Scripts/test-webkitperl'], cwd=/mock-checkout
137
MOCK run_and_throw_if_fail: ['Tools/Scripts/test-webkitperl'], cwd=/mock-checkout
135
Running JavaScriptCore tests
138
Running JavaScriptCore tests
136
MOCK run_and_throw_if_fail: ['Tools/Scripts/run-javascriptcore-tests'], cwd=/mock-checkout
139
MOCK run_and_throw_if_fail: ['Tools/Scripts/run-javascriptcore-tests', '--no-fail-fast', '--json-output=jsc_test_results.json'], cwd=/mock-checkout
137
Running bindings generation tests
140
Running bindings generation tests
138
MOCK run_and_throw_if_fail: ['Tools/Scripts/run-bindings-tests'], cwd=/mock-checkout
141
MOCK run_and_throw_if_fail: ['Tools/Scripts/run-bindings-tests'], cwd=/mock-checkout
139
Running run-webkit-tests
142
Running run-webkit-tests
140
MOCK run_and_throw_if_fail: ['Tools/Scripts/run-webkit-tests', '--debug', '--quiet'], cwd=/mock-checkout
143
MOCK run_and_throw_if_fail: ['Tools/Scripts/run-webkit-tests', '--debug', '--quiet'], cwd=/mock-checkout
141
"""
144
"""
142
        OutputCapture().assert_outputs(self, step.run, [{}], expected_logs=expected_logs)
145
        OutputCapture().assert_outputs(self, step.run, [{}], expected_logs=expected_logs)
146
147
    def test_runtests_jsc(self):
148
        mock_options = self._step_options()
149
        mock_options.non_interactive = False
150
        mock_options.build_style = "release"
151
        mock_options.group = "jsc"
152
        step = steps.RunTests(MockTool(log_executive=True), mock_options)
153
        tool = MockTool(log_executive=True)
154
        # FIXME: We shouldn't use a real port-object here, but there is too much to mock at the moment.
155
        tool._deprecated_port = DeprecatedPort()
156
        step = steps.RunTests(tool, mock_options)
157
        expected_logs = """MOCK run_and_throw_if_fail: ['Tools/Scripts/run-javascriptcore-tests', '--no-fail-fast', '--json-output=jsc_test_results.json'], cwd=/mock-checkout
158
"""
159
        OutputCapture().assert_outputs(self, step.run, [{}], expected_logs=expected_logs)
160
161
    def test_runtests_jsc_debug(self):
162
        mock_options = self._step_options()
163
        mock_options.non_interactive = False
164
        mock_options.build_style = "debug"
165
        mock_options.group = "jsc"
166
        tool = MockTool(log_executive=True)
167
        # FIXME: We shouldn't use a real port-object here, but there is too much to mock at the moment.
168
        tool._deprecated_port = DeprecatedPort()
169
        step = steps.RunTests(tool, mock_options)
170
        expected_logs = """MOCK run_and_throw_if_fail: ['Tools/Scripts/run-javascriptcore-tests', '--no-fail-fast', '--json-output=jsc_test_results.json', '--debug'], cwd=/mock-checkout
171
"""
172
        OutputCapture().assert_outputs(self, step.run, [{}], expected_logs=expected_logs)
173
174
    def test_build_jsc_debug(self):
175
        mock_options = self._step_options()
176
        mock_options.non_interactive = False
177
        mock_options.build_style = "debug"
178
        mock_options.build = True
179
        mock_options.architecture = True
180
        mock_options.group = "jsc"
181
        tool = MockTool(log_executive=True)
182
        # FIXME: We shouldn't use a real port-object here, but there is too much to mock at the moment.
183
        tool._deprecated_port = DeprecatedPort()
184
        step = steps.Build(tool, mock_options)
185
        expected_logs = """Building WebKit
186
MOCK run_and_throw_if_fail: ['Tools/Scripts/build-jsc', '--debug', 'ARCHS=True'], cwd=/mock-checkout, env={'LC_ALL': 'C', 'TERM': 'none', 'MOCK_ENVIRON_COPY': '1'}
187
"""
188
        OutputCapture().assert_outputs(self, step.run, [{}], expected_logs=expected_logs)
189
190
    def test_build_jsc(self):
191
        mock_options = self._step_options()
192
        mock_options.non_interactive = False
193
        mock_options.build_style = "release"
194
        mock_options.build = True
195
        mock_options.architecture = True
196
        mock_options.group = "jsc"
197
        tool = MockTool(log_executive=True)
198
        # FIXME: We shouldn't use a real port-object here, but there is too much to mock at the moment.
199
        tool._deprecated_port = DeprecatedPort()
200
        step = steps.Build(tool, mock_options)
201
        expected_logs = """Building WebKit
202
MOCK run_and_throw_if_fail: ['Tools/Scripts/build-jsc', '--release', 'ARCHS=True'], cwd=/mock-checkout, env={'LC_ALL': 'C', 'TERM': 'none', 'MOCK_ENVIRON_COPY': '1'}
203
"""
204
        OutputCapture().assert_outputs(self, step.run, [{}], expected_logs=expected_logs)
205
206
    def test_patch_relevant(self):
207
        self.maxDiff = None
208
        mock_options = self._step_options()
209
        tool = MockTool(log_executive=True)
210
        tool.scm()._mockChangedFiles = ["JSTests/MockFile1", "ChangeLog"]
211
        # FIXME: We shouldn't use a real port-object here, but there is too much to mock at the moment.
212
        tool._deprecated_port = DeprecatedPort()
213
        step = steps.CheckPatchRelevance(tool, mock_options)
214
        expected_logs = """Checking relevance of patch
215
This patch has relevant changes.
216
"""
217
        OutputCapture().assert_outputs(self, step.run, [{}], expected_logs=expected_logs)
218
219
    def test_patch_relevant_jsc(self):
220
        self.maxDiff = None
221
        mock_options = self._step_options()
222
        mock_options.group = "jsc"
223
        tool = MockTool(log_executive=True)
224
        tool.scm()._mockChangedFiles = ["JSTests/MockFile1", "ChangeLog"]
225
        # FIXME: We shouldn't use a real port-object here, but there is too much to mock at the moment.
226
        tool._deprecated_port = DeprecatedPort()
227
        step = steps.CheckPatchRelevance(tool, mock_options)
228
        expected_logs = """Checking relevance of patch
229
This patch has relevant changes.
230
"""
231
        OutputCapture().assert_outputs(self, step.run, [{}], expected_logs=expected_logs)
232
233
    def test_patch_not_relevant_jsc(self):
234
        self.maxDiff = None
235
        mock_options = self._step_options()
236
        mock_options.group = "jsc"
237
        tool = MockTool(log_executive=True)
238
        tool.scm()._mockChangedFiles = ["Tools/ChangeLog", "Tools/Scripts/webkitpy/tool/steps/steps_unittest.py"]
239
        # FIXME: We shouldn't use a real port-object here, but there is too much to mock at the moment.
240
        tool._deprecated_port = DeprecatedPort()
241
        step = steps.CheckPatchRelevance(tool, mock_options)
242
        expected_logs = """Checking relevance of patch
243
This patch does not have relevant changes.
244
"""
245
        with self.assertRaises(ScriptError):
246
            OutputCapture().assert_outputs(self, step.run, [{}], expected_logs=expected_logs)

Return to Bug 162458