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

Side by Side Diff: Tools/Scripts/webkitpy/layout_tests/layout_package/bot_test_expectations.py

Issue 1289163002: Improve flakiness logic for print-flaky-tests. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 5 years, 4 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
« no previous file with comments | « no previous file | Tools/Scripts/webkitpy/layout_tests/layout_package/bot_test_expectations_unittest.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright (C) 2013 Google Inc. All rights reserved. 1 # Copyright (C) 2013 Google Inc. All rights reserved.
2 # 2 #
3 # Redistribution and use in source and binary forms, with or without 3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are 4 # modification, are permitted provided that the following conditions are
5 # met: 5 # met:
6 # 6 #
7 # * Redistributions of source code must retain the above copyright 7 # * Redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer. 8 # notice, this list of conditions and the following disclaimer.
9 # * Redistributions in binary form must reproduce the above 9 # * Redistributions in binary form must reproduce the above
10 # copyright notice, this list of conditions and the following disclaimer 10 # copyright notice, this list of conditions and the following disclaimer
(...skipping 18 matching lines...) Expand all
29 """Generates a fake TestExpectations file consisting of flaky tests from the bot 29 """Generates a fake TestExpectations file consisting of flaky tests from the bot
30 corresponding to the give port.""" 30 corresponding to the give port."""
31 31
32 import json 32 import json
33 import logging 33 import logging
34 import os.path 34 import os.path
35 import urllib 35 import urllib
36 import urllib2 36 import urllib2
37 37
38 from webkitpy.layout_tests.port import builders 38 from webkitpy.layout_tests.port import builders
39 from webkitpy.layout_tests.models.test_expectations import TestExpectations 39 from webkitpy.layout_tests.models.test_expectations import TestExpectations, PAS S
40 from webkitpy.layout_tests.models.test_expectations import TestExpectationLine 40 from webkitpy.layout_tests.models.test_expectations import TestExpectationLine
41 41
42 42
43 _log = logging.getLogger(__name__) 43 _log = logging.getLogger(__name__)
44 44
45 45
46 # results.json v4 format: 46 # results.json v4 format:
47 # { 47 # {
48 # 'version': 4, 48 # 'version': 4,
49 # 'builder name' : { 49 # 'builder name' : {
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
141 def expectations_for_builder(self, builder): 141 def expectations_for_builder(self, builder):
142 results_json = self._results_json_for_builder(builder) 142 results_json = self._results_json_for_builder(builder)
143 if not results_json: 143 if not results_json:
144 return None 144 return None
145 return BotTestExpectations(results_json) 145 return BotTestExpectations(results_json)
146 146
147 class BotTestExpectations(object): 147 class BotTestExpectations(object):
148 # FIXME: Get this from the json instead of hard-coding it. 148 # FIXME: Get this from the json instead of hard-coding it.
149 RESULT_TYPES_TO_IGNORE = ['N', 'X', 'Y'] # NO_DATA, SKIP, NOTRUN 149 RESULT_TYPES_TO_IGNORE = ['N', 'X', 'Y'] # NO_DATA, SKIP, NOTRUN
150 150
151 # TODO(ojan): Remove this once crbug.com/514378 is fixed. 151 # TODO(ojan): Remove this once crbug.com/514378 is fixed.
joelo 2015/08/17 23:43:29 should be able to remove now?
152 # The JSON can contain results for expectations, not just actual result type s. 152 # The JSON can contain results for expectations, not just actual result type s.
153 NON_RESULT_TYPES = ['S', 'X'] # SLOW, SKIP 153 NON_RESULT_TYPES = ['S', 'X'] # SLOW, SKIP
154 154
155 PASS_EXPECTATION = 'PASS'
156
157 # specifiers arg is used in unittests to avoid the static dependency on buil ders. 155 # specifiers arg is used in unittests to avoid the static dependency on buil ders.
158 def __init__(self, results_json, specifiers=None): 156 def __init__(self, results_json, specifiers=None):
159 self.results_json = results_json 157 self.results_json = results_json
160 self.specifiers = specifiers or set(builders.specifiers_for_builder(resu lts_json.builder_name)) 158 self.specifiers = specifiers or set(builders.specifiers_for_builder(resu lts_json.builder_name))
161 159
162 def _line_from_test_and_flaky_types(self, test_path, flaky_types): 160 def _line_from_test_and_flaky_types(self, test_path, flaky_types):
163 line = TestExpectationLine() 161 line = TestExpectationLine()
164 line.original_string = test_path 162 line.original_string = test_path
165 line.name = test_path 163 line.name = test_path
166 line.filename = test_path 164 line.filename = test_path
167 line.path = test_path # FIXME: Should this be normpath? 165 line.path = test_path # FIXME: Should this be normpath?
168 line.matching_tests = [test_path] 166 line.matching_tests = [test_path]
169 line.bugs = ["crbug.com/FILE_A_BUG_BEFORE_COMMITTING_THIS"] 167 line.bugs = ["crbug.com/FILE_A_BUG_BEFORE_COMMITTING_THIS"]
170 line.expectations = sorted(map(self.results_json.expectation_for_type, f laky_types)) 168 line.expectations = sorted(flaky_types)
171 line.specifiers = self.specifiers 169 line.specifiers = self.specifiers
172 return line 170 return line
173 171
174 def flakes_by_path(self, only_ignore_very_flaky): 172 def flakes_by_path(self, only_ignore_very_flaky):
175 """Sets test expectations to bot results if there are at least two disti nct results.""" 173 """Sets test expectations to bot results if there are at least two disti nct results."""
176 flakes_by_path = {} 174 flakes_by_path = {}
177 for test_path, entry in self.results_json.walk_results(): 175 for test_path, entry in self.results_json.walk_results():
178 flaky_types = self._flaky_types_in_results(entry, only_ignore_very_f laky) 176 flaky_types = self._flaky_types_in_results(entry, only_ignore_very_f laky)
179 if len(flaky_types) <= 1: 177 if len(flaky_types) <= 1:
180 continue 178 continue
181 flakes_by_path[test_path] = sorted(map(self.results_json.expectation _for_type, flaky_types)) 179 flakes_by_path[test_path] = sorted(flaky_types)
182 return flakes_by_path 180 return flakes_by_path
183 181
184 def unexpected_results_by_path(self): 182 def unexpected_results_by_path(self):
185 """For tests with unexpected results, returns original expectations + re sults.""" 183 """For tests with unexpected results, returns original expectations + re sults."""
186 def exp_to_string(exp): 184 def exp_to_string(exp):
187 return TestExpectations.EXPECTATIONS_TO_STRING.get(exp, None).upper( ) 185 return TestExpectations.EXPECTATIONS_TO_STRING.get(exp, None).upper( )
188 186
189 def string_to_exp(string): 187 def string_to_exp(string):
190 # Needs a bit more logic than the method above, 188 # Needs a bit more logic than the method above,
191 # since a PASS is 0 and evaluates to False. 189 # since a PASS is 0 and evaluates to False.
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
240 238
241 for result_item in run_length_encoded_results: 239 for result_item in run_length_encoded_results:
242 _, result_types = self.results_json.occurances_and_type_from_result_ item(result_item) 240 _, result_types = self.results_json.occurances_and_type_from_result_ item(result_item)
243 241
244 for result_type in result_types: 242 for result_type in result_types:
245 if result_type not in self.RESULT_TYPES_TO_IGNORE: 243 if result_type not in self.RESULT_TYPES_TO_IGNORE:
246 results.add(result_type) 244 results.add(result_type)
247 245
248 return results 246 return results
249 247
248 def _result_to_enum(self, result):
249 return TestExpectations.EXPECTATIONS[result.lower()]
250
250 def _flaky_types_in_results(self, results_entry, only_ignore_very_flaky): 251 def _flaky_types_in_results(self, results_entry, only_ignore_very_flaky):
251 flaky_results = set() 252 flaky_results = set()
252 253
253 latest_expectations = [self.PASS_EXPECTATION] 254 # Always include pass as an expected result. Passes will never turn the bot red.
255 # This fixes cases where the expectations have an implicit Pass, e.g. [ Slow ].
256 latest_expectations = [PASS]
254 if self.results_json.EXPECTATIONS_KEY in results_entry: 257 if self.results_json.EXPECTATIONS_KEY in results_entry:
255 latest_expectations = results_entry[self.results_json.EXPECTATIONS_K EY].split(' ') 258 expectations_list = results_entry[self.results_json.EXPECTATIONS_KEY ].split(' ')
259 latest_expectations += [self._result_to_enum(expectation) for expect ation in expectations_list]
256 260
257 for result_item in results_entry[self.results_json.RESULTS_KEY]: 261 for result_item in results_entry[self.results_json.RESULTS_KEY]:
258 _, result_types_str = self.results_json.occurances_and_type_from_res ult_item(result_item) 262 _, result_types_str = self.results_json.occurances_and_type_from_res ult_item(result_item)
259 263
260 result_types = [] 264 result_types = []
261 for result_type in result_types_str: 265 for result_type in result_types_str:
262 # TODO(ojan): Remove this if-statement once crbug.com/514378 is fixed. 266 # TODO(ojan): Remove this if-statement once crbug.com/514378 is fixed.
joelo 2015/08/17 23:43:30 same here
ojan 2015/08/19 00:42:54 Last I checked, some of the slower bots still had
263 if result_type not in self.NON_RESULT_TYPES: 267 if result_type not in self.NON_RESULT_TYPES:
264 result_types.append(result_type) 268 result_types.append(self.results_json.expectation_for_type(r esult_type))
265 269
266 # It didn't flake if it didn't retry. 270 # It didn't flake if it didn't retry.
267 if len(result_types) <= 1: 271 if len(result_types) <= 1:
268 continue 272 continue
269 273
270 # If the test ran as expected after only one retry, it's not very fl aky. 274 # If the test ran as expected after only one retry, it's not very fl aky.
271 # It's only very flaky if it failed the first run and the first retr y 275 # It's only very flaky if it failed the first run and the first retr y
272 # and then ran as expected in one of the subsequent retries. 276 # and then ran as expected in one of the subsequent retries.
273 if only_ignore_very_flaky and self.results_json.expectation_for_type (result_types[1]) in latest_expectations: 277 # If there are only two entries, then that means it failed on the fi rst
274 # Once we get a pass, we don't retry again. So if the first retr y passed, 278 # try and ran as expected on the second because otherwise we'd have
275 # then there should only be 2 entries because we don't do anothe r retry. 279 # a third entry from the next try.
276 # TODO(ojan): Reenable this assert once crbug.com/514378 is fixe d. 280 second_result_type_enum_value = self._result_to_enum(result_types[1] )
277 # assert(len(result_types) == 2) 281 if only_ignore_very_flaky and len(result_types) == 2:
278 continue 282 continue
279 283
280 flaky_results = flaky_results.union(set(result_types)) 284 has_unexpected_results = False
285 for result_type in result_types:
286 result_enum = self._result_to_enum(result_type)
287 # TODO(ojan): We really should be grabbing the expected results from the time
288 # of the run instead of looking at the latest expected results. That's a lot
289 # more complicated though. So far we've been looking at the aggr egated
290 # results_small.json off test_results.appspot, which has all the information
291 # for the last 100 runs. In order to do this, we'd need to look at the
292 # individual runs' full_results.json, which would be slow and mo re complicated.
293 # The only thing we lose by not fixing this is that a test that was flaky
294 # and got fixed will still get printed out until 100 runs have p assed.
295 if not TestExpectations.result_was_expected(result_enum, latest_ expectations, test_needs_rebaselining=False):
296 has_unexpected_results = True
297 break
298
299 if has_unexpected_results:
300 flaky_results = flaky_results.union(set(result_types))
281 301
282 return flaky_results 302 return flaky_results
OLDNEW
« no previous file with comments | « no previous file | Tools/Scripts/webkitpy/layout_tests/layout_package/bot_test_expectations_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698