1 // Copyright (C) 2013 Google Inc. All rights reserved.
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are
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
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.
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.
29 var overview = overview || {};
33 overview._resultsByTestType = {};
34 overview._testTypeIndex = 0;
36 // FIXME: This is a gross hack to make it so that changing the test type in loadNextTestType doesn't reload the page.
37 history.reloadRequiringParameters = history.reloadRequiringParameters.filter(function(item) { return item != 'testType'; });
39 overview.loadNextTestType = function(historyInstance)
41 if (overview._testTypeIndex == builders.testTypes.length) {
42 overview._generatePage();
46 historyInstance.crossDashboardState.testType = builders.testTypes[overview._testTypeIndex++];
48 $('content').innerHTML = (overview._testTypeIndex - 1) + '/' + builders.testTypes.length + ' loaded. Loading ' + historyInstance.crossDashboardState.testType + '...';
50 // FIXME: Gross hack to allow loading all the builders for different test types.
51 // Change loader.js to allow you to pass in the state that it fills instead of setting globals.
52 g_resultsByBuilder = {};
53 overview._resultsByTestType[historyInstance.crossDashboardState.testType] = g_resultsByBuilder;
54 new loader.Loader().load();
57 overview._getFlakyData = function(allTestTypes, resultsByTestType, flipCountThreshold)
60 allTestTypes.forEach(function(testType) {
61 flakyData[testType] = {
62 flakyBelowThreshold: {},
67 var resultsByBuilder = resultsByTestType[testType];
68 for (var builder in resultsByBuilder) {
69 var totalTestCount = results.testCounts(resultsByBuilder[builder][results.NUM_FAILURES_BY_TYPE]).totalTests[0];
70 flakyData[testType].testCount = Math.max(totalTestCount, flakyData[testType].testCount);
72 var allTestsForThisBuilder = resultsByBuilder[builder].tests;
73 for (var test in allTestsForThisBuilder) {
74 var resultsForTest = {};
75 var testData = resultsByBuilder[builder].tests[test].results;
76 var failureMap = resultsByBuilder[builder][results.FAILURE_MAP];
77 results.determineFlakiness(failureMap, testData, resultsForTest);
79 if (resultsForTest.isFlaky)
80 flakyData[testType].flaky[test] = true;
82 if (!resultsForTest.isFlaky || resultsForTest.flipCount <= flipCountThreshold)
84 flakyData[testType].flakyBelowThreshold[test] = true;
91 overview._generatePage = function()
93 var flipCountThreshold = Number(g_history.dashboardSpecificState.flipCount);
94 var flakyData = overview._getFlakyData(builders.testTypes, overview._resultsByTestType, flipCountThreshold);
95 $('content').innerHTML = overview._htmlForFlakyTests(flakyData, g_history.crossDashboardState.group) +
96 '<div>*Tests that fail due to a bad patch being committed are counted as flaky.</div>';
99 overview._htmlForFlakyTests = function(flakyData, group)
101 var html = '<table><tr><th>Test type</th><th>flaky count / total count</th><th>percent</th><th></th></tr>';
103 Object.keys(flakyData).forEach(function(testType) {
104 var testCount = flakyData[testType].testCount;
108 // We want the list of tests to stay stable as you drag the flakiness slider, so only
109 // exclude tests that never flake, even at the lowest flakiness threshold.
110 var flakeCountIgnoringThreshold = Object.keys(flakyData[testType].flaky).length;
111 if (!g_history.dashboardSpecificState.showNoFlakes && !flakeCountIgnoringThreshold)
114 var tests = Object.keys(flakyData[testType].flakyBelowThreshold);
115 var flakyCount = tests.length;
116 var percentage = Math.round(100 * flakyCount / testCount);
118 '<td><a href="flakiness_dashboard.html#group=' + group + '&testType=' + testType + '&tests=' + tests.join(',') + '" target=_blank>' +
121 '<td>' + flakyCount + ' / ' + testCount + '</td>' +
122 '<td>' + percentage + '%</td>' +
123 '<td><div class="flaky-bar" style="width:' + percentage * 5 + 'px"></div>'
127 return html + '</table>';
130 overview.handleValidHashParameter = function(historyInstance, key, value) {
133 return history.validateParameter(historyInstance.dashboardSpecificState, key, value,
135 return !isNaN(Number(value));
139 historyInstance.dashboardSpecificState[key] = value == 'true';
147 overview._htmlForNavBar = function(flipCount, showNoFlakes)
149 return ui.html.navbar(ui.html.select('Group', 'group', builders.getAllGroupNames())) +
150 '<div id=flip-slider-container>' +
151 ui.html.range('flipCount', 'Flakiness threshold (low-->high):', 1, 50, flipCount) +
152 ui.html.checkbox('showNoFlakes', 'Show test suites with no flakes', showNoFlakes) +
156 // FIXME: Once dashboard_base, loader and ui stop using the g_history global, we can stop setting it here.
157 g_history = new history.History({
158 defaultStateValues: {
162 generatePage: overview.loadNextTestType,
163 handleValidHashParameter: overview.handleValidHashParameter,
165 g_history.parseCrossDashboardParameters();
167 window.addEventListener('load', function() {
168 // FIXME: Come up with a better way to do this. This early return is just to avoid
169 // executing this code when it's loaded in the unittests.
173 // Need to parseParameters so that flipCount has the correct value.
174 g_history.parseParameters();
175 $('navbar').innerHTML = overview._htmlForNavBar(g_history.dashboardSpecificState.flipCount);
176 overview.loadNextTestType(g_history);