Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(62)

Side by Side Diff: media/tools/layout_tests/layouttest_analyzer.py

Issue 9476021: Updating Layout test analyzer to add control to show issue detail or not. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: One minor change. Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 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
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
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
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
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((
407 '<td><a href="%s">dashboard</a></td>' 417 '<tr><td><a href="%s">%s</a></td><td><a href="%s">dashboard</a>'
408 '<td>%s</td></tr>') % ( 418 '</td><td>%s</td></tr>') % (
409 layouttest_root_path + testname, testname, 419 layouttest_root_path + testname, testname,
410 ('http://test-results.appspot.com/dashboards/' 420 ('http://test-results.appspot.com/dashboards/'
411 'flakiness_dashboard.html#tests=%s') % testname, 421 'flakiness_dashboard.html#tests=%s') % 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
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
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()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698