diff options
3 files changed, 129 insertions, 25 deletions
diff --git a/webkit/tools/layout_tests/dashboards/dashboard_base.js b/webkit/tools/layout_tests/dashboards/dashboard_base.js index 5a1404a8b..a98283a 100644 --- a/webkit/tools/layout_tests/dashboards/dashboard_base.js +++ b/webkit/tools/layout_tests/dashboards/dashboard_base.js @@ -319,11 +319,15 @@ function setQueryParameter(var_args) { for (var i = 0; i < arguments.length; i += 2) { currentState[arguments[i]] = arguments[i + 1]; } - window.location.replace(getPermaLinkURL()); + // Note: We use window.location.hash rather that window.location.replace + // because of bugs in Chrome where extra entries were getting created + // when back button was pressed and full page navigation was occuring. + // TODO: file those bugs. + window.location.hash = getPermaLinkURLHash(); } -function getPermaLinkURL() { - return window.location.pathname + '#' + joinParameters(currentState); +function getPermaLinkURLHash() { + return '#' + joinParameters(currentState); } function joinParameters(stateObject) { @@ -372,6 +376,41 @@ function showPopup(e, html) { popup.style.top = y + document.body.scrollTop + 'px'; } +/** + * Create a new function with some of its arguements + * pre-filled. + * Taken from goog.partial in the Closure library. + * @param {Function} fn A function to partially apply. + * @param {...*} var_args Additional arguments that are partially + * applied to fn. + * @return {!Function} A partially-applied form of the function bind() was + * invoked as a method of. + */ +function partial(fn, var_args) { + var args = Array.prototype.slice.call(arguments, 1); + return function() { + // Prepend the bound arguments to the current arguments. + var newArgs = Array.prototype.slice.call(arguments); + newArgs.unshift.apply(newArgs, args); + return fn.apply(this, newArgs); + }; +}; + +/** + * Returns the keys of the object/map/hash. + * Taken from goog.object.getKeys in the Closure library. + * + * @param {Object} obj The object from which to get the keys. + * @return {!Array.<string>} Array of property keys. + */ +function getKeys(obj) { + var res = []; + for (var key in obj) { + res.push(key); + } + return res; +} + appendJSONScriptElements(); document.addEventListener('mousedown', function(e) { diff --git a/webkit/tools/layout_tests/flakiness_dashboard.html b/webkit/tools/layout_tests/flakiness_dashboard.html index 7a57941..a385808 100644 --- a/webkit/tools/layout_tests/flakiness_dashboard.html +++ b/webkit/tools/layout_tests/flakiness_dashboard.html @@ -359,7 +359,8 @@ return true; case 'maxResults': - validateParameter(currentState, key, value, + case 'updateIndex': + validateParameter(currentState, key, Number(value), function() { return value.match(/^\d+$/); }); @@ -397,7 +398,8 @@ showWontFixSkip: false, showSlow: false, showSkipped: false, - expectationsUpdate: false + expectationsUpdate: false, + updateIndex: 0 }; ////////////////////////////////////////////////////////////////////////////// @@ -418,6 +420,8 @@ // Maps test path to an array of {builder, testResults} objects. var testToResultsMap = {}; var numFlakyTestsPerBuilder = {}; + // Tests that the user wants to update expectations for. + var confirmedTests = {}; function createResultsObjectForTest(test, builder) { return { @@ -1511,30 +1515,91 @@ } } - var confirmedTests = {}; - var NUM_UPDATES_BEFORE_BREAK = 20; - var i = 0; - for (test in testsNeedingUpdate) { - i++ - // To maintain sanity when doing updates, give a chance to break out of - // the confirm loop every once in a while. - if (!(i % NUM_UPDATES_BEFORE_BREAK)) { - if (!confirm('Processed ' + i + - ' updates. Continue processing updates?')) - break; - } + var keys = getKeys(testsNeedingUpdate); + showUpdateInfoForTest(testsNeedingUpdate, keys); + } + + /** + * Show the test results and the json for differing expectations, and + * allow the user to include or exclude this update. + * + * @param {Object} testsNeedingUpdate Tests that need updating. + * @param {Array.<string>} keys Keys into the testNeedingUpdate object. + */ + function showUpdateInfoForTest(testsNeedingUpdate, keys) { + var test = keys[currentState.updateIndex]; + document.body.innerHTML = '<b>' + test + '</b><br><br>'; + + var buttonRegion = document.createElement('div'); + var includeBtn = document.createElement('input'); + includeBtn.type = 'button'; + includeBtn.value = 'include'; + includeBtn.addEventListener('click', + partial(handleUpdate, true, testsNeedingUpdate, keys), + false); + buttonRegion.appendChild(includeBtn); + + var excludeBtn = document.createElement('input'); + excludeBtn.type = 'button'; + excludeBtn.value = 'exclude'; + excludeBtn.addEventListener('click', + partial(handleUpdate, false, testsNeedingUpdate, keys), + false); + buttonRegion.appendChild(excludeBtn); + + var doneBtn = document.createElement('input'); + doneBtn.type = 'button'; + doneBtn.value = 'done'; + doneBtn.addEventListener('click', finishUpdate, false); + buttonRegion.appendChild(doneBtn); + + document.body.appendChild(buttonRegion); + + var confirmStr = JSON.stringify(testsNeedingUpdate[test], null, 4); + + var pre = document.createElement('pre'); + pre.innerHTML = confirmStr; + document.body.appendChild(pre); + var div = document.createElement('div'); + div.innerHTML = getHTMLForIndividulTestOnAllBuilders(test); + document.body.appendChild(div); + } - document.body.innerHTML = getHTMLForIndividulTestOnAllBuilders(test); - var confirmStr = 'Include this update?\n' + - JSON.stringify(testsNeedingUpdate[test], null, 4); - if (confirm(confirmStr)) { - confirmedTests[test] = testsNeedingUpdate[test]; - } - } + /** + * When the user has finished selecting expectations to update, provide them + * with json to copy over. + * TODO(jparent): This could also probably spit out instructinos on what to + * do next. + */ + function finishUpdate() { document.body.innerHTML = JSON.stringify(confirmedTests); } + /** + * Handle user click on either "include" or "exclude" buttons. + * @param {boolean} isAccepted Whether the user accepted this update. + * @param {Object} testsNeedingUpdate Tests that need updating. + * @param {Array.<string>} keys Keys into the testNeedingUpdate object. + * + */ + function handleUpdate(isAccepted, testsNeedingUpdate, keys) { + var test = keys[currentState.updateIndex]; + if (isAccepted) { + confirmedTests[test] = testsNeedingUpdate[test]; + } else if (confirmedTests[test]) { + delete confirmedTests[test]; + } + + setState("updateIndex", currentState.updateIndex + 1); + + if (currentState.updateIndex < keys.length) { + showUpdateInfoForTest(testsNeedingUpdate, keys); + } else { + finishUpdate(); + } + } + function getHTMLForIndividulTestOnAllBuilders(test) { createTableHeadersArray('builder'); processTestRunsForAllBuilders(); diff --git a/webkit/tools/layout_tests/update_expectations_from_dashboard.py b/webkit/tools/layout_tests/update_expectations_from_dashboard.py index 1866b1e..40c5521 100644 --- a/webkit/tools/layout_tests/update_expectations_from_dashboard.py +++ b/webkit/tools/layout_tests/update_expectations_from_dashboard.py @@ -9,7 +9,7 @@ and apply them to test_expectations.txt. Usage: 1. Go to http://src.chromium.org/viewvc/chrome/trunk/src/webkit/tools/layout_tests/flakiness_dashboard.html#expectationsUpdate=true 2. Copy-paste that JSON into a local file. -3. python update_expectations_from_dashboard.py --update-json-file path/to/local/file +3. python update_expectations_from_dashboard.py path/to/local/file """ import logging |