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

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

Issue 2687093005: WPT importer: Use concise lists of version specifiers in expectation lines. (Closed)
Patch Set: versions->version_specifiers, accept, upper-case macros, use issubset, mame -> name Created 3 years, 10 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
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 layout test expectations and baselines when updating w3c tests. 5 """Updates layout test expectations and baselines when updating w3c tests.
6 6
7 Specifically, this class fetches results from try bots for the current CL, then 7 Specifically, this class fetches results from try bots for the current CL, then
8 (1) downloads new baseline files for any tests that can be rebaselined, and 8 (1) downloads new baseline files for any tests that can be rebaselined, and
9 (2) updates the generic TestExpectations file for any other failing tests. 9 (2) updates the generic TestExpectations file for any other failing tests.
10 """ 10 """
11 11
12 import argparse 12 import argparse
13 import copy 13 import copy
14 import logging 14 import logging
15 15
16 from webkitpy.common.memoized import memoized
16 from webkitpy.common.net.git_cl import GitCL 17 from webkitpy.common.net.git_cl import GitCL
17 from webkitpy.common.net.rietveld import Rietveld 18 from webkitpy.common.net.rietveld import Rietveld
18 from webkitpy.common.webkit_finder import WebKitFinder 19 from webkitpy.common.webkit_finder import WebKitFinder
19 from webkitpy.layout_tests.models.test_expectations import TestExpectationLine 20 from webkitpy.layout_tests.models.test_expectations import TestExpectationLine, TestExpectations
20 from webkitpy.w3c.test_parser import TestParser 21 from webkitpy.w3c.test_parser import TestParser
21 22
22 _log = logging.getLogger(__name__) 23 _log = logging.getLogger(__name__)
23 24
24 MARKER_COMMENT = '# ====== New tests from w3c-test-autoroller added here ======' 25 MARKER_COMMENT = '# ====== New tests from w3c-test-autoroller added here ======'
25 26
26 27
27 class WPTExpectationsUpdater(object): 28 class WPTExpectationsUpdater(object):
28 29
29 def __init__(self, host): 30 def __init__(self, host):
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
66 test_expectation_lines = self.create_line_list(test_expectations) 67 test_expectation_lines = self.create_line_list(test_expectations)
67 self.write_to_test_expectations(test_expectation_lines) 68 self.write_to_test_expectations(test_expectation_lines)
68 return 0 69 return 0
69 70
70 def get_issue_number(self): 71 def get_issue_number(self):
71 """Returns current CL number. Can be replaced in unit tests.""" 72 """Returns current CL number. Can be replaced in unit tests."""
72 return GitCL(self.host).get_issue_number() 73 return GitCL(self.host).get_issue_number()
73 74
74 def get_try_bots(self): 75 def get_try_bots(self):
75 """Returns try bot names. Can be replaced in unit tests.""" 76 """Returns try bot names. Can be replaced in unit tests."""
77 # TODO(qyearsley): This method is unnecessary; unit tests can set up
78 # a BuilderList with try builder names, instead of overriding this.
76 return self.host.builders.all_try_builder_names() 79 return self.host.builders.all_try_builder_names()
77 80
78 def get_failing_results_dict(self, build): 81 def get_failing_results_dict(self, build):
79 """Returns a nested dict of failing test results. 82 """Returns a nested dict of failing test results.
80 83
81 Retrieves a full list of layout test results from a builder result URL. 84 Retrieves a full list of layout test results from a builder result URL.
82 Collects the builder name, platform and a list of tests that did not 85 Collects the builder name, platform and a list of tests that did not
83 run as expected. 86 run as expected.
84 87
85 Args: 88 Args:
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
121 test_name = result.test_name() 124 test_name = result.test_name()
122 test_dict[test_name] = { 125 test_dict[test_name] = {
123 full_port_name: { 126 full_port_name: {
124 'expected': result.expected_results(), 127 'expected': result.expected_results(),
125 'actual': result.actual_results(), 128 'actual': result.actual_results(),
126 'bug': 'crbug.com/626703' 129 'bug': 'crbug.com/626703'
127 } 130 }
128 } 131 }
129 return test_dict 132 return test_dict
130 133
131 def _port_name_to_platform_specifier(self, port_name):
132 """Maps a port name to the platform specifier used in expectation lines.
133
134 For example:
135 linux-trusty -> Trusty
136 mac-mac10.11 -> Mac10.11.
137 """
138 builder_name = self.host.builders.builder_name_for_port_name(port_name)
139 specifiers = self.host.builders.specifiers_for_builder(builder_name)
140 return specifiers[0]
141
142 def merge_dicts(self, target, source, path=None): 134 def merge_dicts(self, target, source, path=None):
143 """Recursively merges nested dictionaries. 135 """Recursively merges nested dictionaries.
144 136
145 Args: 137 Args:
146 target: First dictionary, which is updated based on source. 138 target: First dictionary, which is updated based on source.
147 source: Second dictionary, not modified. 139 source: Second dictionary, not modified.
148 140
149 Returns: 141 Returns:
150 An updated target dictionary. 142 An updated target dictionary.
151 """ 143 """
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
254 'platform': { 246 'platform': {
255 'expected: 'PASS', 247 'expected: 'PASS',
256 'actual': 'FAIL', 248 'actual': 'FAIL',
257 'bug': 'crbug.com/11111' 249 'bug': 'crbug.com/11111'
258 } 250 }
259 } 251 }
260 } 252 }
261 253
262 Returns: 254 Returns:
263 A list of test expectations lines with the format: 255 A list of test expectations lines with the format:
264 ['BUG_URL [PLATFORM(S)] TEST_MAME [EXPECTATION(S)]'] 256 ['BUG_URL [PLATFORM(S)] TEST_NAME [EXPECTATION(S)]']
265 """ 257 """
266 line_list = [] 258 line_list = []
267 for test_name, port_results in merged_results.iteritems(): 259 for test_name, port_results in merged_results.iteritems():
268 for port_names in port_results: 260 for port_names in sorted(port_results):
269 if test_name.startswith('external'): 261 if test_name.startswith('external'):
270 bug_part = port_results[port_names]['bug'] 262 line_parts = [port_results[port_names]['bug']]
271 specifier_part = '[ %s ]' % ' '.join(self.to_list(port_names )) 263 specifier_part = self.specifier_part(self.to_list(port_names ), test_name)
272 expectations_part = '[ %s ]' % ' '.join(self.get_expectation s(port_results[port_names])) 264 if specifier_part:
273 line = ' '.join([bug_part, specifier_part, test_name, expect ations_part]) 265 line_parts.append(specifier_part)
274 line_list.append(line) 266 line_parts.append(test_name)
267 line_parts.append('[ %s ]' % ' '.join(self.get_expectations( port_results[port_names])))
268 line_list.append(' '.join(line_parts))
275 return line_list 269 return line_list
276 270
271 def specifier_part(self, port_names, test_name):
272 """Returns the specifier part for a new test expectations line.
273
274 Args:
275 port_names: A list of full port names that the line should apply to.
276 test_name: The test name for the expectation line.
277
278 Returns:
279 The specifier part of the new expectation line, e.g. "[ Mac ]".
280 This will be an empty string if the line should apply to all platfor ms.
281 """
282 specifiers = []
283 for name in sorted(port_names):
284 specifiers.append(self.host.builders.version_specifier_for_port_name (name))
285 port = self.host.port_factory.get()
286 specifiers = self.simplify_specifiers(specifiers, port.configuration_spe cifier_macros())
287 specifiers.extend(self.skipped_specifiers(test_name))
288 if not specifiers:
289 return ''
290 return '[ %s ]' % ' '.join(specifiers)
291
277 @staticmethod 292 @staticmethod
278 def to_list(tuple_or_value): 293 def to_list(tuple_or_value):
294 """Converts a tuple to a list, and a string value to a one-item list."""
279 if isinstance(tuple_or_value, tuple): 295 if isinstance(tuple_or_value, tuple):
280 return list(tuple_or_value) 296 return list(tuple_or_value)
281 return [tuple_or_value] 297 return [tuple_or_value]
282 298
299 def skipped_specifiers(self, test_name):
300 """Returns a list of platform specifiers for which the test is skipped." ""
301 # TODO(qyearsley): Change Port.skips_test so that this can be simplified .
302 specifiers = []
303 for port in self.all_try_builder_ports():
304 generic_expectations = TestExpectations(port, tests=[test_name], inc lude_overrides=False)
305 full_expectations = TestExpectations(port, tests=[test_name], includ e_overrides=True)
306 if port.skips_test(test_name, generic_expectations, full_expectation s):
307 specifiers.append(self.host.builders.version_specifier_for_port_ name(port.name()))
308 return specifiers
309
310 @memoized
311 def all_try_builder_ports(self):
312 """Returns a list of Port objects for all try builders."""
313 return [self.host.port_factory.get_from_builder_name(name) for name in s elf.get_try_bots()]
314
315 @staticmethod
316 def simplify_specifiers(specifiers, configuration_specifier_macros): # pyli nt: disable=unused-argument
317 """Converts some collection of specifiers to an equivalent and maybe sho rter list.
318
319 The input strings are all case-insensitive, but the strings in the
320 return value will all be capitalized.
321
322 Args:
323 specifiers: A collection of lower-case specifiers.
324 configuration_specifier_macros: A dict mapping "macros" for
325 groups of specifiers to lists of specific specifiers. In
326 practice, this is a dict mapping operating systems to
327 supported versions, e.g. {"win": ["win7", "win10"]}.
328
329 Returns:
330 A shortened list of specifiers. For example, ["win7", "win10"]
331 would be converted to ["Win"]. If the given list covers all
332 supported platforms, then an empty list is returned.
333 This list will be sorted and have capitalized specifier strings.
334 """
335 specifiers = {specifier.lower() for specifier in specifiers}
336 for macro_specifier, version_specifiers in configuration_specifier_macro s.iteritems():
337 macro_specifier = macro_specifier.lower()
338 version_specifiers = {specifier.lower() for specifier in version_spe cifiers}
339 if version_specifiers.issubset(specifiers):
340 specifiers -= version_specifiers
341 specifiers.add(macro_specifier)
342 if specifiers == set(configuration_specifier_macros):
343 return []
344 return sorted(specifier.capitalize() for specifier in specifiers)
345
283 def write_to_test_expectations(self, line_list): 346 def write_to_test_expectations(self, line_list):
284 """Writes to TestExpectations. 347 """Writes to TestExpectations.
285 348
286 The place in the file where the new lines are inserted is after a 349 The place in the file where the new lines are inserted is after a
287 marker comment line. If this marker comment line is not found, it will 350 marker comment line. If this marker comment line is not found, it will
288 be added to the end of the file. 351 be added to the end of the file.
289 352
290 Args: 353 Args:
291 line_list: A list of lines to add to the TestExpectations file. 354 line_list: A list of lines to add to the TestExpectations file.
292 """ 355 """
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
376 439
377 Args: 440 Args:
378 test_path: A file path relative to the layout tests directory. 441 test_path: A file path relative to the layout tests directory.
379 This might correspond to a deleted file or a non-test. 442 This might correspond to a deleted file or a non-test.
380 """ 443 """
381 absolute_path = self.host.filesystem.join(self.finder.layout_tests_dir() , test_path) 444 absolute_path = self.host.filesystem.join(self.finder.layout_tests_dir() , test_path)
382 test_parser = TestParser(absolute_path, self.host) 445 test_parser = TestParser(absolute_path, self.host)
383 if not test_parser.test_doc: 446 if not test_parser.test_doc:
384 return False 447 return False
385 return test_parser.is_jstest() 448 return test_parser.is_jstest()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698