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

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

Issue 2136723002: Create test expectations line automatically from failing test results (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add function to write to TestExpectations with unittest Created 4 years, 5 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 side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Tools/Scripts/webkitpy/w3c/update_w3c_test_expectations.py
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/update_w3c_test_expectations.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/update_w3c_test_expectations.py
new file mode 100644
index 0000000000000000000000000000000000000000..4654cdba2a7f2acbf712775539ccfa6b70d63b2a
--- /dev/null
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/update_w3c_test_expectations.py
@@ -0,0 +1,169 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""A script to modify TestExpectations lines based layout test failures in try jobs.
+
+This script outputs a list of test expectation lines to add to a "TestExpectations" file
+by retrieving the try job results for the current CL.
+
+Platform_Results_dict structure:
+ {Test Name(s): { Platform(s): {'actual': ACTUAL_RESULTS, 'expected': EXPECTED_RESULTS, 'bug': BUG_URL}}}
+ each Test Name and Platform are keys in their respective dictionaries.
+"""
+
+import logging
+
+from webkitpy.common.checkout.scm.git import Git
+from webkitpy.common.host import Host
+from webkitpy.common.net import buildbot
+from webkitpy.common.net import rietveld
+from webkitpy.common.net.web import Web
+from webkitpy.layout_tests.builder_list import BuilderList
+from webkitpy.common.config.builders import BUILDERS as Builders_list_dict
qyearsley 2016/07/18 18:31:42 You can keep the name BUILDERS, since that's simpl
dcampb 2016/07/18 20:50:04 I have removed this import as well as builder_list
+
+
+_log = logging.getLogger(__name__)
+
+
+TRY_BOTS = ['linux_chromium_rel_ng', 'mac_chromium_rel_ng', 'win_chromium_rel_ng']
+
+
+def main():
+ host = Host()
+ port = host.port_factory.get()
+ expectations_file = port.path_to_generic_test_expectations_file()
+ counter = 0
+ builderlist = BuilderList(Builders_list_dict)
qyearsley 2016/07/18 18:31:42 builderlist -> builder_list
+ git = Git('.')
+ web = Web()
+ expectations_line_adder = W3CExpectationsLineAdder(git, web, builderlist)
+ issue_number = expectations_line_adder._git.get_issue_number()
qyearsley 2016/07/18 18:31:42 Here a private attribute of another object is acce
dcampb 2016/07/18 20:50:04 I moved this line and the line 42 into their own f
+ try_bots = expectations_line_adder._builder_list.all_try_builder_names()
+ try_jobs_info = expectations_line_adder.get_try_jobs_information(issue_number, try_bots)
+ line_expectations_dict = {}
+ while counter < len(try_bots):
+ try:
+ builder_name = try_jobs_info[counter][0]
+ build_number = try_jobs_info[counter][1]
+ builder = buildbot.Builder(builder_name, buildbot.BuildBot())
+ build = buildbot.Build(builder, build_number)
+ platform_results_dict = expectations_line_adder.get_failing_results_dict(builder, build)
+ line_expectations_dict = expectations_line_adder.merge_dicts(line_expectations_dict, platform_results_dict)
+ counter += 1
+ except IndexError:
+ print "no tryjob info was collected"
qyearsley 2016/07/18 18:31:42 You could add capitalization and punctuation to th
+ return 1
+ for platform_results_dicts in line_expectations_dict.values():
+ platform_results_dicts = expectations_line_adder.merge_same_valued_keys(platform_results_dicts)
+ line_list = expectations_line_adder.create_line_list(line_expectations_dict)
+ expectations_line_adder.write_to_testexpectations(host, expectations_file, line_list)
+
+
+class W3CExpectationsLineAdder(object):
qyearsley 2016/07/18 18:31:42 Formatting note: Usually there's a blank line befo
+ def __init__(self, git, web, builderlist):
qyearsley 2016/07/18 18:31:42 builderlist -> builder_list
+ self._git = git
+ self._web = web
+ self._builder_list = builderlist
+
+ # This function will return only tryjobs with failing results.
+ # If no failing results, try_job info will not be returned. If one try server
+ # has two try jobs, it will return both.
qyearsley 2016/07/18 18:31:42 This comment can go inside a docstring, and update
+ def get_try_jobs_information(self, issue_number, try_bots):
+ info = rietveld.latest_try_jobs(issue_number, try_bots, self._web)
+ return info
qyearsley 2016/07/18 18:31:41 The variable info doesn't provide any extra inform
+
+ def _generate_results_dict(self, platform, result_list):
+ test_dict = {}
+ dash = platform.find("-")
+ if dash != -1:
qyearsley 2016/07/18 18:31:42 To find if a character exists in a string you can
dcampb 2016/07/18 20:50:04 done
+ platform = platform[dash + 1:].capitalize()
+ for result in result_list:
+ test_dict[result.test_name()] = {platform: {'expected': result.expected_results(), 'actual': result.actual_results(), 'bug': 'crbug.com/626703'}}
qyearsley 2016/07/18 18:31:42 This line is a bit long; reformatting it may make
dcampb 2016/07/18 20:50:04 done
+ return test_dict
+
+ def get_failing_results_dict(self, builder, build):
+ layout_test_results = builder.fetch_layout_test_results(build.results_url())
+ builder_name = layout_test_results.builder_name()
+ platform = self._builder_list.port_name_for_builder_name(builder_name)
+ result_list = layout_test_results.didnt_run_as_expected_results()
+ failing_results_dict = self._generate_results_dict(platform, result_list)
+ return failing_results_dict
+
+ def merge_dicts(self, final, temp, path=None):
+ path = path or []
+ for key in temp:
+ if key in final:
+ if (isinstance(final[key], dict)) and isinstance(temp[key], dict):
+ self.merge_dicts(final[key], temp[key], path + [str(key)])
+ elif final[key] == temp[key]:
+ pass
+ else:
+ raise Exception('conflict at %s' % '.'.join(path))
+ else:
+ final[key] = temp[key]
+ return final
+
+ def merge_same_valued_keys(self, dictionary):
+ matching_value_keys = set()
+ keys = dictionary.keys()
+ isLastItem = False
+ for index, item in enumerate(keys):
+ if isLastItem:
+ break
+ for i in range(index + 1, len(keys)):
+ next_item = keys[i]
+ if dictionary[item] == dictionary[next_item]:
+ matching_value_keys.update([item, next_item])
+ dictionary[tuple(matching_value_keys)] = dictionary[item]
+ isLastItem = next_item == keys[-1]
+ del dictionary[item]
+ del dictionary[next_item]
+ return dictionary
+
+ def get_expectations(self, results):
+ expectations = []
+ failure_expectations = ['TEXT', 'FAIL', 'IMAGE+TEXT', 'IMAGE']
+ pass_crash_timeout = ['TIMEOUT', 'CRASH', 'PASS']
+ if results['expected'] in pass_crash_timeout and results['actual'] in failure_expectations:
+ expectations.append('Failure')
+ if results['expected'] in failure_expectations and results['actual'] in pass_crash_timeout:
+ expectations.append(results['actual'].capitalize())
+ if results['expected'] in pass_crash_timeout and results['actual'] in pass_crash_timeout:
+ expectations.append(results['actual'].capitalize())
+ expectations.append(results['expected'].capitalize())
+ return expectations
+
+ def create_line_list(self, dictionary):
+ line_list = []
+ for key, value in dictionary.iteritems():
+ test_name = key
+ for key2 in value:
+ platform = []
+ bug = []
+ expectations = []
+ if isinstance(key2, tuple):
+ platform = list(key2)
+ else:
+ platform.append(key2)
+ bug.append(value[key2]['bug'])
+ expectations = self.get_expectations(value[key2])
+ line = '%s [ %s ] %s [ %s ]' % (bug[0], ' '.join(platform), test_name, ' '.join(expectations))
+ line_list.append(str(line))
+ return line_list
+
+ def write_to_testexpectations(self, host, path, line_list):
+ file_contents = host.filesystem.read_text_file(path)
+ w3c_comment_line_index = file_contents.find("# Tests added from W3C auto import bot")
+ all_lines = ""
+ for line in line_list:
+ all_lines += str(line) + "\n"
+ all_lines = all_lines[:-1]
+ if w3c_comment_line_index == -1:
+ file_contents += "\n\n# Tests added from W3C auto import bot\n"
+ file_contents += all_lines
+ else:
+ end_of_comment_line = (file_contents[w3c_comment_line_index:].find('\n')) + w3c_comment_line_index
+ new_data = file_contents[: end_of_comment_line + 1] + all_lines + file_contents[end_of_comment_line:]
+ file_contents = new_data
+ host.filesystem.write_text_file(path, file_contents)

Powered by Google App Engine
This is Rietveld 408576698