OLD | NEW |
---|---|
(Empty) | |
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 | |
3 # found in the LICENSE file. | |
4 | |
5 """A script to modify TestExpectations lines based layout test failures in try j obs. | |
6 | |
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. | |
9 | |
10 Platform_Results_dict structure: | |
11 {Test Name(s): { Platform(s): {'actual': ACTUAL_RESULTS, 'expected': EXPECTED_R ESULTS, 'bug': BUG_URL}}} | |
12 each Test Name and Platform are keys in their respective dictionaries. | |
13 """ | |
14 | |
15 import logging | |
16 | |
17 from webkitpy.common.checkout.scm.git import Git | |
18 from webkitpy.common.host import Host | |
19 from webkitpy.common.net import buildbot | |
20 from webkitpy.common.net import rietveld | |
21 from webkitpy.common.net.web import Web | |
22 from webkitpy.layout_tests.builder_list import BuilderList | |
23 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
| |
24 | |
25 | |
26 _log = logging.getLogger(__name__) | |
27 | |
28 | |
29 TRY_BOTS = ['linux_chromium_rel_ng', 'mac_chromium_rel_ng', 'win_chromium_rel_ng '] | |
30 | |
31 | |
32 def main(): | |
33 host = Host() | |
34 port = host.port_factory.get() | |
35 expectations_file = port.path_to_generic_test_expectations_file() | |
36 counter = 0 | |
37 builderlist = BuilderList(Builders_list_dict) | |
qyearsley
2016/07/18 18:31:42
builderlist -> builder_list
| |
38 git = Git('.') | |
39 web = Web() | |
40 expectations_line_adder = W3CExpectationsLineAdder(git, web, builderlist) | |
41 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
| |
42 try_bots = expectations_line_adder._builder_list.all_try_builder_names() | |
43 try_jobs_info = expectations_line_adder.get_try_jobs_information(issue_numbe r, try_bots) | |
44 line_expectations_dict = {} | |
45 while counter < len(try_bots): | |
46 try: | |
47 builder_name = try_jobs_info[counter][0] | |
48 build_number = try_jobs_info[counter][1] | |
49 builder = buildbot.Builder(builder_name, buildbot.BuildBot()) | |
50 build = buildbot.Build(builder, build_number) | |
51 platform_results_dict = expectations_line_adder.get_failing_results_ dict(builder, build) | |
52 line_expectations_dict = expectations_line_adder.merge_dicts(line_ex pectations_dict, platform_results_dict) | |
53 counter += 1 | |
54 except IndexError: | |
55 print "no tryjob info was collected" | |
qyearsley
2016/07/18 18:31:42
You could add capitalization and punctuation to th
| |
56 return 1 | |
57 for platform_results_dicts in line_expectations_dict.values(): | |
58 platform_results_dicts = expectations_line_adder.merge_same_valued_keys( platform_results_dicts) | |
59 line_list = expectations_line_adder.create_line_list(line_expectations_dict) | |
60 expectations_line_adder.write_to_testexpectations(host, expectations_file, l ine_list) | |
61 | |
62 | |
63 class W3CExpectationsLineAdder(object): | |
qyearsley
2016/07/18 18:31:42
Formatting note: Usually there's a blank line befo
| |
64 def __init__(self, git, web, builderlist): | |
qyearsley
2016/07/18 18:31:42
builderlist -> builder_list
| |
65 self._git = git | |
66 self._web = web | |
67 self._builder_list = builderlist | |
68 | |
69 # This function will return only tryjobs with failing results. | |
70 # If no failing results, try_job info will not be returned. If one try serve r | |
71 # has two try jobs, it will return both. | |
qyearsley
2016/07/18 18:31:42
This comment can go inside a docstring, and update
| |
72 def get_try_jobs_information(self, issue_number, try_bots): | |
73 info = rietveld.latest_try_jobs(issue_number, try_bots, self._web) | |
74 return info | |
qyearsley
2016/07/18 18:31:41
The variable info doesn't provide any extra inform
| |
75 | |
76 def _generate_results_dict(self, platform, result_list): | |
77 test_dict = {} | |
78 dash = platform.find("-") | |
79 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
| |
80 platform = platform[dash + 1:].capitalize() | |
81 for result in result_list: | |
82 test_dict[result.test_name()] = {platform: {'expected': result.expec ted_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
| |
83 return test_dict | |
84 | |
85 def get_failing_results_dict(self, builder, build): | |
86 layout_test_results = builder.fetch_layout_test_results(build.results_ur l()) | |
87 builder_name = layout_test_results.builder_name() | |
88 platform = self._builder_list.port_name_for_builder_name(builder_name) | |
89 result_list = layout_test_results.didnt_run_as_expected_results() | |
90 failing_results_dict = self._generate_results_dict(platform, result_list ) | |
91 return failing_results_dict | |
92 | |
93 def merge_dicts(self, final, temp, path=None): | |
94 path = path or [] | |
95 for key in temp: | |
96 if key in final: | |
97 if (isinstance(final[key], dict)) and isinstance(temp[key], dict ): | |
98 self.merge_dicts(final[key], temp[key], path + [str(key)]) | |
99 elif final[key] == temp[key]: | |
100 pass | |
101 else: | |
102 raise Exception('conflict at %s' % '.'.join(path)) | |
103 else: | |
104 final[key] = temp[key] | |
105 return final | |
106 | |
107 def merge_same_valued_keys(self, dictionary): | |
108 matching_value_keys = set() | |
109 keys = dictionary.keys() | |
110 isLastItem = False | |
111 for index, item in enumerate(keys): | |
112 if isLastItem: | |
113 break | |
114 for i in range(index + 1, len(keys)): | |
115 next_item = keys[i] | |
116 if dictionary[item] == dictionary[next_item]: | |
117 matching_value_keys.update([item, next_item]) | |
118 dictionary[tuple(matching_value_keys)] = dictionary[item] | |
119 isLastItem = next_item == keys[-1] | |
120 del dictionary[item] | |
121 del dictionary[next_item] | |
122 return dictionary | |
123 | |
124 def get_expectations(self, results): | |
125 expectations = [] | |
126 failure_expectations = ['TEXT', 'FAIL', 'IMAGE+TEXT', 'IMAGE'] | |
127 pass_crash_timeout = ['TIMEOUT', 'CRASH', 'PASS'] | |
128 if results['expected'] in pass_crash_timeout and results['actual'] in fa ilure_expectations: | |
129 expectations.append('Failure') | |
130 if results['expected'] in failure_expectations and results['actual'] in pass_crash_timeout: | |
131 expectations.append(results['actual'].capitalize()) | |
132 if results['expected'] in pass_crash_timeout and results['actual'] in pa ss_crash_timeout: | |
133 expectations.append(results['actual'].capitalize()) | |
134 expectations.append(results['expected'].capitalize()) | |
135 return expectations | |
136 | |
137 def create_line_list(self, dictionary): | |
138 line_list = [] | |
139 for key, value in dictionary.iteritems(): | |
140 test_name = key | |
141 for key2 in value: | |
142 platform = [] | |
143 bug = [] | |
144 expectations = [] | |
145 if isinstance(key2, tuple): | |
146 platform = list(key2) | |
147 else: | |
148 platform.append(key2) | |
149 bug.append(value[key2]['bug']) | |
150 expectations = self.get_expectations(value[key2]) | |
151 line = '%s [ %s ] %s [ %s ]' % (bug[0], ' '.join(platform), test _name, ' '.join(expectations)) | |
152 line_list.append(str(line)) | |
153 return line_list | |
154 | |
155 def write_to_testexpectations(self, host, path, line_list): | |
156 file_contents = host.filesystem.read_text_file(path) | |
157 w3c_comment_line_index = file_contents.find("# Tests added from W3C auto import bot") | |
158 all_lines = "" | |
159 for line in line_list: | |
160 all_lines += str(line) + "\n" | |
161 all_lines = all_lines[:-1] | |
162 if w3c_comment_line_index == -1: | |
163 file_contents += "\n\n# Tests added from W3C auto import bot\n" | |
164 file_contents += all_lines | |
165 else: | |
166 end_of_comment_line = (file_contents[w3c_comment_line_index:].find(' \n')) + w3c_comment_line_index | |
167 new_data = file_contents[: end_of_comment_line + 1] + all_lines + fi le_contents[end_of_comment_line:] | |
168 file_contents = new_data | |
169 host.filesystem.write_text_file(path, file_contents) | |
OLD | NEW |