Title: [90652] trunk/Tools
Revision
90652
Author
[email protected]
Date
2011-07-08 12:26:32 -0700 (Fri, 08 Jul 2011)

Log Message

Teach garden-o-matic how to display test results
https://bugs.webkit.org/show_bug.cgi?id=64141

Reviewed by Ojan Vafai.

This patch includes basic infrastructure for probing build.chromium.org
for test results.  We only handle text and image tests, not anything
complicated like reftests.  Also, we're using the revision/build
independent results store on the server, so we're avoiding that
complication for now.

It's slightly hacky that we need to probe the server to see what kinds
of results exist.  A better solution would be to add CORS support to
the server or to use the local server to help.

* Scripts/webkitpy/tool/servers/data/gardeningserver/base.js:
* Scripts/webkitpy/tool/servers/data/gardeningserver/index.html:
* Scripts/webkitpy/tool/servers/data/gardeningserver/main.js:
* Scripts/webkitpy/tool/servers/data/gardeningserver/results.js:
* Scripts/webkitpy/tool/servers/data/gardeningserver/ui.js:
* Scripts/webkitpy/tool/servers/data/gardeningserver/ui_unittests.js:

Modified Paths

Diff

Modified: trunk/Tools/ChangeLog (90651 => 90652)


--- trunk/Tools/ChangeLog	2011-07-08 19:21:41 UTC (rev 90651)
+++ trunk/Tools/ChangeLog	2011-07-08 19:26:32 UTC (rev 90652)
@@ -1,3 +1,27 @@
+2011-07-08  Adam Barth  <[email protected]>
+
+        Teach garden-o-matic how to display test results
+        https://bugs.webkit.org/show_bug.cgi?id=64141
+
+        Reviewed by Ojan Vafai.
+
+        This patch includes basic infrastructure for probing build.chromium.org
+        for test results.  We only handle text and image tests, not anything
+        complicated like reftests.  Also, we're using the revision/build
+        independent results store on the server, so we're avoiding that
+        complication for now.
+
+        It's slightly hacky that we need to probe the server to see what kinds
+        of results exist.  A better solution would be to add CORS support to
+        the server or to use the local server to help.
+
+        * Scripts/webkitpy/tool/servers/data/gardeningserver/base.js:
+        * Scripts/webkitpy/tool/servers/data/gardeningserver/index.html:
+        * Scripts/webkitpy/tool/servers/data/gardeningserver/main.js:
+        * Scripts/webkitpy/tool/servers/data/gardeningserver/results.js:
+        * Scripts/webkitpy/tool/servers/data/gardeningserver/ui.js:
+        * Scripts/webkitpy/tool/servers/data/gardeningserver/ui_unittests.js:
+
 2011-07-08  Dirk Pranke  <[email protected]>
 
         REGRESSION(90419) NRWT's httpd locking is broken for --child-processes=1

Modified: trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/base.js (90651 => 90652)


--- trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/base.js	2011-07-08 19:21:41 UTC (rev 90651)
+++ trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/base.js	2011-07-08 19:26:32 UTC (rev 90652)
@@ -2,11 +2,27 @@
 
 (function(){
 
+base.endsWith = function(string, suffix)
+{
+    if (suffix.length > string.length)
+        return false;
+    var expectedIndex = string.length - suffix.length;
+    return string.lastIndexOf(suffix) == expectedIndex;
+};
+
 base.joinPath = function(parent, child)
 {
     if (parent.length == 0)
         return child;
     return parent + '/' + child;
+};
+
+base.trimExtension = function(url)
+{
+    var index = url.lastIndexOf('.');
+    if (index == -1)
+        return url;
+    return url.substr(0, index);
 }
 
 base.filterTree = function(tree, isLeaf, predicate)
@@ -29,6 +45,23 @@
 
     walkSubtree(tree, '');
     return filteredTree;
-}
+};
 
+base.probe = function(url, options)
+{
+    var scriptElement = document.createElement('script');
+    scriptElement.addEventListener('load', function() {
+        $(scriptElement).detach();
+        if (options.success)
+            options.success.call();
+    }, false);
+    scriptElement.addEventListener('error', function() {
+        $(scriptElement).detach();
+        if (options.error)
+            options.error.call();
+    }, false);
+    scriptElement.src = ""
+    document.head.appendChild(scriptElement);
+};
+
 })();

Modified: trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/base_unittests.js (90651 => 90652)


--- trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/base_unittests.js	2011-07-08 19:21:41 UTC (rev 90651)
+++ trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/base_unittests.js	2011-07-08 19:26:32 UTC (rev 90652)
@@ -5,6 +5,27 @@
     equals(value, "path/to/test.html");
 });
 
+test("endsWith", 9, function() {
+    ok(base.endsWith("xyz", ""));
+    ok(base.endsWith("xyz", "z"));
+    ok(base.endsWith("xyz", "yz"));
+    ok(base.endsWith("xyz", "xyz"));
+    ok(!base.endsWith("xyz", "wxyz"));
+    ok(!base.endsWith("xyz", "gwxyz"));
+    ok(base.endsWith("", ""));
+    ok(!base.endsWith("", "z"));
+    ok(!base.endsWith("xyxy", "yx"));
+});
+
+test("trimExtension", 6, function() {
+    equals(base.trimExtension("xyz"), "xyz");
+    equals(base.trimExtension("xy.z"), "xy");
+    equals(base.trimExtension("x.yz"), "x");
+    equals(base.trimExtension("x.y.z"), "x.y");
+    equals(base.trimExtension(".xyz"), "");
+    equals(base.trimExtension(""), "");
+});
+
 test("joinPath with empty parent", 1, function() {
     var value = base.joinPath("", "test.html");
     equals(value, "test.html");

Modified: trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/index.html (90651 => 90652)


--- trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/index.html	2011-07-08 19:21:41 UTC (rev 90651)
+++ trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/index.html	2011-07-08 19:26:32 UTC (rev 90652)
@@ -40,10 +40,14 @@
 .failures .builders {
   color: #888;
 }
-.failures .builderName, .failures .actual {
+.builder .builderName, .builder .actual {
   float: left;
   width: 200px;
 }
+.results iframe, .results img {
+  width: 400px;
+  height: 300px;
+}
 </style>
 <link rel="icon" id="favicon" type="image/png" href=""
 </head>

Modified: trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/main.js (90651 => 90652)


--- trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/main.js	2011-07-08 19:21:41 UTC (rev 90651)
+++ trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/main.js	2011-07-08 19:26:32 UTC (rev 90652)
@@ -17,20 +17,33 @@
 {
     var faviconURL = 'favicon-' + (hasFailures ? 'red' : 'green') + '.png';
     $('#favicon').attr('href', faviconURL);
-};
+}
 
 function fetchResults(onsuccess)
 {
     results.fetchResultsByBuilder(config.builders, function(resultsByBuilder) {
-        var unexpectedFailures = ui.resultsByTest(results.unexpectedFailuresByTest(resultsByBuilder));
+        var unexpectedFailures = ui.summarizeResultsByTest(results.unexpectedFailuresByTest(resultsByBuilder));
         $('.failures').append(unexpectedFailures);
         onsuccess();
     });
     setIconState($('.failures').length);
 }
 
+function expandResults()
+{
+    var resultsSummary = $(this);
+    var testName = $('.testName', resultsSummary).text();
+    $('.builderName', resultsSummary).each(function() {
+        var builderName = $(this).text();
+        results.fetchResultsURLs(builderName, testName, function(resultURLs) {
+            resultsSummary.append(ui.results(resultURLs));
+        });
+    });
+}
+
 $('.hide').live('click', hide);
 $('.quit').live('click', quit);
+$('.results-summary .test').live('click', expandResults);
 
 $(document).ready(function() {
     fetchResults(function() {

Modified: trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/results.js (90651 => 90652)


--- trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/results.js	2011-07-08 19:21:41 UTC (rev 90651)
+++ trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/results.js	2011-07-08 19:26:32 UTC (rev 90652)
@@ -7,6 +7,26 @@
 var kResultsName = 'full_results.json';
 var kMasterName = 'ChromiumWebkit';
 
+var kLayoutTestResultsServer = 'http://build.chromium.org/f/chromium/layout_test_results/';
+var kLayoutTestResultsPath = '/results/layout-test-results/';
+
+var kPossibleSuffixList = [
+    '-expected.png',
+    '-actual.png',
+    '-diff.png',
+    '-expected.txt',
+    '-actual.txt',
+    '-diff.txt',
+    // FIXME: Add support for these result types.
+    // '-wdiff.html',
+    // '-pretty-diff.html',
+    // '-expected.html',
+    // '-expected-mismatch.html',
+    // '-expected.wav',
+    // '-actual.wav',
+    // ... and possibly more.
+];
+
 var PASS = 'PASS';
 var TIMEOUT = 'TIMEOUT';
 var TEXT = 'TEXT';
@@ -16,6 +36,17 @@
 
 var kFailingResults = [TIMEOUT, TEXT, CRASH, IMAGE, IMAGE_TEXT];
 
+// Kinds of results.
+results.kActualKind = 'actual';
+results.kExpectedKind = 'expected';
+results.kDiffKind = 'diff';
+results.kUnknownKind = 'unknown';
+
+// Types of tests.
+results.kImageType = 'image'
+results.kTextType = 'text'
+// FIXME: There are more types of tests.
+
 function isFailure(result)
 {
     return kFailingResults.indexOf(result) != -1;
@@ -89,8 +120,77 @@
     return unexpectedFailures;
 };
 
-function resultsURL(builderName, name)
+function resultsDirectoryForBuilder(builderName)
 {
+    return builderName.replace(/[ .()]/g, '_');
+}
+
+function resultsDirectoryURL(builderName)
+{
+    return kLayoutTestResultsServer + resultsDirectoryForBuilder(builderName) + kLayoutTestResultsPath;
+}
+
+results.resultKind = function(url)
+{
+    if (/-actual\.[a-z]+$/.test(url))
+        return results.kActualKind;
+    else if (/-expected\.[a-z]+$/.test(url))
+        return results.kExpectedKind;
+    else if (/diff\.[a-z]+$/.test(url))
+        return results.kDiffKind;
+    return results.kUnknownKind;
+}
+
+results.resultType = function(url)
+{
+    if (/\.png$/.test(url))
+        return results.kImageType;
+    return results.kTextType;
+}
+
+function sortResultURLsBySuffix(urls)
+{
+    var sortedURLs = [];
+    $.each(kPossibleSuffixList, function(i, suffix) {
+        $.each(urls, function(j, url) {
+            if (!base.endsWith(url, suffix))
+                return;
+            sortedURLs.push(url);
+        });
+    });
+    if (sortedURLs.length != urls.length)
+        throw "sortResultURLsBySuffix failed to return the same number of URLs."
+    return sortedURLs;
+}
+
+results.fetchResultsURLs = function(builderName, testName, callback)
+{
+    var stem = resultsDirectoryURL(builderName);
+    var testNameStem = base.trimExtension(testName);
+
+    var resultURLs = [];
+    var requestsInFlight = kPossibleSuffixList.length;
+
+    function checkComplete()
+    {
+        if (--requestsInFlight == 0)
+            callback(sortResultURLsBySuffix(resultURLs));
+    }
+
+    $.each(kPossibleSuffixList, function(index, suffix) {
+        var url = "" + testNameStem + suffix;
+        base.probe(url, {
+            success: function() {
+                resultURLs.push(url);
+                checkComplete();
+            },
+            error: checkComplete,
+        });
+    });
+};
+
+function resultsSummaryURL(builderName, name)
+{
     return kTestResultsServer + 'testfile' +
           '?builder=' + builderName +
           '&master=' + kMasterName +
@@ -101,7 +201,7 @@
 results.fetchResultsForBuilder = function(builderName, onsuccess)
 {
     $.ajax({
-        url: resultsURL(builderName, kResultsName),
+        url: resultsSummaryURL(builderName, kResultsName),
         dataType: 'jsonp',
         success: function(data) {
             onsuccess(new results.BuilderResults(data));

Modified: trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/results_unittests.js (90651 => 90652)


--- trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/results_unittests.js	2011-07-08 19:21:41 UTC (rev 90651)
+++ trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/results_unittests.js	2011-07-08 19:26:32 UTC (rev 90652)
@@ -62,3 +62,74 @@
         }
     });
 });
+
+test("resultKind", 12, function() {
+    equals(results.resultKind("http://example.com/foo-actual.txt"), "actual");
+    equals(results.resultKind("http://example.com/foo-expected.txt"), "expected");
+    equals(results.resultKind("http://example.com/foo-diff.txt"), "diff");
+    equals(results.resultKind("http://example.com/foo.bar-actual.txt"), "actual");
+    equals(results.resultKind("http://example.com/foo.bar-expected.txt"), "expected");
+    equals(results.resultKind("http://example.com/foo.bar-diff.txt"), "diff");
+    equals(results.resultKind("http://example.com/foo-actual.png"), "actual");
+    equals(results.resultKind("http://example.com/foo-expected.png"), "expected");
+    equals(results.resultKind("http://example.com/foo-diff.png"), "diff");
+    equals(results.resultKind("http://example.com/foo-pretty-diff.html"), "diff");
+    equals(results.resultKind("http://example.com/foo-wdiff.html"), "diff");
+    equals(results.resultKind("http://example.com/foo-xyz.html"), "unknown");
+});
+
+test("resultType", 12, function() {
+    equals(results.resultType("http://example.com/foo-actual.txt"), "text");
+    equals(results.resultType("http://example.com/foo-expected.txt"), "text");
+    equals(results.resultType("http://example.com/foo-diff.txt"), "text");
+    equals(results.resultType("http://example.com/foo.bar-actual.txt"), "text");
+    equals(results.resultType("http://example.com/foo.bar-expected.txt"), "text");
+    equals(results.resultType("http://example.com/foo.bar-diff.txt"), "text");
+    equals(results.resultType("http://example.com/foo-actual.png"), "image");
+    equals(results.resultType("http://example.com/foo-expected.png"), "image");
+    equals(results.resultType("http://example.com/foo-diff.png"), "image");
+    equals(results.resultType("http://example.com/foo-pretty-diff.html"), "text");
+    equals(results.resultType("http://example.com/foo-wdiff.html"), "text");
+    equals(results.resultType("http://example.com/foo.xyz"), "text");
+});
+
+test("fetchResultsURLs", 3, function() {
+    var realBase = window.base;
+
+    var pendingCallbacks = {};
+    window.base = {};
+    base.probe = function(url, options) {
+        pendingCallbacks[url] = options;
+    };
+    base.endsWith = realBase.endsWith;
+    base.trimExtension = realBase.trimExtension;
+
+    results.fetchResultsURLs("Mock Builder", "userscripts/another-test.html", function(resultURLs) {
+        deepEqual(resultURLs, [
+            "http://build.chromium.org/f/chromium/layout_test_results/Mock_Builder/results/layout-test-results/userscripts/another-test-expected.txt",
+            "http://build.chromium.org/f/chromium/layout_test_results/Mock_Builder/results/layout-test-results/userscripts/another-test-actual.txt",
+            "http://build.chromium.org/f/chromium/layout_test_results/Mock_Builder/results/layout-test-results/userscripts/another-test-diff.txt",
+        ]);
+    });
+
+    var probedURLs = [];
+    for (var url in pendingCallbacks) {
+        probedURLs.push(url);
+        if (realBase.endsWith(url, '.txt'))
+            pendingCallbacks[url].success.call();
+        else
+            pendingCallbacks[url].error.call();
+    }
+
+    deepEqual(probedURLs, [
+        "http://build.chromium.org/f/chromium/layout_test_results/Mock_Builder/results/layout-test-results/userscripts/another-test-expected.png",
+        "http://build.chromium.org/f/chromium/layout_test_results/Mock_Builder/results/layout-test-results/userscripts/another-test-actual.png",
+        "http://build.chromium.org/f/chromium/layout_test_results/Mock_Builder/results/layout-test-results/userscripts/another-test-diff.png",
+        "http://build.chromium.org/f/chromium/layout_test_results/Mock_Builder/results/layout-test-results/userscripts/another-test-expected.txt",
+        "http://build.chromium.org/f/chromium/layout_test_results/Mock_Builder/results/layout-test-results/userscripts/another-test-actual.txt",
+        "http://build.chromium.org/f/chromium/layout_test_results/Mock_Builder/results/layout-test-results/userscripts/another-test-diff.txt",
+    ]);
+
+    window.base = realBase;
+    equal(window.base, realBase, "Failed to restore real base!");
+});

Modified: trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/ui.js (90651 => 90652)


--- trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/ui.js	2011-07-08 19:21:41 UTC (rev 90651)
+++ trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/ui.js	2011-07-08 19:26:32 UTC (rev 90652)
@@ -2,9 +2,9 @@
 
 (function () {
 
-ui.resultsByTest = function(resultsByTest)
+ui.summarizeResultsByTest = function(resultsByTest)
 {
-    var block = $('<div class="results"></div>');
+    var block = $('<div class="results-summary"></div>');
     $.each(resultsByTest, function(testName, resultNodesByBuilder) {
         var testBlock = $('<div class="test"><div class="testName"></div><div class="builders"></div></div>');
         block.append(testBlock);
@@ -21,4 +21,16 @@
     return block;
 };
 
+ui.results = function(resultsURLs)
+{
+    var block = $('<div class="results"></div>');
+    $.each(resultsURLs, function(index, resultURL) {
+        var kind = results.resultKind(resultURL);
+        var type = results.resultType(resultURL);
+        var fragment = type == results.kImageType ? '<img>' : '<iframe></iframe>';
+        block.append($(fragment).attr('src', resultURL).addClass(kind))
+    });
+    return block;
+};
+
 })();

Modified: trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/ui_unittests.js (90651 => 90652)


--- trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/ui_unittests.js	2011-07-08 19:21:41 UTC (rev 90651)
+++ trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/ui_unittests.js	2011-07-08 19:26:32 UTC (rev 90652)
@@ -19,9 +19,9 @@
     }
 }
 
-test("BuilderResults.resultsByTest", 1, function() {
-    var resultsByTest = ui.resultsByTest(kExampleResultsByTest);
-    equal(resultsByTest.html(),
+test("summarizeResultsByTest", 1, function() {
+    var resultsSummary = ui.summarizeResultsByTest(kExampleResultsByTest);
+    equal(resultsSummary.html(),
         '<div class="test">' +
             '<div class="testName">scrollbars/custom-scrollbar-with-incomplete-style.html</div>' +
                 '<div class="builders">' +
@@ -36,3 +36,21 @@
             '</div>' +
         '</div>');
 });
+
+test("results", 1, function() {
+    var testResults = ui.results([
+        'http://example.com/layout-test-results/foo-bar-expected.txt',
+        'http://example.com/layout-test-results/foo-bar-actual.txt',
+        'http://example.com/layout-test-results/foo-bar-diff.txt',
+        'http://example.com/layout-test-results/foo-bar-expected.png',
+        'http://example.com/layout-test-results/foo-bar-actual.png',
+        'http://example.com/layout-test-results/foo-bar-diff.png',
+    ]);
+    equal(testResults.html(),
+        '<iframe src="" class="expected"></iframe>' +
+        '<iframe src="" class="actual"></iframe>' +
+        '<iframe src="" class="diff"></iframe>' +
+        '<img src="" class="expected">' +
+        '<img src="" class="actual">' +
+        '<img src="" class="diff">');
+});
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to