OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env 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 """Main functions for the Layout Test Analyzer module.""" | 6 """Main functions for the Layout Test Analyzer module.""" |
7 | 7 |
8 import csv | 8 import csv |
9 from datetime import datetime | 9 from datetime import datetime |
10 import optparse | 10 import optparse |
11 import os | 11 import os |
12 import sys | 12 import sys |
13 import time | 13 import time |
14 | 14 |
15 import layouttest_analyzer_helpers | |
15 import layouttests | 16 import layouttests |
16 import layouttest_analyzer_helpers | 17 |
17 from test_expectations import TestExpectations | 18 from test_expectations import TestExpectations |
18 from trend_graph import TrendGraph | 19 from trend_graph import TrendGraph |
19 | 20 |
20 # Predefined result directory. | 21 # Predefined result directory. |
21 DEFAULT_RESULT_DIR = 'result' | 22 DEFAULT_RESULT_DIR = 'result' |
22 DEFAULT_ANNO_FILE = os.path.join('anno', 'anno.csv') | 23 DEFAULT_ANNO_FILE = os.path.join('anno', 'anno.csv') |
23 DEFAULT_GRAPH_FILE = os.path.join('graph', 'graph.html') | 24 DEFAULT_GRAPH_FILE = os.path.join('graph', 'graph.html') |
24 DEFAULT_STATS_CSV_FILENAME = 'stats.csv' | 25 DEFAULT_STATS_CSV_FILENAME = 'stats.csv' |
25 DEFAULT_ISSUES_CSV_FILENAME = 'issues.csv' | 26 DEFAULT_ISSUES_CSV_FILENAME = 'issues.csv' |
26 # Predefined result files for debug. | 27 # Predefined result files for debug. |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
66 dest='test_group_file_location', | 67 dest='test_group_file_location', |
67 help=('Location of the test group file; ' | 68 help=('Location of the test group file; ' |
68 'file is expected to be in CSV format ' | 69 'file is expected to be in CSV format ' |
69 'and lists all test name patterns. ' | 70 'and lists all test name patterns. ' |
70 'When this option is not specified, ' | 71 'When this option is not specified, ' |
71 'the value of --test-group-name is used ' | 72 'the value of --test-group-name is used ' |
72 'for a test name pattern.'), | 73 'for a test name pattern.'), |
73 default=None) | 74 default=None) |
74 option_parser.add_option('-x', '--test-group-name', | 75 option_parser.add_option('-x', '--test-group-name', |
75 dest='test_group_name', | 76 dest='test_group_name', |
76 help='A name of test group. Either ' | 77 help=('A name of test group. Either ' |
77 '--test_group_file_location or this option ' | 78 '--test_group_file_location or this option ' |
78 'needs to be specified.') | 79 'needs to be specified.')) |
79 option_parser.add_option('-d', '--result-directory-location', | 80 option_parser.add_option('-d', '--result-directory-location', |
80 dest='result_directory_location', | 81 dest='result_directory_location', |
81 help=('Name of result directory location ' | 82 help=('Name of result directory location ' |
82 '(default to %default).'), | 83 '(default to %default).'), |
83 default=DEFAULT_RESULT_DIR) | 84 default=DEFAULT_RESULT_DIR) |
84 option_parser.add_option('-b', '--email-appended-text-file-location', | 85 option_parser.add_option('-b', '--email-appended-text-file-location', |
85 dest='email_appended_text_file_location', | 86 dest='email_appended_text_file_location', |
86 help=('File location of the email appended text. ' | 87 help=('File location of the email appended text. ' |
87 'The text is appended in the status email. ' | 88 'The text is appended in the status email. ' |
88 '(default to %default and no text is ' | 89 '(default to %default and no text is ' |
89 'appended in that case).'), | 90 'appended in that case).'), |
90 default=None) | 91 default=None) |
91 option_parser.add_option('-c', '--email-only-change-mode', | 92 option_parser.add_option('-c', '--email-only-change-mode', |
92 dest='email_only_change_mode', | 93 dest='email_only_change_mode', |
93 help=('With this mode, email is sent out ' | 94 help=('With this mode, email is sent out ' |
94 'only when there is a change in the ' | 95 'only when there is a change in the ' |
95 'analyzer result compared to the previous ' | 96 'analyzer result compared to the previous ' |
96 'result (off by default)'), | 97 'result (off by default)'), |
97 action='store_true', default=False) | 98 action='store_true', default=False) |
98 option_parser.add_option('-q', '--dashboard-file-location', | 99 option_parser.add_option('-q', '--dashboard-file-location', |
99 dest='dashboard_file_location', | 100 dest='dashboard_file_location', |
100 help=('Location of dashboard file. The results are ' | 101 help=('Location of dashboard file. The results are ' |
101 'not reported to the dashboard if this ' | 102 'not reported to the dashboard if this ' |
102 'option is not specified.')) | 103 'option is not specified.')) |
104 option_parser.add_option('-z', '--issue-detail-mode', | |
105 dest='issue_detail_mode', | |
106 help=('With this mode, email includes issue details ' | |
107 '(links to the flakiness dashboard)' | |
108 ' (off by default)'), | |
109 action='store_true', default=False) | |
103 return option_parser.parse_args()[0] | 110 return option_parser.parse_args()[0] |
104 | 111 |
105 | 112 |
106 def GetCurrentAndPreviousResults(debug, test_group_file_location, | 113 def GetCurrentAndPreviousResults(debug, test_group_file_location, |
107 test_group_name, result_directory_location): | 114 test_group_name, result_directory_location): |
108 """Get current and the latest previous analyzer results. | 115 """Get current and the latest previous analyzer results. |
109 | 116 |
110 In debug mode, they are read from predefined files. In non-debug mode, | 117 In debug mode, they are read from predefined files. In non-debug mode, |
111 current analyzer results are dynamically obtained from Webkit SVN and | 118 current analyzer results are dynamically obtained from Webkit SVN and |
112 the latest previous result is read from the corresponding file. | 119 the latest previous result is read from the corresponding file. |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
153 test_group_name += '/' | 160 test_group_name += '/' |
154 parent_location_list = [test_group_name] | 161 parent_location_list = [test_group_name] |
155 filter_names = None | 162 filter_names = None |
156 recursion = True | 163 recursion = True |
157 layouttests_object = layouttests.LayoutTests( | 164 layouttests_object = layouttests.LayoutTests( |
158 parent_location_list=parent_location_list, recursion=recursion, | 165 parent_location_list=parent_location_list, recursion=recursion, |
159 filter_names=filter_names) | 166 filter_names=filter_names) |
160 analyzer_result_map = layouttest_analyzer_helpers.AnalyzerResultMap( | 167 analyzer_result_map = layouttest_analyzer_helpers.AnalyzerResultMap( |
161 layouttests_object.JoinWithTestExpectation(TestExpectations())) | 168 layouttests_object.JoinWithTestExpectation(TestExpectations())) |
162 result = layouttest_analyzer_helpers.FindLatestResult( | 169 result = layouttest_analyzer_helpers.FindLatestResult( |
163 result_directory_location) | 170 result_directory_location) |
164 if result: | 171 if result: |
165 (prev_time, prev_analyzer_result_map) = result | 172 (prev_time, prev_analyzer_result_map) = result |
166 else: | 173 else: |
167 prev_time = None | 174 prev_time = None |
168 prev_analyzer_result_map = None | 175 prev_analyzer_result_map = None |
169 else: | 176 else: |
170 analyzer_result_map = layouttest_analyzer_helpers.AnalyzerResultMap.Load( | 177 analyzer_result_map = layouttest_analyzer_helpers.AnalyzerResultMap.Load( |
171 CURRENT_RESULT_FILE_FOR_DEBUG) | 178 CURRENT_RESULT_FILE_FOR_DEBUG) |
172 prev_time = PREV_TIME_FOR_DEBUG | 179 prev_time = PREV_TIME_FOR_DEBUG |
173 prev_analyzer_result_map = ( | 180 prev_analyzer_result_map = ( |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
210 print 'cannot open email appended text file %s. Skipping.' % ( | 217 print 'cannot open email appended text file %s. Skipping.' % ( |
211 email_appended_text_file_location) | 218 email_appended_text_file_location) |
212 else: | 219 else: |
213 appended_text_to_email = ''.join(file_object.readlines()) | 220 appended_text_to_email = ''.join(file_object.readlines()) |
214 file_object.close() | 221 file_object.close() |
215 return (anno_map, appended_text_to_email) | 222 return (anno_map, appended_text_to_email) |
216 | 223 |
217 | 224 |
218 def SendEmail(prev_time, prev_analyzer_result_map, analyzer_result_map, | 225 def SendEmail(prev_time, prev_analyzer_result_map, analyzer_result_map, |
219 anno_map, appended_text_to_email, email_only_change_mode, debug, | 226 anno_map, appended_text_to_email, email_only_change_mode, debug, |
220 receiver_email_address, test_group_name): | 227 receiver_email_address, test_group_name, issue_detail_mode): |
221 """Send result status email. | 228 """Send result status email. |
222 | 229 |
223 Args: | 230 Args: |
224 prev_time: the previous time string that is compared against. | 231 prev_time: the previous time string that is compared against. |
225 prev_analyzer_result_map: previous analyzer result map. Please refer to | 232 prev_analyzer_result_map: previous analyzer result map. Please refer to |
226 layouttest_analyzer_helpers.AnalyzerResultMap. | 233 layouttest_analyzer_helpers.AnalyzerResultMap. |
227 analyzer_result_map: current analyzer result map. Please refer to | 234 analyzer_result_map: current analyzer result map. Please refer to |
228 layouttest_analyzer_helpers.AnalyzerResultMap. | 235 layouttest_analyzer_helpers.AnalyzerResultMap. |
229 anno_map: a dictionary that maps bug names to their annotations. | 236 anno_map: a dictionary that maps bug names to their annotations. |
230 appended_text_to_email: the text string to append to the status email. | 237 appended_text_to_email: the text string to append to the status email. |
231 email_only_change_mode: please refer to |options|. | 238 email_only_change_mode: please refer to |options|. |
232 debug: please refer to |options|. | 239 debug: please refer to |options|. |
233 receiver_email_address: please refer to |options|. | 240 receiver_email_address: please refer to |options|. |
234 test_group_name: please refer to |options|. | 241 test_group_name: please refer to |options|. |
242 issue_detail_mode: please refer to |options|. | |
235 | 243 |
236 Returns: | 244 Returns: |
237 a tuple of the following: | 245 a tuple of the following: |
238 result_change: a boolean indicating whether there is a change in the | 246 result_change: a boolean indicating whether there is a change in the |
239 result compared with the latest past result. | 247 result compared with the latest past result. |
240 diff_map: please refer to | 248 diff_map: please refer to |
241 layouttest_analyzer_helpers.SendStatusEmail(). | 249 layouttest_analyzer_helpers.SendStatusEmail(). |
242 simple_rev_str: a simple version of revision string that is sent in | 250 simple_rev_str: a simple version of revision string that is sent in |
243 the email. | 251 the email. |
244 rev: the latest revision number for the given test group. | 252 rev: the latest revision number for the given test group. |
245 rev_date: the latest revision date for the given test group. | 253 rev_date: the latest revision date for the given test group. |
246 email_content: email content string (without | 254 email_content: email content string (without |
247 |appended_text_to_email|) that will be shown on the dashboard. | 255 |appended_text_to_email|) that will be shown on the dashboard. |
248 """ | 256 """ |
249 rev = '' | 257 rev = '' |
250 rev_date = '' | 258 rev_date = '' |
251 email_content = '' | 259 email_content = '' |
252 if prev_analyzer_result_map: | 260 if prev_analyzer_result_map: |
253 diff_map = analyzer_result_map.CompareToOtherResultMap( | 261 diff_map = analyzer_result_map.CompareToOtherResultMap( |
254 prev_analyzer_result_map) | 262 prev_analyzer_result_map) |
255 result_change = (any(diff_map['whole']) or any(diff_map['skip']) or | 263 result_change = (any(diff_map['whole']) or any(diff_map['skip']) or |
256 any(diff_map['nonskip'])) | 264 any(diff_map['nonskip'])) |
257 # Email only when |email_only_change_mode| is False or there | 265 # Email only when |email_only_change_mode| is False or there |
258 # is a change in the result compared to the last result. | 266 # is a change in the result compared to the last result. |
259 simple_rev_str = '' | 267 simple_rev_str = '' |
260 if not email_only_change_mode or result_change: | 268 if not email_only_change_mode or result_change: |
261 prev_time_in_float = datetime.strptime(prev_time, '%Y-%m-%d-%H') | 269 prev_time_in_float = datetime.strptime(prev_time, '%Y-%m-%d-%H') |
262 prev_time_in_float = time.mktime(prev_time_in_float.timetuple()) | 270 prev_time_in_float = time.mktime(prev_time_in_float.timetuple()) |
263 if debug: | 271 if debug: |
264 cur_time_in_float = datetime.strptime(CUR_TIME_FOR_DEBUG, | 272 cur_time_in_float = datetime.strptime(CUR_TIME_FOR_DEBUG, |
265 '%Y-%m-%d-%H') | 273 '%Y-%m-%d-%H') |
266 cur_time_in_float = time.mktime(cur_time_in_float.timetuple()) | 274 cur_time_in_float = time.mktime(cur_time_in_float.timetuple()) |
267 else: | 275 else: |
268 cur_time_in_float = time.time() | 276 cur_time_in_float = time.time() |
269 (rev_str, simple_rev_str, rev, rev_date) = ( | 277 (rev_str, simple_rev_str, rev, rev_date) = ( |
270 layouttest_analyzer_helpers.GetRevisionString(prev_time_in_float, | 278 layouttest_analyzer_helpers.GetRevisionString(prev_time_in_float, |
271 cur_time_in_float, | 279 cur_time_in_float, |
272 diff_map)) | 280 diff_map)) |
273 email_content = analyzer_result_map.ConvertToString(prev_time, diff_map, | 281 email_content = analyzer_result_map.ConvertToString(prev_time, |
274 anno_map) | 282 diff_map, |
283 anno_map, | |
284 issue_detail_mode) | |
275 if receiver_email_address: | 285 if receiver_email_address: |
276 layouttest_analyzer_helpers.SendStatusEmail( | 286 layouttest_analyzer_helpers.SendStatusEmail( |
277 prev_time, analyzer_result_map, diff_map, anno_map, | 287 prev_time, analyzer_result_map, diff_map, anno_map, |
278 receiver_email_address, test_group_name, | 288 receiver_email_address, test_group_name, |
279 appended_text_to_email, email_content, rev_str, | 289 appended_text_to_email, email_content, rev_str, |
280 email_only_change_mode) | 290 email_only_change_mode) |
281 if simple_rev_str: | 291 if simple_rev_str: |
282 simple_rev_str = '\'' + simple_rev_str + '\'' | 292 simple_rev_str = '\'' + simple_rev_str + '\'' |
283 else: | 293 else: |
284 simple_rev_str = 'undefined' # GViz uses undefined for NONE. | 294 simple_rev_str = 'undefined' # GViz uses undefined for NONE. |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
396 escaped_tg_name = test_group_name.replace('/', '_') | 406 escaped_tg_name = test_group_name.replace('/', '_') |
397 for tg in ['whole', 'skip', 'nonskip']: | 407 for tg in ['whole', 'skip', 'nonskip']: |
398 file_name = os.path.join( | 408 file_name = os.path.join( |
399 os.path.dirname(dashboard_file_location), | 409 os.path.dirname(dashboard_file_location), |
400 escaped_tg_name + '_' + tg + '.html') | 410 escaped_tg_name + '_' + tg + '.html') |
401 file_object = open(file_name, 'wb') | 411 file_object = open(file_name, 'wb') |
402 file_object.write('<table border="1">') | 412 file_object.write('<table border="1">') |
403 sorted_testnames = data_map[tg][0].keys() | 413 sorted_testnames = data_map[tg][0].keys() |
404 sorted_testnames.sort() | 414 sorted_testnames.sort() |
405 for testname in sorted_testnames: | 415 for testname in sorted_testnames: |
406 file_object.write(('<tr><td><a href="%s">%s</a></td>' | 416 file_object.write(( |
dennis_jeffrey
2012/02/29 17:50:32
nit: I think the second ( in this line might be un
imasaki1
2012/03/02 19:12:07
I got gpylint error like the one below when I remo
dennis_jeffrey
2012/03/02 20:55:15
Ok, I must have read the line incorrectly the firs
imasaki1
2012/03/02 21:50:50
Done.
| |
407 '<td><a href="%s">dashboard</a></td>' | 417 '<tr><td><a href="%s">%s</a></td><td><a href="%s">dashboard</a></td>' |
408 '<td>%s</td></tr>') % ( | 418 '<td>%s</td></tr>') % (layouttest_root_path + testname, testname, |
409 layouttest_root_path + testname, testname, | 419 ('http://test-results.appspot.com/dashboards/' |
410 ('http://test-results.appspot.com/dashboards/' | 420 'flakiness_dashboard.html#tests=%s') % ( |
411 'flakiness_dashboard.html#tests=%s') % testname, | 421 testname), |
412 data_map[tg][0][testname])) | 422 data_map[tg][0][testname])) |
413 file_object.write('</table>') | 423 file_object.write('</table>') |
414 file_object.close() | 424 file_object.close() |
415 email_content_with_link = '' | 425 email_content_with_link = '' |
416 if email_content: | 426 if email_content: |
417 file_name = os.path.join(os.path.dirname(dashboard_file_location), | 427 file_name = os.path.join(os.path.dirname(dashboard_file_location), |
418 escaped_tg_name + '_email.html') | 428 escaped_tg_name + '_email.html') |
419 file_object = open(file_name, 'wb') | 429 file_object = open(file_name, 'wb') |
420 file_object.write(email_content) | 430 file_object.write(email_content) |
421 file_object.close() | 431 file_object.close() |
422 email_content_with_link = '<a href="%s_email.html">info</a>' % ( | 432 email_content_with_link = '<a href="%s_email.html">info</a>' % ( |
(...skipping 29 matching lines...) Expand all Loading... | |
452 options.test_group_file_location, | 462 options.test_group_file_location, |
453 options.test_group_name, | 463 options.test_group_name, |
454 options.result_directory_location)) | 464 options.result_directory_location)) |
455 (anno_map, appended_text_to_email) = ReadEmailInformation( | 465 (anno_map, appended_text_to_email) = ReadEmailInformation( |
456 options.bug_annotation_file_location, | 466 options.bug_annotation_file_location, |
457 options.email_appended_text_file_location) | 467 options.email_appended_text_file_location) |
458 (result_change, diff_map, simple_rev_str, rev, rev_date, email_content) = ( | 468 (result_change, diff_map, simple_rev_str, rev, rev_date, email_content) = ( |
459 SendEmail(prev_time, prev_analyzer_result_map, analyzer_result_map, | 469 SendEmail(prev_time, prev_analyzer_result_map, analyzer_result_map, |
460 anno_map, appended_text_to_email, | 470 anno_map, appended_text_to_email, |
461 options.email_only_change_mode, options.debug, | 471 options.email_only_change_mode, options.debug, |
462 options.receiver_email_address, options.test_group_name)) | 472 options.receiver_email_address, options.test_group_name, |
473 options.issue_detail_mode)) | |
463 | 474 |
464 # Create CSV texts and save them for bug spreadsheet. | 475 # Create CSV texts and save them for bug spreadsheet. |
465 (stats, issues_txt) = analyzer_result_map.ConvertToCSVText( | 476 (stats, issues_txt) = analyzer_result_map.ConvertToCSVText( |
466 start_time.strftime('%Y-%m-%d-%H')) | 477 start_time.strftime('%Y-%m-%d-%H')) |
467 file_object = open(os.path.join(options.result_directory_location, | 478 file_object = open(os.path.join(options.result_directory_location, |
468 DEFAULT_STATS_CSV_FILENAME), 'wb') | 479 DEFAULT_STATS_CSV_FILENAME), 'wb') |
469 file_object.write(stats) | 480 file_object.write(stats) |
470 file_object.close() | 481 file_object.close() |
471 file_object = open(os.path.join(options.result_directory_location, | 482 file_object = open(os.path.join(options.result_directory_location, |
472 DEFAULT_ISSUES_CSV_FILENAME), 'wb') | 483 DEFAULT_ISSUES_CSV_FILENAME), 'wb') |
(...skipping 12 matching lines...) Expand all Loading... | |
485 # Report the result to dashboard. | 496 # Report the result to dashboard. |
486 if options.dashboard_file_location: | 497 if options.dashboard_file_location: |
487 UpdateDashboard(options.dashboard_file_location, options.test_group_name, | 498 UpdateDashboard(options.dashboard_file_location, options.test_group_name, |
488 data_map, layouttests.DEFAULT_LAYOUTTEST_LOCATION, rev, | 499 data_map, layouttests.DEFAULT_LAYOUTTEST_LOCATION, rev, |
489 rev_date, options.receiver_email_address, | 500 rev_date, options.receiver_email_address, |
490 email_content) | 501 email_content) |
491 | 502 |
492 | 503 |
493 if '__main__' == __name__: | 504 if '__main__' == __name__: |
494 main() | 505 main() |
OLD | NEW |