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

Side by Side Diff: third_party/WebKit/Tools/Scripts/webkitpy/w3c/update_w3c_test_expectations.py

Issue 2183913002: Removes build and builder object refrences along with minor bug fixes (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Adds more failure types and test expectation types to get_expectations Created 4 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
« no previous file with comments | « no previous file | third_party/WebKit/Tools/Scripts/webkitpy/w3c/update_w3c_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 """A script to modify TestExpectations lines based layout test failures in try j obs. 5 """A script to modify TestExpectations lines based layout test failures in try j obs.
6 6
7 This script outputs a list of test expectation lines to add to a 'TestExpectatio ns' file 7 This script outputs a list of test expectation lines to add to a 'TestExpectatio ns' file
8 by retrieving the try job results for the current CL. 8 by retrieving the try job results for the current CL.
9 """ 9 """
10 10
11 import logging 11 import logging
12 12
13 from webkitpy.common.net import buildbot 13 from webkitpy.common.net.buildbot import BuildBot
14 from webkitpy.common.net import rietveld 14 from webkitpy.common.net import rietveld
15 15
16 16
17 _log = logging.getLogger(__name__) 17 _log = logging.getLogger(__name__)
18 18
19 19
20 def main(host, port): 20 def main(host, port):
21 expectations_file = port.path_to_generic_test_expectations_file() 21 expectations_file = port.path_to_generic_test_expectations_file()
22 expectations_line_adder = W3CExpectationsLineAdder(host) 22 expectations_line_adder = W3CExpectationsLineAdder(host)
23 issue_number = expectations_line_adder.get_issue_number() 23 issue_number = expectations_line_adder.get_issue_number()
24 try_bots = expectations_line_adder.get_try_bots() 24 try_bots = expectations_line_adder.get_try_bots()
25 try_jobs = rietveld.latest_try_jobs(issue_number, try_bots, host.web) 25 try_jobs = rietveld.latest_try_jobs(issue_number, try_bots, host.web)
26 line_expectations_dict = {} 26 test_expectations = {}
27 if not try_jobs: 27 if not try_jobs:
28 print 'No Try Job information was collected.' 28 print 'No Try Job information was collected.'
29 return 1 29 return 1
30 for try_job in try_jobs: 30 for job in try_jobs:
31 builder_name = try_job[0] 31 platform_results = expectations_line_adder.get_failing_results_dict(Buil dBot(), job.builder_name, job.build_number)
32 build_number = try_job[1] 32 test_expectations = expectations_line_adder.merge_dicts(test_expectation s, platform_results)
33 builder = buildbot.Builder(builder_name, host.buildbot) 33 for test_name, platform_result in test_expectations.iteritems():
34 build = buildbot.Build(builder, build_number) 34 test_expectations[test_name] = expectations_line_adder.merge_same_valued _keys(platform_result)
35 platform_results_dict = expectations_line_adder.get_failing_results_dict (builder, build) 35 test_expectation_lines = expectations_line_adder.create_line_list(test_expec tations)
36 line_expectations_dict = expectations_line_adder.merge_dicts(line_expect ations_dict, platform_results_dict) 36 expectations_line_adder.write_to_test_expectations(host, expectations_file, test_expectation_lines)
37 for platform_results_dicts in line_expectations_dict.values():
38 platform_results_dicts = expectations_line_adder.merge_same_valued_keys( platform_results_dicts)
39 line_list = expectations_line_adder.create_line_list(line_expectations_dict)
40 expectations_line_adder.write_to_test_expectations(host, expectations_file, line_list)
41 37
42 38
43 class W3CExpectationsLineAdder(object): 39 class W3CExpectationsLineAdder(object):
44 40
45 def __init__(self, host): 41 def __init__(self, host):
46 self._host = host 42 self._host = host
47 self.filesystem = host.filesystem 43 self.filesystem = host.filesystem
48 44
49 def get_issue_number(self): 45 def get_issue_number(self):
50 return self._host.scm().get_issue_number() 46 return self._host.scm().get_issue_number()
51 47
52 def get_try_bots(self): 48 def get_try_bots(self):
53 return self._host.builders.all_try_builder_names() 49 return self._host.builders.all_try_builder_names()
54 50
55 def _generate_results_dict(self, platform, result_list): 51 def _generate_results_dict(self, platform, result_list):
56 test_dict = {} 52 test_dict = {}
57 if '-' in platform: 53 if '-' in platform:
58 platform = platform[platform.find('-') + 1:].capitalize() 54 platform = platform[platform.find('-') + 1:].capitalize()
59 for result in result_list: 55 for result in result_list:
60 test_dict[result.test_name()] = { 56 test_dict[result.test_name()] = {
61 platform: { 57 platform: {
62 'expected': result.expected_results(), 58 'expected': result.expected_results(),
63 'actual': result.actual_results(), 59 'actual': result.actual_results(),
64 'bug': 'crbug.com/626703' 60 'bug': 'crbug.com/626703'
65 }} 61 }}
66 return test_dict 62 return test_dict
67 63
68 def get_failing_results_dict(self, builder, build): 64 def get_failing_results_dict(self, buildbot, builder_name, build_number):
69 """Returns a nested dict of failing test results. 65 """Returns a nested dict of failing test results.
70 66
71 Retrieves a full list of layout test results from a builder result URL. Collects 67 Retrieves a full list of layout test results from a builder result URL. Collects
72 the builder name, platform and a list of tests that did not run as expec ted. 68 the builder name, platform and a list of tests that did not run as expec ted.
73 69
74 Args: 70 Args:
75 builder: A Builder object. 71 builder: A Builder object.
76 build: A Build object. 72 build: A Build object.
77 73
78 Returns: 74 Returns:
79 A dictionary with the structure: { 75 A dictionary with the structure: {
80 'key': { 76 'key': {
81 'expected': 'TIMEOUT', 77 'expected': 'TIMEOUT',
82 'actual': 'CRASH', 78 'actual': 'CRASH',
83 'bug': 'crbug.com/11111' 79 'bug': 'crbug.com/11111'
84 } 80 }
85 } 81 }
86 """ 82 """
87 layout_test_results = builder.fetch_layout_test_results(build.results_ur l()) 83 results_url = buildbot.results_url(builder_name, build_number)
88 builder_name = layout_test_results.builder_name() 84 layout_test_results = buildbot.fetch_layout_test_results(results_url)
89 platform = self._host.builders.port_name_for_builder_name(builder_name) 85 platform = self._host.builders.port_name_for_builder_name(builder_name)
90 result_list = layout_test_results.didnt_run_as_expected_results() 86 result_list = layout_test_results.didnt_run_as_expected_results()
91 failing_results_dict = self._generate_results_dict(platform, result_list ) 87 failing_results_dict = self._generate_results_dict(platform, result_list )
92 return failing_results_dict 88 return failing_results_dict
93 89
94 def merge_dicts(self, target, source, path=None): 90 def merge_dicts(self, target, source, path=None):
95 """Recursively merge nested dictionaries, returning the target dictionar y 91 """Recursively merge nested dictionaries, returning the target dictionar y
96 92
97 Merges the keys and values from the source dict into the target dict. 93 Merges the keys and values from the source dict into the target dict.
98 94
(...skipping 23 matching lines...) Expand all
122 """Merges keys in dictionary with same value. 118 """Merges keys in dictionary with same value.
123 119
124 Traverses through a dict and compares the values of keys to one another. 120 Traverses through a dict and compares the values of keys to one another.
125 If the values match, the keys are combined to a tuple and the previous k eys 121 If the values match, the keys are combined to a tuple and the previous k eys
126 are removed from the dict. 122 are removed from the dict.
127 123
128 Args: 124 Args:
129 dictionary: A dictionary with a dictionary as the value. 125 dictionary: A dictionary with a dictionary as the value.
130 126
131 Returns: 127 Returns:
132 A dictionary with updated keys to reflect matching values of keys. 128 A new dictionary with updated keys to reflect matching values of key s.
133 Example: { 129 Example: {
134 'one': {'foo': 'bar'}, 130 'one': {'foo': 'bar'},
135 'two': {'foo': 'bar'}, 131 'two': {'foo': 'bar'},
136 'three': {'foo': bar'} 132 'three': {'foo': 'bar'}
137 } 133 }
138 is converted to {('one', 'two', 'three'): {'foo': 'bar'}} 134 is converted to a new dictionary with that contains
135 {('one', 'two', 'three'): {'foo': 'bar'}}
139 """ 136 """
137 merged_dict = {}
140 matching_value_keys = set() 138 matching_value_keys = set()
141 keys = dictionary.keys() 139 keys = sorted(dictionary.keys())
142 is_last_item = False 140 while keys:
143 for index, item in enumerate(keys): 141 current_key = keys[0]
144 if is_last_item: 142 found_match = False
143 if current_key == keys[-1]:
144 merged_dict[current_key] = dictionary[current_key]
145 keys.remove(current_key)
145 break 146 break
146 for i in range(index + 1, len(keys)): 147 for next_item in keys[1:]:
147 next_item = keys[i] 148 if dictionary[current_key] == dictionary[next_item]:
148 if dictionary[item] == dictionary[next_item]: 149 found_match = True
149 matching_value_keys.update([item, next_item]) 150 matching_value_keys.update([current_key, next_item])
150 dictionary[tuple(matching_value_keys)] = dictionary[item] 151 if next_item == keys[-1]:
151 is_last_item = next_item == keys[-1] 152 if found_match:
152 del dictionary[item] 153 merged_dict[tuple(matching_value_keys)] = dictionary[cur rent_key]
153 del dictionary[next_item] 154 keys = [k for k in keys if k not in matching_value_keys]
154 return dictionary 155 else:
156 merged_dict[current_key] = dictionary[current_key]
157 keys.remove(current_key)
158 matching_value_keys = set()
159 return merged_dict
155 160
156 def get_expectations(self, results): 161 def get_expectations(self, results):
157 """Returns a list of test expectations for a given test dict. 162 """Returns a set of test expectations for a given test dict.
158 163
159 Returns a list of one or more test expectations based on the expected 164 Returns a set of one or more test expectations based on the expected
160 and actual results of a given test name. 165 and actual results of a given test name.
161 166
162 Args: 167 Args:
163 results: A dictionary that maps one test to its results. Example: { 168 results: A dictionary that maps one test to its results. Example: {
164 'test_name': { 169 'test_name': {
165 'expected': 'PASS', 170 'expected': 'PASS',
166 'actual': 'FAIL', 171 'actual': 'FAIL',
167 'bug': 'crbug.com/11111' 172 'bug': 'crbug.com/11111'
168 } 173 }
169 } 174 }
170 175
171 Returns: 176 Returns:
172 A list of one or more test expectations with the first letter capita lized. Example: 177 A set of one or more test expectations with the first letter capital ized. Example:
173 ['Failure', 'Timeout'] 178 set(['Failure', 'Timeout'])
174 """ 179 """
175 expectations = [] 180 expectations = set()
176 failure_expectations = ['TEXT', 'FAIL', 'IMAGE+TEXT', 'IMAGE'] 181 failure_types = ['TEXT', 'FAIL', 'IMAGE+TEXT', 'IMAGE', 'AUDIO', 'MISSIN G', 'LEAK']
177 pass_crash_timeout = ['TIMEOUT', 'CRASH', 'PASS'] 182 test_expectation_types = ['SLOW', 'TIMEOUT', 'CRASH', 'PASS', 'REBASELIN E', 'NEEDSREBASELINE', 'NEEDSMANUALREBASELINE']
178 if results['expected'] in pass_crash_timeout and results['actual'] in fa ilure_expectations: 183 for expected in results['expected'].split():
179 expectations.append('Failure') 184 for actual in results['actual'].split():
180 if results['expected'] in failure_expectations and results['actual'] in pass_crash_timeout: 185 if expected in test_expectation_types and actual in failure_type s:
181 expectations.append(results['actual'].capitalize()) 186 expectations.add('Failure')
182 if results['expected'] in pass_crash_timeout and results['actual'] in pa ss_crash_timeout: 187 if expected in failure_types and actual in test_expectation_type s:
183 expectations.append(results['actual'].capitalize()) 188 expectations.add(actual.capitalize())
184 expectations.append(results['expected'].capitalize()) 189 if expected in test_expectation_types and actual in test_expecta tion_types:
190 expectations.add(actual.capitalize())
185 return expectations 191 return expectations
186 192
187 def create_line_list(self, merged_results): 193 def create_line_list(self, merged_results):
188 """Creates list of test expectations lines. 194 """Creates list of test expectations lines.
189 195
190 Traverses through a merged_results and parses the value to create a test 196 Traverses through a merged_results and parses the value to create a test
191 expectations line per key. 197 expectations line per key.
192 198
193 Args: 199 Args:
194 merged_results: A merged_results with the format { 200 merged_results: A merged_results with the format {
195 'test_name': { 201 'test_name': {
196 'platform': { 202 'platform': {
197 'expected: 'PASS', 203 'expected: 'PASS',
198 'actual': 'FAIL', 204 'actual': 'FAIL',
199 'bug': 'crbug.com/11111' 205 'bug': 'crbug.com/11111'
200 } 206 }
201 } 207 }
202 } 208 }
203 It is possible for the dicitonary to have many test_name 209 It is possible for the dicitonary to have many test_name
204 keys. 210 keys.
205 211
206 Returns: 212 Returns:
207 A list of test expectations lines with the format 213 A list of test expectations lines with the format
208 ['BUG_URL [PLATFORM(S)] TEST_MAME [EXPECTATION(S)]'] 214 ['BUG_URL [PLATFORM(S)] TEST_MAME [EXPECTATION(S)]']
209 """ 215 """
210 line_list = [] 216 line_list = []
211 for test_name, platform_results in merged_results.iteritems(): 217 for test_name, platform_results in merged_results.iteritems():
212 for platform in platform_results: 218 for platform in platform_results:
213 platform_list = [] 219 if test_name.startswith('imported'):
214 bug = [] 220 print platform_results
215 expectations = [] 221 platform_list = []
216 if isinstance(platform, tuple): 222 bug = []
217 platform_list = list(platform) 223 expectations = []
218 else: 224 if isinstance(platform, tuple):
219 platform_list.append(platform) 225 platform_list = list(platform)
220 bug.append(platform_results[platform]['bug']) 226 else:
221 expectations = self.get_expectations(platform_results[platform]) 227 platform_list.append(platform)
222 line = '%s [ %s ] %s [ %s ]' % (bug[0], ' '.join(platform_list), test_name, ' '.join(expectations)) 228 bug.append(platform_results[platform]['bug'])
223 line_list.append(str(line)) 229 expectations = self.get_expectations(platform_results[platfo rm])
230 line = '%s [ %s ] %s [ %s ]' % (bug[0], ' '.join(platform_li st), test_name, ' '.join(expectations))
231 line_list.append(str(line))
224 return line_list 232 return line_list
225 233
226 def write_to_test_expectations(self, host, path, line_list): 234 def write_to_test_expectations(self, host, path, line_list):
227 """Writes to TestExpectations. 235 """Writes to TestExpectations.
228 236
229 Writes to the test expectations lines in line_list 237 Writes to the test expectations lines in line_list
230 to LayoutTest/TestExpectations. Checks the file for the string 238 to LayoutTest/TestExpectations. Checks the file for the string
231 '# Tests added from W3C auto import bot' and writes expectation 239 '# Tests added from W3C auto import bot' and writes expectation
232 lines directly under it. If not found, it writes to the end of 240 lines directly under it. If not found, it writes to the end of
233 the file. If the test name is already in LayoutTests/TestExpectations, 241 the file. If the test name is already in LayoutTests/TestExpectations,
(...skipping 19 matching lines...) Expand all
253 all_lines += str(line) + '\n' 261 all_lines += str(line) + '\n'
254 all_lines = all_lines[:-1] 262 all_lines = all_lines[:-1]
255 if w3c_comment_line_index == -1: 263 if w3c_comment_line_index == -1:
256 file_contents += '\n%s\n' % comment_line 264 file_contents += '\n%s\n' % comment_line
257 file_contents += all_lines 265 file_contents += all_lines
258 else: 266 else:
259 end_of_comment_line = (file_contents[w3c_comment_line_index:].find(' \n')) + w3c_comment_line_index 267 end_of_comment_line = (file_contents[w3c_comment_line_index:].find(' \n')) + w3c_comment_line_index
260 new_data = file_contents[: end_of_comment_line + 1] + all_lines + fi le_contents[end_of_comment_line:] 268 new_data = file_contents[: end_of_comment_line + 1] + all_lines + fi le_contents[end_of_comment_line:]
261 file_contents = new_data 269 file_contents = new_data
262 host.filesystem.write_text_file(path, file_contents) 270 host.filesystem.write_text_file(path, file_contents)
OLDNEW
« no previous file with comments | « no previous file | third_party/WebKit/Tools/Scripts/webkitpy/w3c/update_w3c_test_expectations_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698