Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(360)

Side by Side Diff: webkit/tools/layout_tests/flakiness_dashboard.html

Issue 243104: Make the legend show on '?' keypresses and hide on escape. Make it hidden... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 11 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 <!DOCTYPE HTML> 1 <!DOCTYPE HTML>
2 <html> 2 <html>
3 3
4 <head> 4 <head>
5 <title>Webkit Layout Test History</title> 5 <title>Webkit Layout Test History</title>
6 <style> 6 <style>
7 body { 7 body {
8 font-family: arial; 8 font-family: arial;
9 font-size: 13px; 9 font-size: 13px;
10 } 10 }
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
74 .results { 74 .results {
75 cursor: pointer; 75 cursor: pointer;
76 padding: 0; 76 padding: 0;
77 font-size: 10px; 77 font-size: 10px;
78 text-align: center; 78 text-align: center;
79 } 79 }
80 #legend { 80 #legend {
81 position: fixed; 81 position: fixed;
82 top: 5px; 82 top: 5px;
83 right: 5px; 83 right: 5px;
84 width: 130px; 84 width: 200px;
85 padding: 2px;
85 border: 2px solid grey; 86 border: 2px solid grey;
86 background-color: white; 87 background-color: white;
87 } 88 }
88 #legend-contents * { 89 #legend-contents * {
89 margin: 3px; 90 margin: 3px 0;
90 padding: 0 2px; 91 padding: 0 2px;
91 } 92 }
92 body > div > :not(#legend) {
93 margin-right: 145px;
94 }
95 #builders * { 93 #builders * {
96 margin: 0 5px; 94 margin: 0 5px;
97 display: inline-block; 95 display: inline-block;
98 white-space: nowrap; 96 white-space: nowrap;
99 } 97 }
100 .test-table .wrong-expectations, 98 .test-table .wrong-expectations,
101 .wrong-expectations { 99 .wrong-expectations {
102 background-color: #pink; 100 background-color: #pink;
103 } 101 }
104 .P { 102 .P {
(...skipping 16 matching lines...) Expand all
121 } 119 }
122 .F { 120 .F {
123 background-color: #e98080; 121 background-color: #e98080;
124 } 122 }
125 .O { 123 .O {
126 background-color: #69f; 124 background-color: #69f;
127 } 125 }
128 .merge { 126 .merge {
129 background-color: grey; 127 background-color: grey;
130 } 128 }
131 :not(#legend-contents) > .merge { 129 table .merge {
132 width: 1px; 130 width: 1px;
133 } 131 }
134 .separator { 132 .separator {
135 border: 1px solid lightgray; 133 border: 1px solid lightgray;
136 height: 0px; 134 height: 0px;
137 } 135 }
138 .different-platform { 136 .different-platform {
139 color: gray; 137 color: gray;
140 font-size: 10px; 138 font-size: 10px;
141 } 139 }
(...skipping 30 matching lines...) Expand all
172 padding: 3px; 170 padding: 3px;
173 -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.5); 171 -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.5);
174 -moz-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.5); 172 -moz-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.5);
175 -webkit-border-radius: 5px; 173 -webkit-border-radius: 5px;
176 -moz-border-radius: 5px; 174 -moz-border-radius: 5px;
177 } 175 }
178 #popup > ul { 176 #popup > ul {
179 margin: 0; 177 margin: 0;
180 padding-left: 20px; 178 padding-left: 20px;
181 } 179 }
180 .expectations-container {
181 clear: both;
182 }
183 .expectations-item {
184 float: left;
185 border: 1px solid grey;
186 }
187 .expectations-item .expectation {
188 width: 400px;
189 height: 300px;
190 border: 0;
191 border-top: 1px solid grey;
192 }
193 .expectations-item .large {
194 width: 800px;
195 height: 600px;
196 }
197 .expectations-item .checksum {
198 height: 30px;
199 }
200 .fallback-list {
201 margin-top: 0;
202 }
203 .used-platform {
204 float: right;
205 color: darkblue;
206 margin: 0 5px;
207 }
208 .expectations-title {
209 /* Hack to make a containing block for absolute positioned elements. */
210 position: relative;
211 overflow: hidden;
212 }
213 .title {
214 /* Position absolutely so the container does not grow to contain this. */
215 position: absolute;
216 }
217 .platforms {
218 position: absolute;
219 background-color: white;
220 right: 0;
221 z-index: 1;
222 }
182 </style> 223 </style>
183 224
184 <script src="dashboards/dashboard_base.js"></script> 225 <script src="dashboards/dashboard_base.js"></script>
185 <script> 226 <script>
186 /** 227 /**
187 * @fileoverview Creates a dashboard for multiple runs of a given set of tests 228 * @fileoverview Creates a dashboard for multiple runs of a given set of tests
188 * on the buildbots. Pulls in JSONP-ish files with the results for running 229 * on the buildbots. Pulls in JSONP-ish files with the results for running
189 * tests on a given builder (i.e. ADD_RESULTS(json_here)) and the expectations 230 * tests on a given builder (i.e. ADD_RESULTS(json_here)) and the expectations
190 * for all tests on all builders (i.e. ADD_EXPECTATIONS(json_here)). 231 * for all tests on all builders (i.e. ADD_EXPECTATIONS(json_here)).
191 * 232 *
192 * This shows flakiness of the tests as well as runtimes for slow tests. 233 * This shows flakiness of the tests as well as runtimes for slow tests.
193 * 234 *
194 * Also, each column in the dashboard is sortable. 235 * Also, each column in the dashboard is sortable.
195 * 236 *
196 * Currently, only webkit tests are supported, but adding other test types 237 * Currently, only webkit tests are supported, but adding other test types
197 * should just require the following steps: 238 * should just require the following steps:
198 * -generate results.json and expectations.json for these tests 239 * -generate results.json and expectations.json for these tests
199 * -copy them to the appropriate location 240 * -copy them to the appropriate location
200 * -add the builder name to the list of builders below. 241 * -add the builder name to the list of builders below.
201 */ 242 */
202 243
203 ////////////////////////////////////////////////////////////////////////////// 244 //////////////////////////////////////////////////////////////////////////////
204 // CONSTANTS 245 // CONSTANTS
205 ////////////////////////////////////////////////////////////////////////////// 246 //////////////////////////////////////////////////////////////////////////////
206 var ALL = 'ALL'; 247 var ALL = 'ALL';
207 var FORWARD = 'forward'; 248 var FORWARD = 'forward';
208 var BACKWARD = 'backward'; 249 var BACKWARD = 'backward';
250 var LAYOUT_TESTS_PREFIX = 'LayoutTests/';
251 var CHROME_TEST_BASE_URL = 'http://src.chromium.org/viewvc/chrome/trunk/' +
252 'src/webkit/data/layout_tests/platform/';
209 var TEST_URL_BASE_PATH = 253 var TEST_URL_BASE_PATH =
210 'http://trac.webkit.org/projects/webkit/browser/trunk/'; 254 'http://trac.webkit.org/projects/webkit/browser/trunk/';
211 var BUILDERS_BASE_PATH = 255 var BUILDERS_BASE_PATH =
212 'http://build.chromium.org/buildbot/waterfall/builders/'; 256 'http://build.chromium.org/buildbot/waterfall/builders/';
213 var TEST_RESULTS_BASE_PATH = 257 var TEST_RESULTS_BASE_PATH =
214 'http://build.chromium.org/buildbot/layout_test_results/'; 258 'http://build.chromium.org/buildbot/layout_test_results/';
215 var PLATFORMS = { 259 var PLATFORMS = {
216 'MAC': 'MAC', 260 'MAC': 'MAC',
217 'LINUX': 'LINUX', 261 'LINUX': 'LINUX',
218 'WIN': 'WIN', 262 'WIN': 'WIN',
(...skipping 25 matching lines...) Expand all
244 288
245 if (currentState.tests) { 289 if (currentState.tests) {
246 createTableHeadersArray('builder'); 290 createTableHeadersArray('builder');
247 generatePageForIndividualTests(getIndividualTests()); 291 generatePageForIndividualTests(getIndividualTests());
248 } else { 292 } else {
249 createTableHeadersArray('test'); 293 createTableHeadersArray('test');
250 generatePageForBuilder(currentState.builder); 294 generatePageForBuilder(currentState.builder);
251 } 295 }
252 296
253 $('max-results-input').value = currentState.maxResults; 297 $('max-results-input').value = currentState.maxResults;
254 updateLegendDisplay();
255 298
256 for (var builder in builders) { 299 for (var builder in builders) {
257 processTestResultsForBuilderAsync(builder); 300 processTestResultsForBuilderAsync(builder);
258 } 301 }
259 } 302 }
260 303
261 function handleValidHashParameter(key, value) { 304 function handleValidHashParameter(key, value) {
262 switch(key) { 305 switch(key) {
263 case 'tests': 306 case 'tests':
264 validateParameter(currentState, key, value, 307 validateParameter(currentState, key, value,
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
298 return true; 341 return true;
299 342
300 case 'maxResults': 343 case 'maxResults':
301 validateParameter(currentState, key, value, 344 validateParameter(currentState, key, value,
302 function() { 345 function() {
303 return value.match(/^\d+$/) 346 return value.match(/^\d+$/)
304 }); 347 });
305 348
306 return true; 349 return true;
307 350
351 case 'showCorrectExpectations':
352 case 'showExpectations':
353 case 'showFlaky':
354 case 'showLargeExpectations':
355 case 'showSkipped':
308 case 'showWontFix': 356 case 'showWontFix':
309 case 'showCorrectExpectations':
310 case 'showFlaky':
311 case 'showLegend':
312 case 'showSkipped':
313 currentState[key] = value == 'true'; 357 currentState[key] = value == 'true';
314 358
315 return true; 359 return true;
316 360
317 default: 361 default:
318 return false; 362 return false;
319 } 363 }
320 } 364 }
321 365
322 defaultStateValues = { 366 defaultStateValues = {
323 sortOrder: BACKWARD, 367 sortOrder: BACKWARD,
324 sortColumn: 'flakiness', 368 sortColumn: 'flakiness',
369 showCorrectExpectations: false,
370 showExpectations: false,
371 showFlaky: true,
372 showLargeExpectations: false,
325 showWontFix: false, 373 showWontFix: false,
326 showCorrectExpectations: false,
327 showLegend: true,
328 showFlaky: true,
329 showSkipped: false, 374 showSkipped: false,
330 maxResults: 200, 375 maxResults: 200
331 }; 376 };
332 377
333 ////////////////////////////////////////////////////////////////////////////// 378 //////////////////////////////////////////////////////////////////////////////
334 // GLOBALS 379 // GLOBALS
335 ////////////////////////////////////////////////////////////////////////////// 380 //////////////////////////////////////////////////////////////////////////////
336 381
337 // Text to put inside the header for each column of the test table. 382 // Text to put inside the header for each column of the test table.
338 var tableHeaders; 383 var tableHeaders;
339 var perBuilderPlatformAndBuildType = {}; 384 var perBuilderPlatformAndBuildType = {};
340 var perBuilderFailures = {}; 385 var perBuilderFailures = {};
(...skipping 546 matching lines...) Expand 10 before | Expand all | Expand 10 after
887 var buildNumbers = resultsByBuilder[builder].buildNumbers; 932 var buildNumbers = resultsByBuilder[builder].buildNumbers;
888 html += '<li>' + 933 html += '<li>' +
889 getLinkHTMLToOpenWindow(BUILDERS_BASE_PATH + builder + '/builds/' + 934 getLinkHTMLToOpenWindow(BUILDERS_BASE_PATH + builder + '/builds/' +
890 buildNumbers[index], 'Build log and blamelist') + '</li></ul>'; 935 buildNumbers[index], 'Build log and blamelist') + '</li></ul>';
891 936
892 showPopup(e, html); 937 showPopup(e, html);
893 } 938 }
894 939
895 function showPopupForTest(e, test) { 940 function showPopupForTest(e, test) {
896 showPopup(e, getHTMLForIndividulTestOnAllBuilders(test)); 941 showPopup(e, getHTMLForIndividulTestOnAllBuilders(test));
942 appendExpectations();
897 } 943 }
898 944
899 function getHtmlForTestResults(test, builder) { 945 function getHtmlForTestResults(test, builder) {
900 var html = ''; 946 var html = '';
901 var results = test.rawResults.concat(); 947 var results = test.rawResults.concat();
902 var times = test.rawTimes.concat(); 948 var times = test.rawTimes.concat();
903 var buildNumbers = resultsByBuilder[builder].buildNumbers; 949 var buildNumbers = resultsByBuilder[builder].buildNumbers;
904 950
905 var indexToReplaceCurrentResult = -1; 951 var indexToReplaceCurrentResult = -1;
906 var indexToReplaceCurrentTime = -1; 952 var indexToReplaceCurrentTime = -1;
(...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after
1179 } 1225 }
1180 1226
1181 tests.sort(sortFunctionGetter(resultsProperty, order == BACKWARD)); 1227 tests.sort(sortFunctionGetter(resultsProperty, order == BACKWARD));
1182 } 1228 }
1183 1229
1184 function getHTMLForIndividulTestOnAllBuilders(test) { 1230 function getHTMLForIndividulTestOnAllBuilders(test) {
1185 for (var builder in builders) 1231 for (var builder in builders)
1186 processTestRunsForBuilder(builder); 1232 processTestRunsForBuilder(builder);
1187 1233
1188 var testResults = testToResultsMap[test]; 1234 var testResults = testToResultsMap[test];
1235 var html = '';
1189 if (testResults && testResults.length) { 1236 if (testResults && testResults.length) {
1190 var tracURL = TEST_URL_BASE_PATH + test 1237 var tracURL = TEST_URL_BASE_PATH + test
1191 var html = getLinkHTMLToOpenWindow(tracURL, tracURL) + 1238 html += getLinkHTMLToOpenWindow(tracURL, tracURL) +
1192 '<div><b>If a builder is not listed, that means the builder does ' + 1239 '<div><b>If a builder is not listed, that means the builder does ' +
1193 'run that test or all runs of the test passed.</b></div>'; 1240 'run that test or all runs of the test passed.</b></div>';
1194 1241
1195 for (var j = 0; j < testResults.length; j++) { 1242 for (var j = 0; j < testResults.length; j++) {
1196 html += getHTMLForSingleTestRow(testResults[j].results, 1243 html += getHTMLForSingleTestRow(testResults[j].results,
1197 testResults[j].builder, true); 1244 testResults[j].builder, true);
1198 } 1245 }
1199 return getHTMLForTestTable(html); 1246 html = getHTMLForTestTable(html);
1200 } else { 1247 } else {
1201 var html = '';
1202 if (expectationsByTest[test]) { 1248 if (expectationsByTest[test]) {
1203 for (var i = 0; i < expectationsByTest[test].length; i++) { 1249 for (var i = 0; i < expectationsByTest[test].length; i++) {
1204 html += '<div>' + expectationsByTest[test][i].modifiers + ' | ' + 1250 html += '<div>' + expectationsByTest[test][i].modifiers + ' | ' +
1205 expectationsByTest[test][i].expectations + '</div>'; 1251 expectationsByTest[test][i].expectations + '</div>';
1206 } 1252 }
1207 } 1253 }
1208 return html + '<div class="not-found">Test not found. Either it does ' + 1254 html += '<div class="not-found">Test not found. Either it does ' +
1209 'not exist, is skipped or passes on all platforms.</div>'; 1255 'not exist, is skipped or passes on all platforms.</div>';
1210 } 1256 }
1257 return html + '<div class=expectations test=' + test + '><div>' +
1258 getLinkHTMLToToggleState('showExpectations', 'expectations') + ' | ' +
1259 getLinkHTMLToToggleState('showLargeExpectations', 'large thumbnails') +
1260 '</div></div>';
1261 }
1262
1263 function getExpectationsContainer(expectationsContainers, parentContainer,
1264 expectationsType) {
1265 if (!expectationsContainers[expectationsType]) {
1266 var container = document.createElement('div');
1267 container.className = 'expectations-container';
1268 parentContainer.appendChild(container);
1269 expectationsContainers[expectationsType] = container;
1270 }
1271 return expectationsContainers[expectationsType];
1272 }
1273
1274 function getExtension(path) {
1275 var parts = path.split('.')
1276 var extension = parts[parts.length - 1];
1277 return extension == 'html' ? 'txt' : extension;
1278 }
1279
1280 function ensureTrailingSlash(path) {
1281 if (path.match(/\/$/))
1282 return path;
1283 return path + '/';
1284 }
1285
1286 /**
1287 * Adds a specific expectation. If it's an image, it's only added on the
1288 * image's onload handler. If it's a text file, then a script tag is appended
1289 * as a hack to see if the file 404s (necessary since it's cross-domain).
1290 * Once all the expectations for a specific type have loaded or errored
1291 * (e.g. all the checksums), then we go through and identify which platform
1292 * uses which expectation.
1293 *
1294 * @param {Object} expectationsContainers Map from expectations type to
1295 * container DIV.
1296 * @param {Element} parentContainer Container element for
1297 * expectationsContainer divs.
1298 * @param {string} platform Platform string. "LayoutTests/" for non-platform
1299 * specific expectations.
1300 * @param {string} path Relative path to the expectation.
1301 * @param {string} base Base path for the expectation URL.
1302 * @param {string} opt_suffix Suffix to place at the end of the path.
1303 */
1304 function addExpectationItem(expectationsContainers, parentContainer, platform,
1305 path, base, opt_suffix) {
1306 var fileExtension = getExtension(path);
1307 var container = getExpectationsContainer(expectationsContainers,
1308 parentContainer, fileExtension);
1309 var isImage = path.match(/\.png$/);
1310
1311 // TODO(ojan): Is there any way to do this that doesn't rely on script
1312 // tags? They spew a lot of errors to the console.
1313 var dummyNode = document.createElement(isImage ? 'img' : 'script');
1314 var suffix = opt_suffix || '';
1315 var platformPart = platform ? ensureTrailingSlash(platform) : '';
1316 dummyNode.src = base + platformPart + path + suffix;
1317
1318 var childContainer = document.createElement('span');
1319 childContainer.className = 'unloaded';
1320
1321 dummyNode.onload = function() {
1322 childContainer.appendChild(getExpectationsTitle(platform, path));
1323 childContainer.className = 'expectations-item';
1324
1325 var item;
1326 if (isImage) {
1327 item = dummyNode;
1328 } else {
1329 item = document.createElement('iframe');
1330 item.src = dummyNode.src;
1331 }
1332
1333 item.className = 'expectation ' + fileExtension;
1334 if (currentState.showLargeExpectations)
1335 item.className += ' large';
1336 childContainer.appendChild(item);
1337 handleFinishedLoadingExpectations(container);
1338 }
1339 dummyNode.onerror = function() {
1340 childContainer.parentNode.removeChild(childContainer);
1341 handleFinishedLoadingExpectations(container);
1342 }
1343
1344 // Append script elements now so that they load. Images load without being
1345 // appended to the DOM.
1346 if (!isImage) {
1347 childContainer.appendChild(dummyNode);
1348 }
1349
1350 container.appendChild(childContainer);
1351 }
1352
1353 /**
1354 * Identifies which expectations are used on which platform once all the
1355 * expectations of a given type have loaded (e.g. the container for checksum
1356 * expectations for this test had no child elements with the class
1357 * "unloaded").
1358 *
1359 * @param {string} container Element containing the expectations for a given
1360 * test and a given type (e.g. checksum).
1361 */
1362 function handleFinishedLoadingExpectations(container) {
1363 if (container.getElementsByClassName('unloaded').length)
1364 return;
1365
1366 var titles = container.getElementsByClassName('expectations-title');
1367 for (var platform in fallbacksMap) {
1368 var fallbacks = fallbacksMap[platform];
1369 var winner = null;
1370 var winningIndex = -1;
1371 for (var i = 0; i < titles.length; i++) {
1372 var title = titles[i];
1373
1374 if (!winner && title.platform == LAYOUT_TESTS_PREFIX) {
1375 winner = title;
1376 continue;
1377 }
1378
1379 for (var j = 0; j < fallbacks.length; j++) {
1380 if ((winningIndex == -1 || winningIndex > j) &&
1381 title.platform == fallbacks[j]) {
1382 winningIndex = j;
1383 winner = title;
1384 break;
1385 }
1386 }
1387 }
1388 if (winner) {
1389 winner.getElementsByClassName('platforms')[0].innerHTML +=
1390 '<div class=used-platform>' + platform + '</div>';
1391 } else {
1392 console.log('No expectations identified for this test. This means ' +
1393 'there is a logic bug in the dashboard for which expectations a ' +
1394 'platform uses or trac.webkit.org/src.chromium.org is giving ' +
1395 ' 5XXs.');
1396 }
1397 }
1398 }
1399
1400 var TRAC_IMAGE_BASE_URL;
1401 /**
1402 * Trac seems to only show the raw image if you're viewing at a specific
1403 * revision. Use the latest revision on any builder.
1404 */
1405 function getTracImageBaseURL() {
1406 if (!TRAC_IMAGE_BASE_URL) {
1407 TRAC_IMAGE_BASE_URL = 'http://trac.webkit.org/export/' +
1408 getLatestKnownRevision(false) + '/trunk/';
1409 }
1410 return TRAC_IMAGE_BASE_URL;
1411 }
1412
1413 function getLatestKnownRevision(isChrome) {
1414 var revision = 0;
1415 for (var builder in builders) {
1416 var results = resultsByBuilder[builder];
1417 var revisions = isChrome ? results.chromeRevision :
1418 results.webkitRevision;
1419 if (revision < revisions[0])
1420 revision = revisions[0];
1421 }
1422 return revision;
1423 }
1424
1425 function addExpectations(expectationsContainers, container, base, imageBase,
1426 platform, text, checksum, png, textSuffix) {
1427 addExpectationItem(expectationsContainers, container, platform, text, base,
1428 textSuffix);
1429 addExpectationItem(expectationsContainers, container, platform, checksum,
1430 base, textSuffix);
1431 addExpectationItem(expectationsContainers, container, platform, png,
1432 imageBase);
1433 }
1434
1435 function getExpectationsTitle(platform, path) {
1436 var header = document.createElement('h3');
1437 header.className = 'expectations-title';
1438
1439 var innerHTML;
1440 if (platform == LAYOUT_TESTS_PREFIX) {
1441 var parts = path.split('/');
1442 innerHTML = parts[parts.length - 1];
1443 } else {
1444 innerHTML = platform || path;
1445 }
1446
1447 header.innerHTML = '<div class=title>' + innerHTML +
1448 '</div><div style="float:left">&nbsp;</div>' +
1449 '<div class=platforms style="float:right"></div>';
1450 header.style.clear = 'both';
1451 header.platform = platform;
1452 return header;
1453 }
1454
1455 function loadExpectations(expectationsContainer) {
1456 // Map from file extension to container div for expectations of that type.
1457 var expectationsContainers = {};
1458
1459 var test = expectationsContainer.getAttribute('test');
1460 var textSuffixWebKit = '?format=txt';
1461 addExpectationItem(expectationsContainers, expectationsContainer, null,
1462 test, TEST_URL_BASE_PATH, textSuffixWebKit);
1463
1464 var testWithoutSuffix = test.substring(0, test.lastIndexOf('.'));
1465
1466 var isUpstreamTest = startsWith(test, LAYOUT_TESTS_PREFIX);
1467 if (isUpstreamTest) {
1468 var testWithoutPrefix = testWithoutSuffix.substring(
1469 LAYOUT_TESTS_PREFIX.length);
1470 var textWithoutPrefix = testWithoutPrefix + "-expected.txt";
1471 var checksumWithoutPrefix = testWithoutPrefix + "-expected.checksum"
1472 var pngWithoutPrefix = testWithoutPrefix + "-expected.png";
1473
1474 addExpectations(expectationsContainers, expectationsContainer,
1475 TEST_URL_BASE_PATH, getTracImageBaseURL(), LAYOUT_TESTS_PREFIX,
1476 textWithoutPrefix, checksumWithoutPrefix, pngWithoutPrefix,
1477 textSuffixWebKit);
1478 }
1479
1480 var text = testWithoutSuffix + "-expected.txt";
1481 var checksum = testWithoutSuffix + "-expected.checksum"
1482 var png = testWithoutSuffix + "-expected.png";
1483
1484 var textSuffixChrome = '?revision=' + getLatestKnownRevision(true);
1485
1486 var fallbacks = getAllFallbacks();
1487 for (var i = 0; i < fallbacks.length; i++) {
1488 var fallback = fallbacks[i];
1489 if (startsWith(fallback, 'platform')) {
1490 if (isUpstreamTest) {
1491 addExpectations(expectationsContainers, expectationsContainer,
1492 TEST_URL_BASE_PATH + LAYOUT_TESTS_PREFIX,
1493 getTracImageBaseURL() + LAYOUT_TESTS_PREFIX,
1494 fallback, textWithoutPrefix,
1495 checksumWithoutPrefix, pngWithoutPrefix, textSuffixWebKit);
1496 }
1497 } else {
1498 addExpectations(expectationsContainers, expectationsContainer,
1499 CHROME_TEST_BASE_URL, CHROME_TEST_BASE_URL, fallback, text,
1500 checksum, png, textSuffixChrome);
1501 }
1502 }
1503
1504 // Add a clearing element so floated elements don't bleed out of their
1505 // containing block.
1506 var br = document.createElement('br');
1507 br.style.clear = 'both';
1508 expectationsContainer.appendChild(br);
1509 }
1510
1511 var allFallbacks;
1512
1513 /**
1514 * Returns the reverse sorted, deduped list of all platform fallback
1515 * directories.
1516 */
1517 function getAllFallbacks() {
1518 if (!allFallbacks) {
1519 var holder = {};
1520 for (var platform in fallbacksMap) {
1521 var fallbacks = fallbacksMap[platform];
1522 for (var i = 0; i < fallbacks.length; i++) {
1523 holder[fallbacks[i]] = 1;
1524 }
1525 }
1526
1527 allFallbacks = [];
1528 for (var fallback in holder) {
1529 allFallbacks.push(fallback);
1530 }
1531 allFallbacks.sort(function(a, b) {
1532 if (a == b)
1533 return 0;
1534 return a < b;
1535 });
1536 }
1537 return allFallbacks;
1538 }
1539
1540 /**
1541 * Appends the expectations for each test listed.
1542 */
1543 function appendExpectations() {
1544 if (currentState.showExpectations) {
1545 var expectations = document.getElementsByClassName('expectations');
1546 for (var i = 0, len = expectations.length; i < len; i++) {
1547 loadExpectations(expectations[i]);
1548 }
1549 }
1211 } 1550 }
1212 1551
1213 function generatePageForIndividualTests(tests) { 1552 function generatePageForIndividualTests(tests) {
1214 var html = getHTMLForNavBar(); 1553 var testsHTML = [];
1215 for (var i = 0; i < tests.length; i++) { 1554 for (var i = 0; i < tests.length; i++) {
1216 html += '<h2>' + tests[i] + '</h2>' + 1555 testsHTML.push('<h2>' + tests[i] + '</h2>' +
1217 getHTMLForIndividulTestOnAllBuilders(tests[i]); 1556 getHTMLForIndividulTestOnAllBuilders(tests[i]));
1218 } 1557 }
1219 setFullPageHTML(html); 1558 setFullPageHTML(getHTMLForNavBar() + testsHTML.join('<hr>'));
1220 1559
1560 appendExpectations();
1221 $('tests-input').value = currentState.tests; 1561 $('tests-input').value = currentState.tests;
1222 } 1562 }
1223 1563
1224 function getHTMLForNavBar(opt_builderName) { 1564 function getHTMLForNavBar(opt_builderName) {
1225 var html = '<div id=builders>'; 1565 var html = '<div id=builders>';
1226 for (var builder in builders) { 1566 for (var builder in builders) {
1227 var className = builder == opt_builderName ? 'current-builder' : 'link'; 1567 var className = builder == opt_builderName ? 'current-builder' : 'link';
1228 html += '<span class=' + className + 1568 html += '<span class=' + className +
1229 ' onclick=\'setState("builder", "' + builder + '")\'>' + 1569 ' onclick=\'setState("builder", "' + builder + '")\'>' +
1230 builder + '</span>'; 1570 builder + '</span>';
1231 } 1571 }
1232 html += '</div>' + 1572 return html + '</div>' +
1233 '<form id=tests-form ' + 1573 '<form id=tests-form ' +
1234 'onsubmit="setState(\'tests\', tests.value);return false;">' + 1574 'onsubmit="setState(\'tests\', tests.value);return false;">' +
1235 '<div>Show tests on all platforms: </div><input name=tests ' + 1575 '<div>Show tests on all platforms: </div><input name=tests ' +
1236 'placeholder="Comma or space-separated list of tests or partial ' + 1576 'placeholder="Comma or space-separated list of tests or partial ' +
1237 'paths to show test results across all builders, e.g., ' + 1577 'paths to show test results across all builders, e.g., ' +
1238 'LayoutTests/foo/bar.html,LayoutTests/foo/baz,forms" ' + 1578 'LayoutTests/foo/bar.html,LayoutTests/foo/baz,forms" ' +
1239 'id=tests-input></form>' + 1579 'id=tests-input></form>' +
1240 '<form id=max-results-form ' + 1580 '<form id=max-results-form ' +
1241 'onsubmit="setState(\'maxResults\', maxResults.value);return false;"' + 1581 'onsubmit="setState(\'maxResults\', maxResults.value);return false;"' +
1242 '><span>Number of results to show (max=500): </span>' + 1582 '><span>Number of results to show (max=500): </span>' +
1243 '<input name=maxResults id=max-results-input></form>' + 1583 '<input name=maxResults id=max-results-input></form> | ' +
1244 '<div id="loading-ui">LOADING...</div><div id=legend>' + 1584 '<b>Type ? for legend and expectations fallback order</b>' +
1245 '<div id=legend-toggle>' + getLinkHTMLToToggleLegendDisplay() + 1585 '<div id="loading-ui">LOADING...</div>';
1246 '</div><div id=legend-contents>';
1247
1248 for (var expectation in EXPECTATIONS_MAP) {
1249 html += '<div class=' + expectation + '>' +
1250 EXPECTATIONS_MAP[expectation] + '</div>';
1251 }
1252 return html + '<div class=wrong-expectations>WRONG EXPECTATIONS</div>' +
1253 '<div class=merge>WEBKIT MERGE</div></div></div>';
1254 } 1586 }
1255 1587
1256 function getLinkHTMLToToggleState(key, linkText) { 1588 function getLinkHTMLToToggleState(key, linkText) {
1257 var isTrue = currentState[key]; 1589 var isTrue = currentState[key];
1258 return '<span class=link onclick="setState(\'' + key + '\', ' + !isTrue + 1590 return '<span class=link onclick="setState(\'' + key + '\', ' + !isTrue +
1259 ')">' + (isTrue ? 'Hide' : 'Show') + ' ' + linkText + '</span>'; 1591 ')">' + (isTrue ? 'Hide' : 'Show') + ' ' + linkText + '</span>';
1260 } 1592 }
1261 1593
1262 function generatePageForBuilder(builderName) { 1594 function generatePageForBuilder(builderName) {
1263 processTestRunsForBuilder(builderName); 1595 processTestRunsForBuilder(builderName);
1264 1596
1265 var tableRowsHTML = ''; 1597 var tableRowsHTML = '';
1266 var results = perBuilderFailures[builderName]; 1598 var results = perBuilderFailures[builderName];
1267 sortTests(results, currentState.sortColumn, currentState.sortOrder); 1599 sortTests(results, currentState.sortColumn, currentState.sortOrder);
1268 for (var i = 0; i < results.length; i++) { 1600 for (var i = 0; i < results.length; i++) {
1269 tableRowsHTML += getHTMLForSingleTestRow(results[i], builderName); 1601 tableRowsHTML += getHTMLForSingleTestRow(results[i], builderName);
1270 } 1602 }
1271 1603
1272 var testsHTML = tableRowsHTML ? getHTMLForTestTable(tableRowsHTML) : 1604 var testsHTML = tableRowsHTML ? getHTMLForTestTable(tableRowsHTML) :
1273 '<div>No tests. Try showing tests with correct expectations.</div>'; 1605 '<div>No tests. Try showing tests with correct expectations.</div>';
1274 1606
1275 var html = getHTMLForNavBar(builderName) + 1607 var html = getHTMLForNavBar(builderName) +
1276 getHTMLForTestsWithExpectationsButNoFailures(builderName) + 1608 getHTMLForTestsWithExpectationsButNoFailures(builderName) +
1277 '<h2>Failing tests</h2><div>' + 1609 '<h2>Failing tests</h2><div>' +
1278 getLinkHTMLToToggleState('showWontFix', 'WONTFIX tests') + ' | ' + 1610 getLinkHTMLToToggleState('showWontFix', 'WONTFIX tests') + ' | ' +
1279 getLinkHTMLToToggleState('showCorrectExpectations', 1611 getLinkHTMLToToggleState('showCorrectExpectations',
1280 'tests with correct expectations') + ' | ' + 1612 'tests with correct expectations') + ' | ' +
1281 getLinkHTMLToToggleState('showFlaky', 'flaky tests') + ' | ' + 1613 getLinkHTMLToToggleState('showFlaky', 'flaky tests') + ' | ' +
1282 '<b>All columns are sortable. | ' + 1614 'All columns are sortable. | ' +
1283 'Flakiness reader order is newer --> older runs.</b></div>' + 1615 'Flakiness reader order is newer --> older runs.</div>' +
1284 testsHTML; 1616 testsHTML;
1285 1617
1286 setFullPageHTML(html); 1618 setFullPageHTML(html);
1287 1619
1288 var ths = document.getElementsByTagName('th'); 1620 var ths = document.getElementsByTagName('th');
1289 for (var i = 0; i < ths.length; i++) { 1621 for (var i = 0; i < ths.length; i++) {
1290 ths[i].addEventListener('click', changeSort, false); 1622 ths[i].addEventListener('click', changeSort, false);
1291 ths[i].className = "sortable"; 1623 ths[i].className = "sortable";
1292 } 1624 }
1293 } 1625 }
1294 1626
1295 function getLinkHTMLToToggleLegendDisplay() {
1296 return getLinkHTMLToToggleState('showLegend', 'Legend');
1297 }
1298
1299 function updateLegendDisplay() {
1300 $('legend-contents').style.display = currentState.showLegend ? '' : 'none';
1301 }
1302
1303 function createTableHeadersArray(firstColumnHeader) { 1627 function createTableHeadersArray(firstColumnHeader) {
1304 tableHeaders = [firstColumnHeader].concat(BASE_TABLE_HEADERS); 1628 tableHeaders = [firstColumnHeader].concat(BASE_TABLE_HEADERS);
1305 } 1629 }
1306 1630
1307 /** 1631 /**
1308 * Clears the processed test state for perBuilderFailures. 1632 * Clears the processed test state for perBuilderFailures.
1309 * TODO(ojan): This really should probably clear all the state we've 1633 * TODO(ojan): This really should probably clear all the state we've
1310 * generated, but that's kind of a pain given the many global objects state is 1634 * generated, but that's kind of a pain given the many global objects state is
1311 * stored in. There should probably be one global generatedState 1635 * stored in. There should probably be one global generatedState
1312 * object that all the generated state lives off of. 1636 * object that all the generated state lives off of.
1313 */ 1637 */
1314 function clearProcessedTestState() { 1638 function clearProcessedTestState() {
1315 for (var builder in builders) { 1639 for (var builder in builders) {
1316 delete perBuilderFailures[builder]; 1640 delete perBuilderFailures[builder];
1317 delete perBuilderPlatformAndBuildType[builder]; 1641 delete perBuilderPlatformAndBuildType[builder];
1318 delete perBuilderWithExpectationsButNoFailures[builder]; 1642 delete perBuilderWithExpectationsButNoFailures[builder];
1319 delete perBuilderSkippedPaths[builder]; 1643 delete perBuilderSkippedPaths[builder];
1320 } 1644 }
1321 1645
1322 for (var key in testToResultsMap) { 1646 for (var key in testToResultsMap) {
1323 delete testToResultsMap[key] 1647 delete testToResultsMap[key]
1324 } 1648 }
1325 } 1649 }
1326 1650
1651 var VALID_KEYS_FOR_INDIVIDUAL_TESTS = {
1652 tests: 1,
1653 maxResults: 1,
1654 showExpectations: 1,
1655 showLargeExpectations: 1
1656 };
1657
1327 /** 1658 /**
1328 * Sets the page state and regenerates the page. Takes varargs of key, value 1659 * Sets the page state and regenerates the page. Takes varargs of key, value
1329 * pairs. 1660 * pairs.
1330 */ 1661 */
1331 function setState(var_args) { 1662 function setState(var_args) {
1332 var shouldRegeneratePage = true; 1663 var shouldRegeneratePage = true;
1333 for (var i = 0; i < arguments.length; i += 2) { 1664 for (var i = 0; i < arguments.length; i += 2) {
1334 var key = arguments[i]; 1665 var key = arguments[i];
1335 1666
1336 if (key != 'tests' && key != 'maxResults') { 1667 if (!(key in VALID_KEYS_FOR_INDIVIDUAL_TESTS)) {
1337 delete currentState.tests; 1668 delete currentState.tests;
1338 } 1669 }
1339 1670
1340 if (key == 'maxResults') { 1671 if (key == 'maxResults') {
1341 // Processing the test results JSON makes assumptions about the number 1672 // Processing the test results JSON makes assumptions about the number
1342 // of results to show. This makes changing the number of maxResults slow 1673 // of results to show. This makes changing the number of maxResults slow
1343 // but is considerably easier than refactoring all the other code. 1674 // but is considerably easier than refactoring all the other code.
1344 clearProcessedTestState(); 1675 clearProcessedTestState();
1345 } 1676 }
1346
1347 if (key == 'showLegend') {
1348 // No need to regenerate the page if only the legend's display is being
1349 // updated.
1350 shouldRegeneratePage = keys.length == 1;
1351 updateLegendDisplay();
1352 $('legend-toggle').innerHTML = getLinkHTMLToToggleLegendDisplay();
1353 }
1354 } 1677 }
1355 1678
1356 // Set all the custom state for this dashboard before calling 1679 // Set all the custom state for this dashboard before calling
1357 // setQueryParameter since setQueryParameter updates the location bar. 1680 // setQueryParameter since setQueryParameter updates the location bar.
1358 setQueryParameter.apply(null, arguments); 1681 setQueryParameter.apply(null, arguments);
1359 1682
1360 if (shouldRegeneratePage) 1683 if (shouldRegeneratePage)
1361 handleLocationChange(); 1684 handleLocationChange();
1362 } 1685 }
1363 1686
1687 function hideLegend() {
1688 var legend = $('legend');
1689 if (legend)
1690 legend.parentNode.removeChild(legend);
1691 }
1692
1693 var fallbacksMap = {};
1694 fallbacksMap['WIN-VISTA'] = ['chromium-win-vista', 'chromium-win',
1695 'platform/win', 'platform/mac'];
1696 fallbacksMap['WIN-XP'] = ['chromium-win-xp'].concat(
1697 fallbacksMap['WIN-VISTA']);
1698 // Should mac look at the tiger results?
1699 fallbacksMap['MAC'] = ['chromium-mac', 'platform/mac',
1700 'platform/mac-snowleopard', 'platform/mac-leopard', 'platform/mac-tiger'];
1701 fallbacksMap['LINUX'] = ['chromium-linux', 'chromium-win', 'platform/win',
1702 'platform/mac'];
1703
1704 function htmlForFallbackHelp(fallbacks) {
1705 return '<ol class=fallback-list><li>' + fallbacks.join('</li><li>') +
1706 '</li></ol>';
1707 }
1708
1709 function showLegend() {
1710 var legend = $('legend');
1711 if (!legend) {
1712 legend = document.createElement('div');
1713 legend.id = 'legend';
1714 document.body.appendChild(legend);
1715 }
1716
1717 var innerHTML = '<div id=legend-toggle onclick="hideLegend()">Hide ' +
1718 'legend (or hit esc to close)</div><div id=legend-contents>';
1719 for (var expectation in EXPECTATIONS_MAP) {
1720 innerHTML += '<div class=' + expectation + '>' +
1721 EXPECTATIONS_MAP[expectation] + '</div>';
1722 }
1723 innerHTML += '<div class=wrong-expectations>WRONG EXPECTATIONS</div>' +
1724 '<div class=merge>WEBKIT MERGE</div></div>' +'</div>' +
1725 '<h3>Test expectatons fallback order.</h3>';
1726
1727 for (var platform in fallbacksMap) {
1728 innerHTML += '<div class=fallback-header>' + platform + '</div>' +
1729 htmlForFallbackHelp(fallbacksMap[platform]);
1730 }
1731 legend.innerHTML = innerHTML;
1732 }
1733
1734 document.addEventListener('keydown', function(e) {
1735 if (e.keyCode == 191 && e.shiftKey) {
1736 // ? key
arv (Not doing code reviews) 2009/10/05 23:59:29 This will not work on different keyboard layouts.
1737 showLegend();
1738 } else if (e.keyCode == 27) {
1739 // escape key
1740 hideLegend();
1741 hidePopup();
1742 }
1743 }, false);
1364 1744
1365 </script> 1745 </script>
1366 </head> 1746 </head>
1367 1747
1368 <body></body> 1748 <body></body>
1369 </html> 1749 </html>
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698