Changeset 91021 in webkit


Ignore:
Timestamp:
Jul 14, 2011 12:24:24 PM (13 years ago)
Author:
ojan@chromium.org
Message:

fix coding style of dashboard_base.js
https://bugs.webkit.org/show_bug.cgi?id=64545

Reviewed by Adam Roben.

The code changes to the files other than dashboard_base.js
are just fallout from renaming globals in dashboard_base.js.

  • TestResultServer/static-dashboards/aggregate_results.html:
  • TestResultServer/static-dashboards/builders.js:
  • TestResultServer/static-dashboards/dashboard_base.js:
  • TestResultServer/static-dashboards/flakiness_dashboard.html:
  • TestResultServer/static-dashboards/flakiness_dashboard_tests.js:
  • TestResultServer/static-dashboards/timeline_explorer.html:
  • TestResultServer/static-dashboards/treemap.html:
Location:
trunk/Tools
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/Tools/ChangeLog

    r91011 r91021  
     12011-07-14  Ojan Vafai  <ojan@chromium.org>
     2
     3        fix coding style of dashboard_base.js
     4        https://bugs.webkit.org/show_bug.cgi?id=64545
     5
     6        Reviewed by Adam Roben.
     7
     8        The code changes to the files other than dashboard_base.js
     9        are just fallout from renaming globals in dashboard_base.js.
     10
     11        * TestResultServer/static-dashboards/aggregate_results.html:
     12        * TestResultServer/static-dashboards/builders.js:
     13        * TestResultServer/static-dashboards/dashboard_base.js:
     14        * TestResultServer/static-dashboards/flakiness_dashboard.html:
     15        * TestResultServer/static-dashboards/flakiness_dashboard_tests.js:
     16        * TestResultServer/static-dashboards/timeline_explorer.html:
     17        * TestResultServer/static-dashboards/treemap.html:
     18
    1192011-07-14  Carlos Garcia Campos  <cgarcia@igalia.com>
    220
  • trunk/Tools/TestResultServer/static-dashboards/aggregate_results.html

    r90674 r91021  
    7070  function generatePage() {
    7171    var html = getHTMLForTestTypeSwitcher(true) + '<br>';
    72     for (var builder in builders) {
     72    for (var builder in g_builders) {
    7373      html += getHTMLForBuilder(builder);
    7474    }
     
    7979    switch(key) {
    8080      case 'rawValues':
    81         currentState[key] = value == 'true';
     81        g_currentState[key] = value == 'true';
    8282
    8383        return true;
     
    8888  }
    8989
    90   defaultStateValues = {
     90  g_defaultStateValues = {
    9191    rawValues: false
    9292  };
    9393
    9494  function getHTMLForBuilder(builder) {
    95     var results = resultsByBuilder[builder];
     95    var results = g_resultsByBuilder[builder];
    9696    // Some keys were added later than others, so they don't have as many
    9797    // builds. Use the shortest.
     
    102102    var html = '<div class=container><h2>' + builder + '</h2>';
    103103
    104     if (currentState.rawValues) {
     104    if (g_currentState.rawValues) {
    105105      html += getRawValuesHTML(results, numColumns);
    106106    } else {
  • trunk/Tools/TestResultServer/static-dashboards/builders.js

    r90674 r91021  
    7474  // TODO(mihaip): instead of copying these to globals, it would be better if
    7575  // the rest of the code read things from the BuilderGroup instance directly
    76   defaultBuilderName = this.defaultBuilder;
    77   expectationsBuilder = this.expectationsBuilder;
    78   builders = this.builders;
     76  g_defaultBuilderName = this.defaultBuilder;
     77  g_expectationsBuilder = this.expectationsBuilder;
     78  g_builders = this.builders;
    7979};
    8080
  • trunk/Tools/TestResultServer/static-dashboards/dashboard_base.js

    r90964 r91021  
    1 /*
    2  * Copyright (C) 2011 Google Inc. All rights reserved.
    3  *
    4  * Redistribution and use in source and binary forms, with or without
    5  * modification, are permitted provided that the following conditions are
    6  * met:
    7  *
    8  *     * Redistributions of source code must retain the above copyright
    9  * notice, this list of conditions and the following disclaimer.
    10  *     * Redistributions in binary form must reproduce the above
    11  * copyright notice, this list of conditions and the following disclaimer
    12  * in the documentation and/or other materials provided with the
    13  * distribution.
    14  *     * Neither the name of Google Inc. nor the names of its
    15  * contributors may be used to endorse or promote products derived from
    16  * this software without specific prior written permission.
    17  *
    18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    29  */
    30 
    31 /**
    32  * @fileoverview Base JS file for pages that want to parse the results JSON
    33  * from the testing bots. This deals with generic utility functions, visible
    34  * history, popups and appending the script elements for the JSON files.
    35  *
    36  * The calling page is expected to implement the following "abstract"
    37  * functions/objects:
    38  */
    39 var pageLoadStartTime = Date.now();
    40 
    41 /**
    42  * Generates the contents of the dashboard. The page should override this with
    43  * a function that generates the page assuming all resources have loaded.
    44  */
    45 function generatePage() {
    46 }
    47 
    48 /**
    49  * Takes a key and a value and sets the currentState[key] = value iff key is
    50  * a valid hash parameter and the value is a valid value for that key.
    51  *
    52  * @return {boolean} Whether the key what inserted into the currentState.
    53  */
    54 function handleValidHashParameter(key, value) {
    55   return false;
    56 }
    57 
    58 /**
    59  * Default hash parameters for the page. The page should override this to create
    60  * default states.
    61  */
    62 var defaultStateValues = {};
    63 
    64 
    65 /**
    66  * The page should override this to modify page state due to
    67  * changing query parameters.
    68  * @param {Object} params New or modified query params as key: value.
    69  * @return {boolean} Whether changing this parameter should cause generatePage to be called.
    70  */
    71 function handleQueryParameterChange(params) {
    72   return true;
     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// @fileoverview Base JS file for pages that want to parse the results JSON
     30// from the testing bots. This deals with generic utility functions, visible
     31// history, popups and appending the script elements for the JSON files.
     32//
     33// The calling page is expected to implement the following "abstract"
     34// functions/objects:
     35var g_pageLoadStartTime = Date.now();
     36
     37// Generates the contents of the dashboard. The page should override this with
     38// a function that generates the page assuming all resources have loaded.
     39function generatePage() {}
     40
     41// Takes a key and a value and sets the g_currentState[key] = value iff key is
     42// a valid hash parameter and the value is a valid value for that key.
     43//
     44// @return {boolean} Whether the key what inserted into the g_currentState.
     45function handleValidHashParameter(key, value)
     46{
     47    return false;
     48}
     49
     50// Default hash parameters for the page. The page should override this to create
     51// default states.
     52var g_defaultStateValues = {};
     53
     54
     55// The page should override this to modify page state due to
     56// changing query parameters.
     57// @param {Object} params New or modified query params as key: value.
     58// @return {boolean} Whether changing this parameter should cause generatePage to be called.
     59function handleQueryParameterChange(params)
     60{
     61    return true;
    7362}
    7463
     
    7766//////////////////////////////////////////////////////////////////////////////
    7867var GTEST_EXPECTATIONS_MAP_ = {
    79   'P': 'PASS',
    80   'F': 'FAIL',
    81   'L': 'FLAKY',
    82   'N': 'NO DATA',
    83   'X': 'DISABLED'
     68    'P': 'PASS',
     69    'F': 'FAIL',
     70    'L': 'FLAKY',
     71    'N': 'NO DATA',
     72    'X': 'DISABLED'
    8473};
    8574
    8675var LAYOUT_TEST_EXPECTATIONS_MAP_ = {
    87   'P': 'PASS',
    88   'N': 'NO DATA',
    89   'X': 'SKIP',
    90   'T': 'TIMEOUT',
    91   'F': 'TEXT',
    92   'C': 'CRASH',
    93   'I': 'IMAGE',
    94   'Z': 'IMAGE+TEXT',
    95   // We used to glob a bunch of expectations into "O" as OTHER. Expectations
    96   // are more precise now though and it just means MISSING.
    97   'O': 'MISSING'
     76    'P': 'PASS',
     77    'N': 'NO DATA',
     78    'X': 'SKIP',
     79    'T': 'TIMEOUT',
     80    'F': 'TEXT',
     81    'C': 'CRASH',
     82    'I': 'IMAGE',
     83    'Z': 'IMAGE+TEXT',
     84    // We used to glob a bunch of expectations into "O" as OTHER. Expectations
     85    // are more precise now though and it just means MISSING.
     86    'O': 'MISSING'
    9887};
    9988
    10089var FAILURE_EXPECTATIONS_ = {
    101   'T': 1,
    102   'F': 1,
    103   'C': 1,
    104   'I': 1,
    105   'Z': 1
     90    'T': 1,
     91    'F': 1,
     92    'C': 1,
     93    'I': 1,
     94    'Z': 1
    10695};
    10796
     
    124113// See http://test-results.appspot.com/testfile.
    125114var TEST_TYPES = ['app_unittests', 'base_unittests', 'browser_tests',
    126     'cache_invalidation_unittests', 'courgette_unittests',
    127     'crypto_unittests', 'googleurl_unittests', 'gpu_unittests',
    128     'installer_util_unittests', 'interactive_ui_tests', 'ipc_tests',
    129     'jingle_unittests', 'layout-tests', 'media_unittests',
    130     'mini_installer_test', 'nacl_ui_tests', 'net_unittests',
    131     'printing_unittests', 'remoting_unittests', 'safe_browsing_tests',
    132     'sync_unit_tests', 'sync_integration_tests',
    133     'test_shell_tests', 'ui_tests', 'unit_tests'];
     115        'cache_invalidation_unittests', 'courgette_unittests',
     116        'crypto_unittests', 'googleurl_unittests', 'gpu_unittests',
     117        'installer_util_unittests', 'interactive_ui_tests', 'ipc_tests',
     118        'jingle_unittests', 'layout-tests', 'media_unittests',
     119        'mini_installer_test', 'nacl_ui_tests', 'net_unittests',
     120        'printing_unittests', 'remoting_unittests', 'safe_browsing_tests',
     121        'sync_unit_tests', 'sync_integration_tests',
     122        'test_shell_tests', 'ui_tests', 'unit_tests'];
    134123
    135124var RELOAD_REQUIRING_PARAMETERS = ['showAllRuns', 'group', 'testType'];
     
    138127// 0 is where the count is length is stored. 1 is the value.
    139128var RLE = {
    140   LENGTH: 0,
    141   VALUE: 1
    142 }
    143 
    144 // The server that hosts the builder results json files.
     129    LENGTH: 0,
     130    VALUE: 1
     131}
     132
    145133var TEST_RESULTS_SERVER = 'http://test-results.appspot.com/';
    146134
    147 /**
    148  * @return {boolean} Whether the value represents a failing result.
    149  */
    150 function isFailingResult(value) {
    151   return 'FSTOCIZ'.indexOf(value) != -1;
    152 }
    153 
    154 /**
    155  * Takes a key and a value and sets the currentState[key] = value iff key is
    156  * a valid hash parameter and the value is a valid value for that key. Handles
    157  * cross-dashboard parameters then falls back to calling
    158  * handleValidHashParameter for dashboard-specific parameters.
    159  *
    160  * @return {boolean} Whether the key what inserted into the currentState.
    161  */
    162 function handleValidHashParameterWrapper(key, value) {
    163   switch(key) {
     135function isFailingResult(value)
     136{
     137    return 'FSTOCIZ'.indexOf(value) != -1;
     138}
     139
     140// Takes a key and a value and sets the g_currentState[key] = value iff key is
     141// a valid hash parameter and the value is a valid value for that key. Handles
     142// cross-dashboard parameters then falls back to calling
     143// handleValidHashParameter for dashboard-specific parameters.
     144//
     145// @return {boolean} Whether the key what inserted into the g_currentState.
     146function handleValidHashParameterWrapper(key, value)
     147{
     148    switch(key) {
    164149    case 'testType':
    165       validateParameter(currentState, key, value,
    166           function() {
    167             return TEST_TYPES.indexOf(value) != -1;
    168           });
    169       return true;
     150        validateParameter(g_currentState, key, value,
     151            function() { return TEST_TYPES.indexOf(value) != -1; });
     152        return true;
    170153
    171154    case 'group':
    172       validateParameter(currentState, key, value,
    173           function() {
    174             return value in LAYOUT_TESTS_BUILDER_GROUPS;
    175           });
    176       return true;
     155        validateParameter(g_currentState, key, value,
     156            function() { return value in LAYOUT_TESTS_BUILDER_GROUPS; });
     157        return true;
    177158
    178159    // FIXME: remove support for this parameter once the waterfall starts to
    179160    // pass in the builder name instead.
    180161    case 'master':
    181       validateParameter(currentState, key, value,
    182           function() {
    183             return value in LEGACY_BUILDER_MASTERS_TO_GROUPS;
    184           });
    185       return true;
     162        validateParameter(g_currentState, key, value,
     163            function() { return value in LEGACY_BUILDER_MASTERS_TO_GROUPS; });
     164        return true;
    186165
    187166    case 'builder':
    188       validateParameter(currentState, key, value,
    189           function() {
    190             return value in builders;
    191           });
    192       return true;
     167        validateParameter(g_currentState, key, value,
     168            function() { return value in g_builders; });
     169        return true;
    193170
    194171    case 'useTestData':
    195172    case 'showAllRuns':
    196       currentState[key] = value == 'true';
    197       return true;
     173        g_currentState[key] = value == 'true';
     174        return true;
    198175
    199176    case 'buildDir':
    200       currentState['testType'] = 'layout-test-results';
    201       if (value === 'Debug' || value == 'Release') {
    202         currentState[key] = value;
    203         return true;
    204       } else {
    205         return false;
    206       }
     177        g_currentState['testType'] = 'layout-test-results';
     178        if (value === 'Debug' || value == 'Release') {
     179            g_currentState[key] = value;
     180            return true;
     181        } else
     182            return false;
    207183
    208184    default:
    209       return handleValidHashParameter(key, value);
    210   }
    211 }
    212 
    213 var defaultCrossDashboardStateValues = {
    214   group: '@DEPS - chromium.org',
    215   showAllRuns: false,
    216   testType: 'layout-tests',
    217   buildDir : ''
     185        return handleValidHashParameter(key, value);
     186    }
     187}
     188
     189var g_defaultCrossDashboardStateValues = {
     190    group: '@DEPS - chromium.org',
     191    showAllRuns: false,
     192    testType: 'layout-tests',
     193    buildDir : ''
    218194}
    219195
    220196// Generic utility functions.
    221 function $(id) {
    222   return document.getElementById(id);
    223 }
    224 
    225 function stringContains(a, b) {
    226   return a.indexOf(b) != -1;
    227 }
    228 
    229 function caseInsensitiveContains(a, b) {
    230   return a.match(new RegExp(b, 'i'));
    231 }
    232 
    233 function startsWith(a, b) {
    234   return a.indexOf(b) == 0;
    235 }
    236 
    237 function endsWith(a, b) {
    238   return a.lastIndexOf(b) == a.length - b.length;
    239 }
    240 
    241 function isValidName(str) {
    242   return str.match(/[A-Za-z0-9\-\_,]/);
    243 }
    244 
    245 function trimString(str) {
    246   return str.replace(/^\s+|\s+$/g, '');
    247 }
    248 
    249 function request(url, success, error, opt_isBinaryData) {
    250   console.log('XMLHttpRequest: ' + url);
    251   var xhr = new XMLHttpRequest();
    252   xhr.open('GET', url, true);
    253   if (opt_isBinaryData)
    254     xhr.overrideMimeType('text/plain; charset=x-user-defined');
    255   xhr.onreadystatechange = function(e) {
    256     if (xhr.readyState == 4) {
    257       if (xhr.status == 200)
    258         success(xhr);
    259       else
    260         error(xhr);
    261     }
    262   }
    263   xhr.send();
    264 }
    265 
    266 function validateParameter(state, key, value, validateFn) {
    267   if (validateFn()) {
    268     state[key] = value;
    269   } else {
    270     console.log(key + ' value is not valid: ' + value);
    271   }
    272 }
    273 
    274 /**
    275  * Parses window.location.hash and set the currentState values appropriately.
    276  */
    277 function parseParameters(parameterStr) {
    278   oldState = currentState;
    279   currentState = {};
    280 
    281   var hash = window.location.hash;
    282   var paramsList = hash ? hash.substring(1).split('&') : [];
    283   var paramsMap = {};
    284   var invalidKeys = [];
    285   for (var i = 0; i < paramsList.length; i++) {
    286     var thisParam = paramsList[i].split('=');
    287     if (thisParam.length != 2) {
    288       console.log('Invalid query parameter: ' + paramsList[i]);
    289       continue;
    290     }
    291 
    292     paramsMap[thisParam[0]] = decodeURIComponent(thisParam[1]);
    293   }
    294 
    295   function parseParam(key) {
    296     var value = paramsMap[key];
    297     if (!handleValidHashParameterWrapper(key, value))
    298       invalidKeys.push(key + '=' + value);
    299   }
    300 
    301   // Parse builder param last, since the list of valid builders depends on the
    302   // other parameters.
    303   for (var key in paramsMap) {
    304     if (key != 'builder')
    305       parseParam(key);
    306   }
    307   if ('builder' in paramsMap) {
    308     if (!builders) {
    309       var tempState = {};
    310       for (var key in currentState) {
    311         tempState[key] = currentState[key];
    312       }
    313       fillMissingValues(tempState, defaultCrossDashboardStateValues);
    314       fillMissingValues(tempState, defaultStateValues);
    315       initBuilders(tempState);
    316     }
    317     parseParam('builder');
    318   }
    319 
    320   if (invalidKeys.length)
    321     console.log("Invalid query parameters: " + invalidKeys.join(','));
    322 
    323   var diffState = diffStates();
    324 
    325   fillMissingValues(currentState, defaultCrossDashboardStateValues);
    326   fillMissingValues(currentState, defaultStateValues);
    327 
    328   // Some parameters require loading different JSON files when the value changes. Do a reload.
    329   if (oldState) {
    330     for (var key in currentState) {
    331       if (oldState[key] != currentState[key] && RELOAD_REQUIRING_PARAMETERS.indexOf(key) != -1)
    332         window.location.reload();
    333     }
    334   }
    335 
    336   return diffState;
    337 }
    338 
    339 /**
    340  * Find the difference of currentState with oldState.
    341  * @return {Object} key:values of the new or changed params.
    342  */
    343 function diffStates() {
    344   // If there is no old state, everything in the current state is new.
    345   if (!oldState) {
    346     return currentState;
    347   }
    348 
    349   var changedParams = {};
    350   for (curKey in currentState) {
    351     var oldVal = oldState[curKey];
    352     var newVal = currentState[curKey];
    353     // Add new keys or changed values.
    354     if (!oldVal || oldVal != newVal) {
    355       changedParams[curKey] = newVal;
    356     }
    357   }
    358   return changedParams;
    359 }
    360 
    361 function getDefaultValue(key) {
    362   if (key in defaultStateValues)
    363     return defaultStateValues[key];
    364   return defaultCrossDashboardStateValues[key];
    365 }
    366 
    367 function fillMissingValues(to, from) {
    368   for (var state in from) {
    369     if (!(state in to))
    370       to[state] = from[state];
    371   }
    372 }
    373 
    374 /**
    375  * Load a script.
    376  * @param {string} path Path to the script to load.
    377  * @param {Function=} opt_onError Optional function to call if the script
    378  *     does not load.
    379  * @param {Function=} opt_onLoad Optional function to call when the script
    380  *     is loaded.  Called with the script element as its 1st argument.
    381  */
    382 function appendScript(path, opt_onError, opt_onLoad) {
    383   var script = document.createElement('script');
    384   script.src = path;
    385   if (opt_onLoad) {
    386     script.onreadystatechange = function() {
    387       if (this.readyState == 'complete') opt_onLoad(script);
    388     };
    389     script.onload = function() { opt_onLoad(script); };
    390   }
    391   if (opt_onError) {
    392     script.onerror = opt_onError;
    393   }
    394   document.getElementsByTagName('head')[0].appendChild(script);
     197function $(id)
     198{
     199    return document.getElementById(id);
     200}
     201
     202function stringContains(a, b)
     203{
     204    return a.indexOf(b) != -1;
     205}
     206
     207function caseInsensitiveContains(a, b)
     208{
     209    return a.match(new RegExp(b, 'i'));
     210}
     211
     212function startsWith(a, b)
     213{
     214    return a.indexOf(b) == 0;
     215}
     216
     217function endsWith(a, b)
     218{
     219    return a.lastIndexOf(b) == a.length - b.length;
     220}
     221
     222function isValidName(str)
     223{
     224    return str.match(/[A-Za-z0-9\-\_,]/);
     225}
     226
     227function trimString(str)
     228{
     229    return str.replace(/^\s+|\s+$/g, '');
     230}
     231
     232function request(url, success, error, opt_isBinaryData)
     233{
     234    console.log('XMLHttpRequest: ' + url);
     235    var xhr = new XMLHttpRequest();
     236    xhr.open('GET', url, true);
     237    if (opt_isBinaryData)
     238        xhr.overrideMimeType('text/plain; charset=x-user-defined');
     239    xhr.onreadystatechange = function(e) {
     240        if (xhr.readyState == 4) {
     241            if (xhr.status == 200)
     242                success(xhr);
     243            else
     244                error(xhr);
     245        }
     246    }
     247    xhr.send();
     248}
     249
     250function validateParameter(state, key, value, validateFn)
     251{
     252    if (validateFn())
     253        state[key] = value;
     254    else
     255        console.log(key + ' value is not valid: ' + value);
     256}
     257
     258function parseParameters(parameterStr)
     259{
     260    g_oldState = g_currentState;
     261    g_currentState = {};
     262
     263    var hash = window.location.hash;
     264    var paramsList = hash ? hash.substring(1).split('&') : [];
     265    var paramsMap = {};
     266    var invalidKeys = [];
     267    for (var i = 0; i < paramsList.length; i++) {
     268        var thisParam = paramsList[i].split('=');
     269        if (thisParam.length != 2) {
     270            console.log('Invalid query parameter: ' + paramsList[i]);
     271            continue;
     272        }
     273
     274        paramsMap[thisParam[0]] = decodeURIComponent(thisParam[1]);
     275    }
     276
     277    function parseParam(key)
     278    {
     279        var value = paramsMap[key];
     280        if (!handleValidHashParameterWrapper(key, value))
     281            invalidKeys.push(key + '=' + value);
     282    }
     283
     284    // Parse builder param last, since the list of valid builders depends on the other parameters.
     285    for (var key in paramsMap) {
     286        if (key != 'builder')
     287            parseParam(key);
     288    }
     289    if ('builder' in paramsMap) {
     290        if (!g_builders) {
     291            var tempState = {};
     292            for (var key in g_currentState)
     293                tempState[key] = g_currentState[key];
     294            fillMissingValues(tempState, g_defaultCrossDashboardStateValues);
     295            fillMissingValues(tempState, g_defaultStateValues);
     296            initBuilders(tempState);
     297        }
     298        parseParam('builder');
     299    }
     300
     301    if (invalidKeys.length)
     302        console.log("Invalid query parameters: " + invalidKeys.join(','));
     303
     304    var diffState = diffStates();
     305
     306    fillMissingValues(g_currentState, g_defaultCrossDashboardStateValues);
     307    fillMissingValues(g_currentState, g_defaultStateValues);
     308
     309    // Some parameters require loading different JSON files when the value changes. Do a reload.
     310    if (g_oldState) {
     311        for (var key in g_currentState) {
     312            if (g_oldState[key] != g_currentState[key] && RELOAD_REQUIRING_PARAMETERS.indexOf(key) != -1)
     313                window.location.reload();
     314        }
     315    }
     316
     317    return diffState;
     318}
     319
     320// Find the difference of g_currentState with g_oldState.
     321// @return {Object} key:values of the new or changed params.
     322function diffStates()
     323{
     324    // If there is no old state, everything in the current state is new.
     325    if (!g_oldState)
     326        return g_currentState;
     327
     328    var changedParams = {};
     329    for (curKey in g_currentState) {
     330        var oldVal = g_oldState[curKey];
     331        var newVal = g_currentState[curKey];
     332        // Add new keys or changed values.
     333        if (!oldVal || oldVal != newVal)
     334            changedParams[curKey] = newVal;
     335    }
     336    return changedParams;
     337}
     338
     339function getDefaultValue(key)
     340{
     341    if (key in g_defaultStateValues)
     342        return g_defaultStateValues[key];
     343    return g_defaultCrossDashboardStateValues[key];
     344}
     345
     346function fillMissingValues(to, from)
     347{
     348    for (var state in from) {
     349        if (!(state in to))
     350            to[state] = from[state];
     351    }
     352}
     353
     354// Load a script.
     355// @param {string} path Path to the script to load.
     356// @param {Function=} opt_onError Optional function to call if the script
     357//         does not load.
     358// @param {Function=} opt_onLoad Optional function to call when the script
     359//         is loaded.    Called with the script element as its 1st argument.
     360function appendScript(path, opt_onError, opt_onLoad)
     361{
     362    var script = document.createElement('script');
     363    script.src = path;
     364    if (opt_onLoad) {
     365        script.onreadystatechange = function() {
     366            if (this.readyState == 'complete')
     367                opt_onLoad(script);
     368        };
     369        script.onload = function() { opt_onLoad(script); };
     370    }
     371    if (opt_onError)
     372        script.onerror = opt_onError;
     373    document.getElementsByTagName('head')[0].appendChild(script);
    395374}
    396375
    397376// Permalinkable state of the page.
    398 var currentState;
    399 
    400 // Saved value of previous currentState. This is used to detect changing from
     377var g_currentState;
     378
     379// Saved value of previous g_currentState. This is used to detect changing from
    401380// one set of builders to another, which requires reloading the page.
    402 var oldState;
     381var g_oldState;
    403382
    404383// Parse cross-dashboard parameters before using them.
    405384parseParameters();
    406385
    407 function isLayoutTestResults() {
    408   return currentState.testType == 'layout-tests';
    409 }
    410 
    411 function getCurrentBuilderGroup(opt_state) {
    412   var state = opt_state || currentState;
    413   switch (state.testType) {
     386function isLayoutTestResults()
     387{
     388    return g_currentState.testType == 'layout-tests';
     389}
     390
     391function getCurrentBuilderGroup(opt_state)
     392{
     393    var state = opt_state || g_currentState;
     394    switch (state.testType) {
    414395    case 'layout-tests':
    415       return LAYOUT_TESTS_BUILDER_GROUPS[state.group]
    416       break;
     396        return LAYOUT_TESTS_BUILDER_GROUPS[state.group]
     397        break;
    417398    case 'app_unittests':
    418399    case 'base_unittests':
     
    439420    case 'ui_tests':
    440421    case 'unit_tests':
    441       return G_TESTS_BUILDER_GROUP;
    442       break;
     422        return G_TESTS_BUILDER_GROUP;
     423        break;
    443424    default:
    444       console.log('invalid testType parameter: ' + state.testType);
    445   }
    446 }
    447 
    448 function getBuilderMaster(builderName) {
    449   return BUILDER_TO_MASTER[builderName];
    450 }
    451 
    452 function isTipOfTreeWebKitBuilder() {
    453   return getCurrentBuilderGroup().isToTWebKit;
    454 }
    455 
    456 var defaultBuilderName, builders, expectationsBuilder;
    457 function initBuilders(state) {
    458   if (state.buildDir) {
    459     // If buildDir is set, point to the results.json and expectations.json in the
    460     // local tree. Useful for debugging changes to the python JSON generator.
    461     defaultBuilderName = 'DUMMY_BUILDER_NAME';
    462     builders = {'DUMMY_BUILDER_NAME': ''};
    463     var loc = document.location.toString();
    464     var offset = loc.indexOf('webkit/');
    465   } else {
    466     // FIXME: remove support for mapping from the master parameter to the group
    467     // one once the waterfall starts to pass in the builder name instead.
    468     if (state.master) {
    469       state.group = LEGACY_BUILDER_MASTERS_TO_GROUPS[state.master];
    470       window.location.hash = window.location.hash.replace('master=' + state.master, 'group=' + state.group);
    471       delete state.master;
    472     }
    473     getCurrentBuilderGroup(state).setup();
    474   }
    475 }
    476 initBuilders(currentState);
     425        console.log('invalid testType parameter: ' + state.testType);
     426    }
     427}
     428
     429function getBuilderMaster(builderName)
     430{
     431    return BUILDER_TO_MASTER[builderName];
     432}
     433
     434function isTipOfTreeWebKitBuilder()
     435{
     436    return getCurrentBuilderGroup().isToTWebKit;
     437}
     438
     439var g_defaultBuilderName, g_builders, g_expectationsBuilder;
     440function initBuilders(state)
     441{
     442    if (state.buildDir) {
     443        // If buildDir is set, point to the results.json and expectations.json in the
     444        // local tree. Useful for debugging changes to the python JSON generator.
     445        g_defaultBuilderName = 'DUMMY_BUILDER_NAME';
     446        g_builders = {'DUMMY_BUILDER_NAME': ''};
     447        var loc = document.location.toString();
     448        var offset = loc.indexOf('webkit/');
     449    } else {
     450        // FIXME: remove support for mapping from the master parameter to the group
     451        // one once the waterfall starts to pass in the builder name instead.
     452        if (state.master) {
     453            state.group = LEGACY_BUILDER_MASTERS_TO_GROUPS[state.master];
     454            window.location.hash = window.location.hash.replace('master=' + state.master, 'group=' + state.group);
     455            delete state.master;
     456        }
     457        getCurrentBuilderGroup(state).setup();
     458    }
     459}
     460initBuilders(g_currentState);
    477461
    478462// Append JSON script elements.
    479 var resultsByBuilder = {};
    480 var expectationsByTest = {};
    481 function ADD_RESULTS(builds) {
    482   for (var builderName in builds) {
    483     if (builderName != 'version')
    484       resultsByBuilder[builderName] = builds[builderName];
    485   }
    486 
    487   handleResourceLoad();
    488 }
    489 
    490 function getPathToBuilderResultsFile(builderName) {
    491   return TEST_RESULTS_SERVER + 'testfile?builder=' + builderName +
    492       '&master=' + getBuilderMaster(builderName).name +
    493       '&testtype=' + currentState.testType + '&name=';
     463var g_resultsByBuilder = {};
     464var g_expectationsByTest = {};
     465function ADD_RESULTS(builds)
     466{
     467    for (var builderName in builds) {
     468        if (builderName != 'version')
     469            g_resultsByBuilder[builderName] = builds[builderName];
     470    }
     471
     472    handleResourceLoad();
     473}
     474
     475function getPathToBuilderResultsFile(builderName)
     476{
     477    return TEST_RESULTS_SERVER + 'testfile?builder=' + builderName +
     478            '&master=' + getBuilderMaster(builderName).name +
     479            '&testtype=' + g_currentState.testType + '&name=';
    494480}
    495481
    496482// Only webkit tests have a sense of test expectations.
    497 var waitingOnExpectations = isLayoutTestResults() && !isTreeMap();
    498 if (waitingOnExpectations) {
    499   function ADD_EXPECTATIONS(expectations) {
    500     waitingOnExpectations = false;
    501     expectationsByTest = expectations;
     483var g_waitingOnExpectations = isLayoutTestResults() && !isTreeMap();
     484if (g_waitingOnExpectations) {
     485    function ADD_EXPECTATIONS(expectations)
     486    {
     487        g_waitingOnExpectations = false;
     488        g_expectationsByTest = expectations;
     489        handleResourceLoad();
     490    }
     491}
     492
     493function isTreeMap()
     494{
     495    return endsWith(window.location.pathname, 'treemap.html');
     496}
     497
     498function appendJSONScriptElementFor(builderName)
     499{
     500    var resultsFilename;
     501    if (isTreeMap())
     502        resultsFilename = 'times_ms.json';
     503    else if (g_currentState.showAllRuns)
     504        resultsFilename = 'results.json';
     505    else
     506        resultsFilename = 'results-small.json';
     507
     508    appendScript(getPathToBuilderResultsFile(builderName) + resultsFilename,
     509            partial(handleResourceLoadError, builderName),
     510            partial(handleScriptLoaded, builderName));
     511}
     512
     513function appendJSONScriptElements()
     514{
     515    clearErrors();
     516
     517    if (isTreeMap())
     518        return;
     519
     520    parseParameters();
     521
     522    if (g_currentState.useTestData) {
     523        appendScript('flakiness_dashboard_tests.js');
     524        return;
     525    }
     526
     527    for (var builderName in g_builders)
     528        appendJSONScriptElementFor(builderName);
     529
     530    // Grab expectations file from the fastest builder, which is Linux release
     531    // right now.    Could be changed to any other builder if needed.
     532    if (g_waitingOnExpectations)
     533        appendScript(getPathToBuilderResultsFile(g_expectationsBuilder) + 'expectations.json');
     534}
     535
     536var g_hasDoneInitialPageGeneration = false;
     537// String of error messages to display to the user.
     538var g_errorMessages = '';
     539
     540function handleResourceLoad()
     541{
     542    // In case we load a results.json that's not in the list of builders,
     543    // make sure to only call handleLocationChange once from the resource loads.
     544    if (!g_hasDoneInitialPageGeneration)
     545        handleLocationChange();
     546}
     547
     548function handleScriptLoaded(builderName, script)
     549{
     550    // We need this work-around for webkit.org/b/50589.
     551    if (!g_resultsByBuilder[builderName]) {
     552        var error = new Error("Builder data was empty");
     553        error.target = script;
     554        handleResourceLoadError(builderName, error);
     555    }
     556}
     557
     558// Handle resource loading errors - 404s, 500s, etc.    Recover from the error to
     559// still show as much data as possible, but show some UI about the failure, and
     560// do not try using this resource again until user refreshes.
     561//
     562// @param {string} builderName Name of builder that the resource failed for.
     563// @param {Event} e The error event.
     564function handleResourceLoadError(builderName, e)
     565{
     566    var error = e.target.src + ' failed to load for ' + builderName + '.';
     567
     568    if (isLayoutTestResults()) {
     569        console.error(error);
     570        addError(error);
     571    } else {
     572        // Avoid to show error/warning messages for non-layout tests. We may be
     573        // checking the builders that are not running the tests.
     574        console.info('info:' + error);
     575    }
     576
     577    // Remove this builder from builders, so we don't try to use the
     578    // data that isn't there.
     579    delete g_builders[builderName];
     580
     581    // Change the default builder name if it has been deleted.
     582    if (g_defaultBuilderName == builderName) {
     583        g_defaultBuilderName = null;
     584        for (var availableBuilderName in g_builders) {
     585            g_defaultBuilderName = availableBuilderName;
     586            g_defaultStateValues.builder = availableBuilderName;
     587            break;
     588        }
     589        if (!g_defaultBuilderName) {
     590            var error = 'No tests results found for ' + g_currentState.testType + '. Reload the page to try fetching it again.';
     591            console.error(error);
     592            addError(error);
     593        }
     594    }
     595
     596    // Proceed as if the resource had loaded.
    502597    handleResourceLoad();
    503   }
    504 }
    505 
    506 function isTreeMap() {
    507   return endsWith(window.location.pathname, 'treemap.html');
    508 }
    509 
    510 function appendJSONScriptElementFor(builderName) {
    511   var resultsFilename;
    512   if (isTreeMap())
    513     resultsFilename = 'times_ms.json';
    514   else if (currentState.showAllRuns)
    515     resultsFilename = 'results.json';
    516   else
    517     resultsFilename = 'results-small.json';
    518 
    519   appendScript(getPathToBuilderResultsFile(builderName) + resultsFilename,
    520       partial(handleResourceLoadError, builderName),
    521       partial(handleScriptLoaded, builderName));
    522 }
    523 
    524 function appendJSONScriptElements() {
    525   clearErrors();
    526 
    527   if (isTreeMap())
    528     return;
    529 
    530   parseParameters();
    531 
    532   if (currentState.useTestData) {
    533     appendScript('flakiness_dashboard_tests.js');
    534     return;
    535   }
    536 
    537   for (var builderName in builders) {
    538     appendJSONScriptElementFor(builderName);
    539   }
    540 
    541   // Grab expectations file from the fastest builder, which is Linux release
    542   // right now.  Could be changed to any other builder if needed.
    543   if (waitingOnExpectations) {
    544     appendScript(getPathToBuilderResultsFile(expectationsBuilder) +
    545         'expectations.json');
    546   }
    547 }
    548 
    549 var hasDoneInitialPageGeneration = false;
    550 // String of error messages to display to the user.
    551 var errorMessages = '';
    552 
    553 function handleResourceLoad() {
    554   // In case we load a results.json that's not in the list of builders,
    555   // make sure to only call handleLocationChange once from the resource loads.
    556   if (!hasDoneInitialPageGeneration)
    557     handleLocationChange();
    558 }
    559 
    560 function handleScriptLoaded(builderName, script) {
    561   // We need this work-around for webkit.org/b/50589.
    562   if (!resultsByBuilder[builderName]) {
    563     var error = new Error("Builder data was empty");
    564     error.target = script;
    565     handleResourceLoadError(builderName, error);
    566   }
    567 }
    568 
    569 /**
    570  * Handle resource loading errors - 404s, 500s, etc.  Recover from the error to
    571  * still show as much data as possible, but show some UI about the failure, and
    572  * do not try using this resource again until user refreshes.
    573  *
    574  * @param {string} builderName Name of builder that the resource failed for.
    575  * @param {Event} e The error event.
    576  */
    577 function handleResourceLoadError(builderName, e) {
    578   var error = e.target.src + ' failed to load for ' + builderName + '.';
    579 
    580   if (isLayoutTestResults()) {
    581     console.error(error);
    582     addError(error);
    583   } else {
    584     // Avoid to show error/warning messages for non-layout tests. We may be
    585     // checking the builders that are not running the tests.
    586     console.info('info:' + error);
    587   }
    588 
    589   // Remove this builder from builders, so we don't try to use the
    590   // data that isn't there.
    591   delete builders[builderName];
    592 
    593   // Change the default builder name if it has been deleted.
    594   if (defaultBuilderName == builderName) {
    595     defaultBuilderName = null;
    596     for (var availableBuilderName in builders) {
    597       defaultBuilderName = availableBuilderName;
    598       defaultStateValues.builder = availableBuilderName;
    599       break;
    600     }
    601     if (!defaultBuilderName) {
    602       var error = 'No tests results found for ' + currentState.testType +
    603           '. Reload the page to try fetching it again.';
    604       console.error(error);
    605       addError(error);
    606     }
    607   }
    608 
    609   // Proceed as if the resource had loaded.
    610   handleResourceLoad();
    611 }
    612 
    613 
    614 /**
    615  * Record a new error message.
    616  * @param {string} errorMsg The message to show to the user.
    617  */
    618 function addError(errorMsg) {
    619   errorMessages += errorMsg + '<br />';
    620 }
    621 
    622 /**
    623  * Clear out error and warning messages.
    624  */
    625 function clearErrors() {
    626   errorMessages = '';
    627 }
    628 
    629 /**
    630  * If there are errors, show big and red UI for errors so as to be noticed.
    631  */
    632 function showErrors() {
    633   var errors = $('errors');
    634 
    635   if (!errorMessages) {
    636     if (errors)
    637       errors.parentNode.removeChild(errors);
    638     return;
    639   }
    640 
    641   if (!errors) {
    642     errors = document.createElement('H2');
    643     errors.style.color = 'red';
    644     errors.id = 'errors';
    645     document.body.appendChild(errors);
    646   }
    647 
    648   errors.innerHTML = errorMessages;
    649 }
    650 
    651 /**
    652  * @return {boolean} Whether the json files have all completed loading.
    653  */
    654 function haveJsonFilesLoaded() {
    655   if (waitingOnExpectations)
    656     return false;
    657 
    658   if (isTreeMap())
     598}
     599
     600
     601// Record a new error message.
     602// @param {string} errorMsg The message to show to the user.
     603function addError(errorMsg)
     604{
     605    g_errorMessages += errorMsg + '<br />';
     606}
     607
     608// Clear out error and warning messages.
     609function clearErrors()
     610{
     611    g_errorMessages = '';
     612}
     613
     614// If there are errors, show big and red UI for errors so as to be noticed.
     615function showErrors()
     616{
     617    var errors = $('errors');
     618
     619    if (!g_errorMessages) {
     620        if (errors)
     621            errors.parentNode.removeChild(errors);
     622        return;
     623    }
     624
     625    if (!errors) {
     626        errors = document.createElement('H2');
     627        errors.style.color = 'red';
     628        errors.id = 'errors';
     629        document.body.appendChild(errors);
     630    }
     631
     632    errors.innerHTML = g_errorMessages;
     633}
     634
     635// @return {boolean} Whether the json files have all completed loading.
     636function haveJsonFilesLoaded()
     637{
     638    if (g_waitingOnExpectations)
     639        return false;
     640
     641    if (isTreeMap())
     642        return true;
     643
     644    for (var builder in g_builders) {
     645        if (!g_resultsByBuilder[builder])
     646            return false;
     647    }
    659648    return true;
    660 
    661   for (var builder in builders) {
    662     if (!resultsByBuilder[builder])
    663       return false;
    664   }
    665   return true;
    666 }
    667 
    668 function handleLocationChange() {
    669   if(!haveJsonFilesLoaded()) {
    670     return;
    671   }
    672 
    673   hasDoneInitialPageGeneration = true;
    674 
    675   var params = parseParameters();
    676   var shouldGeneratePage = true;
    677   if (Object.keys(params).length)
    678     shouldGeneratePage = handleQueryParameterChange(params);
    679 
    680   var newHash = getPermaLinkURLHash();
    681   var winHash = window.location.hash || "#";
    682   // Make sure the location is the same as the state we are using internally.
    683   // These get out of sync if processQueryParamChange changed state.
    684   if (newHash != winHash) {
    685     // This will cause another hashchange, and when we loop
    686     // back through here next time, we'll go through generatePage.
    687     window.location.hash = newHash;
    688   } else if (shouldGeneratePage) {
    689     generatePage();
    690   }
     649}
     650
     651function handleLocationChange()
     652{
     653    if(!haveJsonFilesLoaded())
     654        return;
     655
     656    g_hasDoneInitialPageGeneration = true;
     657
     658    var params = parseParameters();
     659    var shouldGeneratePage = true;
     660    if (Object.keys(params).length)
     661        shouldGeneratePage = handleQueryParameterChange(params);
     662
     663    var newHash = getPermaLinkURLHash();
     664    var winHash = window.location.hash || "#";
     665    // Make sure the location is the same as the state we are using internally.
     666    // These get out of sync if processQueryParamChange changed state.
     667    if (newHash != winHash) {
     668        // This will cause another hashchange, and when we loop
     669        // back through here next time, we'll go through generatePage.
     670        window.location.hash = newHash;
     671    } else if (shouldGeneratePage)
     672        generatePage();
    691673}
    692674
    693675window.onhashchange = handleLocationChange;
    694676
    695 /**
    696  * Sets the page state. Takes varargs of key, value pairs.
    697  */
    698 function setQueryParameter(var_args) {
    699   var state = Object.create(currentState);
    700   for (var i = 0; i < arguments.length; i += 2) {
    701     var key = arguments[i];
    702     state[key] = arguments[i + 1];
    703   }
    704   // Note: We use window.location.hash rather that window.location.replace
    705   // because of bugs in Chrome where extra entries were getting created
    706   // when back button was pressed and full page navigation was occuring.
    707   // TODO: file those bugs.
    708   window.location.hash = getPermaLinkURLHash(state);
    709 }
    710 
    711 function getPermaLinkURLHash(opt_state) {
    712   var state = opt_state || currentState;
    713   return '#' + joinParameters(state);
    714 }
    715 
    716 function joinParameters(stateObject) {
    717   var state = [];
    718   for (var key in stateObject) {
    719     var value = stateObject[key];
    720     if (value != getDefaultValue(key))
    721       state.push(key + '=' + encodeURIComponent(value));
    722   }
    723   return state.join('&');
    724 }
    725 
    726 function logTime(msg, startTime) {
    727   console.log(msg + ': ' + (Date.now() - startTime));
    728 }
    729 
    730 function hidePopup() {
    731   var popup = $('popup');
    732   if (popup)
    733     popup.parentNode.removeChild(popup);
    734 }
    735 
    736 function showPopup(e, html) {
    737   var popup = $('popup');
    738   if (!popup) {
    739     popup = document.createElement('div');
    740     popup.id = 'popup';
    741     document.body.appendChild(popup);
    742   }
    743 
    744   // Set html first so that we can get accurate size metrics on the popup.
    745   popup.innerHTML = html;
    746 
    747   var targetRect = e.target.getBoundingClientRect();
    748 
    749   var x = Math.min(targetRect.left - 10,
    750       document.documentElement.clientWidth - popup.offsetWidth);
    751   x = Math.max(0, x);
    752   popup.style.left = x + document.body.scrollLeft + 'px';
    753 
    754   var y = targetRect.top + targetRect.height;
    755   if (y + popup.offsetHeight > document.documentElement.clientHeight) {
    756     y = targetRect.top - popup.offsetHeight;
    757   }
    758   y = Math.max(0, y);
    759   popup.style.top = y + document.body.scrollTop + 'px';
    760 }
    761 
    762 /**
    763  * Create a new function with some of its arguements
    764  * pre-filled.
    765  * Taken from goog.partial in the Closure library.
    766  * @param {Function} fn A function to partially apply.
    767  * @param {...*} var_args Additional arguments that are partially
    768  *     applied to fn.
    769  * @return {!Function} A partially-applied form of the function bind() was
    770  *     invoked as a method of.
    771  */
    772 function partial(fn, var_args) {
    773   var args = Array.prototype.slice.call(arguments, 1);
    774   return function() {
    775     // Prepend the bound arguments to the current arguments.
    776     var newArgs = Array.prototype.slice.call(arguments);
    777     newArgs.unshift.apply(newArgs, args);
    778     return fn.apply(this, newArgs);
    779   };
     677// Sets the page state. Takes varargs of key, value pairs.
     678function setQueryParameter(var_args)
     679{
     680    var state = Object.create(g_currentState);
     681    for (var i = 0; i < arguments.length; i += 2) {
     682        var key = arguments[i];
     683        state[key] = arguments[i + 1];
     684    }
     685    // Note: We use window.location.hash rather that window.location.replace
     686    // because of bugs in Chrome where extra entries were getting created
     687    // when back button was pressed and full page navigation was occuring.
     688    // TODO: file those bugs.
     689    window.location.hash = getPermaLinkURLHash(state);
     690}
     691
     692function getPermaLinkURLHash(opt_state)
     693{
     694    var state = opt_state || g_currentState;
     695    return '#' + joinParameters(state);
     696}
     697
     698function joinParameters(stateObject)
     699{
     700    var state = [];
     701    for (var key in stateObject) {
     702        var value = stateObject[key];
     703        if (value != getDefaultValue(key))
     704            state.push(key + '=' + encodeURIComponent(value));
     705    }
     706    return state.join('&');
     707}
     708
     709function logTime(msg, startTime)
     710{
     711    console.log(msg + ': ' + (Date.now() - startTime));
     712}
     713
     714function hidePopup()
     715{
     716    var popup = $('popup');
     717    if (popup)
     718        popup.parentNode.removeChild(popup);
     719}
     720
     721function showPopup(e, html)
     722{
     723    var popup = $('popup');
     724    if (!popup) {
     725        popup = document.createElement('div');
     726        popup.id = 'popup';
     727        document.body.appendChild(popup);
     728    }
     729
     730    // Set html first so that we can get accurate size metrics on the popup.
     731    popup.innerHTML = html;
     732
     733    var targetRect = e.target.getBoundingClientRect();
     734
     735    var x = Math.min(targetRect.left - 10, document.documentElement.clientWidth - popup.offsetWidth);
     736    x = Math.max(0, x);
     737    popup.style.left = x + document.body.scrollLeft + 'px';
     738
     739    var y = targetRect.top + targetRect.height;
     740    if (y + popup.offsetHeight > document.documentElement.clientHeight)
     741        y = targetRect.top - popup.offsetHeight;
     742    y = Math.max(0, y);
     743    popup.style.top = y + document.body.scrollTop + 'px';
     744}
     745
     746// Create a new function with some of its arguements
     747// pre-filled.
     748// Taken from goog.partial in the Closure library.
     749// @param {Function} fn A function to partially apply.
     750// @param {...*} var_args Additional arguments that are partially
     751//         applied to fn.
     752// @return {!Function} A partially-applied form of the function bind() was
     753//         invoked as a method of.
     754function partial(fn, var_args)
     755{
     756    var args = Array.prototype.slice.call(arguments, 1);
     757    return function() {
     758        // Prepend the bound arguments to the current arguments.
     759        var newArgs = Array.prototype.slice.call(arguments);
     760        newArgs.unshift.apply(newArgs, args);
     761        return fn.apply(this, newArgs);
     762    };
    780763};
    781764
    782 /**
    783  * Returns the keys of the object/map/hash.
    784  * Taken from goog.object.getKeys in the Closure library.
    785  *
    786  * @param {Object} obj The object from which to get the keys.
    787  * @return {!Array.<string>} Array of property keys.
    788  */
    789 function getKeys(obj) {
    790   var res = [];
    791   for (var key in obj) {
    792     res.push(key);
    793   }
    794   return res;
    795 }
    796 
    797 /**
    798  * Returns the appropriate expectatiosn map for the current testType.
    799  */
    800 function getExpectationsMap() {
    801   return isLayoutTestResults() ? LAYOUT_TEST_EXPECTATIONS_MAP_ :
    802       GTEST_EXPECTATIONS_MAP_;
    803 }
    804 
    805 function toggleQueryParameter(param) {
    806   setQueryParameter(param, !currentState[param]);
    807 }
    808 
    809 function checkboxHTML(queryParameter, label, isChecked, opt_extraJavaScript) {
    810   var js = opt_extraJavaScript || '';
    811   return '<label style="padding-left: 2em">' +
    812       '<input type="checkbox" onchange="toggleQueryParameter(\'' + queryParameter + '\');' + js + '" ' +
    813           (isChecked ? 'checked' : '') + '>' + label +
    814       '</label>';
    815 }
    816 
    817 function selectHTML(label, queryParameter, options) {
    818   var html = '<label style="padding-left: 2em">' +
    819       label + ': ' +
    820       '<select onchange="setQueryParameter(\'' +
    821           queryParameter + '\', this[this.selectedIndex].value)">';
    822 
    823   for (var i = 0; i < options.length; i++) {
    824     var value = options[i];
    825     html += '<option value="' + value + '" ' +
    826       (currentState[queryParameter] == value ? 'selected' : '') +
    827       '>' + value + '</option>'
    828   }
    829   html += '</select><label>';
    830   return html;
    831 }
    832 
    833 /**
    834  * Returns the HTML for the select element to switch to different testTypes.
    835  */
    836 function getHTMLForTestTypeSwitcher(opt_noBuilderMenu, opt_extraHtml, opt_includeNoneBuilder) {
    837   var html = '<div style="border-bottom:1px dashed">';
    838   html += '' +
    839       htmlForDashboardLink('Stats', 'aggregate_results.html') +
    840       htmlForDashboardLink('Timeline', 'timeline_explorer.html') +
    841       htmlForDashboardLink('Results', 'flakiness_dashboard.html') +
    842       htmlForDashboardLink('Treemap', 'treemap.html');
    843 
    844   html += selectHTML('Test type', 'testType', TEST_TYPES);
    845 
    846   if (!opt_noBuilderMenu) {
    847     var buildersForMenu = Object.keys(builders);
    848     if (opt_includeNoneBuilder)
    849       buildersForMenu.unshift('--------------');
    850     html += selectHTML('Builder', 'builder', buildersForMenu);
    851   }
    852 
    853   if (isLayoutTestResults()) {
    854     html += selectHTML('Group', 'group', getKeys(LAYOUT_TESTS_BUILDER_GROUPS));
    855   }
    856 
    857   if (!isTreeMap()) {
    858     html += checkboxHTML('showAllRuns', 'Show all runs', currentState.showAllRuns);
    859   }
    860 
    861   if (opt_extraHtml) {
    862     html += opt_extraHtml;
    863   }
    864   return html + '</div>';
    865 }
    866 
    867 function selectBuilder(builder) {
    868   setQueryParameter('builder', builder);
    869 }
    870 
    871 function loadDashboard(fileName) {
    872   var pathName = window.location.pathname;
    873   pathName = pathName.substring(0, pathName.lastIndexOf('/') + 1);
    874   window.location = pathName + fileName + window.location.hash;
    875 }
    876 
    877 function htmlForTopLink(html, onClick, isSelected) {
    878   var cssText = isSelected ? 'font-weight: bold;' :
    879       'color:blue;text-decoration:underline;cursor:pointer;';
    880   cssText += 'margin: 0 5px;';
    881   return '<span style="' + cssText +
    882       '" onclick="' + onClick + '">' + html + '</span>';
    883 }
    884 
    885 function htmlForDashboardLink(html, fileName) {
    886   var pathName = window.location.pathname;
    887   var currentFileName = pathName.substring(pathName.lastIndexOf('/') + 1);
    888   var isSelected = currentFileName == fileName;
    889   var onClick = 'loadDashboard(\'' + fileName + '\')';
    890   return htmlForTopLink(html, onClick, isSelected);
    891 }
    892 
    893 function getRevisionLink(results, index, key, singleUrlTemplate, rangeUrlTemplate) {
    894   var currentRevision = parseInt(results[key][index], 10);
    895   var previousRevision = parseInt(results[key][index + 1], 10);
    896 
    897   function getSingleUrl() {
    898     return singleUrlTemplate.replace('<rev>', currentRevision);
    899   }
    900 
    901   function getRangeUrl() {
    902     return rangeUrlTemplate.replace('<rev1>', currentRevision).
    903         replace('<rev2>', previousRevision + 1);
    904   }
    905 
    906   if (currentRevision == previousRevision) {
    907     return 'At <a href="' + getSingleUrl() + '">r' + currentRevision  + '</a>';
    908   } else if (currentRevision - previousRevision == 1) {
    909     return '<a href="' + getSingleUrl() + '">r' + currentRevision  + '</a>';
    910   } else {
    911     return '<a href="' + getRangeUrl() + '">r' +
    912         (previousRevision + 1) + ' to r' +
    913         currentRevision + '</a>';
    914   }
    915 }
    916 
    917 function getChromiumRevisionLink(results, index) {
    918   return getRevisionLink(
    919       results,
    920       index,
    921       CHROME_REVISIONS_KEY,
    922       'http://src.chromium.org/viewvc/chrome?view=rev&revision=<rev>',
    923       'http://build.chromium.org/f/chromium/perf/dashboard/ui/changelog.html?url=/trunk/src&range=<rev2>:<rev1>&mode=html');
    924 }
    925 
    926 function getWebKitRevisionLink(results, index) {
    927   return getRevisionLink(
    928       results,
    929       index,
    930       WEBKIT_REVISIONS_KEY,
    931       'http://trac.webkit.org/changeset/<rev>',
    932       'http://trac.webkit.org/log/trunk/?rev=<rev1>&stop_rev=<rev2>&limit=100&verbose=on');
    933 }
    934 
    935 /**
    936  * "Decompresses" the RLE-encoding of test results so that we can query it
    937  * by build index and test name.
    938  *
    939  * @param {Object} results results for the current builder
    940  * @return Object with these properties:
    941  *   - testNames: array mapping test index to test names.
    942  *   - resultsByBuild: array of builds, for each build a (sparse) array of test
    943  *                     results by test index.
    944  *   - flakyTests: array with the boolean value true at test indices that are
    945  *                 considered flaky (more than one single-build failure).
    946  *   - flakyDeltasByBuild: array of builds, for each build a count of flaky
    947  *                         test results by expectation, as well as a total.
    948  */
    949 function getTestResultsByBuild(builderResults) {
    950   var builderTestResults = builderResults[TESTS_KEY];
    951   var buildCount = builderResults[FIXABLE_COUNTS_KEY].length;
    952   var testResultsByBuild = new Array(buildCount);
    953   var flakyDeltasByBuild = new Array(buildCount);
    954 
    955   // Pre-sizing the test result arrays for each build saves us ~250ms
    956   var testCount = 0;
    957   for (var testName in builderTestResults) {
    958     testCount++;
    959   }
    960   for (var i = 0; i < buildCount; i++) {
    961     testResultsByBuild[i] = new Array(testCount);
    962     testResultsByBuild[i][testCount - 1] = undefined;
    963 
    964     flakyDeltasByBuild[i] = {};
    965   }
    966 
    967   // Using indices instead of the full test names for each build saves us
    968   // ~1500ms
    969   var testIndex = 0;
    970   var testNames = new Array(testCount);
    971   var flakyTests = new Array(testCount);
    972 
    973   // Decompress and "invert" test results (by build instead of by test) and
    974   // determine which are flaky.
    975   for (var testName in builderTestResults) {
    976     var oneBuildFailureCount = 0;
    977 
    978     testNames[testIndex] = testName;
    979     var testResults = builderTestResults[testName].results;
    980     for (var i = 0, rleResult, currentBuildIndex = 0;
    981          (rleResult = testResults[i]) && currentBuildIndex < buildCount;
    982          i++) {
    983       var count = rleResult[RLE.LENGTH];
    984       var value = rleResult[RLE.VALUE];
    985 
    986       if (count == 1 && value in FAILURE_EXPECTATIONS_) {
    987         oneBuildFailureCount++;
    988       }
    989 
    990       for (var j = 0; j < count; j++) {
    991         testResultsByBuild[currentBuildIndex++][testIndex] = value;
    992         if (currentBuildIndex == buildCount) {
    993           break;
     765// Returns the keys of the object/map/hash.
     766// Taken from goog.object.getKeys in the Closure library.
     767//
     768// @param {Object} obj The object from which to get the keys.
     769// @return {!Array.<string>} Array of property keys.
     770function getKeys(obj)
     771{
     772    var res = [];
     773    for (var key in obj)
     774        res.push(key);
     775    return res;
     776}
     777
     778// Returns the appropriate expectatiosn map for the current testType.
     779function getExpectationsMap()
     780{
     781    return isLayoutTestResults() ? LAYOUT_TEST_EXPECTATIONS_MAP_ : GTEST_EXPECTATIONS_MAP_;
     782}
     783
     784function toggleQueryParameter(param)
     785{
     786    setQueryParameter(param, !g_currentState[param]);
     787}
     788
     789function checkboxHTML(queryParameter, label, isChecked, opt_extraJavaScript)
     790{
     791    var js = opt_extraJavaScript || '';
     792    return '<label style="padding-left: 2em">' +
     793        '<input type="checkbox" onchange="toggleQueryParameter(\'' + queryParameter + '\');' + js + '" ' +
     794            (isChecked ? 'checked' : '') + '>' + label +
     795        '</label>';
     796}
     797
     798function selectHTML(label, queryParameter, options)
     799{
     800    var html = '<label style="padding-left: 2em">' + label + ': ' +
     801        '<select onchange="setQueryParameter(\'' + queryParameter + '\', this[this.selectedIndex].value)">';
     802
     803    for (var i = 0; i < options.length; i++) {
     804        var value = options[i];
     805        html += '<option value="' + value + '" ' +
     806            (g_currentState[queryParameter] == value ? 'selected' : '') +
     807            '>' + value + '</option>'
     808    }
     809    html += '</select><label>';
     810    return html;
     811}
     812
     813// Returns the HTML for the select element to switch to different testTypes.
     814function getHTMLForTestTypeSwitcher(opt_noBuilderMenu, opt_extraHtml, opt_includeNoneBuilder)
     815{
     816    var html = '<div style="border-bottom:1px dashed">';
     817    html += '' +
     818        htmlForDashboardLink('Stats', 'aggregate_results.html') +
     819        htmlForDashboardLink('Timeline', 'timeline_explorer.html') +
     820        htmlForDashboardLink('Results', 'flakiness_dashboard.html') +
     821        htmlForDashboardLink('Treemap', 'treemap.html');
     822
     823    html += selectHTML('Test type', 'testType', TEST_TYPES);
     824
     825    if (!opt_noBuilderMenu) {
     826        var buildersForMenu = Object.keys(g_builders);
     827        if (opt_includeNoneBuilder)
     828            buildersForMenu.unshift('--------------');
     829        html += selectHTML('Builder', 'builder', buildersForMenu);
     830    }
     831
     832    if (isLayoutTestResults())
     833        html += selectHTML('Group', 'group', getKeys(LAYOUT_TESTS_BUILDER_GROUPS));
     834
     835    if (!isTreeMap())
     836        html += checkboxHTML('showAllRuns', 'Show all runs', g_currentState.showAllRuns);
     837
     838    if (opt_extraHtml)
     839        html += opt_extraHtml;
     840    return html + '</div>';
     841}
     842
     843function selectBuilder(builder)
     844{
     845    setQueryParameter('builder', builder);
     846}
     847
     848function loadDashboard(fileName)
     849{
     850    var pathName = window.location.pathname;
     851    pathName = pathName.substring(0, pathName.lastIndexOf('/') + 1);
     852    window.location = pathName + fileName + window.location.hash;
     853}
     854
     855function htmlForTopLink(html, onClick, isSelected)
     856{
     857    var cssText = isSelected ? 'font-weight: bold;' : 'color:blue;text-decoration:underline;cursor:pointer;';
     858    cssText += 'margin: 0 5px;';
     859    return '<span style="' + cssText + '" onclick="' + onClick + '">' + html + '</span>';
     860}
     861
     862function htmlForDashboardLink(html, fileName)
     863{
     864    var pathName = window.location.pathname;
     865    var currentFileName = pathName.substring(pathName.lastIndexOf('/') + 1);
     866    var isSelected = currentFileName == fileName;
     867    var onClick = 'loadDashboard(\'' + fileName + '\')';
     868    return htmlForTopLink(html, onClick, isSelected);
     869}
     870
     871function getRevisionLink(results, index, key, singleUrlTemplate, rangeUrlTemplate)
     872{
     873    var currentRevision = parseInt(results[key][index], 10);
     874    var previousRevision = parseInt(results[key][index + 1], 10);
     875
     876    function getSingleUrl()
     877    {
     878        return singleUrlTemplate.replace('<rev>', currentRevision);
     879    }
     880
     881    function getRangeUrl()
     882    {
     883        return rangeUrlTemplate.replace('<rev1>', currentRevision).replace('<rev2>', previousRevision + 1);
     884    }
     885
     886    if (currentRevision == previousRevision)
     887        return 'At <a href="' + getSingleUrl() + '">r' + currentRevision    + '</a>';
     888    else if (currentRevision - previousRevision == 1)
     889        return '<a href="' + getSingleUrl() + '">r' + currentRevision    + '</a>';
     890    else
     891        return '<a href="' + getRangeUrl() + '">r' + (previousRevision + 1) + ' to r' + currentRevision + '</a>';
     892}
     893
     894function getChromiumRevisionLink(results, index)
     895{
     896    return getRevisionLink(
     897        results,
     898        index,
     899        CHROME_REVISIONS_KEY,
     900        'http://src.chromium.org/viewvc/chrome?view=rev&revision=<rev>',
     901        'http://build.chromium.org/f/chromium/perf/dashboard/ui/changelog.html?url=/trunk/src&range=<rev2>:<rev1>&mode=html');
     902}
     903
     904function getWebKitRevisionLink(results, index)
     905{
     906    return getRevisionLink(
     907        results,
     908        index,
     909        WEBKIT_REVISIONS_KEY,
     910        'http://trac.webkit.org/changeset/<rev>',
     911        'http://trac.webkit.org/log/trunk/?rev=<rev1>&stop_rev=<rev2>&limit=100&verbose=on');
     912}
     913
     914// "Decompresses" the RLE-encoding of test results so that we can query it
     915// by build index and test name.
     916//
     917// @param {Object} results results for the current builder
     918// @return Object with these properties:
     919//     - testNames: array mapping test index to test names.
     920//     - resultsByBuild: array of builds, for each build a (sparse) array of test
     921//                                         results by test index.
     922//     - flakyTests: array with the boolean value true at test indices that are
     923//                                 considered flaky (more than one single-build failure).
     924//     - flakyDeltasByBuild: array of builds, for each build a count of flaky
     925//                                                 test results by expectation, as well as a total.
     926function getTestResultsByBuild(builderResults)
     927{
     928    var builderTestResults = builderResults[TESTS_KEY];
     929    var buildCount = builderResults[FIXABLE_COUNTS_KEY].length;
     930    var testResultsByBuild = new Array(buildCount);
     931    var flakyDeltasByBuild = new Array(buildCount);
     932
     933    // Pre-sizing the test result arrays for each build saves us ~250ms
     934    var testCount = 0;
     935    for (var testName in builderTestResults)
     936        testCount++;
     937    for (var i = 0; i < buildCount; i++) {
     938        testResultsByBuild[i] = new Array(testCount);
     939        testResultsByBuild[i][testCount - 1] = undefined;
     940        flakyDeltasByBuild[i] = {};
     941    }
     942
     943    // Using indices instead of the full test names for each build saves us
     944    // ~1500ms
     945    var testIndex = 0;
     946    var testNames = new Array(testCount);
     947    var flakyTests = new Array(testCount);
     948
     949    // Decompress and "invert" test results (by build instead of by test) and
     950    // determine which are flaky.
     951    for (var testName in builderTestResults) {
     952        var oneBuildFailureCount = 0;
     953
     954        testNames[testIndex] = testName;
     955        var testResults = builderTestResults[testName].results;
     956        for (var i = 0, rleResult, currentBuildIndex = 0; (rleResult = testResults[i]) && currentBuildIndex < buildCount; i++) {
     957            var count = rleResult[RLE.LENGTH];
     958            var value = rleResult[RLE.VALUE];
     959
     960            if (count == 1 && value in FAILURE_EXPECTATIONS_)
     961                oneBuildFailureCount++;
     962
     963            for (var j = 0; j < count; j++) {
     964                testResultsByBuild[currentBuildIndex++][testIndex] = value;
     965                if (currentBuildIndex == buildCount)
     966                    break;
     967            }
    994968        }
    995       }
    996     }
    997 
    998     if (oneBuildFailureCount > 2) {
    999       flakyTests[testIndex] = true;
    1000     }
    1001 
    1002     testIndex++;
    1003   }
    1004 
    1005   // Now that we know which tests are flaky, count the test results that are
    1006   // from flaky tests for each build.
    1007   testIndex = 0;
    1008   for (var testName in builderTestResults) {
    1009     if (!flakyTests[testIndex++]) {
    1010       continue;
    1011     }
    1012 
    1013     var testResults = builderTestResults[testName].results;
    1014     for (var i = 0, rleResult, currentBuildIndex = 0;
    1015         (rleResult = testResults[i]) && currentBuildIndex < buildCount;
    1016         i++) {
    1017       var count = rleResult[RLE.LENGTH];
    1018       var value = rleResult[RLE.VALUE];
    1019 
    1020       for (var j = 0; j < count; j++) {
    1021         var buildTestResults = flakyDeltasByBuild[currentBuildIndex++];
    1022         function addFlakyDelta(key) {
    1023           if (!(key in buildTestResults)) {
    1024             buildTestResults[key] = 0;
    1025           }
    1026           buildTestResults[key]++;
     969
     970        if (oneBuildFailureCount > 2)
     971            flakyTests[testIndex] = true;
     972
     973        testIndex++;
     974    }
     975
     976    // Now that we know which tests are flaky, count the test results that are
     977    // from flaky tests for each build.
     978    testIndex = 0;
     979    for (var testName in builderTestResults) {
     980        if (!flakyTests[testIndex++])
     981            continue;
     982
     983        var testResults = builderTestResults[testName].results;
     984        for (var i = 0, rleResult, currentBuildIndex = 0; (rleResult = testResults[i]) && currentBuildIndex < buildCount; i++) {
     985            var count = rleResult[RLE.LENGTH];
     986            var value = rleResult[RLE.VALUE];
     987
     988            for (var j = 0; j < count; j++) {
     989                var buildTestResults = flakyDeltasByBuild[currentBuildIndex++];
     990                function addFlakyDelta(key)
     991                {
     992                    if (!(key in buildTestResults))
     993                        buildTestResults[key] = 0;
     994                    buildTestResults[key]++;
     995                }
     996                addFlakyDelta(value);
     997                if (value != 'P' && value != 'N')
     998                    addFlakyDelta('total');
     999                if (currentBuildIndex == buildCount)
     1000                    break;
     1001            }
    10271002        }
    1028         addFlakyDelta(value);
    1029         if (value != 'P' && value != 'N') {
    1030           addFlakyDelta('total');
    1031         }
    1032         if (currentBuildIndex == buildCount) {
    1033           break;
    1034         }
    1035       }
    1036     }
    1037   }
    1038 
    1039   return {
    1040     testNames: testNames,
    1041     resultsByBuild: testResultsByBuild,
    1042     flakyTests: flakyTests,
    1043     flakyDeltasByBuild: flakyDeltasByBuild
    1044   };
     1003    }
     1004
     1005    return {
     1006        testNames: testNames,
     1007        resultsByBuild: testResultsByBuild,
     1008        flakyTests: flakyTests,
     1009        flakyDeltasByBuild: flakyDeltasByBuild
     1010    };
    10451011}
    10461012
     
    10491015
    10501016document.addEventListener('mousedown', function(e) {
    1051       // Clear the open popup, unless the click was inside the popup.
    1052       var popup = $('popup');
    1053       if (popup && e.target != popup &&
    1054           !(popup.compareDocumentPosition(e.target) & 16)) {
     1017    // Clear the open popup, unless the click was inside the popup.
     1018    var popup = $('popup');
     1019    if (popup && e.target != popup && !(popup.compareDocumentPosition(e.target) & 16))
    10551020        hidePopup();
    1056       }
    1057     }, false);
     1021}, false);
    10581022
    10591023window.addEventListener('load', function() {
    1060       // This doesn't seem totally accurate as there is a race between
    1061       // onload firing and the last script tag being executed.
    1062       logTime('Time to load JS', pageLoadStartTime);
    1063     }, false);
     1024    // This doesn't seem totally accurate as there is a race between
     1025    // onload firing and the last script tag being executed.
     1026    logTime('Time to load JS', g_pageLoadStartTime);
     1027}, false);
  • trunk/Tools/TestResultServer/static-dashboards/flakiness_dashboard.html

    r90964 r91021  
    346346function generatePage()
    347347{
    348     if (currentState.useTestData)
     348    if (g_currentState.useTestData)
    349349        return;
    350350
     
    355355    // tests expands to all tests that match the CSV list.
    356356    // result expands to all tests that ever have the given result
    357     if (currentState.tests || currentState.result)
     357    if (g_currentState.tests || g_currentState.result)
    358358        generatePageForIndividualTests(individualTests());
    359     else if (currentState.expectationsUpdate)
     359    else if (g_currentState.expectationsUpdate)
    360360        generatePageForExpectationsUpdate();
    361361    else
    362         generatePageForBuilder(currentState.builder);
    363 
    364     for (var builder in builders)
     362        generatePageForBuilder(g_currentState.builder);
     363
     364    for (var builder in g_builders)
    365365        processTestResultsForBuilderAsync(builder);
    366366}
     
    370370    switch(key) {
    371371    case 'tests':
    372         validateParameter(currentState, key, value,
     372        validateParameter(g_currentState, key, value,
    373373            function() {
    374374                return isValidName(value);
     
    378378    case 'result':
    379379        value = value.toUpperCase();
    380         validateParameter(currentState, key, value,
     380        validateParameter(g_currentState, key, value,
    381381            function() {
    382382                for (var result in LAYOUT_TEST_EXPECTATIONS_MAP_) {
     
    389389
    390390    case 'builder':
    391         validateParameter(currentState, key, value,
     391        validateParameter(g_currentState, key, value,
    392392            function() {
    393                 return value in builders;
     393                return value in g_builders;
    394394            });
    395395        return true;
    396396
    397397    case 'sortColumn':
    398         validateParameter(currentState, key, value,
     398        validateParameter(g_currentState, key, value,
    399399            function() {
    400400                // Get all possible headers since the actual used set of headers
    401                 // depends on the values in currentState, which are currently being set.
     401                // depends on the values in g_currentState, which are currently being set.
    402402                var headers = tableHeaders(true);
    403403                for (var i = 0; i < headers.length; i++) {
     
    410410
    411411    case 'sortOrder':
    412         validateParameter(currentState, key, value,
     412        validateParameter(g_currentState, key, value,
    413413            function() {
    414414                return value == FORWARD || value == BACKWARD;
     
    419419    case 'updateIndex':
    420420    case 'revision':
    421         validateParameter(currentState, key, Number(value),
     421        validateParameter(g_currentState, key, Number(value),
    422422            function() {
    423423                return value.match(/^\d+$/);
     
    436436    case 'expectationsUpdate':
    437437    case 'showRunsOnBuilderPage':
    438         currentState[key] = value == 'true';
     438        g_currentState[key] = value == 'true';
    439439        return true;
    440440
     
    444444}
    445445
    446 defaultStateValues = {
     446g_defaultStateValues = {
    447447    sortOrder: BACKWARD,
    448448    sortColumn: 'flakiness',
     
    459459    showRunsOnBuilderPage: false,
    460460    updateIndex: 0,
    461     builder: defaultBuilderName,
     461    builder: g_defaultBuilderName,
    462462    resultsHeight: 300,
    463463    revision: null
     
    568568    if (!g_allTests) {
    569569        g_allTests = {};
    570         for (var builder in builders)
     570        for (var builder in g_builders)
    571571            addTestsForBuilder(builder, g_allTests);
    572572    }
     
    579579function individualTests()
    580580{
    581     if (currentState.result)
    582         return allTestsWithResult(currentState.result);
    583 
    584     if (!currentState.tests)
     581    if (g_currentState.result)
     582        return allTestsWithResult(g_currentState.result);
     583
     584    if (!g_currentState.tests)
    585585        return [];
    586586
     
    591591{
    592592    // Convert windows slashes to unix slashes.
    593     var tests = currentState.tests.replace(/\\/g, '/');
     593    var tests = g_currentState.tests.replace(/\\/g, '/');
    594594    var separator = stringContains(tests, ' ') ? ' ' : ',';
    595595    var testList = tests.split(separator);
     
    678678function addTestsForBuilder(builder, testMapToPopulate)
    679679{
    680     var tests = resultsByBuilder[builder].tests;
     680    var tests = g_resultsByBuilder[builder].tests;
    681681    for (var test in tests) {
    682682        testMapToPopulate[test] = true;
     
    698698    if (!g_allTestsByPlatformAndBuildType[platform][buildType]) {
    699699        var tests = {};
    700         for (var thisBuilder in builders) {
     700        for (var thisBuilder in g_builders) {
    701701            var thisBuilderBuildInfo = platformAndBuildType(thisBuilder);
    702702            if (thisBuilderBuildInfo.buildType == buildType && thisBuilderBuildInfo.platform == platform) {
     
    770770    htmlArrays.bugs = [];
    771771
    772     var tests = resultsByBuilder[resultsObject.builder].tests;
     772    var tests = g_resultsByBuilder[resultsObject.builder].tests;
    773773
    774774    var testObject = g_allExpectations[test];
     
    883883
    884884    var expectationsArray = [];
    885     for (var path in expectationsByTest)
    886         expectationsArray.push({path: path, expectations: expectationsByTest[path]});
     885    for (var path in g_expectationsByTest)
     886        expectationsArray.push({path: path, expectations: g_expectationsByTest[path]});
    887887
    888888    // Sort the array to hit more specific paths last. More specific
     
    952952function processTestRunsForAllBuilders()
    953953{
    954     for (var builder in builders)
     954    for (var builder in g_builders)
    955955        processTestRunsForBuilder(builder);
    956956}
     
    961961      return;
    962962
    963     if (!resultsByBuilder[builderName]) {
     963    if (!g_resultsByBuilder[builderName]) {
    964964        console.error('No tests found for ' + builderName);
    965965        g_perBuilderFailures[builderName] = [];
     
    976976
    977977    var failures = [];
    978     var allTestsForThisBuilder = resultsByBuilder[builderName].tests;
     978    var allTestsForThisBuilder = g_resultsByBuilder[builderName].tests;
    979979
    980980    for (var test in allTestsForThisBuilder) {
     
    982982        populateExpectationsData(resultsForTest);
    983983
    984         var rawTest = resultsByBuilder[builderName].tests[test];
     984        var rawTest = g_resultsByBuilder[builderName].tests[test];
    985985        resultsForTest.rawTimes = rawTest.times;
    986986        var rawResults = rawTest.results;
     
    10931093                // test_expectations.txt, delete all the legacyExpectationsSemantics
    10941094                // code.
    1095                 if (currentState.legacyExpectationsSemantics) {
     1095                if (g_currentState.legacyExpectationsSemantics) {
    10961096                    if (element == 'FAIL') {
    10971097                        for (var i = 0; i < FAIL_RESULTS.length; i++) {
     
    11141114                // test_expectations.txt, delete all the legacyExpectationsSemantics
    11151115                // code.
    1116                 if (currentState.legacyExpectationsSemantics) {
     1116                if (g_currentState.legacyExpectationsSemantics) {
    11171117                    if (expectation == 'FAIL') {
    11181118                        for (var j = 0; j < FAIL_RESULTS.length; j++) {
     
    12191219{
    12201220    var currentIndex = 0;
    1221     var rawResults = resultsByBuilder[builder].tests[testName].results;
     1221    var rawResults = g_resultsByBuilder[builder].tests[testName].results;
    12221222    for (var i = 0; i < rawResults.length; i++) {
    12231223        currentIndex += rawResults[i][RLE.LENGTH];
     
    12311231function buildNumbersForFailures(builder, testName)
    12321232{
    1233     var rawResults = resultsByBuilder[builder].tests[testName].results;
    1234     var buildNumbers = resultsByBuilder[builder].buildNumbers;
     1233    var rawResults = g_resultsByBuilder[builder].tests[testName].results;
     1234    var buildNumbers = g_resultsByBuilder[builder].buildNumbers;
    12351235    var index = 0;
    12361236    var failures = [];
     
    12491249function pathToFailureLog(testName)
    12501250{
    1251     return '/steps/' + currentState.testType + '/logs/' + testName.split('.')[1]
     1251    return '/steps/' + g_currentState.testType + '/logs/' + testName.split('.')[1]
    12521252}
    12531253
     
    12561256    var html = '';
    12571257
    1258     var time = resultsByBuilder[builder].secondsSinceEpoch[index];
     1258    var time = g_resultsByBuilder[builder].secondsSinceEpoch[index];
    12591259    if (time) {
    12601260        var date = new Date(time * 1000);
     
    12621262    }
    12631263
    1264     var buildNumber = resultsByBuilder[builder].buildNumbers[index];
     1264    var buildNumber = g_resultsByBuilder[builder].buildNumbers[index];
    12651265    var builderMaster = getBuilderMaster(builder);
    12661266    var buildBasePath = builderMaster.getLogPath(builder, buildNumber);
     
    12681268    html += '<ul><li>' + linkHTMLToOpenWindow(buildBasePath, 'Build log') +
    12691269        '</li><li>' +
    1270         createBlameListHTML(resultsByBuilder[builder].webkitRevision, index,
     1270        createBlameListHTML(g_resultsByBuilder[builder].webkitRevision, index,
    12711271            'http://trac.webkit.org/log/?verbose=on&rev=', '&stop_rev=',
    12721272            'WebKit') +
     
    12741274
    12751275    if (builderMaster == WEBKIT_BUILDER_MASTER) {
    1276         var revision = resultsByBuilder[builder].webkitRevision[index];
     1276        var revision = g_resultsByBuilder[builder].webkitRevision[index];
    12771277        html += '<li><span class=link onclick="setQueryParameter(\'revision\',' +
    12781278            revision + ')">Show results for WebKit r' + revision +
     
    12801280    } else {
    12811281        html += '<li>' +
    1282             createBlameListHTML(resultsByBuilder[builder].chromeRevision, index,
     1282            createBlameListHTML(g_resultsByBuilder[builder].chromeRevision, index,
    12831283                'http://build.chromium.org/f/chromium/perf/dashboard/ui/changelog.html?url=/trunk/src&mode=html&range=', ':', 'Chrome') +
    12841284            '</li>';
    12851285
    1286         var chromeRevision = resultsByBuilder[builder].chromeRevision[index];
     1286        var chromeRevision = g_resultsByBuilder[builder].chromeRevision[index];
    12871287        if (chromeRevision && isLayoutTestResults()) {
    1288             html += '<li><a href="' + TEST_RESULTS_BASE_PATH + builders[builder] +
     1288            html += '<li><a href="' + TEST_RESULTS_BASE_PATH + g_builders[builder] +
    12891289                '/' + chromeRevision + '/layout-test-results.zip">layout-test-results.zip</a></li>';
    12901290        }
     
    13061306function htmlForTestResults(test)
    13071307{
    1308     if (!currentState.showRunsOnBuilderPage && !isCrossBuilderView())
     1308    if (!g_currentState.showRunsOnBuilderPage && !isCrossBuilderView())
    13091309        return '<td>' + test.flips;
    13101310
     
    13141314    var builder = test.builder;
    13151315    var builderMaster = getBuilderMaster(builder);
    1316     var buildNumbers = resultsByBuilder[builder].buildNumbers;
     1316    var buildNumbers = g_resultsByBuilder[builder].buildNumbers;
    13171317
    13181318    var indexToReplaceCurrentResult = -1;
     
    13481348
    13491349        var extraClassNames = '';
    1350         var webkitRevision = resultsByBuilder[builder].webkitRevision;
     1350        var webkitRevision = g_resultsByBuilder[builder].webkitRevision;
    13511351        var isWebkitMerge = webkitRevision[i + 1] && webkitRevision[i] != webkitRevision[i + 1];
    13521352        if (isWebkitMerge && builderMaster != WEBKIT_BUILDER_MASTER)
     
    13731373
    13741374    if (tests.length) {
    1375         html +=  '<h3>Have not failed in last ' + resultsByBuilder[builder].buildNumbers.length + ' runs.</h3><div id="passing-tests">';
     1375        html +=  '<h3>Have not failed in last ' + g_resultsByBuilder[builder].buildNumbers.length + ' runs.</h3><div id="passing-tests">';
    13761376
    13771377        for (var i = 0; i < tests.length; i++)
     
    13841384        html += '<h3>' + linkHTMLToToggleState('showSkipped', 'Skipped tests in test_expectations.txt') + '</h3>';
    13851385
    1386         if (currentState.showSkipped)
     1386        if (g_currentState.showSkipped)
    13871387            html += '<div id="passing-tests">' + open + skippedPaths.join('</div>' + open) + '</div></div>';
    13881388    }
     
    13941394{
    13951395    if (testResult.isWontFixSkip)
    1396         return !currentState.showWontFixSkip;
     1396        return !g_currentState.showWontFixSkip;
    13971397
    13981398    if (testResult.isFlaky)
    1399         return !currentState.showFlaky;
     1399        return !g_currentState.showFlaky;
    14001400
    14011401    if (isSlowTest(testResult))
    1402         return !currentState.showSlow;
     1402        return !g_currentState.showSlow;
    14031403
    14041404    if (testResult.meetsExpectations)
    1405         return !currentState.showCorrectExpectations;
    1406 
    1407     return !currentState.showWrongExpectations;
     1405        return !g_currentState.showCorrectExpectations;
     1406
     1407    return !g_currentState.showWrongExpectations;
    14081408}
    14091409
     
    14291429function isCrossBuilderView()
    14301430{
    1431     return currentState.tests || currentState.result || currentState.expectationsUpdate;
     1431    return g_currentState.tests || g_currentState.result || g_currentState.expectationsUpdate;
    14321432}
    14331433
     
    14431443    if (isLayoutTestResults() || opt_getAll) {
    14441444        headers.push('bugs');
    1445         if (isCrossBuilderView() || currentState.showRunsOnBuilderPage || opt_getAll)
     1445        if (isCrossBuilderView() || g_currentState.showRunsOnBuilderPage || opt_getAll)
    14461446            headers.push('modifiers', 'expectations');
    14471447    }
    14481448
    1449     if (currentState.showRunsOnBuilderPage || opt_getAll || isCrossBuilderView())
     1449    if (g_currentState.showRunsOnBuilderPage || opt_getAll || isCrossBuilderView())
    14501450        headers.push('missing', 'extra');
    14511451
     
    14551455    var FLIPS_HEADER = 'flakiness (number of flips)';
    14561456
    1457     if (currentState.showRunsOnBuilderPage || opt_getAll)
     1457    if (g_currentState.showRunsOnBuilderPage || opt_getAll)
    14581458        headers.push(FLAKINESS_HEADER);
    14591459
    1460     if (!currentState.showRunsOnBuilderPage || opt_getAll)
     1460    if (!g_currentState.showRunsOnBuilderPage || opt_getAll)
    14611461        headers.push(FLIPS_HEADER);
    14621462
     
    15151515    // Use the first word of the header title as the sortkey
    15161516    var thisSortValue = sortColumnFromTableHeader(headerName);
    1517     var arrowHTML = thisSortValue == currentState.sortColumn ?
    1518         '<span class=' + currentState.sortOrder + '>' + (currentState.sortOrder == FORWARD ? '&uarr;' : '&darr;' ) + '</span>' : '';
     1517    var arrowHTML = thisSortValue == g_currentState.sortColumn ?
     1518        '<span class=' + g_currentState.sortOrder + '>' + (g_currentState.sortOrder == FORWARD ? '&uarr;' : '&darr;' ) + '</span>' : '';
    15191519    return '<th sortValue=' + thisSortValue +
    15201520        // Extend last th through all the rest of the columns.
     
    16061606    var sort = 'sortColumn';
    16071607    var orderKey = 'sortOrder';
    1608     if (sortValue == currentState[sort] && currentState[orderKey] == FORWARD)
     1608    if (sortValue == g_currentState[sort] && g_currentState[orderKey] == FORWARD)
    16091609        order = BACKWARD;
    16101610    else
     
    16811681{
    16821682    // Always show all runs when auto-updating expectations.
    1683     if (!currentState.showAllRuns)
     1683    if (!g_currentState.showAllRuns)
    16841684        setQueryParameter('showAllRuns', true);
    16851685
     
    17021702    }
    17031703
    1704     for (var builder in builders) {
     1704    for (var builder in g_builders) {
    17051705        var tests = g_perBuilderWithExpectationsButNoFailures[builder]
    17061706        for (var i = 0; i < tests.length; i++) {
     
    17271727function showUpdateInfoForTest(testsNeedingUpdate, keys)
    17281728{
    1729     var test = keys[currentState.updateIndex];
     1729    var test = keys[g_currentState.updateIndex];
    17301730    document.body.innerHTML = '<b>' + test + '</b>' +
    1731         '<div style="float:right">' + (currentState.updateIndex + 1) + ' of ' +
     1731        '<div style="float:right">' + (g_currentState.updateIndex + 1) + ' of ' +
    17321732        + keys.length + ' tests</div><br><br>';
    17331733
     
    17441744    previousBtn.addEventListener('click',
    17451745        function() {
    1746           setUpdateIndex(currentState.updateIndex - 1, testsNeedingUpdate, keys);
     1746          setUpdateIndex(g_currentState.updateIndex - 1, testsNeedingUpdate, keys);
    17471747        },
    17481748        false);
     
    18061806function handleUpdate(testsNeedingUpdate, keys)
    18071807{
    1808     var test = keys[currentState.updateIndex];
     1808    var test = keys[g_currentState.updateIndex];
    18091809    var updates = testsNeedingUpdate[test];
    18101810    for (var builder in updates) {
     
    18301830function nextUpdate(testsNeedingUpdate, keys)
    18311831{
    1832     setUpdateIndex(currentState.updateIndex + 1, testsNeedingUpdate, keys);
     1832    setUpdateIndex(g_currentState.updateIndex + 1, testsNeedingUpdate, keys);
    18331833}
    18341834
     
    18711871        html = htmlForTestTable(html);
    18721872    } else {
    1873         if (expectationsByTest[test]) {
    1874             for (var i = 0; i < expectationsByTest[test].length; i++) {
    1875               html += '<div>' + expectationsByTest[test][i].modifiers + ' | ' +
    1876                   expectationsByTest[test][i].expectations + '</div>';
     1873        if (g_expectationsByTest[test]) {
     1874            for (var i = 0; i < g_expectationsByTest[test].length; i++) {
     1875              html += '<div>' + g_expectationsByTest[test][i].modifiers + ' | ' +
     1876                  g_expectationsByTest[test][i].expectations + '</div>';
    18771877            }
    18781878        }
     
    18871887        html += ' | ' + linkHTMLToToggleState('showLargeExpectations', 'large thumbnails');
    18881888        if (builderMaster == WEBKIT_BUILDER_MASTER) {
    1889             var revision = currentState.revision || '';
     1889            var revision = g_currentState.revision || '';
    18901890            html += '<form onsubmit="setQueryParameter(\'revision\', revision.value);' +
    18911891                'return false;">Show results for WebKit revision: ' +
     
    18971897      html += ' | <span>Results height:<input ' +
    18981898          'onchange="setQueryParameter(\'resultsHeight\',this.value)" value="' +
    1899           currentState.resultsHeight + '" style="width:2.5em">px</span>';
     1899          g_currentState.resultsHeight + '" style="width:2.5em">px</span>';
    19001900    }
    19011901    html += '</div></div>';
     
    19851985        childContainer.className = 'expectations-item';
    19861986        item.className = 'expectation ' + fileExtension;
    1987         if (currentState.showLargeExpectations)
     1987        if (g_currentState.showLargeExpectations)
    19881988            item.className += ' large';
    19891989        childContainer.appendChild(item);
     
    21992199        item.src = dummyNode.src;
    22002200        item.className = 'non-webkit-results';
    2201         item.style.height = currentState.resultsHeight + 'px';
     2201        item.style.height = g_currentState.resultsHeight + 'px';
    22022202        container.appendChild(item);
    22032203    }
     
    22112211function buildInfoForRevision(builder, revision)
    22122212{
    2213     var revisions = resultsByBuilder[builder].webkitRevision;
     2213    var revisions = g_resultsByBuilder[builder].webkitRevision;
    22142214    var revisionStart = 0, revisionEnd = 0, buildNumber = 0;
    22152215    for (var i = 0; i < revisions.length; i++) {
     
    22172217            revisionStart = revisions[i - 1];
    22182218            revisionEnd = revisions[i];
    2219             buildNumber = resultsByBuilder[builder].buildNumbers[i - 1];
     2219            buildNumber = g_resultsByBuilder[builder].buildNumbers[i - 1];
    22202220            break;
    22212221        }
     
    22392239    revisionContainer.textContent = "Showing results for: "
    22402240    expectationsContainer.appendChild(revisionContainer);
    2241     for (var builder in builders) {
     2241    for (var builder in g_builders) {
    22422242        if (getBuilderMaster(builder) == WEBKIT_BUILDER_MASTER) {
    2243             var latestRevision = currentState.revision || resultsByBuilder[builder].webkitRevision[0];
     2243            var latestRevision = g_currentState.revision || g_resultsByBuilder[builder].webkitRevision[0];
    22442244            var buildInfo = buildInfoForRevision(builder, latestRevision);
    22452245            var revisionInfo = document.createElement('div');
     
    22712271    var actualResultSuffixes = ['-actual.txt', '-actual.png', '-crash-log.txt', '-diff.txt', '-wdiff.html', '-diff.png'];
    22722272
    2273     for (var builder in builders) {
     2273    for (var builder in g_builders) {
    22742274        var actualResultsBase;
    22752275        if (getBuilderMaster(builder) == WEBKIT_BUILDER_MASTER) {
    2276             var latestRevision = currentState.revision || resultsByBuilder[builder].webkitRevision[0];
     2276            var latestRevision = g_currentState.revision || g_resultsByBuilder[builder].webkitRevision[0];
    22772277            var buildInfo = buildInfoForRevision(builder, latestRevision);
    22782278            actualResultsBase = 'http://build.webkit.org/results/' + builder +
    22792279                '/r' + buildInfo.revisionStart + ' (' + buildInfo.buildNumber + ')/';
    22802280        } else
    2281             actualResultsBase = TEST_RESULTS_BASE_PATH + builders[builder] + '/results/layout-test-results/';
     2281            actualResultsBase = TEST_RESULTS_BASE_PATH + g_builders[builder] + '/results/layout-test-results/';
    22822282
    22832283        for (var i = 0; i < actualResultSuffixes.length; i++) {
     
    23232323function appendExpectations()
    23242324{
    2325     var expectations = currentState.showExpectations ? document.getElementsByClassName('expectations') : [];
     2325    var expectations = g_currentState.showExpectations ? document.getElementsByClassName('expectations') : [];
    23262326    // Loading expectations is *very* slow. Use a large timeout to avoid
    23272327    // totally hanging the renderer.
     
    23462346        appendHTML(htmlForIndividualTests(chunk));
    23472347    }, appendExpectations, 500);
    2348     $('tests-input').value = currentState.tests;
     2348    $('tests-input').value = g_currentState.tests;
    23492349}
    23502350
     
    23742374    var extraHTML = '';
    23752375    if (!isCrossBuilderView())
    2376         extraHTML += checkboxHTML('showRunsOnBuilderPage', 'Show flakiness details', currentState.showRunsOnBuilderPage);
     2376        extraHTML += checkboxHTML('showRunsOnBuilderPage', 'Show flakiness details', g_currentState.showRunsOnBuilderPage);
    23772377
    23782378    var html = getHTMLForTestTypeSwitcher(false, extraHTML, isCrossBuilderView());
     
    23942394function linkHTMLToToggleState(key, linkText)
    23952395{
    2396     var isTrue = currentState[key];
     2396    var isTrue = g_currentState[key];
    23972397    return '<span class=link onclick="setQueryParameter(\'' + key + '\', ' +
    23982398        !isTrue + ')">' + (isTrue ? 'Hide' : 'Show') + ' ' + linkText + '</span>';
     
    24042404
    24052405    var results = g_perBuilderFailures[builderName];
    2406     sortTests(results, currentState.sortColumn, currentState.sortOrder);
     2406    sortTests(results, g_currentState.sortColumn, g_currentState.sortOrder);
    24072407
    24082408    var testsHTML = '';
     
    24562456function isInvalidKeyForCrossBuilderView(key)
    24572457{
    2458     return !(key in VALID_KEYS_FOR_CROSS_BUILDER_VIEW) && !(key in defaultCrossDashboardStateValues);
     2458    return !(key in VALID_KEYS_FOR_CROSS_BUILDER_VIEW) && !(key in g_defaultCrossDashboardStateValues);
    24592459}
    24602460
     
    24622462{
    24632463    if (isCrossBuilderView())
    2464         delete defaultStateValues.builder;
     2464        delete g_defaultStateValues.builder;
    24652465    else
    2466         defaultStateValues.builder = defaultBuilderName;
     2466        g_defaultStateValues.builder = g_defaultBuilderName;
    24672467}
    24682468
     
    24742474        if (key == 'tests') {
    24752475            // Entering cross-builder view, only keep valid keys for that view.
    2476             for (var currentKey in currentState) {
     2476            for (var currentKey in g_currentState) {
    24772477              if (isInvalidKeyForCrossBuilderView(currentKey)) {
    2478                 delete currentState[currentKey];
     2478                delete g_currentState[currentKey];
    24792479              }
    24802480            }
    24812481        } else if (isInvalidKeyForCrossBuilderView(key)) {
    2482             delete currentState.tests;
    2483             delete currentState.result;
     2482            delete g_currentState.tests;
     2483            delete g_currentState.result;
    24842484        }
    24852485    }
  • trunk/Tools/TestResultServer/static-dashboards/flakiness_dashboard_tests.js

    r90674 r91021  
    4949  allExpectations = null;
    5050  allTests = null;
    51   expectationsByTest = {};
    52   resultsByBuilder = {};
    53   builders = {};
     51  g_expectationsByTest = {};
     52  g_resultsByBuilder = {};
     53  g_builders = {};
    5454}
    5555
     
    6666 */
    6767function runExpectationsTest(builder, test, expectations, modifiers) {
    68   builders[builder] = true;
     68  g_builders[builder] = true;
    6969
    7070  // Put in some dummy results. processExpectations expects the test to be
     
    7272  var tests = {};
    7373  tests[test] = {'results': [[100, 'F']], 'times': [[100, 0]]};
    74   resultsByBuilder[builder] = {'tests': tests};
     74  g_resultsByBuilder[builder] = {'tests': tests};
    7575
    7676  processExpectations();
     
    9898    {'modifiers': 'RELEASE', 'expectations': 'FAIL'}
    9999  ];
    100   expectationsByTest[test] = expectationsArray;
     100  g_expectationsByTest[test] = expectationsArray;
    101101  runExpectationsTest(builder, test, 'FAIL', 'RELEASE');
    102102}
     
    109109    {'modifiers': 'DEBUG', 'expectations': 'CRASH'}
    110110  ];
    111   expectationsByTest[test] = expectationsArray;
     111  g_expectationsByTest[test] = expectationsArray;
    112112  runExpectationsTest(builder, test, 'FAIL', 'RELEASE');
    113113}
     
    120120    {'modifiers': 'DEBUG', 'expectations': 'CRASH'}
    121121  ];
    122   expectationsByTest[test] = expectationsArray;
     122  g_expectationsByTest[test] = expectationsArray;
    123123  runExpectationsTest(builder, test, 'CRASH', 'DEBUG');
    124124}
     
    126126function testOverrideJustBuildType() {
    127127  var test = 'bar/1.html';
    128   expectationsByTest['bar'] = [
     128  g_expectationsByTest['bar'] = [
    129129    {'modifiers': 'WONTFIX', 'expectations': 'FAIL PASS TIMEOUT'}
    130130  ];
    131   expectationsByTest[test] = [
     131  g_expectationsByTest[test] = [
    132132    {'modifiers': 'WONTFIX MAC', 'expectations': 'FAIL'},
    133133    {'modifiers': 'LINUX DEBUG', 'expectations': 'CRASH'},
  • trunk/Tools/TestResultServer/static-dashboards/timeline_explorer.html

    r90674 r91021  
    113113  function generatePage() {
    114114    buildIndicesByTimestamp = {};
    115     var results = resultsByBuilder[currentState.builder];
     115    var results = g_resultsByBuilder[g_currentState.builder];
    116116
    117117    for (var i = 0; i < results[FIXABLE_COUNTS_KEY].length; i++) {
     
    120120    }
    121121
    122     if (currentState.buildTimestamp != -1 &&
    123         currentState.buildTimestamp in buildIndicesByTimestamp) {
     122    if (g_currentState.buildTimestamp != -1 &&
     123        g_currentState.buildTimestamp in buildIndicesByTimestamp) {
    124124        var newBuildIndex =
    125             buildIndicesByTimestamp[currentState.buildTimestamp];
     125            buildIndicesByTimestamp[g_currentState.buildTimestamp];
    126126
    127127        if (newBuildIndex == currentBuildIndex) {
     
    141141        false,
    142142        checkboxHTML('ignoreFlakyTests', 'Ignore flaky tests',
    143             currentState.ignoreFlakyTests, 'currentBuildIndex = -1')
     143            g_currentState.ignoreFlakyTests, 'currentBuildIndex = -1')
    144144    );
    145145
     
    150150    var startTime = Date.now();
    151151    currentBuilderTestResults =
    152         getTestResultsByBuild(resultsByBuilder[currentState.builder]);
     152        getTestResultsByBuild(g_resultsByBuilder[g_currentState.builder]);
    153153    console.log(
    154154        'Time to get test results by build: ' + (Date.now() - startTime));
     
    158158    switch(key) {
    159159      case 'buildTimestamp':
    160         currentState.buildTimestamp = parseInt(value, 10);
     160        g_currentState.buildTimestamp = parseInt(value, 10);
    161161        return true;
    162162      case 'ignoreFlakyTests':
    163         currentState.ignoreFlakyTests = value == 'true';
     163        g_currentState.ignoreFlakyTests = value == 'true';
    164164        return true;
    165165      default:
     
    168168  }
    169169
    170   defaultStateValues = {
     170  g_defaultStateValues = {
    171171    buildTimestamp: -1,
    172     builder: defaultBuilderName,
     172    builder: g_defaultBuilderName,
    173173    ignoreFlakyTests: true
    174174  };
    175175
    176176  function updateTimelineForBuilder() {
    177     var builder = currentState.builder;
    178     var results = resultsByBuilder[builder];
     177    var builder = g_currentState.builder;
     178    var results = g_resultsByBuilder[builder];
    179179    var graphData = [];
    180180
     
    188188      var failureCount = Math.min(results[FIXABLE_COUNT_KEY][i], 10000);
    189189
    190       if (currentState.ignoreFlakyTests) {
     190      if (g_currentState.ignoreFlakyTests) {
    191191        failureCount -=
    192192            currentBuilderTestResults.flakyDeltasByBuild[i].total || 0;
     
    300300      var resultsUrl =
    301301          'http://build.chromium.org/f/chromium/layout_test_results/' +
    302           builders[builder] + '/' + results[CHROME_REVISIONS_KEY][index];
     302          g_builders[builder] + '/' + results[CHROME_REVISIONS_KEY][index];
    303303    }
    304304
     
    337337        var previousCount =
    338338            results[FIXABLE_COUNTS_KEY][index + 1][expectationKey];
    339         if (currentState.ignoreFlakyTests) {
     339        if (g_currentState.ignoreFlakyTests) {
    340340          currentCount -= flakyDeltasByBuild[index][expectationKey] || 0;
    341341          previousCount -= flakyDeltasByBuild[index + 1][expectationKey] || 0;
     
    348348    var currentTotal = results[FIXABLE_COUNT_KEY][index];
    349349    var previousTotal = results[FIXABLE_COUNT_KEY][index + 1];
    350     if (currentState.ignoreFlakyTests) {
     350    if (g_currentState.ignoreFlakyTests) {
    351351      currentTotal -= flakyDeltasByBuild[index].total || 0;
    352352      previousTotal -= flakyDeltasByBuild[index + 1].total || 0;
     
    388388    var deltas = {};
    389389    function addDelta(category, testIndex) {
    390       if (currentState.ignoreFlakyTests && flakyTests[testIndex]) {
     390      if (g_currentState.ignoreFlakyTests && flakyTests[testIndex]) {
    391391        return;
    392392      }
     
    464464      case 'Left':
    465465        selectBuild(
    466             resultsByBuilder[currentState.builder],
    467             currentState.builder,
     466            g_resultsByBuilder[g_currentState.builder],
     467            g_currentState.builder,
    468468            dygraph,
    469469            currentBuildIndex + 1);
     
    471471      case 'Right':
    472472        selectBuild(
    473             resultsByBuilder[currentState.builder],
    474             currentState.builder,
     473            g_resultsByBuilder[g_currentState.builder],
     474            g_currentState.builder,
    475475            dygraph,
    476476            currentBuildIndex - 1);
  • trunk/Tools/TestResultServer/static-dashboards/treemap.html

    r90674 r91021  
    155155}
    156156
    157 var resultsByBuilder = {};
     157var g_resultsByBuilder = {};
    158158
    159159function ADD_RESULTS(data) {
    160160  // TODO(ojan): We should probably include the builderName in the JSON
    161161  // rather than relying on only loading one JSON file per page.
    162   if (!resultsByBuilder[currentState.builder])
    163     resultsByBuilder[currentState.builder] = data;
     162  if (!g_resultsByBuilder[g_currentState.builder])
     163    g_resultsByBuilder[g_currentState.builder] = data;
    164164
    165165  handleLocationChange();
     
    169169
    170170function generatePage() {
    171   if (!resultsByBuilder[currentState.builder]) {
    172     handleResourceLoadError(currentState.builder);
     171  if (!g_resultsByBuilder[g_currentState.builder]) {
     172    handleResourceLoadError(g_currentState.builder);
    173173    return;
    174174  }
     
    176176  isGeneratingPage = true;
    177177
    178   var rawTree = resultsByBuilder[currentState.builder];
     178  var rawTree = g_resultsByBuilder[g_currentState.builder];
    179179  var webtree = convertToWebTreemapFormat('LayoutTests', rawTree);
    180180  appendTreemap($('map'), webtree);
    181181
    182   if (currentState.treemapfocus)
    183     focusPath(webtree, currentState.treemapfocus)
     182  if (g_currentState.treemapfocus)
     183    focusPath(webtree, g_currentState.treemapfocus)
    184184
    185185  isGeneratingPage = false;
     
    214214  switch(key) {
    215215    case 'builder':
    216       validateParameter(currentState, key, value,
     216      validateParameter(g_currentState, key, value,
    217217          function() {
    218             return value in builders;
     218            return value in g_builders;
    219219          });
    220220
     
    222222
    223223    case 'treemapfocus':
    224       validateParameter(currentState, key, value,
     224      validateParameter(g_currentState, key, value,
    225225          function() {
    226226            // TODO(ojan): There's probably a simpler regexp here. Just trying to match ascii + forward-slash.
     
    236236}
    237237
    238 defaultStateValues = {
    239   builder: defaultBuilderName
     238g_defaultStateValues = {
     239  builder: g_defaultBuilderName
    240240};
    241241
    242242function handleQueryParameterChange(params) {
    243   if (!resultsByBuilder[currentState.builder])
    244     appendJSONScriptElementFor(currentState.builder);
     243  if (!g_resultsByBuilder[g_currentState.builder])
     244    appendJSONScriptElementFor(g_currentState.builder);
    245245
    246246  for (var param in params) {
     
    257257  $('map').innerHTML = '<span class=error>Could not load data for ' + builderName + '. ' +
    258258      'Either there was a server-side error or ' + builderName + ' does not run ' +
    259       currentState.testType + '.</span>';
     259      g_currentState.testType + '.</span>';
    260260}
    261261
     
    306306
    307307parseParameters();
    308 appendJSONScriptElementFor(currentState.builder);
     308appendJSONScriptElementFor(g_currentState.builder);
    309309</script>
Note: See TracChangeset for help on using the changeset viewer.