Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(622)

Side by Side Diff: Tools/Scripts/webkitpy/tool/bot/patchanalysistask.py

Issue 15416008: Remove a bunch of dead code from webkitpy (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 # Copyright (c) 2010 Google 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 are
5 # met:
6 #
7 # * Redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer.
9 # * Redistributions in binary form must reproduce the above
10 # copyright notice, this list of conditions and the following disclaimer
11 # in the documentation and/or other materials provided with the
12 # distribution.
13 # * Neither the name of Google Inc. nor the names of its
14 # contributors may be used to endorse or promote products derived from
15 # this software without specific prior written permission.
16 #
17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # (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
29 from webkitpy.common.system.executive import ScriptError
30 from webkitpy.common.net.layouttestresults import LayoutTestResults
31
32
33 class UnableToApplyPatch(Exception):
34 def __init__(self, patch):
35 Exception.__init__(self)
36 self.patch = patch
37
38
39 class PatchAnalysisTaskDelegate(object):
40 def parent_command(self):
41 raise NotImplementedError("subclasses must implement")
42
43 def run_command(self, command):
44 raise NotImplementedError("subclasses must implement")
45
46 def command_passed(self, message, patch):
47 raise NotImplementedError("subclasses must implement")
48
49 def command_failed(self, message, script_error, patch):
50 raise NotImplementedError("subclasses must implement")
51
52 def refetch_patch(self, patch):
53 raise NotImplementedError("subclasses must implement")
54
55 def expected_failures(self):
56 raise NotImplementedError("subclasses must implement")
57
58 def test_results(self):
59 raise NotImplementedError("subclasses must implement")
60
61 def archive_last_test_results(self, patch):
62 raise NotImplementedError("subclasses must implement")
63
64 def build_style(self):
65 raise NotImplementedError("subclasses must implement")
66
67 # We could make results_archive optional, but for now it's required.
68 def report_flaky_tests(self, patch, flaky_tests, results_archive):
69 raise NotImplementedError("subclasses must implement")
70
71
72 class PatchAnalysisTask(object):
73 def __init__(self, delegate, patch):
74 self._delegate = delegate
75 self._patch = patch
76 self._script_error = None
77 self._results_archive_from_patch_test_run = None
78 self._results_from_patch_test_run = None
79 self._expected_failures = delegate.expected_failures()
80
81 def _run_command(self, command, success_message, failure_message):
82 try:
83 self._delegate.run_command(command)
84 self._delegate.command_passed(success_message, patch=self._patch)
85 return True
86 except ScriptError, e:
87 self._script_error = e
88 self.failure_status_id = self._delegate.command_failed(failure_messa ge, script_error=self._script_error, patch=self._patch)
89 return False
90
91 def _clean(self):
92 return self._run_command([
93 "clean",
94 ],
95 "Cleaned working directory",
96 "Unable to clean working directory")
97
98 def _update(self):
99 # FIXME: Ideally the status server log message should include which revi sion we updated to.
100 return self._run_command([
101 "update",
102 ],
103 "Updated working directory",
104 "Unable to update working directory")
105
106 def _apply(self):
107 return self._run_command([
108 "apply-attachment",
109 "--no-update",
110 "--non-interactive",
111 self._patch.id(),
112 ],
113 "Applied patch",
114 "Patch does not apply")
115
116 def _build(self):
117 return self._run_command([
118 "build",
119 "--no-clean",
120 "--no-update",
121 "--build-style=%s" % self._delegate.build_style(),
122 ],
123 "Built patch",
124 "Patch does not build")
125
126 def _build_without_patch(self):
127 return self._run_command([
128 "build",
129 "--force-clean",
130 "--no-update",
131 "--build-style=%s" % self._delegate.build_style(),
132 ],
133 "Able to build without patch",
134 "Unable to build without patch")
135
136 def _test(self):
137 return self._run_command([
138 "build-and-test",
139 "--no-clean",
140 "--no-update",
141 # Notice that we don't pass --build, which means we won't build!
142 "--test",
143 "--non-interactive",
144 ],
145 "Passed tests",
146 "Patch does not pass tests")
147
148 def _build_and_test_without_patch(self):
149 return self._run_command([
150 "build-and-test",
151 "--force-clean",
152 "--no-update",
153 "--build",
154 "--test",
155 "--non-interactive",
156 ],
157 "Able to pass tests without patch",
158 "Unable to pass tests without patch (tree is red?)")
159
160 def _land(self):
161 # Unclear if this should pass --quiet or not. If --parent-command alway s does the reporting, then it should.
162 return self._run_command([
163 "land-attachment",
164 "--force-clean",
165 "--non-interactive",
166 "--parent-command=" + self._delegate.parent_command(),
167 self._patch.id(),
168 ],
169 "Landed patch",
170 "Unable to land patch")
171
172 def _report_flaky_tests(self, flaky_test_results, results_archive):
173 self._delegate.report_flaky_tests(self._patch, flaky_test_results, resul ts_archive)
174
175 def _results_failed_different_tests(self, first, second):
176 first_failing_tests = [] if not first else first.failing_tests()
177 second_failing_tests = [] if not second else second.failing_tests()
178 return first_failing_tests != second_failing_tests
179
180 def _test_patch(self):
181 if self._test():
182 return True
183
184 # Note: archive_last_test_results deletes the results directory, making these calls order-sensitve.
185 # We could remove this dependency by building the test_results from the archive.
186 first_results = self._delegate.test_results()
187 first_results_archive = self._delegate.archive_last_test_results(self._p atch)
188 first_script_error = self._script_error
189 first_failure_status_id = self.failure_status_id
190
191 if self._expected_failures.failures_were_expected(first_results):
192 return True
193
194 if self._test():
195 # Only report flaky tests if we were successful at parsing results.j son and archiving results.
196 if first_results and first_results_archive:
197 self._report_flaky_tests(first_results.failing_test_results(), f irst_results_archive)
198 return True
199
200 second_results = self._delegate.test_results()
201 if self._results_failed_different_tests(first_results, second_results):
202 # We could report flaky tests here, but we would need to be careful
203 # to use similar checks to ExpectedFailures._can_trust_results
204 # to make sure we don't report constant failures as flakes when
205 # we happen to hit the --exit-after-N-failures limit.
206 # See https://bugs.webkit.org/show_bug.cgi?id=51272
207 return False
208
209 # Archive (and remove) second results so test_results() after
210 # build_and_test_without_patch won't use second results instead of the c lean-tree results.
211 second_results_archive = self._delegate.archive_last_test_results(self._ patch)
212
213 if self._build_and_test_without_patch():
214 # The error from the previous ._test() run is real, report it.
215 return self.report_failure(first_results_archive, first_results, fir st_script_error)
216
217 clean_tree_results = self._delegate.test_results()
218 self._expected_failures.update(clean_tree_results)
219
220 # Re-check if the original results are now to be expected to avoid a ful l re-try.
221 if self._expected_failures.failures_were_expected(first_results):
222 return True
223
224 # Now that we have updated information about failing tests with a clean checkout, we can
225 # tell if our original failures were unexpected and fail the patch if ne cessary.
226 if self._expected_failures.unexpected_failures_observed(first_results):
227 self.failure_status_id = first_failure_status_id
228 return self.report_failure(first_results_archive, first_results, fir st_script_error)
229
230 # We don't know what's going on. The tree is likely very red (beyond ou r layout-test-results
231 # failure limit), just keep retrying the patch. until someone fixes the tree.
232 return False
233
234 def results_archive_from_patch_test_run(self, patch):
235 assert(self._patch.id() == patch.id()) # PatchAnalysisTask is not curre ntly re-useable.
236 return self._results_archive_from_patch_test_run
237
238 def results_from_patch_test_run(self, patch):
239 assert(self._patch.id() == patch.id()) # PatchAnalysisTask is not curre ntly re-useable.
240 return self._results_from_patch_test_run
241
242 def report_failure(self, results_archive=None, results=None, script_error=No ne):
243 if not self.validate():
244 return False
245 self._results_archive_from_patch_test_run = results_archive
246 self._results_from_patch_test_run = results
247 raise script_error or self._script_error
248
249 def validate(self):
250 raise NotImplementedError("subclasses must implement")
251
252 def run(self):
253 raise NotImplementedError("subclasses must implement")
OLDNEW
« no previous file with comments | « Tools/Scripts/webkitpy/tool/bot/flakytestreporter_unittest.py ('k') | Tools/Scripts/webkitpy/tool/bot/queueengine.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698