OLD | NEW |
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 <script> | 6 <script> |
7 var pageLoadStartTime = Date.now(); | 7 var pageLoadStartTime = Date.now(); |
8 </script> | 8 </script> |
9 <style> | 9 <style> |
10 body { | 10 body { |
11 font-family: arial; | 11 font-family: arial; |
12 font-size: 13px; | 12 font-size: 13px; |
13 } | 13 } |
14 h2 { | 14 h2 { |
15 font-size: 16px; | 15 font-size: 16px; |
16 margin-bottom: .25em; | 16 margin-bottom: .25em; |
17 } | 17 } |
| 18 h3 { |
| 19 font-size: 13px; |
| 20 margin: 0; |
| 21 } |
18 #max-results-form { | 22 #max-results-form { |
19 display: inline; | 23 display: inline; |
20 } | 24 } |
21 #max-results-input { | 25 #max-results-input { |
22 width: 30px; | 26 width: 30px; |
23 } | 27 } |
24 #tests-form { | 28 #tests-form { |
25 display: -webkit-box; | 29 display: -webkit-box; |
26 } | 30 } |
27 #tests-form > * { | 31 #tests-form > * { |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
117 } | 121 } |
118 .S { | 122 .S { |
119 background-color: #c6c; | 123 background-color: #c6c; |
120 } | 124 } |
121 .F { | 125 .F { |
122 background-color: #e98080; | 126 background-color: #e98080; |
123 } | 127 } |
124 .O { | 128 .O { |
125 background-color: #69f; | 129 background-color: #69f; |
126 } | 130 } |
| 131 .merge { |
| 132 background-color: green; |
| 133 } |
| 134 :not(#legend) > .merge { |
| 135 width: 1px; |
| 136 } |
127 .separator { | 137 .separator { |
128 border: 1px solid lightgray; | 138 border: 1px solid lightgray; |
129 height: 0px; | 139 height: 0px; |
130 } | 140 } |
131 .different-platform { | 141 .different-platform { |
132 color: gray; | 142 color: gray; |
133 font-size: 10px; | 143 font-size: 10px; |
134 } | 144 } |
135 .current-builder { | 145 .current-builder { |
136 font-weight: bold; | 146 font-weight: bold; |
137 } | 147 } |
138 #passing-tests { | 148 #passing-tests { |
139 -webkit-column-count: 2; | 149 -webkit-column-count: 3; |
140 -webkit-column-gap: 25px; | 150 -webkit-column-gap: 25px; |
141 -webkit-column-rule: 1px dashed black; | 151 -webkit-column-rule: 1px dashed black; |
142 -moz-column-count: 2; | 152 -moz-column-count: 3; |
143 -moz-column-gap: 25px; | 153 -moz-column-gap: 25px; |
144 -moz-column-rule: 1px dashed black; | 154 -moz-column-rule: 1px dashed black; |
145 } | 155 } |
146 .not-found { | 156 .not-found { |
147 color: red; | 157 color: red; |
148 font-size: large; | 158 font-size: large; |
149 } | 159 } |
150 #loading-ui { | 160 #loading-ui { |
151 display: none; | 161 display: none; |
152 position: fixed; | 162 position: fixed; |
153 top: 0; | 163 top: 0; |
154 left: 0; | 164 left: 0; |
155 background-color: yellow; | 165 background-color: yellow; |
156 padding: 5px; | 166 padding: 5px; |
157 text-align: center; | 167 text-align: center; |
158 font-weight: bold; | 168 font-weight: bold; |
159 } | 169 } |
| 170 #popup { |
| 171 background-color: white; |
| 172 overflow: hidden; |
| 173 width: 250px; |
| 174 z-index: 1; |
| 175 position: absolute; |
| 176 border: 3px solid grey; |
| 177 padding: 3px; |
| 178 -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.5); |
| 179 -moz-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.5); |
| 180 -webkit-border-radius: 5px; |
| 181 -moz-border-radius: 5px; |
| 182 } |
| 183 #popup > * { |
| 184 width: 100%; |
| 185 } |
| 186 #popup > ul { |
| 187 margin: 0; |
| 188 padding-left: 20px; |
| 189 } |
160 </style> | 190 </style> |
161 | 191 |
162 <script> | 192 <script> |
163 /** | 193 /** |
164 * @fileoverview Creates a dashboard for multiple runs of a given set of tests | 194 * @fileoverview Creates a dashboard for multiple runs of a given set of tests |
165 * on the buildbots. Pulls in JSONP-ish files with the results for running | 195 * on the buildbots. Pulls in JSONP-ish files with the results for running |
166 * tests on a given builder (i.e. ADD_RESULTS(json_here)) and the expectations | 196 * tests on a given builder (i.e. ADD_RESULTS(json_here)) and the expectations |
167 * for all tests on all builders (i.e. ADD_EXPECTATIONS(json_here)). | 197 * for all tests on all builders (i.e. ADD_EXPECTATIONS(json_here)). |
168 * | 198 * |
169 * This shows flakiness of the tests as well as runtimes for slow tests. | 199 * This shows flakiness of the tests as well as runtimes for slow tests. |
170 * | 200 * |
171 * Also, each column in the dashboard is sortable. | 201 * Also, each column in the dashboard is sortable. |
172 * | 202 * |
173 * Currently, only webkit tests are supported, but adding other test types | 203 * Currently, only webkit tests are supported, but adding other test types |
174 * should just require the following steps: | 204 * should just require the following steps: |
175 * -generate results.json and expectations.json for these tests | 205 * -generate results.json and expectations.json for these tests |
176 * -copy them to the appropriate location | 206 * -copy them to the appropriate location |
177 * -add the builder name to the list of builders below. | 207 * -add the builder name to the list of builders below. |
178 */ | 208 */ |
179 | 209 |
180 // CONSTANTS | 210 // CONSTANTS |
181 var FORWARD = 'forward'; | 211 var FORWARD = 'forward'; |
182 var BACKWARD = 'backward'; | 212 var BACKWARD = 'backward'; |
183 var TEST_URL_BASE_PATH = | 213 var TEST_URL_BASE_PATH = |
184 'http://trac.webkit.org/projects/webkit/browser/trunk/'; | 214 'http://trac.webkit.org/projects/webkit/browser/trunk/'; |
185 var BUILDERS_BASE_PATH = | 215 var BUILDERS_BASE_PATH = |
186 'http://build.chromium.org/buildbot/waterfall/builders/'; | 216 'http://build.chromium.org/buildbot/waterfall/builders/'; |
187 var EXPECTATIONS_MAP = { | 217 var TEST_RESULTS_BASE_PATH = |
188 'T': 'TIMEOUT', | 218 'http://build.chromium.org/buildbot/layout_test_results/'; |
189 'C': 'CRASH', | 219 var EXPECTATIONS_MAP = { |
190 'P': 'PASS', | 220 'T': 'TIMEOUT', |
191 'F': 'TEXT FAIL', | 221 'C': 'CRASH', |
192 'S': 'SIMPLIFIED', | 222 'P': 'PASS', |
193 'I': 'IMAGE', | 223 'F': 'TEXT FAIL', |
194 'O': 'OTHER', | 224 'S': 'SIMPLIFIED', |
195 'N': 'NO DATA' | 225 'I': 'IMAGE', |
196 }; | 226 'O': 'OTHER', |
197 var PLATFORMS = {'MAC': 'MAC', 'LINUX': 'LINUX', 'WIN': 'WIN'}; | 227 'N': 'NO DATA' |
198 var BUILD_TYPES = {'DEBUG': 'DBG', 'RELEASE': 'RELEASE'}; | 228 }; |
| 229 var PLATFORMS = {'MAC': 'MAC', 'LINUX': 'LINUX', 'WIN': 'WIN'}; |
| 230 var BUILD_TYPES = {'DEBUG': 'DBG', 'RELEASE': 'RELEASE'}; |
199 | 231 |
200 // GLOBALS | 232 // GLOBALS |
201 // The DUMMYVALUE gets shifted off the array in the first call to | 233 // The DUMMYVALUE gets shifted off the array in the first call to |
202 // generatePage. | 234 // generatePage. |
203 var tableHeaders = ['DUMMYVALUE', 'bugs', 'modifiers', 'expectations', | 235 var tableHeaders = ['DUMMYVALUE', 'bugs', 'modifiers', 'expectations', |
204 'missing', 'extra', 'slowest run', | 236 'missing', 'extra', 'slowest run', |
205 'flakiness (numbers are runtimes in seconds)']; | 237 'flakiness (numbers are runtimes in seconds)']; |
206 var perBuilderPlatformAndBuildType = {}; | 238 var perBuilderPlatformAndBuildType = {}; |
207 var perBuilderFailures = {}; | 239 var perBuilderFailures = {}; |
208 // Map of builder to arrays of tests that are listed in the expectations file | 240 // Map of builder to arrays of tests that are listed in the expectations file |
209 // but have for that builder. | 241 // but have for that builder. |
210 var perBuilderWithExpectationsButNoFailures = {}; | 242 var perBuilderWithExpectationsButNoFailures = {}; |
211 | 243 // Map of builder to arrays of paths that are skipped. This shows the raw |
| 244 // path used in test_expectations.txt rather than the test path since we |
| 245 // don't actually have any data here for skipped tests. |
| 246 var perBuilderSkippedPaths = {}; |
212 | 247 |
213 // Generic utility functions. | 248 // Generic utility functions. |
214 function $(id) { | 249 function $(id) { |
215 return document.getElementById(id); | 250 return document.getElementById(id); |
216 } | 251 } |
217 | 252 |
218 function stringContains(a, b) { | 253 function stringContains(a, b) { |
219 return a.indexOf(b) != -1; | 254 return a.indexOf(b) != -1; |
220 } | 255 } |
221 | 256 |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
299 }; | 334 }; |
300 var builderBase = 'http://build.chromium.org/buildbot/'; | 335 var builderBase = 'http://build.chromium.org/buildbot/'; |
301 } | 336 } |
302 | 337 |
303 var defaultStateValues = { | 338 var defaultStateValues = { |
304 sortOrder: BACKWARD, | 339 sortOrder: BACKWARD, |
305 sortColumn: 'flakiness', | 340 sortColumn: 'flakiness', |
306 showWontFix: false, | 341 showWontFix: false, |
307 showCorrectExpectations: false, | 342 showCorrectExpectations: false, |
308 showFlaky: true, | 343 showFlaky: true, |
| 344 showSkipped: false, |
309 maxResults: 200, | 345 maxResults: 200, |
310 testType: 'layout_test_results' | 346 testType: 'layout_test_results' |
311 }; | 347 }; |
312 | 348 |
313 for (var builder in builders) { | |
314 defaultStateValues.builder = builder; | |
315 break; | |
316 } | |
317 | |
318 function fillDefaultStateValues() { | 349 function fillDefaultStateValues() { |
319 // tests has no states with default values. | |
320 if (currentState.tests) | |
321 return; | |
322 | |
323 for (var state in defaultStateValues) { | 350 for (var state in defaultStateValues) { |
324 if (!(state in currentState)) | 351 if (!(state in currentState)) |
325 currentState[state] = defaultStateValues[state]; | 352 currentState[state] = defaultStateValues[state]; |
326 } | 353 } |
| 354 |
| 355 if (!currentState.tests && !('builder' in currentState)) { |
| 356 for (var builder in builders) { |
| 357 currentState.builder = builder; |
| 358 break; |
| 359 } |
| 360 } |
327 } | 361 } |
328 | 362 |
329 function handleValidHashParameter(key, value) { | 363 function handleValidHashParameter(key, value) { |
330 switch(key) { | 364 switch(key) { |
331 case 'testType': | 365 case 'testType': |
332 validateParameter(currentState, key, value, | 366 validateParameter(currentState, key, value, |
333 function() { | 367 function() { |
334 return isValidName(value); | 368 return isValidName(value); |
335 }); | 369 }); |
336 | 370 |
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
595 } | 629 } |
596 | 630 |
597 return allTestsByPlatformAndBuildType[platform][buildType]; | 631 return allTestsByPlatformAndBuildType[platform][buildType]; |
598 } | 632 } |
599 | 633 |
600 /** | 634 /** |
601 * Adds the given test and path to the appropriate objects depending on | 635 * Adds the given test and path to the appropriate objects depending on |
602 * whether the modifiers match the builders platform and buildType. | 636 * whether the modifiers match the builders platform and buildType. |
603 */ | 637 */ |
604 function addTestAndExpectations(test, prefixPath, builder, expectationsMap, | 638 function addTestAndExpectations(test, prefixPath, builder, expectationsMap, |
605 expectations, testPrefixes) { | 639 expectations, testPrefixes, skippedPaths) { |
606 var modifiersForBuilder = | 640 var modifiersForBuilder = |
607 getModifierThatHasPlatformAndBuildType(builder, expectations); | 641 getModifierThatHasPlatformAndBuildType(builder, expectations); |
608 if (modifiersForBuilder) { | 642 |
609 if (getAllTestsWithSamePlatformAndBuildType(builder)[test]) { | 643 if (!modifiersForBuilder) |
610 expectationsMap[test] = expectations; | 644 return false; |
611 testPrefixes[test] = prefixPath; | 645 |
612 } else if (!stringContains(modifiersForBuilder.modifiers, 'SKIP') && | 646 if (getAllTestsWithSamePlatformAndBuildType(builder)[test]) { |
613 !modifiersForBuilder.expectations.match(/^\s*PASS\s*$/)) { | 647 expectationsMap[test] = expectations; |
| 648 testPrefixes[test] = prefixPath; |
| 649 } else if (!stringContains(modifiersForBuilder.modifiers, 'WONTFIX')) { |
| 650 |
| 651 if (stringContains(modifiersForBuilder.modifiers, 'SKIP')) { |
| 652 skippedPaths[prefixPath] = true; |
| 653 } else if (!modifiersForBuilder.expectations.match(/^\s*PASS\s*$/)) { |
614 // Don't include skip tests here as they'll look the same as a test | 654 // Don't include skip tests here as they'll look the same as a test |
615 // that passes on all builders. | 655 // that passes on all builders. |
616 // Also don't include tests that are only expected to pass, e.g. | 656 // Also don't include tests that are only expected to pass, e.g. |
617 // SLOW : foo/bar/baz.html = PASS | 657 // SLOW : foo/bar/baz.html = PASS |
618 // TODO(ojan): Should we also exclude WONTFIX tests here? | 658 // TODO(ojan): Should we also exclude WONTFIX tests here? |
619 perBuilderWithExpectationsButNoFailures[builder].push(test); | 659 perBuilderWithExpectationsButNoFailures[builder].push(test); |
620 } | 660 } |
621 return true; | |
622 } | 661 } |
623 return false; | 662 |
| 663 return true; |
624 } | 664 } |
625 | 665 |
626 /** | 666 /** |
627 * Naive check that path points to a directory. | 667 * Naive check that path points to a directory. |
628 */ | 668 */ |
629 function isDirectory(path) { | 669 function isDirectory(path) { |
630 return !stringContains(path, '.') | 670 return !stringContains(path, '.') |
631 } | 671 } |
632 | 672 |
633 function addHTMLToIndividualOptionsArray(array, html, isCurrentPlatform) { | 673 function addHTMLToIndividualOptionsArray(array, html, isCurrentPlatform) { |
(...skipping 24 matching lines...) Expand all Loading... |
658 var allTests = getAllTests(); | 698 var allTests = getAllTests(); |
659 | 699 |
660 var expectationsMap = {}; | 700 var expectationsMap = {}; |
661 for (var test in allTests) { | 701 for (var test in allTests) { |
662 if (expectationsByTest[test]) | 702 if (expectationsByTest[test]) |
663 expectationsMap[test] = expectationsByTest[test]; | 703 expectationsMap[test] = expectationsByTest[test]; |
664 } | 704 } |
665 | 705 |
666 var testPrefixes = {}; | 706 var testPrefixes = {}; |
667 perBuilderWithExpectationsButNoFailures[builderName] = []; | 707 perBuilderWithExpectationsButNoFailures[builderName] = []; |
| 708 var skippedPaths = {}; |
668 for (var path in expectationsByTest) { | 709 for (var path in expectationsByTest) { |
669 var expectations = expectationsByTest[path]; | 710 var expectations = expectationsByTest[path]; |
670 if (!isDirectory(path) && | 711 if (!isDirectory(path) && |
671 addTestAndExpectations(path, path, builderName, expectationsMap, | 712 addTestAndExpectations(path, path, builderName, expectationsMap, |
672 expectations, testPrefixes)) { | 713 expectations, testPrefixes, skippedPaths)) { |
673 continue; | 714 continue; |
674 } | 715 } |
675 // Test path doesn't match a specific test, see if it prefix matches | 716 // Test path doesn't match a specific test, see if it prefix matches |
676 // any test. | 717 // any test. |
677 for (var test in allTests) { | 718 for (var test in allTests) { |
678 if (stringContains(test, path) && | 719 if (stringContains(test, path) && |
679 (!testPrefixes[test] || | 720 (!testPrefixes[test] || |
680 !stringContains(testPrefixes[test], path))) { | 721 !stringContains(testPrefixes[test], path))) { |
681 addTestAndExpectations(test, path, builderName, expectationsMap, | 722 addTestAndExpectations(test, path, builderName, expectationsMap, |
682 expectations, testPrefixes); | 723 expectations, testPrefixes, skippedPaths); |
683 } | 724 } |
684 } | 725 } |
685 } | 726 } |
| 727 |
| 728 perBuilderSkippedPaths[builderName] = []; |
| 729 for (var path in skippedPaths) { |
| 730 perBuilderSkippedPaths[builderName].push(path); |
| 731 } |
| 732 perBuilderSkippedPaths[builderName].sort(); |
686 perBuilderWithExpectationsButNoFailures[builderName].sort(); | 733 perBuilderWithExpectationsButNoFailures[builderName].sort(); |
687 | 734 |
688 var allTestsForThisBuilder = resultsByBuilder[builderName].tests; | 735 var allTestsForThisBuilder = resultsByBuilder[builderName].tests; |
689 for (var test in allTestsForThisBuilder) { | 736 for (var test in allTestsForThisBuilder) { |
690 var resultsForTest = createResultsObjectForTest(test); | 737 var resultsForTest = createResultsObjectForTest(test); |
691 | 738 |
692 if (expectationsMap[test] && expectationsMap[test].length) { | 739 if (expectationsMap[test] && expectationsMap[test].length) { |
693 var expectationsArray = expectationsMap[test]; | 740 var expectationsArray = expectationsMap[test]; |
694 var htmlArrays = {}; | 741 var htmlArrays = {}; |
695 htmlArrays.expectations = []; | 742 htmlArrays.expectations = []; |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
769 if (!hasExpectation) | 816 if (!hasExpectation) |
770 missingExpectations.push(result); | 817 missingExpectations.push(result); |
771 } | 818 } |
772 | 819 |
773 var times = resultsByBuilder[builderName].tests[test].times; | 820 var times = resultsByBuilder[builderName].tests[test].times; |
774 for (var i = 0; i < times.length; i++) { | 821 for (var i = 0; i < times.length; i++) { |
775 resultsForTest.slowestTime = Math.max(resultsForTest.slowestTime, | 822 resultsForTest.slowestTime = Math.max(resultsForTest.slowestTime, |
776 times[i][1]); | 823 times[i][1]); |
777 } | 824 } |
778 | 825 |
779 if (resultsForTest.slowestTime && | 826 if (resultsForTest.slowestTime && !resultsMap['TIMEOUT'] && |
780 (!resultsForTest.expectations || | 827 (!resultsForTest.expectations || |
781 !stringContains(resultsForTest.expectations, 'TIMEOUT')) && | 828 !stringContains(resultsForTest.expectations, 'TIMEOUT')) && |
782 (!resultsForTest.modifiers || | 829 (!resultsForTest.modifiers || |
783 !stringContains(resultsForTest.modifiers, 'SLOW'))) { | 830 !stringContains(resultsForTest.modifiers, 'SLOW'))) { |
784 missingExpectations.push('SLOW'); | 831 missingExpectations.push('SLOW'); |
785 } | 832 } |
786 | 833 |
787 resultsForTest.meetsExpectations = | 834 resultsForTest.meetsExpectations = |
788 !missingExpectations.length && !extraExpectations.length; | 835 !missingExpectations.length && !extraExpectations.length; |
789 resultsForTest.missing = missingExpectations.sort().join(' '); | 836 resultsForTest.missing = missingExpectations.sort().join(' '); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
822 * are internal google bugs. | 869 * are internal google bugs. |
823 */ | 870 */ |
824 function getHtmlForBugs(bugs) { | 871 function getHtmlForBugs(bugs) { |
825 bugs = bugs.replace(/BUG(\d{4})(\ |$)/g, externalBugReplaceValue); | 872 bugs = bugs.replace(/BUG(\d{4})(\ |$)/g, externalBugReplaceValue); |
826 bugs = bugs.replace(/BUG(\d{5})(\ |$)/g, externalBugReplaceValue); | 873 bugs = bugs.replace(/BUG(\d{5})(\ |$)/g, externalBugReplaceValue); |
827 bugs = bugs.replace(/BUG(\d{6})(\ |$)/g, internalBugReplaceValue); | 874 bugs = bugs.replace(/BUG(\d{6})(\ |$)/g, internalBugReplaceValue); |
828 bugs = bugs.replace(/BUG(\d{7})(\ |$)/g, internalBugReplaceValue); | 875 bugs = bugs.replace(/BUG(\d{7})(\ |$)/g, internalBugReplaceValue); |
829 return bugs; | 876 return bugs; |
830 } | 877 } |
831 | 878 |
832 function loadBuilderPageForBuildNumber(builderName, buildNumber) { | 879 function getLinkHTMLToOpenWindow(url, text) { |
833 window.open(BUILDERS_BASE_PATH + builderName + '/builds/' + buildNumber); | 880 return '<li class=link onclick="window.open(\'' + url + '\')">' + text + |
| 881 '</li>'; |
| 882 } |
| 883 |
| 884 function showPopupForBuild(e, builder, index) { |
| 885 var html = ''; |
| 886 |
| 887 var time = resultsByBuilder[builder].secondsSinceEpoch[index]; |
| 888 if (time) { |
| 889 var date = new Date(time * 1000); |
| 890 html += date.toLocaleDateString() + ' ' + date.toLocaleTimeString(); |
| 891 } |
| 892 |
| 893 html += '<ul>'; |
| 894 |
| 895 var webkitRevision = resultsByBuilder[builder].webkitRevision; |
| 896 var thisWebkitRevision = webkitRevision[index]; |
| 897 if (thisWebkitRevision) { |
| 898 var previousWebkitRevision = webkitRevision[index + 1] || |
| 899 thisWebkitRevision; |
| 900 html += getLinkHTMLToOpenWindow('http://trac.webkit.org/log/?rev=' + |
| 901 thisWebkitRevision + '&stop_rev=' + previousWebkitRevision, |
| 902 'WebKit blamelist r' + previousWebkitRevision + ':r' + |
| 903 thisWebkitRevision); |
| 904 } |
| 905 |
| 906 var chromeRevision = resultsByBuilder[builder].chromeRevision; |
| 907 var thisChromeRevision = chromeRevision[index]; |
| 908 if (thisChromeRevision) { |
| 909 var previousChromeRevision = chromeRevision[index + 1] || |
| 910 thisChromeRevision; |
| 911 html += getLinkHTMLToOpenWindow( |
| 912 'http://build.chromium.org/buildbot/perf/dashboard/ui/' + |
| 913 'changelog.html?url=/trunk/src&mode=html&range=' + |
| 914 previousChromeRevision + ':' + thisChromeRevision, |
| 915 'Chrome blamelist r' + previousChromeRevision + ':r' + |
| 916 thisChromeRevision) + |
| 917 getLinkHTMLToOpenWindow(TEST_RESULTS_BASE_PATH + builders[builder] + |
| 918 '/' + thisChromeRevision + '/layout-test-results.zip', |
| 919 'layout-test-results.zip'); |
| 920 } |
| 921 |
| 922 var buildNumbers = resultsByBuilder[builder].buildNumbers; |
| 923 html += getLinkHTMLToOpenWindow(BUILDERS_BASE_PATH + builder + '/builds/' + |
| 924 buildNumbers[index], 'Build log and blamelist') + '</ul>'; |
| 925 |
| 926 showPopup(e, html); |
834 } | 927 } |
835 | 928 |
836 function getHtmlForTestResults(test, builder) { | 929 function getHtmlForTestResults(test, builder) { |
837 var html = ''; | 930 var html = ''; |
838 var results = test.rawResults.concat(); | 931 var results = test.rawResults.concat(); |
839 var times = test.rawTimes.concat(); | 932 var times = test.rawTimes.concat(); |
840 var buildNumbers = resultsByBuilder[builder].buildNumbers; | 933 var buildNumbers = resultsByBuilder[builder].buildNumbers; |
841 | 934 |
842 var indexToReplaceCurrentResult = -1; | 935 var indexToReplaceCurrentResult = -1; |
843 var indexToReplaceCurrentTime = -1; | 936 var indexToReplaceCurrentTime = -1; |
844 var currentResultArray, currentTimeArray, currentResult, innerHTML; | 937 var currentResultArray, currentTimeArray, currentResult, innerHTML; |
845 for (var i = 0; | 938 var maxIndex = Math.min(buildNumbers.length, currentState.maxResults); |
846 i < buildNumbers.length && i < currentState.maxResults; | 939 for (var i = 0; i < maxIndex; i++) { |
847 i++) { | |
848 if (i > indexToReplaceCurrentResult) { | 940 if (i > indexToReplaceCurrentResult) { |
849 currentResultArray = results.shift(); | 941 currentResultArray = results.shift(); |
850 if (currentResultArray) { | 942 if (currentResultArray) { |
851 currentResult = currentResultArray[1]; | 943 currentResult = currentResultArray[1]; |
852 indexToReplaceCurrentResult += currentResultArray[0]; | 944 indexToReplaceCurrentResult += currentResultArray[0]; |
853 } else { | 945 } else { |
854 currentResult = 'N'; | 946 currentResult = 'N'; |
855 indexToReplaceCurrentResult += buildNumbers.length; | 947 indexToReplaceCurrentResult += buildNumbers.length; |
856 } | 948 } |
857 } | 949 } |
858 | 950 |
859 if (i > indexToReplaceCurrentTime) { | 951 if (i > indexToReplaceCurrentTime) { |
860 currentTimeArray = times.shift(); | 952 currentTimeArray = times.shift(); |
861 var currentTime = 0; | 953 var currentTime = 0; |
862 if (currentResultArray) { | 954 if (currentResultArray) { |
863 currentTime = currentTimeArray[1]; | 955 currentTime = currentTimeArray[1]; |
864 indexToReplaceCurrentTime += currentTimeArray[0]; | 956 indexToReplaceCurrentTime += currentTimeArray[0]; |
865 } else { | 957 } else { |
866 indexToReplaceCurrentTime += buildNumbers.length; | 958 indexToReplaceCurrentTime += buildNumbers.length; |
867 } | 959 } |
868 innerHTML = currentTime || ' '; | 960 innerHTML = currentTime || ' '; |
869 } | 961 } |
870 | 962 |
871 var buildNumber = buildNumbers[i]; | 963 html += '<td title="Click results for handy links." class="results ' + |
872 html += '<td title="Build:' + buildNumber + '" class="results ' + | 964 currentResult + '" onclick=\'showPopupForBuild(event, "' + builder + |
873 currentResult + '" onclick=\'loadBuilderPageForBuildNumber("' + | 965 '",' + i + ')\'>' + innerHTML + '</td>'; |
874 builder + '","' + buildNumber + '")\'>' + innerHTML + '</td>'; | 966 |
| 967 var webkitRevision = resultsByBuilder[builder].webkitRevision; |
| 968 var isWebkitMerge = webkitRevision[i + 1] && |
| 969 webkitRevision[i] != webkitRevision[i + 1]; |
| 970 if (isWebkitMerge) |
| 971 html += '<td class=merge></td>'; |
875 } | 972 } |
876 return html; | 973 return html; |
877 } | 974 } |
878 | 975 |
879 function getHTMLForTestsWithExpectationsButNoFailures(builder) { | 976 function getHTMLForTestsWithExpectationsButNoFailures(builder) { |
880 var tests = perBuilderWithExpectationsButNoFailures[builder]; | 977 var tests = perBuilderWithExpectationsButNoFailures[builder]; |
881 if (!tests.length) | 978 var skippedPaths = perBuilderSkippedPaths[builder]; |
882 return ''; | |
883 | 979 |
884 var buildInfo = getPlatFormAndBuildType(builder); | 980 var html = ''; |
885 return '<h2>Have expectations for ' + buildInfo.platform + '-' + | 981 if (tests.length || skippedPaths.length) { |
886 buildInfo.buildType + ' but have not failed in last ' + | 982 var buildInfo = getPlatFormAndBuildType(builder); |
| 983 html += '<h2>Expectations for ' + buildInfo.platform + '-' + |
| 984 buildInfo.buildType + ':</h2>'; |
| 985 } |
| 986 |
| 987 if (tests.length) { |
| 988 html += '<h3>Have not failed in last ' + |
887 resultsByBuilder[builderName].buildNumbers.length + | 989 resultsByBuilder[builderName].buildNumbers.length + |
888 ' runs.</h2><div id="passing-tests"><div>' + | 990 ' runs.</h3><div id="passing-tests"><div>' + |
889 tests.join('</div><div>') + '</div></div>'; | 991 tests.join('</div><div>') + '</div></div>'; |
| 992 } |
| 993 |
| 994 if (skippedPaths.length) { |
| 995 html += '<h3>' + |
| 996 getLinkHTMLToToggleState('showSkipped', |
| 997 'Skipped tests in text_expectations.txt') + |
| 998 '</h3>'; |
| 999 |
| 1000 if (currentState.showSkipped) { |
| 1001 html += '<div id="passing-tests"><div>' + |
| 1002 skippedPaths.join('</div><div>') + '</div></div>'; |
| 1003 } |
| 1004 } |
| 1005 return html; |
890 } | 1006 } |
891 | 1007 |
892 /** | 1008 /** |
893 * Returns true if a test should be considered flaky. Uses heuristics to | 1009 * Returns true if a test should be considered flaky. Uses heuristics to |
894 * avoid common non-flaky cases. | 1010 * avoid common non-flaky cases. |
895 */ | 1011 */ |
896 function isTestFlaky(testResult) { | 1012 function isTestFlaky(testResult) { |
897 return testResult.flips > 1 && !isFixedTest(testResult); | 1013 return testResult.flips > 1 && !isFixedTest(testResult); |
898 } | 1014 } |
899 | 1015 |
(...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1138 '<div>Show tests on all platforms (slow): </div><input name=tests ' + | 1254 '<div>Show tests on all platforms (slow): </div><input name=tests ' + |
1139 'placeholder="LayoutTests/foo/bar.html,LayoutTests/foo/baz.html" ' + | 1255 'placeholder="LayoutTests/foo/bar.html,LayoutTests/foo/baz.html" ' + |
1140 'id=tests-input></form><div id="loading-ui">LOADING...</div>' + | 1256 'id=tests-input></form><div id="loading-ui">LOADING...</div>' + |
1141 '<div id=legend>'; | 1257 '<div id=legend>'; |
1142 | 1258 |
1143 for (var expectation in EXPECTATIONS_MAP) { | 1259 for (var expectation in EXPECTATIONS_MAP) { |
1144 html += '<div class=' + expectation + '>' + | 1260 html += '<div class=' + expectation + '>' + |
1145 EXPECTATIONS_MAP[expectation] + '</div>'; | 1261 EXPECTATIONS_MAP[expectation] + '</div>'; |
1146 } | 1262 } |
1147 return html + '<div class=wrong-expectations>WRONG EXPECTATIONS</div>' + | 1263 return html + '<div class=wrong-expectations>WRONG EXPECTATIONS</div>' + |
1148 '</div>'; | 1264 '<div class=merge>WEBKIT MERGE</div></div>'; |
1149 } | 1265 } |
1150 | 1266 |
1151 function getLinkHTMLToToggleState(key, linkText) { | 1267 function getLinkHTMLToToggleState(key, linkText) { |
1152 var isTrue = currentState[key]; | 1268 var isTrue = currentState[key]; |
1153 return '<span class=link onclick="setState(\'' + key + '\', ' + !isTrue + | 1269 return '<span class=link onclick="setState(\'' + key + '\', ' + !isTrue + |
1154 ')">' + (isTrue ? 'Hide' : 'Show') + ' ' + linkText + '</span> | '; | 1270 ')">' + (isTrue ? 'Hide' : 'Show') + ' ' + linkText + '</span>'; |
1155 } | 1271 } |
1156 | 1272 |
1157 function generatePageForBuilder(builderName) { | 1273 function generatePageForBuilder(builderName) { |
1158 processTestRunsForBuilder(builderName); | 1274 processTestRunsForBuilder(builderName); |
1159 | 1275 |
1160 var tableRowsHTML = ''; | 1276 var tableRowsHTML = ''; |
1161 var results = perBuilderFailures[builderName]; | 1277 var results = perBuilderFailures[builderName]; |
1162 sortTests(results, currentState.sortColumn, currentState.sortOrder); | 1278 sortTests(results, currentState.sortColumn, currentState.sortOrder); |
1163 for (var i = 0; i < results.length; i++) { | 1279 for (var i = 0; i < results.length; i++) { |
1164 tableRowsHTML += getHTMLForSingleTestRow(results[i], builderName); | 1280 tableRowsHTML += getHTMLForSingleTestRow(results[i], builderName); |
1165 } | 1281 } |
1166 | 1282 |
1167 var testsHTML = tableRowsHTML ? getHTMLForTestTable(tableRowsHTML) : | 1283 var testsHTML = tableRowsHTML ? getHTMLForTestTable(tableRowsHTML) : |
1168 '<div>No tests. Try showing tests with correct expectations.</div>'; | 1284 '<div>No tests. Try showing tests with correct expectations.</div>'; |
1169 | 1285 |
1170 var html = getHTMLForNavBar(builderName) + | 1286 var html = getHTMLForNavBar(builderName) + |
1171 getHTMLForTestsWithExpectationsButNoFailures(builderName) + | 1287 getHTMLForTestsWithExpectationsButNoFailures(builderName) + |
1172 '<h2>Failing tests</h2><div>' + | 1288 '<h2>Failing tests</h2><div>' + |
1173 getLinkHTMLToToggleState('showWontFix', 'WONTFIX tests') + | 1289 getLinkHTMLToToggleState('showWontFix', 'WONTFIX tests') + ' | ' + |
1174 getLinkHTMLToToggleState('showCorrectExpectations', | 1290 getLinkHTMLToToggleState('showCorrectExpectations', |
1175 'tests with correct expectations') + | 1291 'tests with correct expectations') + ' | ' + |
1176 getLinkHTMLToToggleState('showFlaky', 'flaky tests') + | 1292 getLinkHTMLToToggleState('showFlaky', 'flaky tests') + ' | ' + |
1177 '<form id=max-results-form ' + | 1293 '<form id=max-results-form ' + |
1178 'onsubmit="setState(\'maxResults\', maxResults.value);return false;"' + | 1294 'onsubmit="setState(\'maxResults\', maxResults.value);return false;"' + |
1179 '><span>Max results to show: </span>' + | 1295 '><span>Number of results to show: </span>' + |
1180 '<input name=maxResults id=max-results-input></form> | ' + | 1296 '<input name=maxResults id=max-results-input></form> | ' + |
1181 '<b>All columns are sortable. | Skipped tests are not listed. | ' + | 1297 '<b>All columns are sortable. | Skipped tests are not listed. | ' + |
1182 'Flakiness reader order is newer --> older runs.</b></div>' + | 1298 'Flakiness reader order is newer --> older runs.</b></div>' + |
1183 testsHTML; | 1299 testsHTML; |
1184 | 1300 |
1185 setFullPageHTML(html); | 1301 setFullPageHTML(html); |
1186 | 1302 |
1187 var ths = document.getElementsByTagName('th'); | 1303 var ths = document.getElementsByTagName('th'); |
1188 for (var i = 0; i < ths.length; i++) { | 1304 for (var i = 0; i < ths.length; i++) { |
1189 ths[i].addEventListener('click', changeSort, false); | 1305 ths[i].addEventListener('click', changeSort, false); |
1190 ths[i].className = "sortable"; | 1306 ths[i].className = "sortable"; |
1191 } | 1307 } |
1192 | 1308 |
1193 $('max-results-input').value = currentState.maxResults; | 1309 $('max-results-input').value = currentState.maxResults; |
1194 } | 1310 } |
1195 | 1311 |
1196 var singleBuilderViewParameters = ['sortOrder', 'sortColumn', 'showWontFix', | |
1197 'showCorrectExpectations', 'showFlaky: true', 'maxResults']; | |
1198 | |
1199 /** | 1312 /** |
1200 * Sets the page state and regenerates the page. Takes varargs of key, value | 1313 * Sets the page state and regenerates the page. Takes varargs of key, value |
1201 * pairs. | 1314 * pairs. |
1202 */ | 1315 */ |
1203 function setState(key, value) { | 1316 function setState(key, value) { |
1204 for (var i = 0; i < arguments.length; i = i + 2) { | 1317 for (var i = 0; i < arguments.length; i = i + 2) { |
1205 var key = arguments[i]; | 1318 var key = arguments[i]; |
1206 if (key == 'tests') { | 1319 if (key != 'tests') { |
1207 for (var state in singleBuilderViewParameters) { | |
1208 delete currentState[state]; | |
1209 } | |
1210 } else { | |
1211 delete currentState.tests; | 1320 delete currentState.tests; |
1212 } | 1321 } |
1213 | 1322 |
1214 currentState[key] = arguments[i + 1]; | 1323 currentState[key] = arguments[i + 1]; |
1215 } | 1324 } |
1216 window.location.replace(getPermaLinkURL()); | 1325 window.location.replace(getPermaLinkURL()); |
1217 handleLocationChange(); | 1326 handleLocationChange(); |
1218 } | 1327 } |
1219 | 1328 |
1220 function handleLocationChange() { | 1329 function handleLocationChange() { |
(...skipping 13 matching lines...) Expand all Loading... |
1234 for (var key in stateObject) { | 1343 for (var key in stateObject) { |
1235 state.push(key + '=' + encodeURIComponent(stateObject[key])); | 1344 state.push(key + '=' + encodeURIComponent(stateObject[key])); |
1236 } | 1345 } |
1237 return state.join('&'); | 1346 return state.join('&'); |
1238 } | 1347 } |
1239 | 1348 |
1240 function logTime(msg, startTime) { | 1349 function logTime(msg, startTime) { |
1241 console.log(msg + ': ' + (Date.now() - startTime)); | 1350 console.log(msg + ': ' + (Date.now() - startTime)); |
1242 } | 1351 } |
1243 | 1352 |
| 1353 function hidePopup() { |
| 1354 var popup = $('popup'); |
| 1355 popup.parentNode.removeChild(popup); |
| 1356 } |
| 1357 |
| 1358 function showPopup(e, html) { |
| 1359 var popup = $('popup'); |
| 1360 if (!popup) { |
| 1361 popup = document.createElement('div'); |
| 1362 popup.id = 'popup'; |
| 1363 document.body.appendChild(popup); |
| 1364 } |
| 1365 |
| 1366 // Set html first so that we can get accurate size metrics on the popup. |
| 1367 popup.innerHTML = html; |
| 1368 |
| 1369 var targetRect = e.target.getBoundingClientRect(); |
| 1370 |
| 1371 var x = Math.min(targetRect.left - 10, |
| 1372 document.documentElement.clientWidth - popup.offsetWidth); |
| 1373 popup.style.left = x + document.body.scrollLeft + 'px'; |
| 1374 |
| 1375 var y = targetRect.top + targetRect.height; |
| 1376 if (y + popup.offsetHeight > document.documentElement.clientHeight) { |
| 1377 y = targetRect.top - popup.offsetHeight; |
| 1378 } |
| 1379 popup.style.top = y + document.body.scrollTop + 'px'; |
| 1380 } |
| 1381 |
| 1382 document.onmousedown = function(e) { |
| 1383 // Clear the open popup, unless the click was inside the popup. |
| 1384 var popup = $('popup'); |
| 1385 if (popup && e.target != popup && |
| 1386 !(popup.compareDocumentPosition(e.target) & 16)) { |
| 1387 hidePopup(); |
| 1388 } |
| 1389 }; |
| 1390 |
1244 window.onload = function() { | 1391 window.onload = function() { |
1245 // This doesn't seem totally accurate as there is a race between | 1392 // This doesn't seem totally accurate as there is a race between |
1246 // onload firing and the last script tag being executed. | 1393 // onload firing and the last script tag being executed. |
1247 logTime('Time to load JS', pageLoadStartTime); | 1394 logTime('Time to load JS', pageLoadStartTime); |
1248 setInterval(function() { | 1395 setInterval(function() { |
1249 if (oldLocation != window.location.href) { | 1396 if (oldLocation != window.location.href) { |
1250 parseAllParameters(); | 1397 parseAllParameters(); |
1251 handleLocationChange(); | 1398 handleLocationChange(); |
1252 } | 1399 } |
1253 }, 100); | 1400 }, 100); |
1254 } | 1401 } |
1255 </script> | 1402 </script> |
1256 </head> | 1403 </head> |
1257 | 1404 |
1258 <body></body> | 1405 <body></body> |
1259 </html> | 1406 </html> |
OLD | NEW |