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

Side by Side Diff: sky/tools/webkitpy/tool/servers/data/rebaselineserver/main.js

Issue 675343003: Prune a bunch of webkitpy. (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 6 years, 1 month 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
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2010 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 var ALL_DIRECTORY_PATH = '[all]';
32
33 var STATE_NEEDS_REBASELINE = 'needs_rebaseline';
34 var STATE_REBASELINE_FAILED = 'rebaseline_failed';
35 var STATE_REBASELINE_SUCCEEDED = 'rebaseline_succeeded';
36 var STATE_IN_QUEUE = 'in_queue';
37 var STATE_TO_DISPLAY_STATE = {};
38 STATE_TO_DISPLAY_STATE[STATE_NEEDS_REBASELINE] = 'Needs rebaseline';
39 STATE_TO_DISPLAY_STATE[STATE_REBASELINE_FAILED] = 'Rebaseline failed';
40 STATE_TO_DISPLAY_STATE[STATE_REBASELINE_SUCCEEDED] = 'Rebaseline succeeded';
41 STATE_TO_DISPLAY_STATE[STATE_IN_QUEUE] = 'In queue';
42
43 var results;
44 var testsByFailureType = {};
45 var testsByDirectory = {};
46 var selectedTests = [];
47 var loupe;
48 var queue;
49 var shouldSortTestsByMetric = false;
50
51 function main()
52 {
53 $('failure-type-selector').addEventListener('change', selectFailureType);
54 $('directory-selector').addEventListener('change', selectDirectory);
55 $('test-selector').addEventListener('change', selectTest);
56 $('next-test').addEventListener('click', nextTest);
57 $('previous-test').addEventListener('click', previousTest);
58
59 $('toggle-log').addEventListener('click', function() { toggle('log'); });
60 disableSorting();
61
62 loupe = new Loupe();
63 queue = new RebaselineQueue();
64
65 document.addEventListener('keydown', function(event) {
66 if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) {
67 return;
68 }
69
70 switch (event.keyIdentifier) {
71 case 'Left':
72 event.preventDefault();
73 previousTest();
74 break;
75 case 'Right':
76 event.preventDefault();
77 nextTest();
78 break;
79 case 'U+0051': // q
80 queue.addCurrentTest();
81 break;
82 case 'U+0058': // x
83 queue.removeCurrentTest();
84 break;
85 case 'U+0052': // r
86 queue.rebaseline();
87 break;
88 }
89 });
90
91 loadText('/platforms.json', function(text) {
92 var platforms = JSON.parse(text);
93 platforms.platforms.forEach(function(platform) {
94 var platformOption = document.createElement('option');
95 platformOption.value = platform;
96 platformOption.textContent = platform;
97
98 var targetOption = platformOption.cloneNode(true);
99 targetOption.selected = platform == platforms.defaultPlatform;
100 $('baseline-target').appendChild(targetOption);
101 $('baseline-move-to').appendChild(platformOption.cloneNode(true));
102 });
103 });
104
105 loadText('/results.json', function(text) {
106 results = JSON.parse(text);
107 displayResults();
108 });
109 }
110
111 /**
112 * Groups test results by failure type.
113 */
114 function displayResults()
115 {
116 var failureTypeSelector = $('failure-type-selector');
117 var failureTypes = [];
118
119 for (var testName in results.tests) {
120 var test = results.tests[testName];
121 if (test.actual == 'PASS') {
122 continue;
123 }
124 var failureType = test.actual + ' (expected ' + test.expected + ')';
125 if (!(failureType in testsByFailureType)) {
126 testsByFailureType[failureType] = [];
127 failureTypes.push(failureType);
128 }
129 testsByFailureType[failureType].push(testName);
130 }
131
132 // Sort by number of failures
133 failureTypes.sort(function(a, b) {
134 return testsByFailureType[b].length - testsByFailureType[a].length;
135 });
136
137 for (var i = 0, failureType; failureType = failureTypes[i]; i++) {
138 var failureTypeOption = document.createElement('option');
139 failureTypeOption.value = failureType;
140 failureTypeOption.textContent = failureType + ' - ' + testsByFailureType [failureType].length + ' tests';
141 failureTypeSelector.appendChild(failureTypeOption);
142 }
143
144 selectFailureType();
145
146 document.body.className = '';
147 }
148
149 function enableSorting()
150 {
151 $('toggle-sort').onclick = function() {
152 shouldSortTestsByMetric = !shouldSortTestsByMetric;
153 // Regenerates the list of tests; this alphabetizes, and
154 // then re-sorts if we turned sorting on.
155 selectDirectory();
156 }
157 $('toggle-sort').classList.remove('disabled-control');
158 }
159
160 function disableSorting()
161 {
162 $('toggle-sort').onclick = function() { return false; }
163 $('toggle-sort').classList.add('disabled-control');
164 }
165
166 /**
167 * For a given failure type, gets all the tests and groups them by directory
168 * (populating the directory selector with them).
169 */
170 function selectFailureType()
171 {
172 var selectedFailureType = getSelectValue('failure-type-selector');
173 var tests = testsByFailureType[selectedFailureType];
174
175 testsByDirectory = {}
176 var displayDirectoryNamesByDirectory = {};
177 var directories = [];
178
179 // Include a special option for all tests
180 testsByDirectory[ALL_DIRECTORY_PATH] = tests;
181 displayDirectoryNamesByDirectory[ALL_DIRECTORY_PATH] = 'all';
182 directories.push(ALL_DIRECTORY_PATH);
183
184 // Roll up tests by ancestor directories
185 tests.forEach(function(test) {
186 var pathPieces = test.split('/');
187 var pathDirectories = pathPieces.slice(0, pathPieces.length -1);
188 var ancestorDirectory = '';
189
190 pathDirectories.forEach(function(pathDirectory, index) {
191 ancestorDirectory += pathDirectory + '/';
192 if (!(ancestorDirectory in testsByDirectory)) {
193 testsByDirectory[ancestorDirectory] = [];
194 var displayDirectoryName = new Array(index * 6).join(' ') + pathDirectory;
195 displayDirectoryNamesByDirectory[ancestorDirectory] = displayDir ectoryName;
196 directories.push(ancestorDirectory);
197 }
198
199 testsByDirectory[ancestorDirectory].push(test);
200 });
201 });
202
203 directories.sort();
204
205 var directorySelector = $('directory-selector');
206 directorySelector.innerHTML = '';
207
208 directories.forEach(function(directory) {
209 var directoryOption = document.createElement('option');
210 directoryOption.value = directory;
211 directoryOption.innerHTML =
212 displayDirectoryNamesByDirectory[directory] + ' - ' +
213 testsByDirectory[directory].length + ' tests';
214 directorySelector.appendChild(directoryOption);
215 });
216
217 selectDirectory();
218 }
219
220 /**
221 * For a given failure type and directory and failure type, gets all the tests
222 * in that directory and populatest the test selector with them.
223 */
224 function selectDirectory()
225 {
226 var previouslySelectedTest = getSelectedTest();
227
228 var selectedDirectory = getSelectValue('directory-selector');
229 selectedTests = testsByDirectory[selectedDirectory];
230 selectedTests.sort();
231
232 var testsByState = {};
233 selectedTests.forEach(function(testName) {
234 var state = results.tests[testName].state;
235 if (state == STATE_IN_QUEUE) {
236 state = STATE_NEEDS_REBASELINE;
237 }
238 if (!(state in testsByState)) {
239 testsByState[state] = [];
240 }
241 testsByState[state].push(testName);
242 });
243
244 var optionIndexByTest = {};
245
246 var testSelector = $('test-selector');
247 testSelector.innerHTML = '';
248
249 var selectedFailureType = getSelectValue('failure-type-selector');
250 var sampleSelectedTest = testsByFailureType[selectedFailureType][0];
251 var selectedTypeIsSortable = 'metric' in results.tests[sampleSelectedTest];
252 if (selectedTypeIsSortable) {
253 enableSorting();
254 if (shouldSortTestsByMetric) {
255 for (var state in testsByState) {
256 testsByState[state].sort(function(a, b) {
257 return results.tests[b].metric - results.tests[a].metric
258 })
259 }
260 }
261 } else
262 disableSorting();
263
264 for (var state in testsByState) {
265 var stateOption = document.createElement('option');
266 stateOption.textContent = STATE_TO_DISPLAY_STATE[state];
267 stateOption.disabled = true;
268 testSelector.appendChild(stateOption);
269
270 testsByState[state].forEach(function(testName) {
271 var testOption = document.createElement('option');
272 testOption.value = testName;
273 var testDisplayName = testName;
274 if (testName.lastIndexOf(selectedDirectory) == 0) {
275 testDisplayName = testName.substring(selectedDirectory.length);
276 }
277 testOption.innerHTML = '  ' + testDisplayName;
278 optionIndexByTest[testName] = testSelector.options.length;
279 testSelector.appendChild(testOption);
280 });
281 }
282
283 if (previouslySelectedTest in optionIndexByTest) {
284 testSelector.selectedIndex = optionIndexByTest[previouslySelectedTest];
285 } else if (STATE_NEEDS_REBASELINE in testsByState) {
286 testSelector.selectedIndex =
287 optionIndexByTest[testsByState[STATE_NEEDS_REBASELINE][0]];
288 selectTest();
289 } else {
290 testSelector.selectedIndex = 1;
291 selectTest();
292 }
293
294 selectTest();
295 }
296
297 function getSelectedTest()
298 {
299 return getSelectValue('test-selector');
300 }
301
302 function selectTest()
303 {
304 var selectedTest = getSelectedTest();
305
306 if (results.tests[selectedTest].actual.indexOf('IMAGE') != -1) {
307 $('image-outputs').style.display = '';
308 displayImageResults(selectedTest);
309 } else {
310 $('image-outputs').style.display = 'none';
311 }
312
313 if (results.tests[selectedTest].actual.indexOf('TEXT') != -1) {
314 $('text-outputs').style.display = '';
315 displayTextResults(selectedTest);
316 } else {
317 $('text-outputs').style.display = 'none';
318 }
319
320 var currentBaselines = $('current-baselines');
321 currentBaselines.textContent = '';
322 var baselines = results.tests[selectedTest].baselines;
323 var testName = selectedTest.split('.').slice(0, -1).join('.');
324 getSortedKeys(baselines).forEach(function(platform, i) {
325 if (i != 0) {
326 currentBaselines.appendChild(document.createTextNode('; '));
327 }
328 var platformName = document.createElement('span');
329 platformName.className = 'platform';
330 platformName.textContent = platform;
331 currentBaselines.appendChild(platformName);
332 currentBaselines.appendChild(document.createTextNode(' ('));
333 getSortedKeys(baselines[platform]).forEach(function(extension, j) {
334 if (j != 0) {
335 currentBaselines.appendChild(document.createTextNode(', '));
336 }
337 var link = document.createElement('a');
338 var baselinePath = '';
339 if (platform != 'base') {
340 baselinePath += 'platform/' + platform + '/';
341 }
342 baselinePath += testName + '-expected' + extension;
343 link.href = getTracUrl(baselinePath);
344 if (extension == '.checksum') {
345 link.textContent = 'chk';
346 } else {
347 link.textContent = extension.substring(1);
348 }
349 link.target = '_blank';
350 if (baselines[platform][extension]) {
351 link.className = 'was-used-for-test';
352 }
353 currentBaselines.appendChild(link);
354 });
355 currentBaselines.appendChild(document.createTextNode(')'));
356 });
357
358 updateState();
359 loupe.hide();
360
361 prefetchNextImageTest();
362 }
363
364 function prefetchNextImageTest()
365 {
366 var testSelector = $('test-selector');
367 if (testSelector.selectedIndex == testSelector.options.length - 1) {
368 return;
369 }
370 var nextTest = testSelector.options[testSelector.selectedIndex + 1].value;
371 if (results.tests[nextTest].actual.indexOf('IMAGE') != -1) {
372 new Image().src = getTestResultUrl(nextTest, 'expected-image');
373 new Image().src = getTestResultUrl(nextTest, 'actual-image');
374 }
375 }
376
377 function updateState()
378 {
379 var testName = getSelectedTest();
380 var testIndex = selectedTests.indexOf(testName);
381 var testCount = selectedTests.length
382 $('test-index').textContent = testIndex + 1;
383 $('test-count').textContent = testCount;
384
385 $('next-test').disabled = testIndex == testCount - 1;
386 $('previous-test').disabled = testIndex == 0;
387
388 $('test-link').href = getTracUrl(testName);
389
390 var state = results.tests[testName].state;
391 $('state').className = state;
392 $('state').innerHTML = STATE_TO_DISPLAY_STATE[state];
393
394 queue.updateState();
395 }
396
397 function getTestResultUrl(testName, mode)
398 {
399 return '/test_result?test=' + testName + '&mode=' + mode;
400 }
401
402 var currentExpectedImageTest;
403 var currentActualImageTest;
404
405 function displayImageResults(testName)
406 {
407 if (currentExpectedImageTest == currentActualImageTest
408 && currentExpectedImageTest == testName) {
409 return;
410 }
411
412 function displayImageResult(mode, callback) {
413 var image = $(mode);
414 image.className = 'loading';
415 image.src = getTestResultUrl(testName, mode);
416 image.onload = function() {
417 image.className = '';
418 callback();
419 updateImageDiff();
420 };
421 }
422
423 displayImageResult(
424 'expected-image',
425 function() { currentExpectedImageTest = testName; });
426 displayImageResult(
427 'actual-image',
428 function() { currentActualImageTest = testName; });
429
430 $('diff-canvas').className = 'loading';
431 $('diff-canvas').style.display = '';
432 $('diff-checksum').style.display = 'none';
433 }
434
435 /**
436 * Computes a graphical a diff between the expected and actual images by
437 * rendering each to a canvas, getting the image data, and comparing the RGBA
438 * components of each pixel. The output is put into the diff canvas, with
439 * identical pixels appearing at 12.5% opacity and different pixels being
440 * highlighted in red.
441 */
442 function updateImageDiff() {
443 if (currentExpectedImageTest != currentActualImageTest)
444 return;
445
446 var expectedImage = $('expected-image');
447 var actualImage = $('actual-image');
448
449 function getImageData(image) {
450 var imageCanvas = document.createElement('canvas');
451 imageCanvas.width = image.width;
452 imageCanvas.height = image.height;
453 imageCanvasContext = imageCanvas.getContext('2d');
454
455 imageCanvasContext.fillStyle = 'rgba(255, 255, 255, 1)';
456 imageCanvasContext.fillRect(
457 0, 0, image.width, image.height);
458
459 imageCanvasContext.drawImage(image, 0, 0);
460 return imageCanvasContext.getImageData(
461 0, 0, image.width, image.height);
462 }
463
464 var expectedImageData = getImageData(expectedImage);
465 var actualImageData = getImageData(actualImage);
466
467 var diffCanvas = $('diff-canvas');
468 var diffCanvasContext = diffCanvas.getContext('2d');
469 var diffImageData =
470 diffCanvasContext.createImageData(diffCanvas.width, diffCanvas.height);
471
472 // Avoiding property lookups for all these during the per-pixel loop below
473 // provides a significant performance benefit.
474 var expectedWidth = expectedImage.width;
475 var expectedHeight = expectedImage.height;
476 var expected = expectedImageData.data;
477
478 var actualWidth = actualImage.width;
479 var actual = actualImageData.data;
480
481 var diffWidth = diffImageData.width;
482 var diff = diffImageData.data;
483
484 var hadDiff = false;
485 for (var x = 0; x < expectedWidth; x++) {
486 for (var y = 0; y < expectedHeight; y++) {
487 var expectedOffset = (y * expectedWidth + x) * 4;
488 var actualOffset = (y * actualWidth + x) * 4;
489 var diffOffset = (y * diffWidth + x) * 4;
490 if (expected[expectedOffset] != actual[actualOffset] ||
491 expected[expectedOffset + 1] != actual[actualOffset + 1] ||
492 expected[expectedOffset + 2] != actual[actualOffset + 2] ||
493 expected[expectedOffset + 3] != actual[actualOffset + 3]) {
494 hadDiff = true;
495 diff[diffOffset] = 255;
496 diff[diffOffset + 1] = 0;
497 diff[diffOffset + 2] = 0;
498 diff[diffOffset + 3] = 255;
499 } else {
500 diff[diffOffset] = expected[expectedOffset];
501 diff[diffOffset + 1] = expected[expectedOffset + 1];
502 diff[diffOffset + 2] = expected[expectedOffset + 2];
503 diff[diffOffset + 3] = 32;
504 }
505 }
506 }
507
508 diffCanvasContext.putImageData(
509 diffImageData,
510 0, 0,
511 0, 0,
512 diffImageData.width, diffImageData.height);
513 diffCanvas.className = '';
514
515 if (!hadDiff) {
516 diffCanvas.style.display = 'none';
517 $('diff-checksum').style.display = '';
518 loadTextResult(currentExpectedImageTest, 'expected-checksum');
519 loadTextResult(currentExpectedImageTest, 'actual-checksum');
520 }
521 }
522
523 function loadTextResult(testName, mode, responseIsHtml)
524 {
525 loadText(getTestResultUrl(testName, mode), function(text) {
526 if (responseIsHtml) {
527 $(mode).innerHTML = text;
528 } else {
529 $(mode).textContent = text;
530 }
531 });
532 }
533
534 function displayTextResults(testName)
535 {
536 loadTextResult(testName, 'expected-text');
537 loadTextResult(testName, 'actual-text');
538 loadTextResult(testName, 'diff-text-pretty', true);
539 }
540
541 function nextTest()
542 {
543 var testSelector = $('test-selector');
544 var nextTestIndex = testSelector.selectedIndex + 1;
545 while (true) {
546 if (nextTestIndex == testSelector.options.length) {
547 return;
548 }
549 if (testSelector.options[nextTestIndex].disabled) {
550 nextTestIndex++;
551 } else {
552 testSelector.selectedIndex = nextTestIndex;
553 selectTest();
554 return;
555 }
556 }
557 }
558
559 function previousTest()
560 {
561 var testSelector = $('test-selector');
562 var previousTestIndex = testSelector.selectedIndex - 1;
563 while (true) {
564 if (previousTestIndex == -1) {
565 return;
566 }
567 if (testSelector.options[previousTestIndex].disabled) {
568 previousTestIndex--;
569 } else {
570 testSelector.selectedIndex = previousTestIndex;
571 selectTest();
572 return
573 }
574 }
575 }
576
577 window.addEventListener('DOMContentLoaded', main);
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698