37975d26700abcbf6a932b4f72b45cf651cd4591
[WebKit-https.git] / Tools / TestResultServer / static-dashboards / aggregate_results.html
1 <!-- Copyright (C) 2011 Google Inc. All rights reserved.
2
3 Redistribution and use in source and binary forms, with or without
4 modification, are permitted provided that the following conditions are
5 met:
6
7     * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9     * Redistributions in binary form must reproduce the above
10 copyright notice, this list of conditions and the following disclaimer
11 in the documentation and/or other materials provided with the
12 distribution.
13     * Neither the name of Google Inc. nor the names of its
14 contributors may be used to endorse or promote products derived from
15 this software without specific prior written permission.
16
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 -->
29 <!DOCTYPE HTML>
30 <html>
31
32 <head>
33 <title>Layout test passing status</title>
34 <style>
35 h2 {
36     margin: 0;
37     font-size: 1.2em;
38 }
39 h3 {
40     margin-bottom: 0;
41     font-size: 1em;
42 }
43 .container {
44     display: inline-block;
45     padding: 3px;
46 }
47 img {
48     border: 1px dotted grey;
49     margin-right: 5px;
50     padding: 2px;
51 }
52 </style>
53 <script src="builders.js"></script>
54 <script src="loader.js"></script>
55 <script src="string.js"></script>
56 <script src="dashboard_base.js"></script>
57 <script src="ui.js"></script>
58 <script>
59 // @fileoverview Creates a dashboard for tracking number of passes/failures per run.
60 //
61 // Currently, only webkit tests are supported, but adding other test types
62 // should just require the following steps:
63 //     -generate results.json for these tests
64 //     -copy them to the appropriate location
65 //     -add the builder name to the list of builders in dashboard_base.js.
66
67 //////////////////////////////////////////////////////////////////////////////
68 // Methods and objects from dashboard_base.js to override.
69 //////////////////////////////////////////////////////////////////////////////
70 function generatePage()
71 {
72     var html = ui.html.testTypeSwitcher(true) + '<br>';
73     for (var builder in currentBuilders())
74         html += htmlForBuilder(builder);
75     document.body.innerHTML = html;
76 }
77
78 function handleValidHashParameter(key, value)
79 {
80     switch(key) {
81     case 'rawValues':
82         g_currentState[key] = value == 'true';
83         return true;
84
85     default:
86         return false;
87     }
88 }
89
90 g_defaultDashboardSpecificStateValues = {
91     rawValues: false
92 };
93
94 function htmlForBuilder(builder)
95 {
96     var results = g_resultsByBuilder[builder];
97     // Some keys were added later than others, so they don't have as many
98     // builds. Use the shortest.
99     // FIXME: Once 500 runs have finished, we can get rid of passing this
100     // around and just assume all keys have the same number of builders for a
101     // given builder.
102     var numColumns = results[ALL_FIXABLE_COUNT_KEY].length;
103     var html = '<div class=container><h2>' + builder + '</h2>';
104
105     if (g_currentState.rawValues)
106         html += rawValuesHTML(results, numColumns);
107     else {
108         html += '<a href="timeline_explorer.html' + (location.hash ? location.hash + '&' : '#') + 'builder=' + builder + '">' +
109             chartHTML(results, numColumns) + '</a>';
110     }
111
112     html += '</div>';
113     return html;
114 }
115
116 function rawValuesHTML(results, numColumns)
117 {
118     var html = htmlForSummaryTable(results, numColumns) +
119         htmlForTestType(results, FIXABLE_COUNTS_KEY, FIXABLE_DESCRIPTION, numColumns);
120     if (isLayoutTestResults()) {
121         html += htmlForTestType(results, DEFERRED_COUNTS_KEY, DEFERRED_DESCRIPTION, numColumns) +
122             htmlForTestType(results, WONTFIX_COUNTS_KEY, WONTFIX_DESCRIPTION, numColumns);
123     }
124     return html;
125 }
126
127 function chartHTML(results, numColumns)
128 {
129     var shouldShowWebKitRevisions = isTipOfTreeWebKitBuilder();
130     var revisionKey = shouldShowWebKitRevisions ? WEBKIT_REVISIONS_KEY : CHROME_REVISIONS_KEY;
131     var startRevision = results[revisionKey][numColumns - 1];
132     var endRevision = results[revisionKey][0];
133     var revisionLabel = shouldShowWebKitRevisions ? "WebKit Revision" : "Chromium Revision";
134
135     var fixable = results[FIXABLE_COUNT_KEY].slice(0, numColumns);
136     var html = chart("Total failing", {"": fixable}, revisionLabel, startRevision, endRevision);
137
138     var values = valuesPerExpectation(results[FIXABLE_COUNTS_KEY], numColumns);
139     // Don't care about number of passes for the charts.
140     delete(values['P']);
141
142     return html + chart("Detailed breakdown", values, revisionLabel, startRevision, endRevision);
143 }
144
145 var LABEL_COLORS = ['FF0000', '00FF00', '0000FF', '000000', 'FF6EB4', 'FFA812', '9B30FF', '00FFCC'];
146
147 // FIXME: Find a better way to exclude outliers. This is just so we exclude
148 // runs where every test failed.
149 var MAX_VALUE = 10000;
150
151 function filteredValues(values, desiredNumberOfPoints)
152 {
153     // Filter out values to make the graph a bit more readable and to keep URLs
154     // from exceeding the browsers max length restriction.
155     var filterAmount = Math.floor(values.length / desiredNumberOfPoints);
156     if (filterAmount < 1)
157         return values;
158
159     return values.filter(function(element, index, array) {
160         // Include the most recent and oldest values and exclude outliers.
161         return (index % filterAmount == 0 || index == array.length - 1) && (array[index] < MAX_VALUE && array[index] != 0);
162     });
163 }
164
165 function chartUrl(title, values, revisionLabel, startRevision, endRevision, desiredNumberOfPoints) {
166     var maxValue = 0;
167     for (var expectation in values)
168         maxValue = Math.max(maxValue, Math.max.apply(null, filteredValues(values[expectation], desiredNumberOfPoints)));
169
170     var chartData = '';
171     var labels = '';
172     var numLabels = 0;
173
174     var first = true;
175     for (var expectation in values) {
176         chartData += (first ? 'e:' : ',') + extendedEncode(filteredValues(values[expectation], desiredNumberOfPoints).reverse(), maxValue);
177
178         if (expectation) {
179             numLabels++;
180             labels += (first ? '' : '|') + expectationsMap()[expectation];
181         }
182         first = false;
183     }
184
185     var url = "http://chart.apis.google.com/chart?cht=lc&chs=600x400&chd=" +
186             chartData + "&chg=15,15,1,3&chxt=x,x,y&chxl=1:||" + revisionLabel +
187             "|&chxr=0," + startRevision + "," + endRevision + "|2,0," + maxValue + "&chtt=" + title;
188
189
190     if (labels)
191         url += "&chdl=" + labels + "&chco=" + LABEL_COLORS.slice(0, numLabels).join(',');
192     return url;
193 }
194
195 function chart(title, values, revisionLabel, startRevision, endRevision)
196 {
197     var desiredNumberOfPoints = 400;
198     var url = chartUrl(title, values, revisionLabel, startRevision, endRevision, desiredNumberOfPoints);
199
200     while (url.length >= 2048) {
201         // Decrease the desired number of points gradually until we get a URL that
202         // doesn't exceed chartserver's max URL length.
203         desiredNumberOfPoints = 3 / 4 * desiredNumberOfPoints;
204         url = chartUrl(title, values, revisionLabel, startRevision, endRevision, desiredNumberOfPoints);
205     }
206
207     return '<img src="' + url + '">';
208 }
209
210 function htmlForRevisionRows(results, numColumns)
211 {
212     return htmlForTableRow('WebKit Revision', results[WEBKIT_REVISIONS_KEY].slice(0, numColumns)) +
213         htmlForTableRow('Chrome Revision', results[CHROME_REVISIONS_KEY].slice(0, numColumns));
214 }
215
216 function wrapHTMLInTable(description, html)
217 {
218     return '<h3>' + description + '</h3><table><tbody>' + html + '</tbody></table>';
219 }
220
221 function htmlForSummaryTable(results, numColumns)
222 {
223     var percent = [];
224     var fixable = results[FIXABLE_COUNT_KEY].slice(0, numColumns);
225     var allFixable = results[ALL_FIXABLE_COUNT_KEY].slice(0, numColumns);
226     for (var i = 0; i < numColumns; i++) {
227         var percentage = 100 * (allFixable[i] - fixable[i]) / allFixable[i];
228         // Round to the nearest tenth of a percent.
229         percent.push(Math.round(percentage * 10) / 10 + '%');
230     }
231     var html = htmlForRevisionRows(results, numColumns) +
232         htmlForTableRow('Percent passed', percent) +
233         htmlForTableRow('Failures (deduped)', fixable) +
234         htmlForTableRow('Fixable Tests', allFixable);
235     return wrapHTMLInTable('Summary', html);
236 }
237
238 function valuesPerExpectation(counts, numColumns)
239 {
240     var values = {};
241     for (var i = 0; i < numColumns; i++) {
242         for (var expectation in expectationsMap()) {
243             if (expectation in counts[i]) {
244                 var count = counts[i][expectation];
245                 if (!values[expectation])
246                     values[expectation] = [];
247                 values[expectation].push(count);
248             }
249         }
250     }
251     return values;
252 }
253
254 function htmlForTestType(results, key, description, numColumns)
255 {
256     var counts = results[key];
257     var html = htmlForRevisionRows(results, numColumns);
258     var values = valuesPerExpectation(counts, numColumns);
259     for (var expectation in values)
260         html += htmlForTableRow(expectationsMap()[expectation], values[expectation]);
261     return wrapHTMLInTable(description, html);
262 }
263
264 function htmlForTableRow(columnName, values)
265 {
266     return '<tr><td>' + columnName + '</td><td>' + values.join('</td><td>') + '</td></tr>';
267 }
268
269 // Taken from http://code.google.com/apis/chart/docs/data_formats.html.
270 function extendedEncode(arrVals, maxVal)
271 {
272     var map = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-.';
273     var mapLength = map.length;
274     var mapLengthSquared = mapLength * mapLength;
275
276     var chartData = '';
277
278     for (var i = 0, len = arrVals.length; i < len; i++) {
279         // In case the array vals were translated to strings.
280         var numericVal = new Number(arrVals[i]);
281         // Scale the value to maxVal.
282         var scaledVal = Math.floor(mapLengthSquared * numericVal / maxVal);
283
284         if(scaledVal > mapLengthSquared - 1)
285             chartData += "..";
286         else if (scaledVal < 0)
287             chartData += '__';
288         else {
289             // Calculate first and second digits and add them to the output.
290             var quotient = Math.floor(scaledVal / mapLength);
291             var remainder = scaledVal - mapLength * quotient;
292             chartData += map.charAt(quotient) + map.charAt(remainder);
293         }
294     }
295
296     return chartData;
297 }
298
299 window.addEventListener('load', function() {
300     var resourceLoader = new loader.Loader(intializeHistory);
301     resourceLoader.load();
302 }, false);
303 </script>
304 </head>
305 <body></body>
306 </html>