Home | History | Annotate | Download | only in static-dashboards
      1 // Copyright (C) 2013 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 var overview = overview || {};
     30 
     31 (function() {
     32 
     33 overview._resultsByTestType = {};
     34 overview._testTypeIndex = 0;
     35 
     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'; });
     38 
     39 overview.loadNextTestType = function(historyInstance)
     40 {
     41     if (overview._testTypeIndex == builders.testTypes.length) {
     42         overview._generatePage();
     43         return;
     44     }
     45 
     46     historyInstance.crossDashboardState.testType = builders.testTypes[overview._testTypeIndex++];
     47 
     48     $('content').innerHTML = (overview._testTypeIndex - 1) + '/' + builders.testTypes.length + ' loaded. Loading ' + historyInstance.crossDashboardState.testType + '...';
     49 
     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();
     55 }
     56 
     57 overview._getFlakyData = function(allTestTypes, resultsByTestType, flipCountThreshold)
     58 {
     59     var flakyData = {};
     60     allTestTypes.forEach(function(testType) {
     61         flakyData[testType] = {
     62             flakyBelowThreshold: {},
     63             flaky: {},
     64             testCount: 0
     65         }
     66 
     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);
     71 
     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);
     78 
     79                 if (resultsForTest.isFlaky)
     80                     flakyData[testType].flaky[test] = true;
     81 
     82                 if (!resultsForTest.isFlaky || resultsForTest.flipCount <= flipCountThreshold)
     83                     continue;
     84                 flakyData[testType].flakyBelowThreshold[test] = true;
     85             }
     86         }
     87     });
     88     return flakyData;
     89 }
     90 
     91 overview._generatePage = function()
     92 {
     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>';
     97 }
     98 
     99 overview._htmlForFlakyTests = function(flakyData, group)
    100 {
    101     var html = '<table><tr><th>Test type</th><th>flaky count / total count</th><th>percent</th><th></th></tr>';
    102 
    103     Object.keys(flakyData).forEach(function(testType) {
    104         var testCount = flakyData[testType].testCount;
    105         if (!testCount)
    106             return;
    107 
    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)
    112             return;
    113 
    114         var tests = Object.keys(flakyData[testType].flakyBelowThreshold);
    115         var flakyCount = tests.length;
    116         var percentage = Math.round(100 * flakyCount / testCount);
    117         html += '<tr>' +
    118             '<td><a href="flakiness_dashboard.html#group=' + group + '&testType=' + testType + '&tests=' + tests.join(',') + '" target=_blank>' +
    119                 testType +
    120             '</a></td>' +
    121             '<td>' + flakyCount + ' / ' + testCount + '</td>' +
    122             '<td>' + percentage + '%</td>' +
    123             '<td><div class="flaky-bar" style="width:' + percentage * 5 + 'px"></div>'
    124         '</tr>';
    125     });
    126 
    127     return html + '</table>';
    128 }
    129 
    130 overview.handleValidHashParameter = function(historyInstance, key, value) {
    131     switch(key) {
    132     case 'flipCount':
    133         return history.validateParameter(historyInstance.dashboardSpecificState, key, value,
    134             function() {
    135                 return !isNaN(Number(value));
    136             });
    137 
    138     case 'showNoFlakes':
    139         historyInstance.dashboardSpecificState[key] = value == 'true';
    140         return true;
    141 
    142     default:
    143         return false;
    144     }
    145 }
    146 
    147 overview._htmlForNavBar = function(flipCount, showNoFlakes)
    148 {
    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) +
    153         '</div>';
    154 }
    155 
    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: {
    159         flipCount: 1,
    160         showNoFlakes: false
    161     },
    162     generatePage: overview.loadNextTestType,
    163     handleValidHashParameter: overview.handleValidHashParameter,
    164 });
    165 g_history.parseCrossDashboardParameters();
    166 
    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.
    170     if (!$('navbar'))
    171         return;
    172 
    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);
    177 }, false);
    178 
    179 })();
    180