OLD | NEW |
---|---|
1 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2011 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 """Helper functions for the layout test analyzer.""" | 5 """Helper functions for the layout test analyzer.""" |
6 | 6 |
7 from datetime import datetime | 7 from datetime import datetime |
8 from email.mime.multipart import MIMEMultipart | 8 from email.mime.multipart import MIMEMultipart |
9 from email.mime.text import MIMEText | 9 from email.mime.text import MIMEText |
10 import fileinput | 10 import fileinput |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
67 @staticmethod | 67 @staticmethod |
68 def GetDiffString(diff_map_element, type_str): | 68 def GetDiffString(diff_map_element, type_str): |
69 """Get difference string out of diff map element. | 69 """Get difference string out of diff map element. |
70 | 70 |
71 The difference string shows difference between two analyzer results | 71 The difference string shows difference between two analyzer results |
72 (for example, a result for now and a result for sometime in the past) | 72 (for example, a result for now and a result for sometime in the past) |
73 in HTML format (with colors). This is used for generating email messages. | 73 in HTML format (with colors). This is used for generating email messages. |
74 | 74 |
75 Args: | 75 Args: |
76 diff_map_element: An element of the compared map generated by | 76 diff_map_element: An element of the compared map generated by |
77 |CompareResultMaps()|. The element has two lists of test cases. One | 77 |CompareResultMaps()|. The element has two lists of test cases. One |
78 is for test names that are in the current result but NOT in the | 78 is for test names that are in the current result but NOT in the |
79 previous result. The other is for test names that are in the previous | 79 previous result. The other is for test names that are in the previous |
80 results but NOT in the current result. Please refer to comments in | 80 results but NOT in the current result. Please refer to comments in |
81 |CompareResultMaps()| for details. | 81 |CompareResultMaps()| for details. |
82 type_str: a string indicating the test group to which |diff_map_element| | 82 type_str: a string indicating the test group to which |diff_map_element| |
dennis_jeffrey
2012/02/29 17:50:32
indent this line by 1 more space
imasaki1
2012/03/02 19:12:07
Done.
| |
83 belongs; used for color determination. Must be 'whole', 'skip', or | 83 belongs; used for color determination. Must be 'whole', 'skip', or |
84 'nonskip'. | 84 'nonskip'. |
85 | 85 |
86 Returns: | 86 Returns: |
87 a string in HTML format (with colors) to show difference between two | 87 a string in HTML format (with colors) to show difference between two |
88 analyzer results. | 88 analyzer results. |
89 """ | 89 """ |
90 diff = len(diff_map_element[0]) - len(diff_map_element[1]) | 90 diff = len(diff_map_element[0]) - len(diff_map_element[1]) |
91 if diff == 0: | 91 if diff == 0: |
92 return 'No Change' | 92 return 'No Change' |
93 color = '' | 93 color = '' |
94 if diff > 0 and type_str != 'whole': | 94 if diff > 0 and type_str != 'whole': |
95 color = 'red' | 95 color = 'red' |
96 else: | 96 else: |
97 color = 'green' | 97 color = 'green' |
98 diff_sign = '' | 98 diff_sign = '' |
99 if diff > 0: | 99 if diff > 0: |
100 diff_sign = '+' | 100 diff_sign = '+' |
101 whole_str = '<font color="%s">%s%d</font>' % (color, diff_sign, diff) | 101 whole_str = '<font color="%s">%s%d</font>' % (color, diff_sign, diff) |
102 colors = ['red', 'green'] | |
103 if type_str == 'whole': | |
104 # Bug 107773 - when we increase the number of tests, | |
105 # the name of the tests are in red, it should be green | |
106 # since it is good thing. | |
107 colors = ['green', 'red'] | |
102 str1 = '' | 108 str1 = '' |
103 for (name, _) in diff_map_element[0]: | 109 for (name, _) in diff_map_element[0]: |
104 str1 += '<font color="red">%s,</font> ' % name | 110 str1 += '<font color="%s">%s,</font>' % (colors[0], name) |
105 str1 = str1[:-1] | |
106 str2 = '' | 111 str2 = '' |
107 for (name, _) in diff_map_element[1]: | 112 for (name, _) in diff_map_element[1]: |
108 str2 += '<font color="green">%s,</font> ' % name | 113 str2 += '<font color="%s">%s,</font>' % (colors[1], name) |
109 str2 = str2[:-1] | |
110 if str1 or str2: | 114 if str1 or str2: |
111 whole_str += ':' | 115 whole_str += ':' |
112 if str1: | 116 if str1: |
113 whole_str += str1 | 117 whole_str += str1 |
114 if str2: | 118 if str2: |
115 whole_str += str2 | 119 whole_str += str2 |
120 # Remove the last occurrence of ','. | |
121 whole_str = ''.join(whole_str.rsplit(',', 1)) | |
dennis_jeffrey
2012/02/29 17:50:32
Another way to do this without splitting and joini
imasaki1
2012/03/02 19:12:07
I prefer to leave as it is. but, thanks for the co
| |
116 return whole_str | 122 return whole_str |
117 | 123 |
118 def GetPassingRate(self): | 124 def GetPassingRate(self): |
119 """Get passing rate. | 125 """Get passing rate. |
120 | 126 |
121 Returns: | 127 Returns: |
122 layout test passing rate of this result in percent. | 128 layout test passing rate of this result in percent. |
123 | 129 |
124 Raises: | 130 Raises: |
125 ValueEror when the number of tests in test group "whole" is equal or less | 131 ValueEror when the number of tests in test group "whole" is equal |
126 than that of "skip". | 132 or less than that of "skip". |
127 """ | 133 """ |
128 delta = len(self.result_map['whole'].keys()) - ( | 134 delta = len(self.result_map['whole'].keys()) - ( |
129 len(self.result_map['skip'].keys())) | 135 len(self.result_map['skip'].keys())) |
130 if delta <= 0: | 136 if delta <= 0: |
131 raise ValueError('The number of tests in test group "whole" is equal or ' | 137 raise ValueError('The number of tests in test group "whole" is equal or ' |
132 'less than that of "skip"') | 138 'less than that of "skip"') |
133 return 100 - len(self.result_map['nonskip'].keys()) * 100 / delta | 139 return 100 - len(self.result_map['nonskip'].keys()) * 100 / delta |
134 | 140 |
135 def ConvertToCSVText(self, current_time): | 141 def ConvertToCSVText(self, current_time): |
136 """Convert |self.result_map| into stats and issues text in CSV format. | 142 """Convert |self.result_map| into stats and issues text in CSV format. |
137 | 143 |
138 Both are used as inputs for Google spreadsheet. | 144 Both are used as inputs for Google spreadsheet. |
139 | 145 |
140 Args: | 146 Args: |
141 current_time: a string depicting a time in year-month-day-hour | 147 current_time: a string depicting a time in year-month-day-hour |
142 format (e.g., 2011-11-08-16). | 148 format (e.g., 2011-11-08-16). |
143 | 149 |
144 Returns: | 150 Returns: |
145 a tuple of stats and issues_txt | 151 a tuple of stats and issues_txt |
146 stats: analyzer result in CSV format that shows: | 152 stats: analyzer result in CSV format that shows: |
147 (current_time, the number of tests, the number of skipped tests, | 153 (current_time, the number of tests, the number of skipped tests, |
148 the number of failing tests, passing rate) | 154 the number of failing tests, passing rate) |
149 For example, | 155 For example, |
150 "2011-11-10-15,204,22,12,94" | 156 "2011-11-10-15,204,22,12,94" |
151 issues_txt: issues listed in CSV format that shows: | 157 issues_txt: issues listed in CSV format that shows: |
152 (BUGWK or BUGCR, bug number, the test expectation entry, | 158 (BUGWK or BUGCR, bug number, the test expectation entry, |
153 the name of the test) | 159 the name of the test) |
154 For example, | 160 For example, |
155 "BUGWK,71543,TIMEOUT PASS,media/media-element-play-after-eos.html, | 161 "BUGWK,71543,TIMEOUT PASS,media/media-element-play-after-eos.html, |
156 BUGCR,97657,IMAGE CPU MAC TIMEOUT PASS,media/audio-repaint.html," | 162 BUGCR,97657,IMAGE CPU MAC TIMEOUT PASS,media/audio-repaint.html," |
157 """ | 163 """ |
158 stats = ','.join([current_time, str(len(self.result_map['whole'].keys())), | 164 stats = ','.join([current_time, str(len(self.result_map['whole'].keys())), |
159 str(len(self.result_map['skip'].keys())), | 165 str(len(self.result_map['skip'].keys())), |
160 str(len(self.result_map['nonskip'].keys())), | 166 str(len(self.result_map['nonskip'].keys())), |
161 str(self.GetPassingRate())]) | 167 str(self.GetPassingRate())]) |
162 issues_txt = '' | 168 issues_txt = '' |
163 for bug_txt, test_info_list in ( | 169 for bug_txt, test_info_list in ( |
164 self.GetListOfBugsForNonSkippedTests().iteritems()): | 170 self.GetListOfBugsForNonSkippedTests().iteritems()): |
165 matches = re.match(r'(BUG(CR|WK))(\d+)', bug_txt) | 171 matches = re.match(r'(BUG(CR|WK))(\d+)', bug_txt) |
166 bug_suffix = '' | 172 bug_suffix = '' |
167 bug_no = '' | 173 bug_no = '' |
168 if matches: | 174 if matches: |
169 bug_suffix = matches.group(1) | 175 bug_suffix = matches.group(1) |
170 bug_no = matches.group(3) | 176 bug_no = matches.group(3) |
171 issues_txt += bug_suffix + ',' + bug_no + ',' | 177 issues_txt += bug_suffix + ',' + bug_no + ',' |
172 for test_info in test_info_list: | 178 for test_info in test_info_list: |
173 test_name, te_info = test_info | 179 test_name, te_info = test_info |
174 issues_txt += ' '.join(te_info.keys()) + ',' + test_name + ',' | 180 issues_txt += ' '.join(te_info.keys()) + ',' + test_name + ',' |
175 issues_txt += '\n' | 181 issues_txt += '\n' |
176 return stats, issues_txt | 182 return stats, issues_txt |
177 | 183 |
178 def ConvertToString(self, prev_time, diff_map, bug_anno_map): | 184 def ConvertToString(self, prev_time, diff_map, bug_anno_map, |
185 issue_detail_mode): | |
179 """Convert this result to HTML display for email. | 186 """Convert this result to HTML display for email. |
180 | 187 |
181 Args: | 188 Args: |
182 prev_time: the previous time string that are compared against. | 189 prev_time: the previous time string that are compared against. |
183 diff_map: the compared map generated by |CompareResultMaps()|. | 190 diff_map: the compared map generated by |CompareResultMaps()|. |
184 bug_anno_map: a annotation map where keys are bug names and values are | 191 bug_anno_map: a annotation map where keys are bug names and values are |
185 annotations for the bug. | 192 annotations for the bug. |
193 issue_detail_mode: Please see |options|. | |
dennis_jeffrey
2012/02/29 17:50:32
Since "options" is not defined in this file, it mi
imasaki1
2012/03/02 19:12:07
Done.
| |
186 | 194 |
187 Returns: | 195 Returns: |
188 a analyzer result string in HTML format. | 196 a analyzer result string in HTML format. |
189 """ | 197 """ |
190 return_str = '' | 198 return_str = '' |
191 if diff_map: | 199 if diff_map: |
192 return_str += ('<b>Statistics (Diff Compared to %s):</b><ul>' | 200 return_str += ( |
193 '<li>The number of tests: %d (%s)</li>' | 201 '<b>Statistics (Diff Compared to %s):</b><ul>' |
194 '<li>The number of failing skipped tests: %d (%s)</li>' | 202 '<li>The number of tests: %d (%s)</li>' |
195 '<li>The number of failing non-skipped tests: %d (%s)</li>' | 203 '<li>The number of failing skipped tests: %d (%s)</li>' |
196 '<li>Passing rate: %d %%</li></ul>') % ( | 204 '<li>The number of failing non-skipped tests: %d (%s)</li>' |
197 prev_time, len(self.result_map['whole'].keys()), | 205 '<li>Passing rate: %d %%</li></ul>') % ( |
198 AnalyzerResultMap.GetDiffString(diff_map['whole'], 'whole'), | 206 prev_time, len(self.result_map['whole'].keys()), |
199 len(self.result_map['skip'].keys()), | 207 AnalyzerResultMap.GetDiffString(diff_map['whole'], 'whole'), |
200 AnalyzerResultMap.GetDiffString(diff_map['skip'], 'skip'), | 208 len(self.result_map['skip'].keys()), |
201 len(self.result_map['nonskip'].keys()), | 209 AnalyzerResultMap.GetDiffString(diff_map['skip'], 'skip'), |
202 AnalyzerResultMap.GetDiffString(diff_map['nonskip'], | 210 len(self.result_map['nonskip'].keys()), |
203 'nonskip'), | 211 AnalyzerResultMap.GetDiffString(diff_map['nonskip'], 'nonskip'), |
204 self.GetPassingRate()) | 212 self.GetPassingRate()) |
205 return_str += '<b>Current issues about failing non-skipped tests:</b>' | 213 if issue_detail_mode: |
206 for (bug_txt, test_info_list) in ( | 214 return_str += '<b>Current issues about failing non-skipped tests:</b>' |
207 self.GetListOfBugsForNonSkippedTests().iteritems()): | 215 for (bug_txt, test_info_list) in ( |
208 if not bug_txt in bug_anno_map: | 216 self.GetListOfBugsForNonSkippedTests().iteritems()): |
209 bug_anno_map[bug_txt] = '<font color="red">Needs investigation!</font>' | 217 if not bug_txt in bug_anno_map: |
210 return_str += '<ul>%s (%s)' % (Bug(bug_txt), bug_anno_map[bug_txt]) | 218 bug_anno_map[bug_txt] = '' |
211 for test_info in test_info_list: | 219 else: |
212 (test_name, te_info) = test_info | 220 bug_anno_map[bug_txt] = '(' + bug_anno_map[bug_txt] + ')' |
213 gpu_link = '' | 221 return_str += '<ul>%s %s' % (Bug(bug_txt), bug_anno_map[bug_txt]) |
214 if 'GPU' in te_info: | 222 for test_info in test_info_list: |
215 gpu_link = 'group=%40ToT%20GPU%20Mesa%20-%20chromium.org&' | 223 (test_name, te_info) = test_info |
216 dashboard_link = ('http://test-results.appspot.com/dashboards/' | 224 gpu_link = '' |
217 'flakiness_dashboard.html#%stests=%s') % ( | 225 if 'GPU' in te_info: |
218 gpu_link, test_name) | 226 gpu_link = 'group=%40ToT%20GPU%20Mesa%20-%20chromium.org&' |
219 return_str += '<li><a href="%s">%s</a> (%s) </li>' % ( | 227 dashboard_link = ('http://test-results.appspot.com/dashboards/' |
220 dashboard_link, test_name, ' '.join(te_info.keys())) | 228 'flakiness_dashboard.html#%stests=%s') % ( |
221 return_str += '</ul>\n' | 229 gpu_link, test_name) |
230 return_str += '<li><a href="%s">%s</a> (%s) </li>' % ( | |
231 dashboard_link, test_name, ' '.join(te_info.keys())) | |
232 return_str += '</ul>\n' | |
222 return return_str | 233 return return_str |
223 | 234 |
224 def CompareToOtherResultMap(self, other_result_map): | 235 def CompareToOtherResultMap(self, other_result_map): |
225 """Compare this result map with the other to see if there are any diff. | 236 """Compare this result map with the other to see if there are any diff. |
226 | 237 |
227 The comparison is done for layouttests which belong to 'whole', 'skip', | 238 The comparison is done for layouttests which belong to 'whole', 'skip', |
228 or 'nonskip'. | 239 or 'nonskip'. |
229 | 240 |
230 Args: | 241 Args: |
231 other_result_map: another result map to be compared against the result | 242 other_result_map: another result map to be compared against the result |
232 map of the current object. | 243 map of the current object. |
233 | 244 |
234 Returns: | 245 Returns: |
235 a map that has 'whole', 'skip' and 'nonskip' as keys. | 246 a map that has 'whole', 'skip' and 'nonskip' as keys. |
236 Please refer to |diff_map| in |SendStatusEmail()|. | 247 Please refer to |diff_map| in |SendStatusEmail()|. |
237 """ | 248 """ |
238 comp_result_map = {} | 249 comp_result_map = {} |
239 for name in ['whole', 'skip', 'nonskip']: | 250 for name in ['whole', 'skip', 'nonskip']: |
240 if name == 'nonskip': | 251 if name == 'nonskip': |
241 # Look into expectation to get diff only for non-skipped tests. | 252 # Look into expectation to get diff only for non-skipped tests. |
242 lookIntoTestExpectationInfo = True | 253 lookIntoTestExpectationInfo = True |
243 else: | 254 else: |
244 # Otherwise, only test names are compared to get diff. | 255 # Otherwise, only test names are compared to get diff. |
245 lookIntoTestExpectationInfo = False | 256 lookIntoTestExpectationInfo = False |
246 comp_result_map[name] = GetDiffBetweenMaps( | 257 comp_result_map[name] = GetDiffBetweenMaps( |
247 self.result_map[name], other_result_map.result_map[name], | 258 self.result_map[name], other_result_map.result_map[name], |
248 lookIntoTestExpectationInfo) | 259 lookIntoTestExpectationInfo) |
249 return comp_result_map | 260 return comp_result_map |
250 | 261 |
251 @staticmethod | 262 @staticmethod |
252 def Load(file_path): | 263 def Load(file_path): |
253 """Load the object from |file_path| using pickle library. | 264 """Load the object from |file_path| using pickle library. |
254 | 265 |
255 Args: | 266 Args: |
256 file_path: the string path to the file from which to read the result. | 267 file_path: the string path to the file from which to read the result. |
257 | 268 |
258 Returns: | 269 Returns: |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
324 bug_anno_map: bug annotation map where bug name and annotations are | 335 bug_anno_map: bug annotation map where bug name and annotations are |
325 stored. | 336 stored. |
326 receiver_email_address: receiver's email address. | 337 receiver_email_address: receiver's email address. |
327 test_group_name: string representing the test group name (e.g., 'media'). | 338 test_group_name: string representing the test group name (e.g., 'media'). |
328 appended_text_to_email: a text which is appended at the end of the status | 339 appended_text_to_email: a text which is appended at the end of the status |
329 email. | 340 email. |
330 email_content: an email content string that will be shown on the dashboard. | 341 email_content: an email content string that will be shown on the dashboard. |
331 rev_str: a revision string that contains revision information that is sent | 342 rev_str: a revision string that contains revision information that is sent |
332 out in the status email. It is obtained by calling | 343 out in the status email. It is obtained by calling |
333 |GetRevisionString()|. | 344 |GetRevisionString()|. |
334 email_only_change_mode: please refer to |options|. | 345 email_only_change_mode: please refer to |options|. |
dennis_jeffrey
2012/02/29 17:50:32
Similar comment as line 193 above.
imasaki1
2012/03/02 19:12:07
Done.
| |
335 """ | 346 """ |
336 if rev_str: | 347 if rev_str: |
337 email_content += '<br><b>Revision Information:</b>' | 348 email_content += '<br><b>Revision Information:</b>' |
338 email_content += rev_str | 349 email_content += rev_str |
339 localtime = time.asctime(time.localtime(time.time())) | 350 localtime = time.asctime(time.localtime(time.time())) |
340 change_str = '' | 351 change_str = '' |
341 if email_only_change_mode: | 352 if email_only_change_mode: |
342 change_str = 'Status Change ' | 353 change_str = 'Status Change ' |
343 subject = 'Layout Test Analyzer Result %s(%s): %s' % (change_str, | 354 subject = 'Layout Test Analyzer Result %s(%s): %s' % (change_str, |
344 test_group_name, | 355 test_group_name, |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
392 link = urllib.unquote('http://trac.webkit.org/changeset?new=%d%40trunk' | 403 link = urllib.unquote('http://trac.webkit.org/changeset?new=%d%40trunk' |
393 '%2FLayoutTests%2Fplatform%2Fchromium%2F' | 404 '%2FLayoutTests%2Fplatform%2Fchromium%2F' |
394 'test_expectations.txt&old=%d%40trunk%2F' | 405 'test_expectations.txt&old=%d%40trunk%2F' |
395 'LayoutTests%2Fplatform%2Fchromium%2F' | 406 'LayoutTests%2Fplatform%2Fchromium%2F' |
396 'test_expectations.txt') % (new_rev, old_rev) | 407 'test_expectations.txt') % (new_rev, old_rev) |
397 rev_str += '<ul><a href="%s">%s->%s</a>\n' % (link, old_rev, new_rev) | 408 rev_str += '<ul><a href="%s">%s->%s</a>\n' % (link, old_rev, new_rev) |
398 simple_rev_str = '<a href="%s">%s->%s</a>,' % (link, old_rev, new_rev) | 409 simple_rev_str = '<a href="%s">%s->%s</a>,' % (link, old_rev, new_rev) |
399 rev_str += '<li>%s</li>\n' % author | 410 rev_str += '<li>%s</li>\n' % author |
400 rev_str += '<li>%s</li>\n<ul>' % date | 411 rev_str += '<li>%s</li>\n<ul>' % date |
401 for line in target_lines: | 412 for line in target_lines: |
402 rev_str += '<li>%s</li>\n' % line | 413 # Find *.html pattern (test name) and replace it with the link to |
414 # frakiness dashboard. | |
dennis_jeffrey
2012/02/29 17:50:32
frakiness --> flakiness
imasaki1
2012/03/02 19:12:07
Done.
| |
415 test_name_pattern = r'(\S+.html)' | |
416 match = re.search(test_name_pattern, line) | |
417 if match: | |
418 test_name = match.group(1) | |
419 gpu_link = '' | |
420 if 'GPU' in line: | |
421 gpu_link = 'group=%40ToT%20GPU%20Mesa%20-%20chromium.org&' | |
422 dashboard_link = ('http://test-results.appspot.com/dashboards/' | |
423 'flakiness_dashboard.html#%stests=%s') % ( | |
424 gpu_link, test_name) | |
425 line = line.replace(test_name, "<a href='%s'>%s</a>" % ( | |
dennis_jeffrey
2012/02/29 17:50:32
nit: I recommend swapping the single quotes and do
imasaki1
2012/03/02 19:12:07
Done.
| |
426 dashboard_link, test_name)) | |
427 # Find bug text and replace it with the link to the bug. | |
428 bug = Bug(line) | |
429 new_line = '<li>%s</li>\n' % line.replace(bug.bug_txt, bug.__str__()) | |
dennis_jeffrey
2012/02/29 17:50:32
could we replace bug.__str__() with str(bug)?
imasaki1
2012/03/02 19:12:07
Done.
| |
430 rev_str += new_line | |
403 rev_str += '</ul></ul>' | 431 rev_str += '</ul></ul>' |
404 return (rev_str, simple_rev_str, rev, rev_date) | 432 return (rev_str, simple_rev_str, rev, rev_date) |
405 | 433 |
406 | 434 |
407 def SendEmail(sender_email_address, receivers_email_addresses, subject, | 435 def SendEmail(sender_email_address, receivers_email_addresses, subject, |
408 message): | 436 message): |
409 """Send email using localhost's mail server. | 437 """Send email using localhost's mail server. |
410 | 438 |
411 Args: | 439 Args: |
412 sender_email_address: sender's email address. | 440 sender_email_address: sender's email address. |
413 receivers_email_addresses: receiver's email addresses. | 441 receivers_email_addresses: receiver's email addresses. |
414 subject: subject string. | 442 subject: subject string. |
415 message: email message. | 443 message: email message. |
444 """ | |
445 try: | |
446 html_top = """ | |
447 <html> | |
448 <head></head> | |
449 <body> | |
416 """ | 450 """ |
417 try: | 451 html_bot = """ |
418 html_top = """ | 452 </body> |
419 <html> | 453 </html> |
420 <head></head> | 454 """ |
421 <body> | 455 html = html_top + message + html_bot |
422 """ | 456 msg = MIMEMultipart('alternative') |
423 html_bot = """ | 457 msg['Subject'] = subject |
424 </body> | 458 msg['From'] = sender_email_address |
425 </html> | 459 msg['To'] = receivers_email_addresses[0] |
426 """ | 460 part1 = MIMEText(html, 'html') |
427 html = html_top + message + html_bot | 461 smtp_obj = smtplib.SMTP('localhost') |
428 msg = MIMEMultipart('alternative') | 462 msg.attach(part1) |
429 msg['Subject'] = subject | 463 smtp_obj.sendmail(sender_email_address, receivers_email_addresses, |
430 msg['From'] = sender_email_address | 464 msg.as_string()) |
431 msg['To'] = receivers_email_addresses[0] | 465 print 'Successfully sent email' |
432 part1 = MIMEText(html, 'html') | 466 except smtplib.SMTPException, ex: |
433 smtp_obj = smtplib.SMTP('localhost') | 467 print 'Authentication failed:', ex |
434 msg.attach(part1) | 468 print 'Error: unable to send email' |
435 smtp_obj.sendmail(sender_email_address, receivers_email_addresses, | 469 except (socket.gaierror, socket.error, socket.herror), ex: |
436 msg.as_string()) | 470 print ex |
437 print 'Successfully sent email' | 471 print 'Error: unable to send email' |
438 except smtplib.SMTPException, ex: | |
439 print 'Authentication failed:', ex | |
440 print 'Error: unable to send email' | |
441 except (socket.gaierror, socket.error, socket.herror), ex: | |
442 print ex | |
443 print 'Error: unable to send email' | |
444 | 472 |
445 | 473 |
446 def FindLatestTime(time_list): | 474 def FindLatestTime(time_list): |
447 """Find latest time from |time_list|. | 475 """Find latest time from |time_list|. |
448 | 476 |
449 The current status is compared to the status of the latest file in | 477 The current status is compared to the status of the latest file in |
450 |RESULT_DIR|. | 478 |RESULT_DIR|. |
451 | 479 |
452 Args: | 480 Args: |
453 time_list: a list of time string in the form of 'Year-Month-Day-Hour' | 481 time_list: a list of time string in the form of 'Year-Month-Day-Hour' |
454 (e.g., 2011-10-23-23). Strings not in this format are ignored. | 482 (e.g., 2011-10-23-23). Strings not in this format are ignored. |
455 | 483 |
456 Returns: | 484 Returns: |
457 a string representing latest time among the time_list or None if | 485 a string representing latest time among the time_list or None if |
458 |time_list| is empty or no valid date string in |time_list|. | 486 |time_list| is empty or no valid date string in |time_list|. |
459 """ | 487 """ |
460 if not time_list: | 488 if not time_list: |
461 return None | 489 return None |
462 latest_date = None | 490 latest_date = None |
463 for time_element in time_list: | 491 for time_element in time_list: |
464 try: | 492 try: |
465 item_date = datetime.strptime(time_element, '%Y-%m-%d-%H') | 493 item_date = datetime.strptime(time_element, '%Y-%m-%d-%H') |
466 if latest_date == None or latest_date < item_date: | 494 if latest_date is None or latest_date < item_date: |
467 latest_date = item_date | 495 latest_date = item_date |
468 except ValueError: | 496 except ValueError: |
469 # Do nothing. | 497 # Do nothing. |
470 pass | 498 pass |
471 if latest_date: | 499 if latest_date: |
472 return latest_date.strftime('%Y-%m-%d-%H') | 500 return latest_date.strftime('%Y-%m-%d-%H') |
473 else: | 501 else: |
474 return None | 502 return None |
475 | 503 |
476 | 504 |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
539 a list of tuples (name, te_info) that are in |map1| but not in |map2|. | 567 a list of tuples (name, te_info) that are in |map1| but not in |map2|. |
540 """ | 568 """ |
541 name_list = [] | 569 name_list = [] |
542 for (name, value1) in map1.iteritems(): | 570 for (name, value1) in map1.iteritems(): |
543 if name in map2: | 571 if name in map2: |
544 if lookIntoTestExpectationInfo and 'te_info' in value1: | 572 if lookIntoTestExpectationInfo and 'te_info' in value1: |
545 list1 = value1['te_info'] | 573 list1 = value1['te_info'] |
546 list2 = map2[name]['te_info'] | 574 list2 = map2[name]['te_info'] |
547 te_diff = [item for item in list1 if not item in list2] | 575 te_diff = [item for item in list1 if not item in list2] |
548 if te_diff: | 576 if te_diff: |
549 name_list.append((name, te_diff)) | 577 name_list.append((name, te_diff)) |
550 else: | 578 else: |
551 name_list.append((name, value1)) | 579 name_list.append((name, value1)) |
552 return name_list | 580 return name_list |
553 | 581 |
554 return (GetDiffBetweenMapsHelper(map1, map2, lookIntoTestExpectationInfo), | 582 return (GetDiffBetweenMapsHelper(map1, map2, lookIntoTestExpectationInfo), |
555 GetDiffBetweenMapsHelper(map2, map1, lookIntoTestExpectationInfo)) | 583 GetDiffBetweenMapsHelper(map2, map1, lookIntoTestExpectationInfo)) |
OLD | NEW |