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: third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/update_test_expectations.py

Issue 2380173002: Change update_test_expectations to not require builders for all configurations. (Closed)
Patch Set: Change one log line to warning, update docstring for test method Created 4 years, 2 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
« no previous file with comments | « no previous file | third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/update_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 2016 The Chromium Authors. All rights reserved. 1 # Copyright 2016 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 """Updates TestExpectations based on results in builder bots. 5 """Updates TestExpectations based on results in builder bots.
6 6
7 Scans the TestExpectations file and uses results from actual builder bots runs 7 Scans the TestExpectations file and uses results from actual builder bots runs
8 to remove tests that are marked as flaky but don't fail in the specified way. 8 to remove tests that are marked as flaky but don't fail in the specified way.
9 9
10 E.g. If a test has this expectation: 10 E.g. If a test has this expectation:
(...skipping 15 matching lines...) Expand all
26 import argparse 26 import argparse
27 import logging 27 import logging
28 28
29 from webkitpy.layout_tests.models.test_expectations import TestExpectations 29 from webkitpy.layout_tests.models.test_expectations import TestExpectations
30 30
31 _log = logging.getLogger(__name__) 31 _log = logging.getLogger(__name__)
32 32
33 33
34 def main(host, bot_test_expectations_factory, argv): 34 def main(host, bot_test_expectations_factory, argv):
35 parser = argparse.ArgumentParser(epilog=__doc__, formatter_class=argparse.Ra wTextHelpFormatter) 35 parser = argparse.ArgumentParser(epilog=__doc__, formatter_class=argparse.Ra wTextHelpFormatter)
36 parser.parse_args(argv) 36 parser.add_argument('--verbose', '-v', action='store_true', default=False, h elp='enable more verbose logging')
37 args = parser.parse_args(argv)
38
39 logging.basicConfig(level=logging.DEBUG if args.verbose else logging.INFO, f ormat="%(levelname)s: %(message)s")
37 40
38 port = host.port_factory.get() 41 port = host.port_factory.get()
39
40 logging.basicConfig(level=logging.INFO, format="%(message)s")
41
42 expectations_file = port.path_to_generic_test_expectations_file() 42 expectations_file = port.path_to_generic_test_expectations_file()
43 if not host.filesystem.isfile(expectations_file): 43 if not host.filesystem.isfile(expectations_file):
44 _log.warning("Didn't find generic expectations file at: " + expectations _file) 44 _log.warning("Didn't find generic expectations file at: " + expectations _file)
45 return 1 45 return 1
46 46
47 remove_flakes_o_matic = RemoveFlakesOMatic(host, 47 remove_flakes_o_matic = RemoveFlakesOMatic(host,
48 port, 48 port,
49 bot_test_expectations_factory) 49 bot_test_expectations_factory)
50 50
51 test_expectations = remove_flakes_o_matic.get_updated_test_expectations() 51 test_expectations = remove_flakes_o_matic.get_updated_test_expectations()
52 52
53 remove_flakes_o_matic.write_test_expectations(test_expectations, 53 remove_flakes_o_matic.write_test_expectations(test_expectations,
54 expectations_file) 54 expectations_file)
55 return 0 55 return 0
56 56
57 57
58 class RemoveFlakesOMatic(object): 58 class RemoveFlakesOMatic(object):
59
59 def __init__(self, host, port, bot_test_expectations_factory): 60 def __init__(self, host, port, bot_test_expectations_factory):
60 self._host = host 61 self._host = host
61 self._port = port 62 self._port = port
62 self._expectations_factory = bot_test_expectations_factory 63 self._expectations_factory = bot_test_expectations_factory
63 self._builder_results_by_path = {} 64 self._builder_results_by_path = {}
64 65
65 def _can_delete_line(self, test_expectation_line): 66 def _can_delete_line(self, test_expectation_line):
66 """Returns whether a given line in the expectations can be removed. 67 """Returns whether a given line in the expectations can be removed.
67 68
68 Uses results from builder bots to determine if a given line is stale and 69 Uses results from builder bots to determine if a given line is stale and
(...skipping 16 matching lines...) Expand all
85 # Don't check lines that have expectations like NeedsRebaseline or Skip. 86 # Don't check lines that have expectations like NeedsRebaseline or Skip.
86 if self._has_unstrippable_expectations(expectations): 87 if self._has_unstrippable_expectations(expectations):
87 return False 88 return False
88 89
89 # Don't check lines unless they're flaky. i.e. At least one expectation is a PASS. 90 # Don't check lines unless they're flaky. i.e. At least one expectation is a PASS.
90 if not self._has_pass_expectation(expectations): 91 if not self._has_pass_expectation(expectations):
91 return False 92 return False
92 93
93 # The line can be deleted if the only expectation on the line that appea rs in the actual 94 # The line can be deleted if the only expectation on the line that appea rs in the actual
94 # results is the PASS expectation. 95 # results is the PASS expectation.
96 builders_checked = []
95 for config in test_expectation_line.matching_configurations: 97 for config in test_expectation_line.matching_configurations:
96 builder_name = self._host.builders.builder_name_for_specifiers(confi g.version, config.build_type) 98 builder_name = self._host.builders.builder_name_for_specifiers(confi g.version, config.build_type)
97 99
98 if not builder_name: 100 if not builder_name:
99 _log.error('Failed to get builder for config [%s, %s, %s]', 101 _log.debug('No builder with config %s', config)
100 config.version, config.architecture, config.build_typ e)
101 # TODO(bokan): Matching configurations often give us bots that d on't have a 102 # TODO(bokan): Matching configurations often give us bots that d on't have a
102 # builder in builders.py's exact_matches. Should we ignore those or be conservative 103 # builder in builders.py's exact_matches. Should we ignore those or be conservative
103 # and assume we need these expectations to make a decision? 104 # and assume we need these expectations to make a decision?
104 return False 105 continue
106
107 builders_checked.append(builder_name)
105 108
106 if builder_name not in self._builder_results_by_path.keys(): 109 if builder_name not in self._builder_results_by_path.keys():
107 _log.error('Failed to find results for builder "%s"', builder_na me) 110 _log.error('Failed to find results for builder "%s"', builder_na me)
108 return False 111 return False
109 112
110 results_by_path = self._builder_results_by_path[builder_name] 113 results_by_path = self._builder_results_by_path[builder_name]
111 114
112 # No results means the tests were all skipped or all results are pas sing. 115 # No results means the tests were all skipped or all results are pas sing.
113 if test_expectation_line.path not in results_by_path.keys(): 116 if test_expectation_line.path not in results_by_path.keys():
114 continue 117 continue
115 118
116 results_for_single_test = results_by_path[test_expectation_line.path ] 119 results_for_single_test = results_by_path[test_expectation_line.path ]
117 120
118 if self._expectations_that_were_met(test_expectation_line, results_f or_single_test) != set(['PASS']): 121 if self._expectations_that_were_met(test_expectation_line, results_f or_single_test) != set(['PASS']):
119 return False 122 return False
120 123
124 if builders_checked:
125 _log.debug('Checked builders:\n %s', '\n '.join(builders_checked))
126 else:
127 _log.warning('No matching builders for line, deleting line.')
128 _log.info('Deleting line "%s"', test_expectation_line.original_string.st rip())
121 return True 129 return True
122 130
123 def _has_pass_expectation(self, expectations): 131 def _has_pass_expectation(self, expectations):
124 return 'PASS' in expectations 132 return 'PASS' in expectations
125 133
126 def _expectations_that_were_met(self, test_expectation_line, results_for_sin gle_test): 134 def _expectations_that_were_met(self, test_expectation_line, results_for_sin gle_test):
127 """Returns the set of expectations that appear in the given results. 135 """Returns the set of expectations that appear in the given results.
128 136
129 e.g. If the test expectations is "bug(test) fast/test.html [Crash Failur e Pass]" 137 e.g. If the test expectations is "bug(test) fast/test.html [Crash Failur e Pass]"
130 and the results are ['TEXT', 'PASS', 'PASS', 'TIMEOUT'], then this metho d would 138 and the results are ['TEXT', 'PASS', 'PASS', 'TIMEOUT'], then this metho d would
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
282 """Writes the given TestExpectations object to the filesystem. 290 """Writes the given TestExpectations object to the filesystem.
283 291
284 Args: 292 Args:
285 test_expectations: The TestExpectations object to write. 293 test_expectations: The TestExpectations object to write.
286 test_expectations_file: The full file path of the Blink 294 test_expectations_file: The full file path of the Blink
287 TestExpectations file. This file will be overwritten. 295 TestExpectations file. This file will be overwritten.
288 """ 296 """
289 self._host.filesystem.write_text_file( 297 self._host.filesystem.write_text_file(
290 test_expectations_file, 298 test_expectations_file,
291 TestExpectations.list_to_string(test_expectations, reconstitute_only _these=[])) 299 TestExpectations.list_to_string(test_expectations, reconstitute_only _these=[]))
OLDNEW
« no previous file with comments | « no previous file | third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/update_test_expectations_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698