Chromium Code Reviews| Index: webkit/tools/layout_tests/flakiness_dashboard.html |
| =================================================================== |
| --- webkit/tools/layout_tests/flakiness_dashboard.html (revision 26455) |
| +++ webkit/tools/layout_tests/flakiness_dashboard.html (working copy) |
| @@ -88,7 +88,7 @@ |
| border: 2px solid grey; |
| background-color: white; |
| } |
| - #legend * { |
| + #legend-contents * { |
| margin: 3px; |
| padding: 0 2px; |
| } |
| @@ -131,7 +131,7 @@ |
| .merge { |
| background-color: green; |
| } |
| - :not(#legend) > .merge { |
| + :not(#legend-contents) > .merge { |
| width: 1px; |
| } |
| .separator { |
| @@ -169,8 +169,6 @@ |
| } |
| #popup { |
| background-color: white; |
| - overflow: hidden; |
| - width: 250px; |
| z-index: 1; |
| position: absolute; |
| border: 3px solid grey; |
| @@ -181,7 +179,6 @@ |
| -moz-border-radius: 5px; |
| } |
| #popup > * { |
|
arv (Not doing code reviews)
2009/09/18 02:35:24
remove empty rule?
|
| - width: 100%; |
| } |
| #popup > ul { |
| margin: 0; |
| @@ -244,6 +241,8 @@ |
| // path used in test_expectations.txt rather than the test path since we |
| // don't actually have any data here for skipped tests. |
| var perBuilderSkippedPaths = {}; |
| + // Maps test path to an array of {builder, testResults} objects. |
| + var testToResultsMap = {}; |
| // Generic utility functions. |
| function $(id) { |
| @@ -340,6 +339,7 @@ |
| sortColumn: 'flakiness', |
| showWontFix: false, |
| showCorrectExpectations: false, |
| + showLegend: true, |
| showFlaky: true, |
| showSkipped: false, |
| maxResults: 200, |
| @@ -418,6 +418,7 @@ |
| case 'showWontFix': |
| case 'showCorrectExpectations': |
| case 'showFlaky': |
| + case 'showLegend': |
| currentState[key] = value == 'true'; |
| return true; |
| @@ -442,8 +443,6 @@ |
| // Append JSON script elements. |
| var resultsByBuilder = {}; |
| - // Maps test path to an array of {builder, testResults} objects. |
| - var testToResultsMap = {}; |
| var expectationsByTest = {}; |
| function ADD_RESULTS(builds) { |
| for (var builderName in builds) { |
| @@ -793,7 +792,11 @@ |
| var unexpectedExpectations = []; |
| var resultsMap = {} |
| - for (var i = 0; i < rawResults.length; i++) { |
| + var numResultsSeen = 0; |
| + for (var i = 0; |
| + i < rawResults.length && numResultsSeen < currentState.maxResults; |
| + i++) { |
| + numResultsSeen += rawResults[i][0]; |
| var expectation = getExpectationsFileStringForResult(rawResults[i][1]); |
| resultsMap[expectation] = true; |
| } |
| @@ -818,7 +821,11 @@ |
| } |
| var times = resultsByBuilder[builderName].tests[test].times; |
| - for (var i = 0; i < times.length; i++) { |
| + var numResultsSeen = 0; |
| + for (var i = 0; |
| + i < times.length && numResultsSeen < currentState.maxResults; |
| + i++) { |
| + numResultsSeen += times[i][0]; |
| resultsForTest.slowestTime = Math.max(resultsForTest.slowestTime, |
| times[i][1]); |
| } |
| @@ -877,10 +884,26 @@ |
| } |
| function getLinkHTMLToOpenWindow(url, text) { |
| - return '<li class=link onclick="window.open(\'' + url + '\')">' + text + |
| - '</li>'; |
| + return '<div class=link onclick="window.open(\'' + url + '\')">' + text + |
| + '</div>'; |
| } |
| + function createBlameListHTML(revisions, index, urlBase, separator, repo) { |
| + var thisRevision = revisions[index]; |
| + if (!thisRevision) |
| + return ''; |
| + |
| + var previousRevision = revisions[index + 1]; |
| + if (previousRevision && previousRevision != thisRevision) { |
| + previousRevision++; |
| + return getLinkHTMLToOpenWindow( |
| + urlBase + thisRevision + separator + previousRevision, |
| + repo + ' blamelist r' + previousRevision + ':r' + thisRevision); |
| + } else { |
| + return 'At ' + repo + ' revision: ' + thisRevision; |
| + } |
| + } |
| + |
| function showPopupForBuild(e, builder, index) { |
| var html = ''; |
| @@ -890,42 +913,34 @@ |
| html += date.toLocaleDateString() + ' ' + date.toLocaleTimeString(); |
| } |
| - html += '<ul>'; |
| + html += '<ul><li>' + |
| + createBlameListHTML(resultsByBuilder[builder].webkitRevision, index, |
| + 'http://trac.webkit.org/log/?rev=', '&stop_rev=', 'WebKit') + |
| + '</li><li>' + |
| + createBlameListHTML(resultsByBuilder[builder].chromeRevision, index, |
| + 'http://build.chromium.org/buildbot/perf/dashboard/ui/' + |
| + 'changelog.html?url=/trunk/src&mode=html&range=', ':', 'Chrome') + |
| + '</li>'; |
| - var webkitRevision = resultsByBuilder[builder].webkitRevision; |
| - var thisWebkitRevision = webkitRevision[index]; |
| - if (thisWebkitRevision) { |
| - var previousWebkitRevision = webkitRevision[index + 1] || |
| - thisWebkitRevision; |
| - html += getLinkHTMLToOpenWindow('http://trac.webkit.org/log/?rev=' + |
| - thisWebkitRevision + '&stop_rev=' + previousWebkitRevision, |
| - 'WebKit blamelist r' + previousWebkitRevision + ':r' + |
| - thisWebkitRevision); |
| + var chromeRevision = resultsByBuilder[builder].chromeRevision[index]; |
| + if (chromeRevision) { |
| + html += '<li><a href="' + TEST_RESULTS_BASE_PATH + builders[builder] + |
| + '/' + chromeRevision + '/layout-test-results.zip' + |
| + '">layout-test-results.zip</a></li>'; |
| } |
| - var chromeRevision = resultsByBuilder[builder].chromeRevision; |
| - var thisChromeRevision = chromeRevision[index]; |
| - if (thisChromeRevision) { |
| - var previousChromeRevision = chromeRevision[index + 1] || |
| - thisChromeRevision; |
| - html += getLinkHTMLToOpenWindow( |
| - 'http://build.chromium.org/buildbot/perf/dashboard/ui/' + |
| - 'changelog.html?url=/trunk/src&mode=html&range=' + |
| - previousChromeRevision + ':' + thisChromeRevision, |
| - 'Chrome blamelist r' + previousChromeRevision + ':r' + |
| - thisChromeRevision) + |
| - getLinkHTMLToOpenWindow(TEST_RESULTS_BASE_PATH + builders[builder] + |
| - '/' + thisChromeRevision + '/layout-test-results.zip', |
| - 'layout-test-results.zip'); |
| - } |
| - |
| var buildNumbers = resultsByBuilder[builder].buildNumbers; |
| - html += getLinkHTMLToOpenWindow(BUILDERS_BASE_PATH + builder + '/builds/' + |
| - buildNumbers[index], 'Build log and blamelist') + '</ul>'; |
| + html += '<li>' + |
| + getLinkHTMLToOpenWindow(BUILDERS_BASE_PATH + builder + '/builds/' + |
| + buildNumbers[index], 'Build log and blamelist') + '</li></ul>'; |
| showPopup(e, html); |
| } |
| + function showPopupForTest(e, test) { |
| + showPopup(e, getHTMLForIndividulTestOnAllBuilders(test)); |
| + } |
| + |
| function getHtmlForTestResults(test, builder) { |
| var html = ''; |
| var results = test.rawResults.concat(); |
| @@ -1024,12 +1039,15 @@ |
| if (testResult.isFixedTest === undefined) { |
| var results = testResult.rawResults; |
| var isFixedTest = results[0][1] == 'P'; |
| - if (isFixedTest && results.length > 1) { |
| - var secondResult = results[1][1]; |
| - isFixedTest = secondResult == 'S' || secondResult == 'F' || |
| - secondResult == 'I'; |
| + var numResults = results[0][0]; |
| + if (numResults < currentState.maxResults && |
| + isFixedTest && results.length > 1) { |
| + // We don't care what the value of the second set of results is, just |
| + // how many results there are. |
| + numResults += results[1][0]; |
| } |
| - if (isFixedTest && results.length > 2) { |
| + if (numResults < currentState.maxResults && |
| + isFixedTest && results.length > 2) { |
| isFixedTest = results.length == 3 && results[2][1] == 'N'; |
| } |
| testResult.isFixedTest = isFixedTest; |
| @@ -1071,7 +1089,7 @@ |
| // with results for many builders, so the first column is builder names |
| // instead of test paths. |
| var testCellHTML = opt_isCrossBuilderView ? builder : |
| - '<span class="link" onclick="setState(\'tests\', \'' + test.test + |
| + '<span class="link" onclick="showPopupForTest(event, \'' + test.test + |
| '\');return false;">' + test.test + '</span>'; |
| return '<tr class="' + |
| @@ -1207,34 +1225,39 @@ |
| tableHeaders.unshift('test'); |
| generatePageForBuilder(currentState.builder); |
| } |
| + |
| + $('max-results-input').value = currentState.maxResults; |
| + updateLegendDisplay(); |
| } |
| - function generatePageForIndividualTests(tests) { |
| - // TODO: Add link to trac from individual test page |
| - // TODO: Make links on builder pages to tests be to the individual test page |
| + function getHTMLForIndividulTestOnAllBuilders(test) { |
| for (var builder in builders) |
| processTestRunsForBuilder(builder); |
| - var html = getHTMLForNavBar() + |
| - '<b>IF A BUILDER IS NOT LISTED THAT MEANS THE ' + |
| - 'BUILDER DOES NOT RUN THAT TEST OR ALL RUNS OF THE TEST PASSED.</b>'; |
| + var testResults = testToResultsMap[test]; |
| + if (testResults && testResults.length) { |
| + var tracURL = TEST_URL_BASE_PATH + test |
| + var html = getLinkHTMLToOpenWindow(tracURL, tracURL) + |
| + '<div><b>If a builder is not listed, that means the builder does ' + |
| + 'run that tst or all runs of the test passed.</b></div>'; |
|
arv (Not doing code reviews)
2009/09/18 02:35:24
s/tst/test/
|
| - for (var i = 0; i < tests.length; i++) { |
| - html += '<h2>' + tests[i] + '</h2>'; |
| - |
| - var testResults = testToResultsMap[tests[i]]; |
| - if (testResults && testResults.length) { |
| - var tableRowsHTML = ''; |
| - for (var j = 0; j < testResults.length; j++) { |
| - tableRowsHTML += getHTMLForSingleTestRow(testResults[j].results, |
| - testResults[j].builder, true); |
| - } |
| - html += getHTMLForTestTable(tableRowsHTML); |
| - } else { |
| - html +='<div class="not-found">Test not found. Either it does not ' + |
| - 'exist or it passes on all platforms.</div>'; |
| + for (var j = 0; j < testResults.length; j++) { |
| + html += getHTMLForSingleTestRow(testResults[j].results, |
| + testResults[j].builder, true); |
| } |
| + return getHTMLForTestTable(html); |
| + } else { |
| + return '<div class="not-found">Test not found. Either it does not ' + |
| + 'exist or it passes on all platforms.</div>'; |
| } |
| + } |
| + |
| + function generatePageForIndividualTests(tests) { |
| + var html = getHTMLForNavBar(); |
| + for (var i = 0; i < tests.length; i++) { |
| + html += '<h2>' + tests[i] + '</h2>' + |
| + getHTMLForIndividulTestOnAllBuilders(tests[i]); |
| + } |
| setFullPageHTML(html); |
| $('tests-input').value = currentState.tests; |
| @@ -1253,15 +1276,21 @@ |
| 'onsubmit="setState(\'tests\', tests.value);return false;">' + |
| '<div>Show tests on all platforms (slow): </div><input name=tests ' + |
| 'placeholder="LayoutTests/foo/bar.html,LayoutTests/foo/baz.html" ' + |
| - 'id=tests-input></form><div id="loading-ui">LOADING...</div>' + |
| - '<div id=legend>'; |
| + 'id=tests-input></form>' + |
| + '<form id=max-results-form ' + |
| + 'onsubmit="setState(\'maxResults\', maxResults.value);return false;"' + |
| + '><span>Number of results to show (max=500): </span>' + |
| + '<input name=maxResults id=max-results-input></form>' + |
| + '<div id="loading-ui">LOADING...</div><div id=legend>' + |
| + '<div id=legend-toggle>' + getLinkHTMLToToggleLegendDisplay() + |
| + '</div><div id=legend-contents>'; |
| for (var expectation in EXPECTATIONS_MAP) { |
| html += '<div class=' + expectation + '>' + |
| EXPECTATIONS_MAP[expectation] + '</div>'; |
| } |
| return html + '<div class=wrong-expectations>WRONG EXPECTATIONS</div>' + |
| - '<div class=merge>WEBKIT MERGE</div></div>'; |
| + '<div class=merge>WEBKIT MERGE</div></div></div>'; |
| } |
| function getLinkHTMLToToggleState(key, linkText) { |
| @@ -1290,11 +1319,7 @@ |
| getLinkHTMLToToggleState('showCorrectExpectations', |
| 'tests with correct expectations') + ' | ' + |
| getLinkHTMLToToggleState('showFlaky', 'flaky tests') + ' | ' + |
| - '<form id=max-results-form ' + |
| - 'onsubmit="setState(\'maxResults\', maxResults.value);return false;"' + |
| - '><span>Number of results to show: </span>' + |
| - '<input name=maxResults id=max-results-input></form> | ' + |
| - '<b>All columns are sortable. | Skipped tests are not listed. | ' + |
| + '<b>All columns are sortable. | ' + |
| 'Flakiness reader order is newer --> older runs.</b></div>' + |
| testsHTML; |
| @@ -1305,31 +1330,74 @@ |
| ths[i].addEventListener('click', changeSort, false); |
| ths[i].className = "sortable"; |
| } |
| + } |
| - $('max-results-input').value = currentState.maxResults; |
| + function getLinkHTMLToToggleLegendDisplay() { |
| + return getLinkHTMLToToggleState('showLegend', 'Legend'); |
| } |
| + function updateLegendDisplay() { |
| + $('legend-contents').style.display = currentState.showLegend ? '' : 'none'; |
| + } |
| + |
| /** |
| + * Clears the processed test state for perBuilderFailures. |
| + * TODO(ojan): This really should probably clear all the state we've |
| + * generated, but that's kind of a pain given the many global objects state is |
| + * stored in. There should probably be one global generatedState |
| + * object that all the generated state lives off of. |
| + */ |
| + function clearProcessedTestState() { |
| + for (var builder in builders) { |
| + delete perBuilderFailures[builder]; |
| + delete perBuilderPlatformAndBuildType[builder]; |
| + delete perBuilderWithExpectationsButNoFailures[builder]; |
| + delete perBuilderSkippedPaths[builder]; |
| + } |
| + |
| + for (var key in testToResultsMap) { |
| + delete testToResultsMap[key] |
| + } |
| + } |
| + |
| + /** |
| * Sets the page state and regenerates the page. Takes varargs of key, value |
| * pairs. |
| */ |
| function setState(key, value) { |
| for (var i = 0; i < arguments.length; i = i + 2) { |
| var key = arguments[i]; |
| - if (key != 'tests') { |
| + if (key != 'tests' && key != 'maxResults') { |
| delete currentState.tests; |
| } |
| + if (key == 'maxResults') { |
| + // Processing the test results JSON makes assumptions about the number |
| + // of results to show. This makes changing the number of maxResults slow |
| + // but is considerably easier than refactoring all the other code. |
| + clearProcessedTestState(); |
| + } |
| + |
| currentState[key] = arguments[i + 1]; |
| } |
| window.location.replace(getPermaLinkURL()); |
| - handleLocationChange(); |
| + if (key == 'showLegend') { |
| + saveStoredWindowLocation(); |
| + updateLegendDisplay(); |
| + $('legend-toggle').innerHTML = getLinkHTMLToToggleLegendDisplay(); |
| + } else { |
| + handleLocationChange(); |
| + } |
| } |
| + function saveStoredWindowLocation() { |
| + oldLocation = window.location.href; |
| + } |
| + |
| function handleLocationChange() { |
| $('loading-ui').style.display = 'block'; |
| setTimeout(function() { |
| - oldLocation = window.location.href; |
| + saveStoredWindowLocation(); |
| generatePage(); |
| }, 0); |
| } |
| @@ -1370,12 +1438,14 @@ |
| var x = Math.min(targetRect.left - 10, |
| document.documentElement.clientWidth - popup.offsetWidth); |
| + x = Math.max(0, x); |
| popup.style.left = x + document.body.scrollLeft + 'px'; |
| var y = targetRect.top + targetRect.height; |
| if (y + popup.offsetHeight > document.documentElement.clientHeight) { |
| y = targetRect.top - popup.offsetHeight; |
| } |
| + y = Math.max(0, y); |
| popup.style.top = y + document.body.scrollTop + 'px'; |
| } |