Commit 89e7a144 authored by ojan@chromium.org's avatar ojan@chromium.org

Get sheriff-o-matic data from auto-sheriff.appspot.com.

This moves the logic of which tests are failing and their
regression ranges to the server. This makes the tool much
faster to load. Having it on the server makes it so that
multiple tools can use this data.

Also, the data on the server has all the data we need for
non-layout test steps, so extending sheriff-o-matic will
be very easy once we have this in place.

NOTRY=true
R=abarth@chromium.org

Review URL: https://codereview.chromium.org/402603007

git-svn-id: svn://svn.chromium.org/blink/trunk@178597 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent dd93c209
...@@ -29,7 +29,9 @@ CTCommitLog.prototype._processXml = function(xml) { ...@@ -29,7 +29,9 @@ CTCommitLog.prototype._processXml = function(xml) {
Array.prototype.forEach.call(xml.getElementsByTagName('entry'), function(logentry) { Array.prototype.forEach.call(xml.getElementsByTagName('entry'), function(logentry) {
var author = logentry.getElementsByTagName('author')[0].textContent.trim(); var author = logentry.getElementsByTagName('author')[0].textContent.trim();
var message = logentry.getElementsByTagName('content')[0].textContent.trim(); var message = logentry.getElementsByTagName('content')[0].textContent.trim();
var commit = new CTCommit(author, message); // FIXME: Handle base urls for different repos.
// FIXME: This class should import config.js if it keeps using config.*.
var commit = new CTCommit(author, message, config.kBlinkRevisionURL);
this.commits[commit.revision] = commit; this.commits[commit.revision] = commit;
}.bind(this)); }.bind(this));
} }
......
...@@ -18,10 +18,10 @@ var kExampleCommitMessage = ...@@ -18,10 +18,10 @@ var kExampleCommitMessage =
"\n" + "\n" +
"Review URL: https://chromiumcodereview.appspot.com/25022002\n" + "Review URL: https://chromiumcodereview.appspot.com/25022002\n" +
"\n" + "\n" +
"git-svn-id: svn://svn.chromium.org/blink/trunk@158545 bbb929c8-8fbe-4397-9dbb-9b2b20218538\n"; "git-svn-id: svn://svn.chromium.org/blink/trunk@158545 bbb929c8-8fbe-4397-9dbb-9b2b20218538";
window.CTCommitMock = function() { window.CTCommitMock = function() {
return new CTCommit("mkwst@chromium.org", kExampleCommitMessage); return new CTCommit("mkwst@chromium.org", kExampleCommitMessage, config.kBlinkRevisionURL);
}; };
})(); })();
......
...@@ -5,14 +5,24 @@ found in the LICENSE file. ...@@ -5,14 +5,24 @@ found in the LICENSE file.
--> -->
<script> <script>
function CTCommit(author, message) { function CTCommit(author, message, baseUrl) {
this.author = author; this.author = author;
this.message = message; this.message = message;
this.revision = this._findRevision(); this.revision = this._findRevision();
// FIXME: This is a needlessly expensive way to grab the first line. // FIXME: This is a needlessly expensive way to grab the first line.
this.summary = this.message.split('\n')[0]; this.summary = this.message.split('\n')[0];
this._baseUrl = baseUrl;
} }
Object.defineProperty(CTCommit.prototype, "url", {
get: function url() {
return this._baseUrl + '?' + Object.toQueryString({
view: 'rev',
revision: this.revision,
});
},
});
CTCommit.prototype._findRevision = function() { CTCommit.prototype._findRevision = function() {
// FIXME: Make this regexp more general. // FIXME: Make this regexp more general.
var regexp = /git-svn-id: svn:\/\/svn.chromium.org\/blink\/trunk@(\d+)/; var regexp = /git-svn-id: svn:\/\/svn.chromium.org\/blink\/trunk@(\d+)/;
......
...@@ -43,21 +43,14 @@ THE POSSIBILITY OF SUCH DAMAGE. ...@@ -43,21 +43,14 @@ THE POSSIBILITY OF SUCH DAMAGE.
<ol id="qunit-tests"></ol> <ol id="qunit-tests"></ol>
<script src="bower_components/sugar/release/sugar-full.development.js"></script> <script src="bower_components/sugar/release/sugar-full.development.js"></script>
<script src="scripts/base.js"></script>
<script src="scripts/config.js"></script> <script src="scripts/config.js"></script>
<script src="scripts/net.js"></script> <script src="scripts/net.js"></script>
<script src="scripts/net_unittests.js"></script> <script src="scripts/net_unittests.js"></script>
<script src="scripts/svn-log.js"></script>
<script src="scripts/svn-log_unittests.js"></script>
<script src="scripts/treestatus.js"></script> <script src="scripts/treestatus.js"></script>
<script src="scripts/treestatus_unittests.js"></script> <script src="scripts/treestatus_unittests.js"></script>
<script src="scripts/builders.js"></script>
<script src="scripts/builders_unittests.js"></script>
<script src="scripts/results.js"></script> <script src="scripts/results.js"></script>
<script src="scripts/results_unittests.js"></script> <script src="scripts/results_unittests.js"></script>
<script src="scripts/ui.js"></script> <script src="scripts/ui.js"></script>
<script src="scripts/model.js"></script>
<script src="scripts/model_unittests.js"></script>
<script src="bower_components/platform/platform.js"></script> <script src="bower_components/platform/platform.js"></script>
<link rel="import" href="bower_components/polymer/polymer.html"> <link rel="import" href="bower_components/polymer/polymer.html">
......
/*
* Copyright (C) 2011 Google 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.
*/
var base = base || {};
(function(){
// This is effectively a cache of possibly-resolved promises.
base.AsynchronousCache = function(fetch)
{
this._fetch = fetch;
this._promiseCache = {};
};
base.AsynchronousCache._sentinel = new Object();
base.AsynchronousCache.prototype.get = function(key)
{
if (!(key in this._promiseCache)) {
this._promiseCache[key] = base.AsynchronousCache._sentinel;
this._promiseCache[key] = this._fetch.call(null, key);
}
if (this._promiseCache[key] === base.AsynchronousCache._sentinel)
return Promise.reject(Error("Reentrant request for ", key));
return this._promiseCache[key];
};
base.AsynchronousCache.prototype.clear = function()
{
this._promiseCache = {};
};
})();
/*
* Copyright (C) 2011 Google 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.
*/
var builders = builders || {};
(function() {
var kWebKitTestsStepNames = ['webkit_tests', 'layout-test'];
var kCrashedOrHungOutputMarker = 'crashed or hung';
function urlForBuildInfo(builderName, buildNumber)
{
return config.buildConsoleURL + '/json/builders/' + encodeURIComponent(builderName) + '/builds/' + encodeURIComponent(buildNumber);
}
function didFail(step)
{
if (kWebKitTestsStepNames.indexOf(step.name) != -1) {
// run-webkit-tests fails to generate test coverage when it crashes or hangs.
// FIXME: Do build.webkit.org bots output this marker when the tests fail to run?
return step.text.indexOf(kCrashedOrHungOutputMarker) != -1;
}
// The first item in step.results is the success of the step:
// 0 == pass, 1 == warning, 2 == fail
return step.results[0] == 2;
}
function failingSteps(buildInfo)
{
return buildInfo.steps.filter(didFail);
}
function mostRecentCompletedBuildNumber(individualBuilderStatus)
{
if (!individualBuilderStatus)
return null;
for (var i = individualBuilderStatus.cachedBuilds.length - 1; i >= 0; --i) {
var buildNumber = individualBuilderStatus.cachedBuilds[i];
if (individualBuilderStatus.currentBuilds.indexOf(buildNumber) == -1)
return buildNumber;
}
return null;
}
var g_buildInfoCache = new base.AsynchronousCache(function(key) {
var explodedKey = key.split('\n');
return net.json(urlForBuildInfo(explodedKey[0], explodedKey[1]));
});
builders.clearBuildInfoCache = function()
{
g_buildInfoCache.clear();
};
function fetchMostRecentBuildInfoByBuilder()
{
var buildInfoByBuilder = {};
var requestPromises = [];
return net.json(config.buildConsoleURL + '/json/builders').then(function(builderStatus) {
var builderNames = Object.keys(builderStatus);
builderNames.forEach(function(builderName) {
if (!config.builderApplies(builderName))
return;
var buildNumber = mostRecentCompletedBuildNumber(builderStatus[builderName]);
if (!buildNumber)
return;
requestPromises.push(g_buildInfoCache.get(builderName + '\n' + buildNumber)
.then(function(buildInfo) {
buildInfoByBuilder[builderName] = buildInfo;
}));
});
return Promise.all(requestPromises).then(function() {
return buildInfoByBuilder;
});
});
}
builders.buildersFailingNonLayoutTests = function()
{
return fetchMostRecentBuildInfoByBuilder().then(function(buildInfoByBuilder) {
var failureList = {};
Object.keys(buildInfoByBuilder, function(builderName, buildInfo) {
if (!buildInfo)
return;
var failures = failingSteps(buildInfo);
if (failures.length)
failureList[builderName] = failures.map(function(failure) { return failure.name; });
});
return failureList;
});
};
builders.mostRecentBuildForBuilder = function(builderName) {
return net.json(config.buildConsoleURL + '/json/builders/' + builderName).then(function(builderStatus) {
var cachedBuilds = builderStatus.cachedBuilds;
var mostRecentBuild = Math.max.apply(Math, cachedBuilds);
return mostRecentBuild;
});
};
})();
...@@ -30,9 +30,9 @@ var config = config || {}; ...@@ -30,9 +30,9 @@ var config = config || {};
config = { config = {
kUpdateFrequency: 1000 * 30, kUpdateFrequency: 1000 * 30,
kBlinkRevisionURL: 'http://src.chromium.org/viewvc/blink', kBlinkRevisionURL: 'http://src.chromium.org/viewvc/blink',
buildConsoleURL: 'http://build.chromium.org/p/chromium.webkit',
layoutTestResultsURL: 'https://storage.googleapis.com/chromium-layout-test-archives', layoutTestResultsURL: 'https://storage.googleapis.com/chromium-layout-test-archives',
waterfallURL: 'http://build.chromium.org/p/chromium.webkit/waterfall', waterfallURL: 'http://build.chromium.org/p/chromium.webkit/waterfall',
// FIXME: All usages of this list need to be replaced.
builders: { builders: {
'WebKit XP': {version: 'xp'}, 'WebKit XP': {version: 'xp'},
'WebKit Win7': {version: 'win7'}, 'WebKit Win7': {version: 'win7'},
...@@ -52,13 +52,6 @@ config = { ...@@ -52,13 +52,6 @@ config = {
'WebKit Mac10.9': {version: 'mavericks'}, 'WebKit Mac10.9': {version: 'mavericks'},
'WebKit Android (Nexus4)': {version: 'android'}, 'WebKit Android (Nexus4)': {version: 'android'},
}, },
resultsDirectoryNameFromBuilderName: function(builderName) {
return builderName.replace(/[ .()]/g, '_');
},
builderApplies: function(builderName) {
return builderName.indexOf('GPU') == -1 &&
builderName.indexOf('Oilpan') == -1;
},
}; };
})(); })();
/*
* Copyright (C) 2011 Google 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.
*/
var model = model || {};
(function () {
var kCommitLogLength = 50;
model.state = {};
model.state.failureAnalysisByTest = {};
function findAndMarkRevertedRevisions(commitDataList)
{
var revertedRevisions = {};
Object.keys(commitDataList, function(index, commitData) {
if (commitData.revertedRevision)
revertedRevisions[commitData.revertedRevision] = true;
});
Object.keys(commitDataList, function(index, commitData) {
if (commitData.revision in revertedRevisions)
commitData.wasReverted = true;
});
}
function fuzzyFind(testName, commitData)
{
var indexOfLastDot = testName.lastIndexOf('.');
var stem = indexOfLastDot == -1 ? testName : testName.substr(0, indexOfLastDot);
return commitData.message.indexOf(stem) != -1;
}
function heuristicallyNarrowRegressionRange(failureAnalysis)
{
var commitDataList = model.state.recentCommits;
var commitDataIndex = commitDataList.length - 1;
for(var revision = failureAnalysis.newestPassingRevision + 1; revision <= failureAnalysis.oldestFailingRevision; ++revision) {
while (commitDataIndex >= 0 && commitDataList[commitDataIndex].revision < revision)
--commitDataIndex;
var commitData = commitDataList[commitDataIndex];
if (commitData.revision != revision)
continue;
if (fuzzyFind(failureAnalysis.testName, commitData)) {
failureAnalysis.oldestFailingRevision = revision;
failureAnalysis.newestPassingRevision = revision - 1;
return;
}
}
}
var g_commitIndex = {};
model.updateRecentCommits = function()
{
return trac.recentCommitData('trunk', kCommitLogLength).then(function(commitDataList) {
model.state.recentCommits = commitDataList;
updateCommitIndex();
findAndMarkRevertedRevisions(model.state.recentCommits);
});
};
function updateCommitIndex()
{
model.state.recentCommits.forEach(function(commitData) {
g_commitIndex[commitData.revision] = commitData;
});
}
model.commitDataListForRevisionRange = function(fromRevision, toRevision)
{
var result = [];
for (var revision = fromRevision; revision <= toRevision; ++revision) {
var commitData = g_commitIndex[revision];
if (commitData)
result.push(commitData);
}
return result;
};
model.buildersInFlightForRevision = function(revision)
{
var builders = {};
Object.keys(model.state.resultsByBuilder).forEach(function(builderName) {
var results = model.state.resultsByBuilder[builderName];
if (parseInt(results.blink_revision) < revision)
builders[builderName] = { actual: 'BUILDING' };
});
return builders;
};
model.updateResultsByBuilder = function()
{
return results.fetchResultsByBuilder(Object.keys(config.builders)).then(function(resultsByBuilder) {
model.state.resultsByBuilder = resultsByBuilder;
});
};
// failureCallback is called multiple times: once for each failure
model.analyzeUnexpectedFailures = function(failureCallback)
{
var unexpectedFailures = results.unexpectedFailuresByTest(model.state.resultsByBuilder);
Object.keys(model.state.failureAnalysisByTest, function(testName, failureAnalysis) {
if (!(testName in unexpectedFailures))
delete model.state.failureAnalysisByTest[testName];
});
var failurePromises = [];
Object.keys(unexpectedFailures, function(testName, resultNodesByBuilder) {
var builderNameList = Object.keys(resultNodesByBuilder);
failurePromises.push(results.unifyRegressionRanges(builderNameList, testName).then(function(result) {
var oldestFailingRevision = result[0];
var newestPassingRevision = result[1];
var failureAnalysis = {
'testName': testName,
'resultNodesByBuilder': resultNodesByBuilder,
'oldestFailingRevision': oldestFailingRevision,
'newestPassingRevision': newestPassingRevision,
};
heuristicallyNarrowRegressionRange(failureAnalysis);
var previousFailureAnalysis = model.state.failureAnalysisByTest[testName];
if (previousFailureAnalysis
&& previousFailureAnalysis.oldestFailingRevision <= failureAnalysis.oldestFailingRevision
&& previousFailureAnalysis.newestPassingRevision >= failureAnalysis.newestPassingRevision) {
failureAnalysis.oldestFailingRevision = previousFailureAnalysis.oldestFailingRevision;
failureAnalysis.newestPassingRevision = previousFailureAnalysis.newestPassingRevision;
}
model.state.failureAnalysisByTest[testName] = failureAnalysis;
failureCallback(failureAnalysis, failurePromises.length);
}));
});
return Promise.all(failurePromises);
};
})();
/*
* Copyright (C) 2011 Google 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.
*/
(function () {
module("model");
var kExampleCommitDataXML =
"<feed xmlns='http://www.w3.org/2005/Atom'>\n" +
"<title>blink, branch master</title>\n" +
"<subtitle>Mirror of the Chromium Blink repository.</subtitle>\n" +
"<link rel='alternate' type='text/html' href='http://blink.lc/blink/'/>\n" +
"<entry>\n" +
"<title>Throw SecurityError when setting 'Replaceable' properties cross-origin.</title>\n" +
"<updated>2013-09-30T20:22:01Z</updated>\n" +
"<author>\n" +
"<name>mkwst@chromium.org</name>\n" +
"</author>\n" +
"<published>2013-09-30T20:22:01Z</published>\n" +
"<link rel='alternate' type='text/html' href='http://blink.lc/blink/commit/?id=723e62a4a4e093435b4772b4839aa3fd7cf6b991'/>\n" +
"<id>723e62a4a4e093435b4772b4839aa3fd7cf6b991</id>\n" +
"<content type='text'>\n" +
"This matches Gecko's behavior for these types of properties.\n" +
"\n" +
"BUG=13\n" +
"R=jochen@chromium.org\n" +
"CC=abarth@chromium.org\n" +
"\n" +
"Review URL: https://chromiumcodereview.appspot.com/25022002\n" +
"\n" +
"git-svn-id: svn://svn.chromium.org/blink/trunk@3 bbb929c8-8fbe-4397-9dbb-9b2b20218538\n" +
"</content>\n" +
"</entry>\n" +
"<entry>\n" +
"<title>Fix one more layering violation caught by check-blink-deps</title>\n" +
"<updated>2013-09-30T19:36:21Z</updated>\n" +
"<author>\n" +
"<name>eseidel@chromium.org</name>\n" +
"</author>\n" +
"<published>2013-09-30T19:36:21Z</published>\n" +
"<link rel='alternate' type='text/html' href='http://blink.lc/blink/commit/?id=51e5c70050dcb0980eb31f112d0cd948f3ece820'/>\n" +
"<id>51e5c70050dcb0980eb31f112d0cd948f3ece820</id>\n" +
"<content type='text'>\n" +
"core/platform may not depend on core/ even for testing.\n" +
"\n" +
"BUG=12\n" +
"R=abarth@chromium.org, abarth\n" +
"\n" +
"Review URL: https://codereview.chromium.org/25284004\n" +
"\n" +
"git-svn-id: svn://svn.chromium.org/blink/trunk@2 bbb929c8-8fbe-4397-9dbb-9b2b20218538\n" +
"</content>\n" +
"</entry>\n" +
"<entry>\n" +
"<title>Update DEPS include_rules after addition of root-level platform directory</title>\n" +
"<updated>2013-09-30T19:28:49Z</updated>\n" +
"<author>\n" +
"<name>eseidel@chromium.org</name>\n" +
"</author>\n" +
"<published>2013-09-30T19:28:49Z</published>\n" +
"<link rel='alternate' type='text/html' href='http://blink.lc/blink/commit/?id=227add0156e8ab272abcd3368dfc0b5a91f35749'/>\n" +
"<id>227add0156e8ab272abcd3368dfc0b5a91f35749</id>\n" +
"<content type='text'>\n" +
"These were all failures noticed when running check-blink-deps\n" +
"\n" +
"R=abarth@chromium.org, abarth\n" +
"BUG=11\n" +
"\n" +
"Review URL: https://codereview.chromium.org/25275005\n" +
"\n" +
"git-svn-id: svn://svn.chromium.org/blink/trunk@1 bbb929c8-8fbe-4397-9dbb-9b2b20218538\n" +
"</content>\n" +
"</entry>\n" +
"</feed>\n";
asyncTest("updateRecentCommits", 2, function() {
var simulator = new NetworkSimulator();
simulator.xml = function(url)
{
var parser = new DOMParser();
var responseDOM = parser.parseFromString(kExampleCommitDataXML, "application/xml");
return Promise.resolve(responseDOM);
};
simulator.runTest(function() {
model.updateRecentCommits().then(function() {
var recentCommits = model.state.recentCommits;
delete model.state.recentCommits;
recentCommits.forEach(function(commitData) {
delete commitData.message;
});
deepEqual(recentCommits, [{
"revision": 3,
"title": "Throw SecurityError when setting 'Replaceable' properties cross-origin.",
"time": "2013-09-30T20:22:01Z",
"summary": "This matches Gecko's behavior for these types of properties.",
"author": "mkwst@chromium.org",
"reviewer": "jochen@chromium.org",
"bugID": [13],
"revertedRevision": undefined,
},
{
"revision": 2,
"title": "Fix one more layering violation caught by check-blink-deps",
"time": "2013-09-30T19:36:21Z",
"summary": "core/platform may not depend on core/ even for testing.",
"author": "eseidel@chromium.org",
"reviewer": "abarth@chromium.org, abarth",
"bugID": [12],
"revertedRevision": undefined
},
{
"revision": 1,
"title": "Update DEPS include_rules after addition of root-level platform directory",
"time": "2013-09-30T19:28:49Z",
"summary": "These were all failures noticed when running check-blink-deps",
"author": "eseidel@chromium.org",
"reviewer": "abarth@chromium.org, abarth",
"bugID": [11],
"revertedRevision": undefined
}
]);
});
}).then(start);
});
asyncTest("commitDataListForRevisionRange", 6, function() {
var simulator = new NetworkSimulator();
simulator.xml = function(url)
{
var parser = new DOMParser();
var responseDOM = parser.parseFromString(kExampleCommitDataXML, "application/xml");
return Promise.resolve(responseDOM);
};
simulator.runTest(function() {
model.updateRecentCommits().then(function() {
function extractBugIDs(commitData)
{
return commitData.bugID;
}
deepEqual(model.commitDataListForRevisionRange(3, 3).map(extractBugIDs), [[13]]);
deepEqual(model.commitDataListForRevisionRange(1, 3).map(extractBugIDs), [[11], [12], [13]]);
deepEqual(model.commitDataListForRevisionRange(0, 1).map(extractBugIDs), [[11]]);
deepEqual(model.commitDataListForRevisionRange(0, 4).map(extractBugIDs), [[11], [12], [13]]);
deepEqual(model.commitDataListForRevisionRange(4, 0).map(extractBugIDs), []);
delete model.state.recentCommits;
});
}).then(start);
});
test("buildersInFlightForRevision", 3, function() {
var unmock = model.state.resultsByBuilder;
model.state.resultsByBuilder = {
'Mr. Beasley': {blink_revision: '5'},
'Mr Dixon': {blink_revision: '1'},
'Mr. Sabatini': {blink_revision: '4'},
'Bob': {blink_revision: '6'}
};
deepEqual(model.buildersInFlightForRevision(1), {});
deepEqual(model.buildersInFlightForRevision(3), {
"Mr Dixon": {
"actual": "BUILDING"
}
});
deepEqual(model.buildersInFlightForRevision(10), {
"Mr. Beasley": {
"actual": "BUILDING"
},
"Mr Dixon": {
"actual": "BUILDING"
},
"Mr. Sabatini": {
"actual": "BUILDING"
},
"Bob": {
"actual": "BUILDING"
}
});
model.state.resultsByBuilder = unmock;
});
})();
/*
* Copyright (C) 2011 Apple Inc. All rights reserved.
* Copyright (C) 2012 Google 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.
*/
var trac = trac || {};
(function() {
function findUsingRegExp(string, regexp)
{
var match = regexp.exec(string);
if (match)
return match[1];
return null;
}
function findReviewer(message)
{
var regexp = /(?:^|\n)\s*(?:TB)?R=(.+)/;
var reviewers = findUsingRegExp(message, regexp);
if (!reviewers)
return null;
return reviewers.replace(/\s*,\s*/g, ', ');
}
function findBugID(message)
{
var regexp = /(?:^|\n)\s*BUG=(.+)/;
var value = findUsingRegExp(message, regexp);
if (!value)
return null;
var result = value.split(/\s*,\s*/).map(function(id) {
var parsedID = parseInt(id.replace(/[^\d]/g, ''), 10);
return isNaN(parsedID) ? 0 : parsedID;
}).filter(function(id) {
return !!id;
});
return result.length ? result : null;
}
function findRevision(message)
{
var regexp = /git-svn-id: svn:\/\/svn.chromium.org\/blink\/trunk@(\d+)/;
var svnRevision = parseInt(findUsingRegExp(message, regexp), 10);
return isNaN(svnRevision) ? null : svnRevision;
}
function parseCommitMessage(message) {
var lines = message.split('\n');
var title = '';
lines.some(function(line) {
if (line) {
title = line;
return true;
}
});
var summary = lines.join('\n').trim();
return {
title: title,
summary: summary,
bugID: findBugID(summary),
reviewer: findReviewer(summary),
revision: findRevision(summary),
};
}
// FIXME: Consider exposing this method for unit testing.
function parseCommitData(responseXML)
{
var commits = Array.prototype.map.call(responseXML.getElementsByTagName('entry'), function(logentry) {
var author = logentry.getElementsByTagName('author')[0].textContent.trim();
var time = logentry.getElementsByTagName('published')[0].textContent;
var titleElement = logentry.getElementsByTagName('title')[0];
var title = titleElement ? titleElement.textContent : null;
// FIXME: This isn't a very high-fidelity reproduction of the commit message,
// but it's good enough for our purposes.
var message = parseCommitMessage(logentry.getElementsByTagName('content')[0].textContent);
return {
'revision': message.revision,
'title': title || message.title,
'time': time,
'summary': message.title,
'author': author,
'reviewer': message.reviewer,
'bugID': message.bugID,
'message': message.summary,
'revertedRevision': undefined,
};
});
return commits;
}
trac._queryParam = function(params)
{
var result = []
Object.keys(params, function(key, value) {
result.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
});
// FIXME: Remove the conversion of space to plus. This is just here
// to remain compatible with jQuery.param, but there's no reason to
// deviate from the built-in encodeURIComponent behavior.
return result.join('&').replace(/%20/g, '+');
}
trac.changesetURL = function(revision)
{
var queryParameters = {
view: 'rev',
revision: revision,
};
return config.kBlinkRevisionURL + '?' + trac._queryParam(queryParameters);
};
trac.recentCommitData = function(path, limit)
{
return net.xml('http://blink.lc/blink/atom').then(function(commitData) {
return parseCommitData(commitData);
});
};
})();
...@@ -125,13 +125,10 @@ found in the LICENSE file. ...@@ -125,13 +125,10 @@ found in the LICENSE file.
passingRevisions.push(failure.newestPassingRevision); passingRevisions.push(failure.newestPassingRevision);
var results = failure.resultNodesByBuilder; var results = failure.resultNodesByBuilder;
Object.keys(results, (function(builder) { Object.keys(results, (function(builder) {
var result = results[builder]; var result = results[builder].actual;
if (!result.is_unexpected) if (!Object.has(this.resultTypes, result))
return; this.resultTypes[result] = {};
this.resultTypes[result][builder] =
if (!Object.has(this.resultTypes, result.actual))
this.resultTypes[result.actual] = {};
this.resultTypes[result.actual][builder] =
config.builders[builder]; config.builders[builder];
}).bind(this)); }).bind(this));
}, this); }, this);
......
...@@ -6,23 +6,24 @@ found in the LICENSE file. ...@@ -6,23 +6,24 @@ found in the LICENSE file.
<link rel="import" href="ct-commit.html"> <link rel="import" href="ct-commit.html">
<link rel="import" href="model/ct-commit-mock.html"> <link rel="import" href="../model/ct-commit-mock.html">
<script> <script>
(function () { (function () {
module("ct-commit"); module("ct-commit");
asyncTest("basic", 2, function() { asyncTest("basic", 3, function() {
var grouper = document.createElement('ct-commit'); var grouper = document.createElement('ct-commit');
grouper.data = new CTCommitMock(); grouper.data = new CTCommitMock();
Platform.endOfMicrotask(function() { requestAnimationFrame(function() {
var html = grouper.shadowRoot.innerHTML; var html = grouper.shadowRoot.innerHTML;
equal(html.indexOf('mkwst') != -1, true) equal(html.indexOf('mkwst') != -1, true);
equal(html.indexOf('behavior for these types') != -1, true) equal(html.indexOf('behavior for these types') != -1, true);
equal(grouper.shadowRoot.querySelector('a').href, grouper.data.url);
start(); start();
}); });
......
...@@ -4,7 +4,7 @@ Use of this source code is governed by a BSD-style license that can be ...@@ -4,7 +4,7 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. found in the LICENSE file.
--> -->
<polymer-element name="ct-commit" attributes="data"> <polymer-element name="ct-commit" attributes="data" noscript>
<template> <template>
<style> <style>
:host { :host {
...@@ -32,14 +32,6 @@ found in the LICENSE file. ...@@ -32,14 +32,6 @@ found in the LICENSE file.
border-bottom: 5px solid white; border-bottom: 5px solid white;
} }
</style> </style>
<a href="{{data.revision|changesetURL}}">{{data.revision}}</a> {{data.summary}} <em>{{data.author}}</em> <a href="{{ data.url }}">{{ data.revision }}</a> {{ data.summary }} <em>{{ data.author }}</em>
</template> </template>
<script>
Polymer({
changesetURL: function(revision) {
// FIXME: This is the last caller of trac.*. Find a better home for this.
return trac.changesetURL(revision);
},
});
</script>
</polymer-element> </polymer-element>
...@@ -4,47 +4,80 @@ Use of this source code is governed by a BSD-style license that can be ...@@ -4,47 +4,80 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. found in the LICENSE file.
--> -->
<polymer-element name="ct-failure-analyzer" attributes="failures status builderLatestRevisions"> <polymer-element name="ct-failure-analyzer" attributes="failures builderLatestRevisions">
<script> <script>
// FIXME: Don't use a polymer component for this. Instead use a Failures model
// object that knows how to do the XHR and process the data appropriately.
Polymer({ Polymer({
failures: {},
pendingUnexpectedFailures: [],
builderLatestRevisions: {}, builderLatestRevisions: {},
failures: {},
update: function() { update: function() {
this._updateFailingBuilders(); net.json('http://auto-sheriff.appspot.com/data').then(function(data) {
this._updateUnexpectedFailures(); // FIXME: Don't special-case the blink master.
this.builderLatestRevisions = data.latest_revisions['chromium.webkit'];
this.failures.builders = {};
this.failures.unexpected = [];
data.range_groups.forEach(function(group) {
this._processFailuresForGroup(group, data.alerts);
}.bind(this));
}.bind(this));
}, },
_updateFailingBuilders: function() { _processFailuresForGroup: function(group, failures) {
builders.buildersFailingNonLayoutTests().then((function(builders) { var failuresByReason = {};
this.failures.builders = builders; var failingBuildersWithoutReasons = {};
}).bind(this));
}, group.failure_keys.forEach(function(failure_key) {
var failure = failures.find(function(item) { return item.key == failure_key; });
if (failure.ignored_by.length)
return;
// FIXME: Make sheriff-o-matic work for all waterfalls.
if (!failure.master_url.endsWith('chromium.webkit'))
return;
// FIXME: Have sheriff-o-matic show non-webkit_tests failures by reason.
if (!failure.reason || failure.step_name != 'webkit_tests') {
var builder = failure.builder_name;
if (!failingBuildersWithoutReasons[builder])
failingBuildersWithoutReasons[builder] = {};
failingBuildersWithoutReasons[builder][failure.step_name] = 1;
return;
}
_updateBuilderLatestRevisions: function() { // FIXME: Store the actual failure type in a different field instead of smashing it into the reason.
this.builderLatestRevisions = {}; var parts = failure.reason.split(':');
Object.keys(config.builders, function(builder) { var reason = parts[0];
this.builderLatestRevisions[builder] = { var failureType = parts[1];
blink: model.state.resultsByBuilder[builder].blink_revision,
if (!failuresByReason[reason])
failuresByReason[reason] = {}
failuresByReason[reason][failure.builder_name] = {
actual: failureType,
}; };
}.bind(this)); }.bind(this));
},
_updateUnexpectedFailures: function() { var groupedFailures = [];
this.pendingUnexpectedFailures = []; var oldestFailingRevision = Number(group.merged_first_failing.blink);
var numberOfTestsAnalyzed = 0; var newestPassingRevision = group.merged_last_passing ? Number(group.merged_last_passing.blink) : undefined;
this.status = 'Updating ...';
Promise.all([model.updateRecentCommits(), model.updateResultsByBuilder()]).then(function() { Object.keys(failuresByReason, function(reason, resultNodesByBuilder) {
this.status = 'Analyzing test failures ...'; groupedFailures.push({
model.analyzeUnexpectedFailures(function(failureAnalysis, total) { testName: reason,
this.status = 'Analyzing test failures ... ' + ++numberOfTestsAnalyzed + '/' + total + ' tests analyzed.'; resultNodesByBuilder: resultNodesByBuilder,
this.pendingUnexpectedFailures.push(failureAnalysis); oldestFailingRevision: oldestFailingRevision,
}.bind(this)).then(function() { newestPassingRevision: newestPassingRevision,
this.status = 'Done'; });
this.failures.unexpected = this.pendingUnexpectedFailures; });
this._updateBuilderLatestRevisions();
}.bind(this)); if (groupedFailures.length)
this.failures.unexpected.push(groupedFailures);
// FIXME: Show these in the failure stream with regression ranges like
// any other kind of failure.
Object.keys(failingBuildersWithoutReasons, function(builder, steps) {
this.failures.builders[builder] = Object.keys(steps);
}.bind(this)); }.bind(this));
}, },
}); });
......
...@@ -5,13 +5,9 @@ found in the LICENSE file. ...@@ -5,13 +5,9 @@ found in the LICENSE file.
--> -->
<script src="../bower_components/sugar/release/sugar-full.development.js"></script> <script src="../bower_components/sugar/release/sugar-full.development.js"></script>
<script src="../scripts/base.js"></script>
<script src="../scripts/builders.js"></script>
<script src="../scripts/config.js"></script> <script src="../scripts/config.js"></script>
<script src="../scripts/model.js"></script>
<script src="../scripts/net.js"></script> <script src="../scripts/net.js"></script>
<script src="../scripts/results.js"></script> <script src="../scripts/results.js"></script>
<script src="../scripts/svn-log.js"></script>
<script src="../scripts/treestatus.js"></script> <script src="../scripts/treestatus.js"></script>
<script src="../scripts/ui.js"></script> <script src="../scripts/ui.js"></script>
......
...@@ -5,7 +5,6 @@ found in the LICENSE file. ...@@ -5,7 +5,6 @@ found in the LICENSE file.
--> -->
<link rel="import" href="../bower_components/paper-button/paper-button.html"> <link rel="import" href="../bower_components/paper-button/paper-button.html">
<link rel="import" href="../bower_components/paper-toast/paper-toast.html">
<link rel="import" href="../model/ct-commit-log.html"> <link rel="import" href="../model/ct-commit-log.html">
<link rel="import" href="ct-failing-builders.html"> <link rel="import" href="ct-failing-builders.html">
<link rel="import" href="ct-failure-analyzer.html"> <link rel="import" href="ct-failure-analyzer.html">
...@@ -16,11 +15,6 @@ found in the LICENSE file. ...@@ -16,11 +15,6 @@ found in the LICENSE file.
<polymer-element name="ct-unexpected-failures"> <polymer-element name="ct-unexpected-failures">
<template> <template>
<style> <style>
paper-toast {
bottom: 40px;
left: 10px;
}
ct-failing-builders { ct-failing-builders {
margin: 5px; margin: 5px;
} }
...@@ -38,13 +32,11 @@ found in the LICENSE file. ...@@ -38,13 +32,11 @@ found in the LICENSE file.
padding: 0; padding: 0;
} }
</style> </style>
<ct-failure-analyzer id="analyzer" status="{{ analyzerStatus }}" failures="{{ failures }}" builderLatestRevisions="{{ builderLatestRevisions }}"></ct-failure-analyzer> <ct-failure-analyzer id="analyzer" failures="{{ failures }}" builderLatestRevisions="{{ builderLatestRevisions }}"></ct-failure-analyzer>
<ct-failure-grouper failures="{{ failures.unexpected }}" groups="{{ failureGroups }}"></ct-failure-grouper>
<ct-tree-status project="chromium"></ct-tree-status> <ct-tree-status project="chromium"></ct-tree-status>
<ct-tree-status project="blink"></ct-tree-status> <ct-tree-status project="blink"></ct-tree-status>
<ct-failing-builders builders="{{ failures.builders }}"></ct-failing-builders> <ct-failing-builders builders="{{ failures.builders }}"></ct-failing-builders>
<ct-failure-stream groups="{{ failureGroups }}" builderLatestRevisions="{{ builderLatestRevisions }}" commits="{{ revisionLog.commits }}"></ct-failure-stream> <ct-failure-stream groups="{{ failures.unexpected }}" builderLatestRevisions="{{ builderLatestRevisions }}" commits="{{revisionLog.commits}}"></ct-failure-stream>
<paper-toast id="toast" text="{{ analyzerStatus }}"></paper-toast>
</template> </template>
<script> <script>
Polymer({ Polymer({
...@@ -63,10 +55,6 @@ found in the LICENSE file. ...@@ -63,10 +55,6 @@ found in the LICENSE file.
for (var i = 0; i < treeStatuses.length; i++) for (var i = 0; i < treeStatuses.length; i++)
treeStatuses[i].update(); treeStatuses[i].update();
}, },
analyzerStatusChanged: function() {
this.$.toast.show();
},
}); });
</script> </script>
</polymer-element> </polymer-element>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment