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 |self.result_map| into stats and issues text in CSV format. |
| 138 |
| 139 Both are used as inputs for Google spreadsheet. |
| 140 |
| 141 Args: |
| 142 current_time: a string depicting a time in year-month-day-hour |
| 143 format (e.g., 2011-11-08-16). |
| 144 |
| 145 Returns: |
| 146 a tuple of stats and issues_txt |
| 147 stats: analyzer result in CSV format that shows: |
| 148 (current_time, the number of tests, the number of skipped tests, |
| 149 the number of failing tests) |
| 150 For example, |
| 151 "2011-11-10-15,204,22,12" |
| 152 issues_txt: issues listed in CSV format that shows: |
| 153 (BUGWK or BUGCR, bug number, the test expectation entry, |
| 154 the name of the test) |
| 155 For example, |
| 156 "BUGWK,71543,TIMEOUT PASS,media/media-element-play-after-eos.html, |
| 157 BUGCR,97657,IMAGE CPU MAC TIMEOUT PASS,media/audio-repaint.html," |
| 158 """ |
| 159 stats = ','.join([current_time, str(len(self.result_map['whole'].keys())), |
| 160 str(len(self.result_map['skip'].keys())), |
| 161 str(len(self.result_map['nonskip'].keys()))]) |
| 162 issues_txt = '' |
| 163 for bug_txt, test_info_list in ( |
| 164 self.GetListOfBugsForNonSkippedTests().iteritems()): |
| 165 matches = re.match(r'(BUG(CR|WK))(\d+)', bug_txt) |
| 166 bug_suffix = '' |
| 167 bug_no = '' |
| 168 if matches: |
| 169 bug_suffix = matches.group(1) |
| 170 bug_no = matches.group(3) |
| 171 issues_txt += bug_suffix + ',' + bug_no + ',' |
| 172 for test_info in test_info_list: |
| 173 test_name, te_info = test_info |
| 174 issues_txt += ' '.join(te_info.keys()) + ',' + test_name + ',' |
| 175 issues_txt += '\n' |
| 176 return stats, issues_txt |
| 177 |
135 def ConvertToString(self, prev_time, diff_map, bug_anno_map): | 178 def ConvertToString(self, prev_time, diff_map, bug_anno_map): |
136 """Convert this result to HTML display for email. | 179 """Convert this result to HTML display for email. |
137 | 180 |
138 Args: | 181 Args: |
139 prev_time: the previous time string that are compared against. | 182 prev_time: the previous time string that are compared against. |
140 diff_map: the compared map generated by |CompareResultMaps()|. | 183 diff_map: the compared map generated by |CompareResultMaps()|. |
141 bug_anno_map: a annotation map where keys are bug names and values are | 184 bug_anno_map: a annotation map where keys are bug names and values are |
142 annotations for the bug. | 185 annotations for the bug. |
143 | 186 |
144 Returns: | 187 Returns: |
145 a analyzer result string in HTML format. | 188 a analyzer result string in HTML format. |
146 """ | 189 """ |
147 return_str = ('<b>Statistics (Diff Compared to %s):</b><ul>' | 190 return_str = '' |
148 '<li>The number of tests: %d (%s)</li>' | 191 if diff_map: |
149 '<li>The number of failing skipped tests: %d (%s)</li>' | 192 return_str += ('<b>Statistics (Diff Compared to %s):</b><ul>' |
150 '<li>The number of failing non-skipped tests: %d (%s)</li>' | 193 '<li>The number of tests: %d (%s)</li>' |
151 '<li>Passing rate: %d %%</li></ul>') % ( | 194 '<li>The number of failing skipped tests: %d (%s)</li>' |
152 prev_time, len(self.result_map['whole'].keys()), | 195 '<li>The number of failing non-skipped tests: %d (%s)</li>' |
153 AnalyzerResultMap.GetDiffString(diff_map['whole'], 'whole'), | 196 '<li>Passing rate: %d %%</li></ul>') % ( |
154 len(self.result_map['skip'].keys()), | 197 prev_time, len(self.result_map['whole'].keys()), |
155 AnalyzerResultMap.GetDiffString(diff_map['skip'], 'skip'), | 198 AnalyzerResultMap.GetDiffString(diff_map['whole'], 'whole'), |
156 len(self.result_map['nonskip'].keys()), | 199 len(self.result_map['skip'].keys()), |
157 AnalyzerResultMap.GetDiffString(diff_map['nonskip'], | 200 AnalyzerResultMap.GetDiffString(diff_map['skip'], 'skip'), |
158 'nonskip'), | 201 len(self.result_map['nonskip'].keys()), |
159 self.GetPassingRate()) | 202 AnalyzerResultMap.GetDiffString(diff_map['nonskip'], |
| 203 'nonskip'), |
| 204 self.GetPassingRate()) |
160 return_str += '<b>Current issues about failing non-skipped tests:</b>' | 205 return_str += '<b>Current issues about failing non-skipped tests:</b>' |
161 for (bug_txt, test_info_list) in ( | 206 for (bug_txt, test_info_list) in ( |
162 self.GetListOfBugsForNonSkippedTests().iteritems()): | 207 self.GetListOfBugsForNonSkippedTests().iteritems()): |
163 if not bug_txt in bug_anno_map: | 208 if not bug_txt in bug_anno_map: |
164 bug_anno_map[bug_txt] = '<font color="red">Needs investigation!</font>' | 209 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]) | 210 return_str += '<ul>%s (%s)' % (Bug(bug_txt), bug_anno_map[bug_txt]) |
166 for test_info in test_info_list: | 211 for test_info in test_info_list: |
167 (test_name, te_info) = test_info | 212 (test_name, te_info) = test_info |
168 gpu_link = '' | 213 gpu_link = '' |
169 if 'GPU' in te_info: | 214 if 'GPU' in te_info: |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
248 if 'Bugs' in te_info: | 293 if 'Bugs' in te_info: |
249 for bug in te_info['Bugs']: | 294 for bug in te_info['Bugs']: |
250 if bug not in bug_map: | 295 if bug not in bug_map: |
251 bug_map[bug] = [] | 296 bug_map[bug] = [] |
252 bug_map[bug].append((name, main_te_info)) | 297 bug_map[bug].append((name, main_te_info)) |
253 return bug_map | 298 return bug_map |
254 | 299 |
255 | 300 |
256 def SendStatusEmail(prev_time, analyzer_result_map, diff_map, | 301 def SendStatusEmail(prev_time, analyzer_result_map, diff_map, |
257 bug_anno_map, receiver_email_address, test_group_name, | 302 bug_anno_map, receiver_email_address, test_group_name, |
258 appended_text_to_email, email_content, rev_str): | 303 appended_text_to_email, email_content, rev_str, |
| 304 email_only_change_mode): |
259 """Send status email. | 305 """Send status email. |
260 | 306 |
261 Args: | 307 Args: |
262 prev_time: the date string such as '2011-10-09-11'. This format has been | 308 prev_time: the date string such as '2011-10-09-11'. This format has been |
263 used in this analyzer. | 309 used in this analyzer. |
264 analyzer_result_map: current analyzer result. | 310 analyzer_result_map: current analyzer result. |
265 diff_map: a map that has 'whole', 'skip' and 'nonskip' as keys. | 311 diff_map: a map that has 'whole', 'skip' and 'nonskip' as keys. |
266 The values of the map are the result of |GetDiffBetweenMaps()|. | 312 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 | 313 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 | 314 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 | 315 result. The other (with index 1) is for test names that are in the |
270 previous results but NOT in the current result. | 316 previous results but NOT in the current result. |
271 For example (test expectation information is omitted for | 317 For example (test expectation information is omitted for |
272 simplicity), | 318 simplicity), |
273 comp_result_map['whole'][0] = ['foo1.html'] | 319 comp_result_map['whole'][0] = ['foo1.html'] |
274 comp_result_map['whole'][1] = ['foo2.html'] | 320 comp_result_map['whole'][1] = ['foo2.html'] |
275 This means that current result has 'foo1.html' but it is NOT in the | 321 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' | 322 previous result. This also means the previous result has 'foo2.html' |
277 but it is NOT in the current result. | 323 but it is NOT in the current result. |
278 bug_anno_map: bug annotation map where bug name and annotations are | 324 bug_anno_map: bug annotation map where bug name and annotations are |
279 stored. | 325 stored. |
280 receiver_email_address: receiver's email address. | 326 receiver_email_address: receiver's email address. |
281 test_group_name: string representing the test group name (e.g., 'media'). | 327 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 | 328 appended_text_to_email: a text which is appended at the end of the status |
283 email. | 329 email. |
284 email_content: an email content string that will be shown on the dashboard. | 330 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 | 331 rev_str: a revision string that contains revision information that is sent |
286 out in the status email. It is obtained by calling | 332 out in the status email. It is obtained by calling |
287 |GetRevisionString()|. | 333 |GetRevisionString()|. |
| 334 email_only_change_mode: please refer to |options|. |
288 """ | 335 """ |
289 if rev_str: | 336 if rev_str: |
290 email_content += '<br><b>Revision Information:</b>' | 337 email_content += '<br><b>Revision Information:</b>' |
291 email_content += rev_str | 338 email_content += rev_str |
292 localtime = time.asctime(time.localtime(time.time())) | 339 localtime = time.asctime(time.localtime(time.time())) |
| 340 change_str = '' |
| 341 if email_only_change_mode: |
| 342 change_str = 'Status Change ' |
| 343 subject = 'Layout Test Analyzer Result %s(%s): %s' % (change_str, |
| 344 test_group_name, |
| 345 localtime) |
293 # TODO(imasaki): remove my name from here. | 346 # 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], | 347 SendEmail('imasaki@chromium.org', [receiver_email_address], |
297 subject, email_content + appended_text_to_email) | 348 subject, email_content + appended_text_to_email) |
298 | 349 |
299 | 350 |
300 def GetRevisionString(prev_time, current_time, diff_map): | 351 def GetRevisionString(prev_time, current_time, diff_map): |
301 """Get a string for revision information during the specified time period. | 352 """Get a string for revision information during the specified time period. |
302 | 353 |
303 Args: | 354 Args: |
304 prev_time: the previous time as a floating point number expressed | 355 prev_time: the previous time as a floating point number expressed |
305 in seconds since the epoch, in UTC. | 356 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'] | 546 list2 = map2[name]['te_info'] |
496 te_diff = [item for item in list1 if not item in list2] | 547 te_diff = [item for item in list1 if not item in list2] |
497 if te_diff: | 548 if te_diff: |
498 name_list.append((name, te_diff)) | 549 name_list.append((name, te_diff)) |
499 else: | 550 else: |
500 name_list.append((name, value1)) | 551 name_list.append((name, value1)) |
501 return name_list | 552 return name_list |
502 | 553 |
503 return (GetDiffBetweenMapsHelper(map1, map2, lookIntoTestExpectationInfo), | 554 return (GetDiffBetweenMapsHelper(map1, map2, lookIntoTestExpectationInfo), |
504 GetDiffBetweenMapsHelper(map2, map1, lookIntoTestExpectationInfo)) | 555 GetDiffBetweenMapsHelper(map2, map1, lookIntoTestExpectationInfo)) |
OLD | NEW |