OLD | NEW |
---|---|
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Helper functions for the layout test analyzer.""" | 6 """Helper functions for the layout test analyzer.""" |
7 | 7 |
8 from datetime import datetime | 8 from datetime import datetime |
9 from email.mime.multipart import MIMEMultipart | 9 from email.mime.multipart import MIMEMultipart |
10 from email.mime.text import MIMEText | 10 from email.mime.text import MIMEText |
11 import fileinput | 11 import fileinput |
12 import os | 12 import os |
13 import pickle | 13 import pickle |
14 import re | |
14 import smtplib | 15 import smtplib |
15 import socket | 16 import socket |
16 import sys | 17 import sys |
17 import time | 18 import time |
18 import urllib | 19 import urllib |
19 | 20 |
20 from bug import Bug | 21 from bug import Bug |
21 from test_expectations_history import TestExpectationsHistory | 22 from test_expectations_history import TestExpectationsHistory |
22 | 23 |
23 | 24 |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
125 ValueEror when the number of tests in test group "whole" is equal or less | 126 ValueEror when the number of tests in test group "whole" is equal or less |
126 than that of "skip". | 127 than that of "skip". |
127 """ | 128 """ |
128 delta = len(self.result_map['whole'].keys()) - ( | 129 delta = len(self.result_map['whole'].keys()) - ( |
129 len(self.result_map['skip'].keys())) | 130 len(self.result_map['skip'].keys())) |
130 if delta <= 0: | 131 if delta <= 0: |
131 raise ValueError('The number of tests in test group "whole" is equal or ' | 132 raise ValueError('The number of tests in test group "whole" is equal or ' |
132 'less than that of "skip"') | 133 'less than that of "skip"') |
133 return 100 - len(self.result_map['nonskip'].keys()) * 100 / delta | 134 return 100 - len(self.result_map['nonskip'].keys()) * 100 / delta |
134 | 135 |
136 def ConvertToCSVText(self, current_time): | |
137 """Convert result_map into stats and issues text in CSV format. | |
dennis_jeffrey
2011/11/11 00:01:36
'result_map' --> |self.result_map|
imasaki1
2011/11/11 00:25:52
Done.
| |
138 | |
139 Both are used for inputs for Google spreadsheet. | |
dennis_jeffrey
2011/11/11 00:01:36
nit: 'for inputs' --> 'as inputs'
imasaki1
2011/11/11 00:25:52
Done.
| |
140 | |
141 Args: | |
142 current_time: a string shows current time (e.g, 2011-11-08-16) | |
dennis_jeffrey
2011/11/11 00:01:36
current_time: a string depicting a time in year-mo
imasaki1
2011/11/11 00:25:52
Done.
| |
143 | |
144 Returns: | |
145 a tuple of stats and issues_txt | |
146 stats: analyzer result in CSV format that shows: | |
147 (current_time, the number of tests, the number of skipped tests, | |
148 the number of failing tests) | |
149 For example, | |
150 "2011-11-10-15,204,22,12" | |
151 issues_txt: issues listed in CSV format that shows: | |
dennis_jeffrey
2011/11/11 00:01:36
Could this include information for multiple issues
imasaki1
2011/11/11 00:25:52
Done.
| |
152 (BUGWK or BUGCR, bug number, the test expectation entry, | |
153 the name of the test) | |
154 For example, | |
155 "71543,TIMEOUT PASS,media/media-element-play-after-eos.html," | |
dennis_jeffrey
2011/11/11 00:01:36
This example seems to be missing the "BUGWK"/"BUGC
imasaki1
2011/11/11 00:25:52
Done.
| |
156 """ | |
157 stats = ','.join([current_time, str(len(self.result_map['whole'].keys())), | |
158 str(len(self.result_map['skip'].keys())), | |
dennis_jeffrey
2011/11/11 00:01:36
nit: indent this by 1 more space.
imasaki1
2011/11/11 00:25:52
Done.
| |
159 str(len(self.result_map['nonskip'].keys()))]) | |
dennis_jeffrey
2011/11/11 00:01:36
nit: indent this by 2 more spaces
imasaki1
2011/11/11 00:25:52
Done.
| |
160 issues_txt = '' | |
161 for (bug_txt, test_info_list) in ( | |
dennis_jeffrey
2011/11/11 00:01:36
I believe the parens are unnecessary in '(bug_txt,
imasaki1
2011/11/11 00:25:52
Done.
| |
162 self.GetListOfBugsForNonSkippedTests().iteritems()): | |
dennis_jeffrey
2011/11/11 00:01:36
nit: indent this by 2 more spaces
imasaki1
2011/11/11 00:25:52
Done.
| |
163 matches = re.match(r'(BUG(CR|WK))(\d+)', bug_txt) | |
164 bug_prefix = '' | |
dennis_jeffrey
2011/11/11 00:01:36
nit: 'bug_prefix' --> 'bug_suffix', since it's the
imasaki1
2011/11/11 00:25:52
Done.
| |
165 bug_no = '' | |
166 if matches: | |
167 bug_prefix = matches.group(1) | |
168 bug_no = matches.group(3) | |
169 issues_txt += bug_prefix + ',' + bug_no + ',' | |
170 for test_info in test_info_list: | |
171 (test_name, te_info) = test_info | |
dennis_jeffrey
2011/11/11 00:01:36
no need for parentheses here
imasaki1
2011/11/11 00:25:52
Done.
| |
172 issues_txt += ' '.join(te_info.keys()) + ',' + test_name + ',' | |
173 issues_txt += '\n' | |
174 return (stats, issues_txt) | |
dennis_jeffrey
2011/11/11 00:01:36
no need for parentheses here
imasaki1
2011/11/11 00:25:52
Done.
| |
175 | |
135 def ConvertToString(self, prev_time, diff_map, bug_anno_map): | 176 def ConvertToString(self, prev_time, diff_map, bug_anno_map): |
136 """Convert this result to HTML display for email. | 177 """Convert this result to HTML display for email. |
137 | 178 |
138 Args: | 179 Args: |
139 prev_time: the previous time string that are compared against. | 180 prev_time: the previous time string that are compared against. |
140 diff_map: the compared map generated by |CompareResultMaps()|. | 181 diff_map: the compared map generated by |CompareResultMaps()|. |
141 bug_anno_map: a annotation map where keys are bug names and values are | 182 bug_anno_map: a annotation map where keys are bug names and values are |
142 annotations for the bug. | 183 annotations for the bug. |
143 | 184 |
144 Returns: | 185 Returns: |
145 a analyzer result string in HTML format. | 186 a analyzer result string in HTML format. |
146 """ | 187 """ |
147 return_str = ('<b>Statistics (Diff Compared to %s):</b><ul>' | 188 return_str = '' |
148 '<li>The number of tests: %d (%s)</li>' | 189 if diff_map: |
149 '<li>The number of failing skipped tests: %d (%s)</li>' | 190 return_str += ('<b>Statistics (Diff Compared to %s):</b><ul>' |
150 '<li>The number of failing non-skipped tests: %d (%s)</li>' | 191 '<li>The number of tests: %d (%s)</li>' |
151 '<li>Passing rate: %d %%</li></ul>') % ( | 192 '<li>The number of failing skipped tests: %d (%s)</li>' |
152 prev_time, len(self.result_map['whole'].keys()), | 193 '<li>The number of failing non-skipped tests: %d (%s)</li>' |
153 AnalyzerResultMap.GetDiffString(diff_map['whole'], 'whole'), | 194 '<li>Passing rate: %d %%</li></ul>') % ( |
154 len(self.result_map['skip'].keys()), | 195 prev_time, len(self.result_map['whole'].keys()), |
155 AnalyzerResultMap.GetDiffString(diff_map['skip'], 'skip'), | 196 AnalyzerResultMap.GetDiffString(diff_map['whole'], 'whole'), |
156 len(self.result_map['nonskip'].keys()), | 197 len(self.result_map['skip'].keys()), |
157 AnalyzerResultMap.GetDiffString(diff_map['nonskip'], | 198 AnalyzerResultMap.GetDiffString(diff_map['skip'], 'skip'), |
158 'nonskip'), | 199 len(self.result_map['nonskip'].keys()), |
159 self.GetPassingRate()) | 200 AnalyzerResultMap.GetDiffString(diff_map['nonskip'], |
201 'nonskip'), | |
202 self.GetPassingRate()) | |
160 return_str += '<b>Current issues about failing non-skipped tests:</b>' | 203 return_str += '<b>Current issues about failing non-skipped tests:</b>' |
161 for (bug_txt, test_info_list) in ( | 204 for (bug_txt, test_info_list) in ( |
162 self.GetListOfBugsForNonSkippedTests().iteritems()): | 205 self.GetListOfBugsForNonSkippedTests().iteritems()): |
163 if not bug_txt in bug_anno_map: | 206 if not bug_txt in bug_anno_map: |
164 bug_anno_map[bug_txt] = '<font color="red">Needs investigation!</font>' | 207 bug_anno_map[bug_txt] = '<font color="red">Needs investigation!</font>' |
165 return_str += '<ul>%s (%s)' % (Bug(bug_txt), bug_anno_map[bug_txt]) | 208 return_str += '<ul>%s (%s)' % (Bug(bug_txt), bug_anno_map[bug_txt]) |
166 for test_info in test_info_list: | 209 for test_info in test_info_list: |
167 (test_name, te_info) = test_info | 210 (test_name, te_info) = test_info |
168 gpu_link = '' | 211 gpu_link = '' |
169 if 'GPU' in te_info: | 212 if 'GPU' in te_info: |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
248 if 'Bugs' in te_info: | 291 if 'Bugs' in te_info: |
249 for bug in te_info['Bugs']: | 292 for bug in te_info['Bugs']: |
250 if bug not in bug_map: | 293 if bug not in bug_map: |
251 bug_map[bug] = [] | 294 bug_map[bug] = [] |
252 bug_map[bug].append((name, main_te_info)) | 295 bug_map[bug].append((name, main_te_info)) |
253 return bug_map | 296 return bug_map |
254 | 297 |
255 | 298 |
256 def SendStatusEmail(prev_time, analyzer_result_map, diff_map, | 299 def SendStatusEmail(prev_time, analyzer_result_map, diff_map, |
257 bug_anno_map, receiver_email_address, test_group_name, | 300 bug_anno_map, receiver_email_address, test_group_name, |
258 appended_text_to_email, email_content, rev_str): | 301 appended_text_to_email, email_content, rev_str, |
302 email_only_change_mode): | |
259 """Send status email. | 303 """Send status email. |
260 | 304 |
261 Args: | 305 Args: |
262 prev_time: the date string such as '2011-10-09-11'. This format has been | 306 prev_time: the date string such as '2011-10-09-11'. This format has been |
263 used in this analyzer. | 307 used in this analyzer. |
264 analyzer_result_map: current analyzer result. | 308 analyzer_result_map: current analyzer result. |
265 diff_map: a map that has 'whole', 'skip' and 'nonskip' as keys. | 309 diff_map: a map that has 'whole', 'skip' and 'nonskip' as keys. |
266 The values of the map are the result of |GetDiffBetweenMaps()|. | 310 The values of the map are the result of |GetDiffBetweenMaps()|. |
267 The element has two lists of test cases. One (with index 0) is for | 311 The element has two lists of test cases. One (with index 0) is for |
268 test names that are in the current result but NOT in the previous | 312 test names that are in the current result but NOT in the previous |
269 result. The other (with index 1) is for test names that are in the | 313 result. The other (with index 1) is for test names that are in the |
270 previous results but NOT in the current result. | 314 previous results but NOT in the current result. |
271 For example (test expectation information is omitted for | 315 For example (test expectation information is omitted for |
272 simplicity), | 316 simplicity), |
273 comp_result_map['whole'][0] = ['foo1.html'] | 317 comp_result_map['whole'][0] = ['foo1.html'] |
274 comp_result_map['whole'][1] = ['foo2.html'] | 318 comp_result_map['whole'][1] = ['foo2.html'] |
275 This means that current result has 'foo1.html' but it is NOT in the | 319 This means that current result has 'foo1.html' but it is NOT in the |
276 previous result. This also means the previous result has 'foo2.html' | 320 previous result. This also means the previous result has 'foo2.html' |
277 but it is NOT in the current result. | 321 but it is NOT in the current result. |
278 bug_anno_map: bug annotation map where bug name and annotations are | 322 bug_anno_map: bug annotation map where bug name and annotations are |
279 stored. | 323 stored. |
280 receiver_email_address: receiver's email address. | 324 receiver_email_address: receiver's email address. |
281 test_group_name: string representing the test group name (e.g., 'media'). | 325 test_group_name: string representing the test group name (e.g., 'media'). |
282 appended_text_to_email: a text which is appended at the end of the status | 326 appended_text_to_email: a text which is appended at the end of the status |
283 email. | 327 email. |
284 email_content: an email content string that will be shown on the dashboard. | 328 email_content: an email content string that will be shown on the dashboard. |
285 rev_str: a revision string that contains revision information that is sent | 329 rev_str: a revision string that contains revision information that is sent |
286 out in the status email. It is obtained by calling | 330 out in the status email. It is obtained by calling |
287 |GetRevisionString()|. | 331 |GetRevisionString()|. |
332 email_only_change_mode: please refer to |options|. | |
288 """ | 333 """ |
289 if rev_str: | 334 if rev_str: |
290 email_content += '<br><b>Revision Information:</b>' | 335 email_content += '<br><b>Revision Information:</b>' |
291 email_content += rev_str | 336 email_content += rev_str |
292 localtime = time.asctime(time.localtime(time.time())) | 337 localtime = time.asctime(time.localtime(time.time())) |
338 change_str = '' | |
339 if email_only_change_mode: | |
340 change_str = 'Status Change' | |
dennis_jeffrey
2011/11/11 00:01:36
add a space right after the 'e' at the end of this
imasaki1
2011/11/11 00:25:52
Done.
| |
341 subject = 'Layout Test Analyzer Result %s (%s): %s' % (change_str, | |
dennis_jeffrey
2011/11/11 00:01:36
remove the space right after the first '%s'
imasaki1
2011/11/11 00:25:52
Done.
| |
342 test_group_name, | |
343 localtime) | |
293 # TODO(imasaki): remove my name from here. | 344 # TODO(imasaki): remove my name from here. |
294 subject = 'Layout Test Analyzer Result (%s): %s' % (test_group_name, | |
295 localtime) | |
296 SendEmail('imasaki@chromium.org', [receiver_email_address], | 345 SendEmail('imasaki@chromium.org', [receiver_email_address], |
297 subject, email_content + appended_text_to_email) | 346 subject, email_content + appended_text_to_email) |
298 | 347 |
299 | 348 |
300 def GetRevisionString(prev_time, current_time, diff_map): | 349 def GetRevisionString(prev_time, current_time, diff_map): |
301 """Get a string for revision information during the specified time period. | 350 """Get a string for revision information during the specified time period. |
302 | 351 |
303 Args: | 352 Args: |
304 prev_time: the previous time as a floating point number expressed | 353 prev_time: the previous time as a floating point number expressed |
305 in seconds since the epoch, in UTC. | 354 in seconds since the epoch, in UTC. |
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
495 list2 = map2[name]['te_info'] | 544 list2 = map2[name]['te_info'] |
496 te_diff = [item for item in list1 if not item in list2] | 545 te_diff = [item for item in list1 if not item in list2] |
497 if te_diff: | 546 if te_diff: |
498 name_list.append((name, te_diff)) | 547 name_list.append((name, te_diff)) |
499 else: | 548 else: |
500 name_list.append((name, value1)) | 549 name_list.append((name, value1)) |
501 return name_list | 550 return name_list |
502 | 551 |
503 return (GetDiffBetweenMapsHelper(map1, map2, lookIntoTestExpectationInfo), | 552 return (GetDiffBetweenMapsHelper(map1, map2, lookIntoTestExpectationInfo), |
504 GetDiffBetweenMapsHelper(map2, map1, lookIntoTestExpectationInfo)) | 553 GetDiffBetweenMapsHelper(map2, map1, lookIntoTestExpectationInfo)) |
OLD | NEW |