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
4 # found in the LICENSE file.
6 """Main function to run the layout test analyzer.
8 The purpose of this script is to run the layout test analyzer for various
9 teams based on the run configuration file in CSV format. The CSV file is based
10 on https://sites.google.com/a/chromium.org/dev/developers/testing/
11 webkit-layout-tests/layout-test-stats-1.
17 from subprocess
import Popen
19 # TODO(shadi): Re-examine the need of external files. Inline data instead?
20 DEFAULT_RUN_CONFIG
= {
21 # test_group_name: ('test_files.csv', 'report_email_address')
22 'media': ('testname/media.csv', 'layout-test-analyzer-result@google.com')
25 # Predefined result/graph directory.
26 DEFAULT_RESULT_DIR
= 'result'
27 DEFAULT_GRAPH_DIR
= 'graph'
31 """Parse command-line options using OptionParser.
34 an object containing all command-line option information.
36 option_parser
= optparse
.OptionParser()
37 option_parser
.add_option('-d', '--result-directory-location',
38 dest
='result_directory_location',
39 help=('Name of result directory location '
40 '(default to %default)'),
41 default
=DEFAULT_RESULT_DIR
)
42 option_parser
.add_option('-p', '--graph-directory-location',
43 dest
='graph_directory_location',
44 help=('Name of graph directory location '
45 '(default to %default)'),
46 default
=DEFAULT_GRAPH_DIR
)
47 option_parser
.add_option('-e', '--email-only-change-mode',
48 dest
='email_only_change_mode',
49 help=('With this mode, email is sent out '
50 'only when there is a change in the '
51 'analyzer result compared to the previous '
52 'result (off by default)'),
53 action
='store_true', default
=False)
54 option_parser
.add_option('-z', '--issue-detail-mode',
55 dest
='issue_detail_mode',
56 help=('With this mode, email includes issue details'
57 ' including links to the flakiness dashboard'
59 action
='store_true', default
=False)
60 return option_parser
.parse_args()[0]
63 def GenerateDashboardHTMLFile(file_name
, test_group_list
):
64 """Generate dashboard HTML file.
66 Currently, it is simple table that shows all the analyzer results.
69 file_name: the file name of the dashboard.
70 test_group_list: a list of test group names such as 'media' or 'composite'.
72 file_object
= open(file_name
, 'wb')
74 <style type="text/css">
76 width: 30px; overflow: hidden;
79 background-color: #CC9999; color: black;
81 width: 30px; overflow: hidden;
84 background-color: #9999CC; color: black;
86 width: 30px; overflow: hidden;
89 <h2>Chromium Layout Test Analyzer Result</h2>
92 <li>#Tests: the number of tests for the given test group
93 <li>#Skipped Tests: the number of tests that are skipped in the
94 <a href='http://svn.webkit.org/repository/webkit/trunk/LayoutTests/platform/\
95 chromium/test_expectations.txt'>test expectaion file</a> (e.g., BUGWK60877
96 SKIP : loader/navigation-while-deferring-loads.html = FAIL)
97 <li>#Non-Skipped Failing Tests: the number of tests that appeared in the
98 test expectation file and were not skipped.
99 <li>Failing rate: #NonSkippedFailing / (#Tests - #Skipped)
100 <li>Passing rate: 100 - (Failing rate)
103 file_object
.write(legend_txt
)
104 file_object
.write('<table border="1">')
105 file_object
.write('<tr><th>Base Directory</th>')
106 file_object
.write('<th>Trend Graph</th>')
107 file_object
.write('<th>#Tests</th>')
108 file_object
.write('<th>#Skipped Tests</th>')
109 file_object
.write('<th>#Non-Skipped Failing Tests</th>')
110 file_object
.write('<th>Failing Rate</th>')
111 file_object
.write('<th>Passing Rate</th>')
112 file_object
.write('<th>Last Revision Number</th>')
113 file_object
.write('<th>Last Revision Date</th>')
114 file_object
.write('<th>Owner Email</th>')
115 file_object
.write('<th>Bug Information</th></tr>\n')
116 test_group_list
.sort()
117 for i
, test_group
in enumerate(test_group_list
):
118 file_object
.write('<tr class="d' + str(i
% 2) + '">\n')
119 file_object
.write('<td>' + test_group
+ '</td>\n')
120 file_object
.write('</tr>\n')
121 file_object
.write('</table>')
125 # TODO(shadi): Use only one file with main()! Remove this file in favor of
126 # layouttest_analyzer.py main().
128 """A main function for the analyzer runner."""
129 options
= ParseOption()
130 run_config_map
= DEFAULT_RUN_CONFIG
131 test_group_list
= run_config_map
.keys()
132 dashboard_file_location
= os
.path
.join(options
.graph_directory_location
,
134 if not os
.path
.exists(dashboard_file_location
):
135 GenerateDashboardHTMLFile(dashboard_file_location
, test_group_list
)
136 for test_group
in test_group_list
:
137 # Prepare the result if it does not exist.
138 # The directory name should be changed to avoid collision
139 # with the file separator.
140 test_group_name_for_data
= test_group
.replace('/', '_')
141 result_dir
= os
.path
.join(options
.result_directory_location
,
142 test_group_name_for_data
)
143 if not os
.path
.exists(result_dir
):
145 graph_file
= os
.path
.join(options
.graph_directory_location
,
146 test_group_name_for_data
+ '.html')
147 if not os
.path
.exists(graph_file
):
148 # Copy the template file.
149 shutil
.copy(os
.path
.join('graph', 'graph.html'),
151 os
.chmod(graph_file
, 0744)
152 cmd
= ('python layouttest_analyzer.py -x %s -d %s -t %s'
154 test_group
, result_dir
, graph_file
, dashboard_file_location
)
155 if run_config_map
[test_group
][0]:
156 cmd
+= '-n ' + run_config_map
[test_group
][0] + ' '
157 if run_config_map
[test_group
][1]:
158 cmd
+= '-r ' + run_config_map
[test_group
][1] + ' '
159 if options
.email_only_change_mode
:
161 if options
.issue_detail_mode
:
163 print 'Running ' + cmd
164 proc
= Popen(cmd
, shell
=True)
168 if '__main__' == __name__
: