blob: 613b775a6175b56a07945e6e9dbf6df100e98dcb [file] [log] [blame]
/*
* Copyright (C) 2013, 2014, 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
BuildbotTesterQueueView = function(queues)
{
BuildbotQueueView.call(this, queues);
this.releaseQueues = this.queues.filter(function(queue) { return queue.debug === false; });
this.debugQueues = this.queues.filter(function(queue) { return queue.debug === true; });
this.update();
};
BaseObject.addConstructorFunctions(BuildbotTesterQueueView);
BuildbotTesterQueueView.prototype = {
constructor: BuildbotTesterQueueView,
__proto__: BuildbotQueueView.prototype,
update: function()
{
BuildbotQueueView.prototype.update.call(this);
this.element.removeChildren();
function appendBuilderQueueStatus(queue)
{
if (queue.buildbot.needsAuthentication && !queue.buildbot.isAuthenticated) {
this._appendUnauthorizedLineView(queue);
return;
}
this._appendPendingRevisionCount(queue, this._latestProductiveIteration.bind(this, queue));
var appendedStatus = false;
var limit = 2;
for (var i = 0; i < queue.iterations.length && limit > 0; ++i) {
var iteration = queue.iterations[i];
if (!iteration.loaded || !iteration.finished)
continue;
--limit;
var willHaveAnotherStatusLine = i + 1 < queue.iterations.length && limit > 0 && !iteration.successful; // This is not 100% correct, as the remaining iterations may not be finished or loaded yet, but close enough.
var messageElement = this.revisionContentForIteration(iteration, (iteration.productive && willHaveAnotherStatusLine) ? iteration.previousProductiveIteration : null);
if (iteration.successful) {
var url = iteration.queue.buildbot.buildPageURLForIteration(iteration);
var status = new StatusLineView(messageElement, StatusLineView.Status.Good, "all tests passed", undefined, url);
limit = 0;
} else if (!iteration.productive) {
var url = iteration.queue.buildbot.buildPageURLForIteration(iteration);
var status = new StatusLineView(messageElement, StatusLineView.Status.Danger, iteration.text, undefined, url);
} else if (iteration.failedTestSteps.length === 0) {
// Something wrong happened, but it was not a test failure.
var url = iteration.queue.buildbot.buildPageURLForIteration(iteration);
var status = new StatusLineView(messageElement, StatusLineView.Status.Danger, iteration.text, undefined, url);
} else if (queue.crashesOnly) {
// A crashes-only queue is a queue where we are only interested in crashes, e.g. a GuardMalloc or an ASan one.
// Currently, only layout tests are supported in such.
var layoutTestResults = iteration.layoutTestResults;
if (!layoutTestResults) {
// Tests did not run.
var url = iteration.queue.buildbot.buildPageURLForIteration(iteration);
var status = new StatusLineView(messageElement, StatusLineView.Status.Danger, iteration.text, undefined, url);
} else if (layoutTestResults.tooManyFailures) {
var status = new StatusLineView(messageElement, StatusLineView.Status.Bad, "failure limit exceeded", undefined, iteration.queue.buildbot.layoutTestResultsURLForIteration(iteration));
new PopoverTracker(status.statusBubbleElement, this._presentPopoverForLayoutTestRegressions.bind(this), iteration);
} else if (layoutTestResults.errorOccurred) {
var url = iteration.queue.buildbot.buildPageURLForIteration(iteration);
var status = new StatusLineView(messageElement, StatusLineView.Status.Danger, iteration.text, undefined, url);
} else if (!layoutTestResults.crashCount) {
var url = iteration.queue.buildbot.buildPageURLForIteration(iteration);
var status = new StatusLineView(messageElement, StatusLineView.Status.Good, "no crashes found", undefined, url);
limit = 0;
} else {
var status = new StatusLineView(messageElement, StatusLineView.Status.Bad, layoutTestResults.crashCount === 1 ? "crash found" : "crashes found", layoutTestResults.crashCount, iteration.queue.buildbot.layoutTestResultsURLForIteration(iteration));
new PopoverTracker(status.statusBubbleElement, this._presentPopoverForLayoutTestRegressions.bind(this), iteration);
}
} else if (iteration.failedTestSteps.length === 1) {
var failedStep = iteration.failedTestSteps[0];
if (failedStep.name === "layout-test") {
var status = new StatusLineView(messageElement, StatusLineView.Status.Bad, this._testStepFailureDescription(failedStep), failedStep.tooManyFailures ? failedStep.failureCount + "\uff0b" : failedStep.failureCount, iteration.queue.buildbot.layoutTestResultsURLForIteration(iteration));
new PopoverTracker(status.statusBubbleElement, this._presentPopoverForLayoutTestRegressions.bind(this), iteration);
} else if (/(?=.*test)(?=.*jsc)/.test(failedStep.name)) {
var status = new StatusLineView(messageElement, StatusLineView.Status.Bad, this._testStepFailureDescription(failedStep), failedStep.failureCount, iteration.queue.buildbot.javaScriptCoreTestStdioUrlForIteration(iteration, failedStep.name));
new PopoverTracker(status.statusBubbleElement, this._presentPopoverForJavaScriptCoreTestRegressions.bind(this, failedStep.name), iteration);
} else if (failedStep.name === "dashboard-tests") {
var status = new StatusLineView(messageElement, StatusLineView.Status.Bad, this._testStepFailureDescription(failedStep), undefined, iteration.queue.buildbot.dashboardTestResultsURLForIteration(iteration));
new PopoverTracker(status.statusBubbleElement, this._presentPopoverForGenericTestFailures.bind(this), iteration);
} else {
var status = new StatusLineView(messageElement, StatusLineView.Status.Bad, this._testStepFailureDescription(failedStep), failedStep.failureCount ? failedStep.failureCount : undefined, failedStep.URL);
new PopoverTracker(status.statusBubbleElement, this._presentPopoverForGenericTestFailures.bind(this), iteration);
}
} else {
var url = iteration.queue.buildbot.buildPageURLForIteration(iteration);
var failureDescriptions = iteration.failedTestSteps.map(function(failedStep) { return this._testStepFailureDescriptionWithCount(failedStep) }, this);
var status = new StatusLineView(messageElement, StatusLineView.Status.Bad, failureDescriptions.join(", "), undefined, url);
new PopoverTracker(status.statusBubbleElement, this._presentPopoverForGenericTestFailures.bind(this), iteration);
}
this.element.appendChild(status.element);
appendedStatus = true;
}
if (!appendedStatus) {
var status = new StatusLineView("unknown", StatusLineView.Status.Neutral, "last passing build");
this.element.appendChild(status.element);
}
}
this.appendBuildStyle.call(this, this.releaseQueues, "Release", appendBuilderQueueStatus);
this.appendBuildStyle.call(this, this.debugQueues, "Debug", appendBuilderQueueStatus);
},
_popoverContentForLayoutTestRegressions: function(iteration)
{
var hasTestHistory = typeof testHistory !== "undefined";
var content = document.createElement("div");
content.className = "test-results-popover";
this._addIterationHeadingToPopover(iteration, content, "layout test failures");
this._addDividerToPopover(content);
if (!iteration.layoutTestResults.regressions) {
var message = document.createElement("div");
message.className = "loading-failure";
message.textContent = "Test results couldn\u2019t be loaded";
content.appendChild(message);
return content;
}
function addFailureInfoLink(rowElement, className, text, url)
{
var linkElement = document.createElement("a");
linkElement.className = className;
linkElement.textContent = text;
linkElement.href = url;
linkElement.target = "_blank";
rowElement.appendChild(linkElement);
}
function addFailureInfoText(rowElement, className, text)
{
var spanElement = document.createElement("span");
spanElement.className = className;
spanElement.textContent = text;
rowElement.appendChild(spanElement);
}
var sortedRegressions = iteration.layoutTestResults.regressions.slice().sort(function(a, b) { return (a.path === b.path) ? 0 : (a.path > b.path) ? 1 : -1; });
for (var i = 0, end = sortedRegressions.length; i != end; ++i) {
var test = sortedRegressions[i];
if (iteration.queue.crashesOnly && !test.crash && !iteration.layoutTestResults.tooManyFailures)
continue;
var rowElement = document.createElement("div");
var testPathElement = document.createElement("span");
testPathElement.className = "test-path";
testPathElement.textContent = test.path;
rowElement.appendChild(testPathElement);
if (test.crash)
addFailureInfoLink(rowElement, "failure-kind-indicator", "crash", iteration.queue.buildbot.layoutTestCrashLogURLForIteration(iteration, test.path));
if (test.timeout)
addFailureInfoText(rowElement, "failure-kind-indicator", "timeout");
if (test.has_diff) {
addFailureInfoLink(rowElement, "additional-link", "diff", iteration.queue.buildbot.layoutTestDiffURLForIteration(iteration, test.path));
if (iteration.hasPrettyPatch)
addFailureInfoLink(rowElement, "additional-link", "pretty\xa0diff", iteration.queue.buildbot.layoutTestPrettyDiffURLForIteration(iteration, test.path));
}
if (test.has_image_diff) {
addFailureInfoLink(rowElement, "additional-link", "images", iteration.queue.buildbot.layoutTestImagesURLForIteration(iteration, test.path));
addFailureInfoLink(rowElement, "additional-link", "image\xa0diff", iteration.queue.buildbot.layoutTestImageDiffURLForIteration(iteration, test.path));
}
if (test.has_stderr)
addFailureInfoLink(rowElement, "additional-link", "stderr", iteration.queue.buildbot.layoutTestStderrURLForIteration(iteration, test.path));
if (hasTestHistory)
addFailureInfoLink(rowElement, "test-history-link", "history", testHistory.historyPageURLForTest(test.path));
content.appendChild(rowElement);
}
content.oncopy = this._onPopoverCopy;
return content;
},
_presentPopoverForLayoutTestRegressions: function(element, popover, iteration)
{
if (iteration.layoutTestResults.regressions)
var content = this._popoverContentForLayoutTestRegressions(iteration);
else {
var content = this._createLoadingIndicator(iteration, "layout test failures");
iteration.loadLayoutTestResults(function() {
popover.content = this._popoverContentForLayoutTestRegressions(iteration);
}.bind(this));
}
var rect = Dashboard.Rect.rectFromClientRect(element.getBoundingClientRect());
popover.content = content;
popover.present(rect, [Dashboard.RectEdge.MIN_Y, Dashboard.RectEdge.MAX_Y, Dashboard.RectEdge.MAX_X, Dashboard.RectEdge.MIN_X]);
return true;
},
_presentPopoverForGenericTestFailures: function(element, popover, iteration)
{
function addResultKind(message, url) {
var line = document.createElement("a");
line.className = "failing-test-kind-summary";
line.href = url;
line.textContent = message;
line.target = "_blank";
content.appendChild(line);
}
var content = document.createElement("div");
content.className = "test-results-popover";
this._addIterationHeadingToPopover(iteration, content);
this._addDividerToPopover(content);
iteration.failedTestSteps.forEach(function(failedStep) {
if (failedStep.name === "layout-test")
addResultKind(this._testStepFailureDescriptionWithCount(failedStep), iteration.queue.buildbot.layoutTestResultsURLForIteration(iteration));
else if (failedStep.name === "dashboard-tests")
addResultKind(this._testStepFailureDescription(failedStep), iteration.queue.buildbot.dashboardTestResultsURLForIteration(iteration));
else
addResultKind(this._testStepFailureDescriptionWithCount(failedStep), failedStep.URL);
}, this);
var rect = Dashboard.Rect.rectFromClientRect(element.getBoundingClientRect());
popover.content = content;
popover.present(rect, [Dashboard.RectEdge.MIN_Y, Dashboard.RectEdge.MAX_Y, Dashboard.RectEdge.MAX_X, Dashboard.RectEdge.MIN_X]);
return true;
}
};