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

Side by Side Diff: Tools/BuildSlaveSupport/build.webkit.org-config/public_html/TestFailures/scripts/ViewController.js

Issue 13712005: Move GardeningServer out of BuildSlaveSupport (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 7 years, 8 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
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2011 Apple 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
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 function ViewController(buildbot) {
27 this._buildbot = buildbot;
28 this._navigationID = 0;
29
30 var self = this;
31 addEventListener('load', function() { self.loaded() }, false);
32 addEventListener('hashchange', function() { self.parseHash(location.hash) }, false);
33 }
34
35 ViewController.prototype = {
36 loaded: function() {
37 this._header = document.createElement('h1');
38 document.body.appendChild(this._header);
39 this._mainContentElement = document.createElement('div');
40 document.body.appendChild(this._mainContentElement);
41 document.body.appendChild(this._domForAuxiliaryUIElements());
42
43 this.parseHash(location.hash);
44 },
45
46 parseHash: function(hash) {
47 ++this._navigationID;
48
49 var match = /#\/(.*)/.exec(hash);
50 if (match)
51 this._displayBuilder(this._buildbot.builderNamed(decodeURIComponent( match[1])));
52 else
53 this._displayTesters();
54 },
55
56 _displayBuilder: function(builder) {
57 this._setTitle(builder.name);
58 this._mainContentElement.removeAllChildren();
59
60 var navigationID = this._navigationID;
61
62 var self = this;
63 (new LayoutTestHistoryAnalyzer(builder)).start(function(data, stillFetch ingData) {
64 if (self._navigationID !== navigationID) {
65 // The user has navigated somewhere else. Stop loading data abou t this tester.
66 return false;
67 }
68
69 var list = document.createElement('ol');
70 list.id = 'failure-history';
71
72 var buildNames = Object.keys(data.history)
73 buildNames.forEach(function(buildName, buildIndex, buildNameArray) {
74 var failingTestNames = Object.keys(data.history[buildName].tests );
75 if (!failingTestNames.length)
76 return;
77
78 var item = document.createElement('li');
79 list.appendChild(item);
80
81 var testList = document.createElement('ol');
82 item.appendChild(testList);
83
84 testList.className = 'test-list';
85 for (var testName in data.history[buildName].tests) {
86 var testItem = document.createElement('li');
87 testItem.appendChild(self._domForFailedTest(builder, buildNa me, testName, data.history[buildName].tests[testName]));
88 testList.appendChild(testItem);
89 }
90
91 if (data.history[buildName].tooManyFailures) {
92 var p = document.createElement('p');
93 p.className = 'info';
94 p.appendChild(document.createTextNode('run-webkit-tests exit ed early due to too many failures/crashes/timeouts'));
95 item.appendChild(p);
96 }
97
98 var passingBuildName;
99 if (buildIndex + 1 < buildNameArray.length)
100 passingBuildName = buildNameArray[buildIndex + 1];
101
102 item.appendChild(self._domForRegressionRange(builder, buildName, passingBuildName, failingTestNames));
103
104 if (passingBuildName || !stillFetchingData) {
105 var bugForm = new FailingTestsBugForm(builder, buildName, pa ssingBuildName, failingTestNames);
106 item.appendChild(self._domForNewAndExistingBugs(builder, fai lingTestNames, bugForm))
107 }
108 });
109
110 self._mainContentElement.removeAllChildren();
111 self._mainContentElement.appendChild(list);
112 self._mainContentElement.appendChild(self._domForPossiblyFlakyTests( builder, data.possiblyFlaky, buildNames));
113
114 if (!stillFetchingData)
115 PersistentCache.prune();
116
117 return true;
118 });
119 },
120
121 _displayTesters: function() {
122 this._setTitle('Testers');
123 this._mainContentElement.removeAllChildren();
124
125 var list = document.createElement('ul');
126 this._mainContentElement.appendChild(list);
127
128 var latestBuildInfos = [];
129 var navigationID = this._navigationID;
130
131 function updateList() {
132 latestBuildInfos.sort(function(a, b) { return a.tester.name.localeCo mpare(b.tester.name) });
133 list.removeAllChildren();
134 latestBuildInfos.forEach(function(buildInfo) {
135 var link = base.createLinkNode('#/' + buildInfo.tester.name, bui ldInfo.tester.name)
136 var item = document.createElement('li');
137 item.appendChild(link);
138 if (buildInfo.tooManyFailures)
139 item.appendChild(document.createTextNode(' (too many failure s/crashes/timeouts)'));
140 else
141 item.appendChild(document.createTextNode(' (' + buildInfo.fa ilureCount + ' failing test' + (buildInfo.failureCount > 1 ? 's' : '') + ')'));
142 list.appendChild(item);
143 });
144 }
145
146 var self = this;
147 this._buildbot.getTesters(function(testers) {
148 if (self._navigationID !== navigationID) {
149 // The user has navigated somewhere else.
150 return;
151 }
152 testers.forEach(function(tester) {
153 tester.getMostRecentCompletedBuildNumber(function(buildNumber) {
154 if (self._navigationID !== navigationID)
155 return;
156 if (buildNumber < 0)
157 return;
158 tester.getNumberOfFailingTests(buildNumber, function(failure Count, tooManyFailures) {
159 if (self._navigationID !== navigationID)
160 return;
161 if (failureCount <= 0)
162 return;
163 latestBuildInfos.push({ tester: tester, failureCount: fa ilureCount, tooManyFailures: tooManyFailures });
164 updateList();
165 });
166 });
167 });
168 });
169 },
170
171 _domForRegressionRange: function(builder, failingBuildName, passingBuildName , failingTestNames) {
172 var result = document.createDocumentFragment();
173
174 var dlItems = [
175 [document.createTextNode('Failed'), this._domForBuildName(builder, f ailingBuildName)],
176 ];
177 if (passingBuildName)
178 dlItems.push([document.createTextNode('Passed'), this._domForBuildNa me(builder, passingBuildName)]);
179 result.appendChild(createDescriptionList(dlItems));
180
181 if (!passingBuildName)
182 return result;
183
184 var firstSuspectRevision = this._buildbot.parseBuildName(passingBuildNam e).revision + 1;
185 var lastSuspectRevision = this._buildbot.parseBuildName(failingBuildName ).revision;
186
187 if (firstSuspectRevision === lastSuspectRevision)
188 return result;
189
190 var suspectsContainer = document.createElement('div');
191 result.appendChild(suspectsContainer);
192
193 var link = base.createLinkNode(trac.logURL('trunk', firstSuspectRevision , lastSuspectRevision, true), 'View regression range in Trac');
194 result.appendChild(link);
195
196 suspectsContainer.appendChild(document.createTextNode('Searching for sus pect revisions\u2026'));
197
198 // FIXME: Maybe some of this code should go in LayoutTestHistoryAnalyzer , or some other class?
199 var self = this;
200 trac.commitDataForRevisionRange('trunk', firstSuspectRevision, lastSuspe ctRevision, function(commits) {
201 var failingTestNamesWithoutExtensions = failingTestNames.map(removeP athExtension);
202 var suspectCommits = commits.filter(function(commit) {
203 return failingTestNamesWithoutExtensions.some(function(testName) {
204 return commit.message.contains(testName);
205 });
206 });
207
208 suspectsContainer.removeAllChildren();
209
210 if (!suspectCommits.length)
211 return;
212
213 var title = 'Suspect revision' + (suspectCommits.length > 1 ? 's' : '') + ':';
214 suspectsContainer.appendChild(document.createTextNode(title));
215
216 var list = document.createElement('ul');
217 suspectsContainer.appendChild(list);
218 list.className = 'suspect-revisions-list';
219
220 function compareCommits(a, b) {
221 return b.revision - a.revision;
222 }
223
224 list.appendChildren(sorted(suspectCommits, compareCommits).map(funct ion(commit) {
225 var item = document.createElement('li');
226 item.appendChild(base.createLinkNode(trac.changesetURL(commit.re vision), commit.title));
227 return item;
228 }));
229 });
230
231 return result;
232 },
233
234 _domForAuxiliaryUIElements: function() {
235 var aside = document.createElement('aside');
236 aside.appendChild(document.createTextNode('Something not working? Have a n idea to improve this page? '));
237 var queryParameters = {
238 product: 'WebKit',
239 component: 'Tools / Tests',
240 version: '528+ (Nightly build)',
241 bug_file_loc: location.href,
242 cc: 'aroben@apple.com',
243 short_desc: 'TestFailures page needs more unicorns!',
244 };
245 aside.appendChild(base.createLinkNode(addQueryParametersToURL(config.kBu gzillaURL + '/enter_bug.cgi', queryParameters), 'File a bug!', '_blank'));
246 return aside;
247 },
248
249 _domForBuildName: function(builder, buildName) {
250 var parsed = this._buildbot.parseBuildName(buildName);
251
252 var sourceLink = base.createLinkNode('http://trac.webkit.org/changeset/' + parsed.revision, 'r' + parsed.revision);
253 var buildLink = base.createLinkNode(builder.buildURL(parsed.buildNumber) , parsed.buildNumber);
254 var resultsLink = base.createLinkNode(builder.resultsPageURL(buildName), 'results.html');
255
256 var result = document.createDocumentFragment();
257 result.appendChild(sourceLink);
258 result.appendChild(document.createTextNode(' ('));
259 result.appendChild(buildLink);
260 result.appendChild(document.createTextNode(') ('));
261 result.appendChild(resultsLink);
262 result.appendChild(document.createTextNode(')'));
263
264 return result;
265 },
266
267 _domForFailedTest: function(builder, buildName, testName, testResult) {
268 var result = document.createDocumentFragment();
269 result.appendChild(document.createTextNode(testName + ': '));
270 result.appendChild(this._domForFailureDiagnosis(builder, buildName, test Name, testResult));
271 return result;
272 },
273
274 _domForFailureDiagnosis: function(builder, buildName, testName, testResult) {
275 var diagnosticInfo = builder.failureDiagnosisTextAndURL(buildName, testN ame, testResult);
276 if (!diagnosticInfo)
277 return document.createTextNode(testResult.failureType);
278
279 var textAndCrashingSymbol = document.createDocumentFragment();
280 textAndCrashingSymbol.appendChild(document.createTextNode(diagnosticInfo .text));
281 if (testResult.crashingSymbol) {
282 var code = document.createElement('code');
283 code.appendChild(document.createTextNode(testResult.crashingSymbol)) ;
284 textAndCrashingSymbol.appendChild(document.createTextNode(' ('));
285 textAndCrashingSymbol.appendChild(code);
286 textAndCrashingSymbol.appendChild(document.createTextNode(')'));
287 }
288
289 if (!('url' in diagnosticInfo))
290 return textAndCrashingSymbol;
291
292 return base.createLinkNode(diagnosticInfo.url, textAndCrashingSymbol);
293 },
294
295 _domForNewAndExistingBugs: function(tester, failingTests, bugForm) {
296 var result = document.createDocumentFragment();
297
298 var container = document.createElement('p');
299 result.appendChild(container);
300
301 container.className = 'existing-and-new-bugs';
302
303 var bugsContainer = document.createElement('div');
304 container.appendChild(bugsContainer);
305
306 bugsContainer.appendChild(document.createTextNode('Searching for bugs re lated to ' + (failingTests.length > 1 ? 'these tests' : 'this test') + '\u2026') );
307
308 bugzilla.quickSearch('ALL ' + failingTests.join('|'), function(bugs) {
309 if (!bugs.length) {
310 bugsContainer.parentNode.removeChild(bugsContainer);
311 return;
312 }
313
314 while (bugsContainer.firstChild)
315 bugsContainer.removeChild(bugsContainer.firstChild);
316
317 bugsContainer.appendChild(document.createTextNode('Existing bugs rel ated to ' + (failingTests.length > 1 ? 'these tests' : 'this test') + ':'));
318
319 var list = document.createElement('ul');
320 bugsContainer.appendChild(list);
321
322 list.className = 'existing-bugs-list';
323
324 function bugToListItem(bug) {
325 var link = base.createLinkNode(bug.url, bug.title);
326 var item = document.createElement('li');
327 item.appendChild(link);
328
329 return item;
330 }
331
332 var openBugs = bugs.filter(function(bug) { return bugzilla.isOpenSta tus(bug.status) });
333 var closedBugs = bugs.filter(function(bug) { return !bugzilla.isOpen Status(bug.status) });
334
335 list.appendChildren(openBugs.map(bugToListItem));
336
337 if (!closedBugs.length)
338 return;
339
340 var item = document.createElement('li');
341 list.appendChild(item);
342
343 item.appendChild(document.createTextNode('Closed bugs:'));
344
345 var closedList = document.createElement('ul');
346 item.appendChild(closedList);
347
348 closedList.appendChildren(closedBugs.map(bugToListItem));
349 });
350
351 var form = bugForm.domElement();
352 result.appendChild(form);
353
354 var linkText = 'File bug for ' + (failingTests.length > 1 ? 'these failu res' : 'this failure');
355 var link = base.createLinkNode('#', linkText);
356 link.addEventListener('click', function(event) { form.submit(); event.pr eventDefault(); });
357
358 container.appendChild(link);
359 return result;
360 },
361
362 _domForPossiblyFlakyTests: function(builder, possiblyFlakyTestData, allBuild s) {
363 var result = document.createDocumentFragment();
364 var flakyTests = Object.keys(possiblyFlakyTestData);
365 if (!flakyTests.length)
366 return result;
367
368 var flakyHeader = document.createElement('h2');
369 result.appendChild(flakyHeader);
370 flakyHeader.appendChild(document.createTextNode('Possibly Flaky Tests')) ;
371
372 var flakyList = document.createElement('ol');
373 result.appendChild(flakyList);
374
375 flakyList.id = 'possibly-flaky-tests';
376
377 var self = this;
378 flakyList.appendChildren(sorted(flakyTests).map(function(testName) {
379 var item = document.createElement('li');
380
381 var disclosureTriangle = document.createElement('span');
382 item.appendChild(disclosureTriangle);
383
384 disclosureTriangle.className = 'disclosure-triangle';
385 const blackRightPointingSmallTriangle = '\u25b8';
386 disclosureTriangle.appendChild(document.createTextNode(blackRightPoi ntingSmallTriangle));
387
388 var failures = possiblyFlakyTestData[testName];
389
390 item.appendChild(document.createTextNode(testName + ' (failed ' + fa ilures.length + ' out of ' + allBuilds.length + ' times)'));
391
392 var container = document.createElement('div');
393 item.appendChild(container);
394
395 container.className = 'expandable';
396
397 disclosureTriangle.addEventListener('click', function() {
398 item.toggleStyleClass('expanded');
399 if (!item.hasStyleClass('expanded'))
400 return;
401
402 if (!container.firstChild) {
403 var failureList = document.createElement('ol');
404 container.appendChild(failureList);
405
406 failureList.className = 'flakiness-examples-list';
407
408 failureList.appendChildren(failures.map(function(historyItem ) {
409 var item = document.createElement('li');
410 item.appendChild(self._domForBuildName(builder, historyI tem.build));
411 item.appendChild(document.createTextNode(': '));
412 item.appendChild(self._domForFailureDiagnosis(builder, h istoryItem.build, testName, historyItem.result));
413 return item;
414 }));
415
416 var failingBuildNames = failures.map(function(historyItem) { return historyItem.build });
417 var bugForm = new FlakyTestBugForm(builder, failingBuildName s, testName, allBuilds.last(), allBuilds[0], allBuilds.length);
418 container.appendChild(self._domForNewAndExistingBugs(builder , [testName], bugForm));
419 }
420 });
421
422 return item;
423 }));
424
425 return result;
426 },
427
428 _setTitle: function(title) {
429 document.title = title;
430 this._header.textContent = title;
431 },
432 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698