<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[161273] trunk/Tools</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/161273">161273</a></dd>
<dt>Author</dt> <dd>ap@apple.com</dd>
<dt>Date</dt> <dd>2014-01-03 11:32:11 -0800 (Fri, 03 Jan 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Please add a way to quick peek at failing tests at build.webkit.org/dashboard
https://bugs.webkit.org/show_bug.cgi?id=122181

Reviewed by Timothy Hatcher and Timothy Horton.

Detailed results are saved by run-webkit-tests to full_results.json (which is actually
JSONP). Dashboard will load them on demand.

* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Buildbot.js:
(Buildbot.prototype.layoutTestResultsURLForIteration): Moved from WebKitBuildbot.js
and made it use a function from WebKitBuildbot that builds results directory path.
(Buildbot.prototype.layoutTestFullResultsURLForIteration): Added a function that builds
a URL for full_results.json.
(Buildbot.prototype.layoutTestCrashLogForIteration): Added a function that builds
a URL for a crash log.

* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/BuildbotIteration.js:
(BuildbotIteration.prototype.loadLayoutTestResults): Load and cache layout test results for
the iteration.

* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/BuildbotQueueView.js:        
(BuildbotQueueView.prototype._presentPopoverForPendingCommits): Updated for changed
popover API (see below).
(BuildbotQueueView.prototype._presentPopoverForRevisionRange): Ditto.

* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/BuildbotTesterQueueView.js:
(BuildbotTesterQueueView.prototype.update.appendBuilderQueueStatus): Added a check
for iterations that were interrupted (previously, they were displayed incorrectly,
often as passes). Install popover trackers for failure bubbles for which we can currently
display something useful.
(BuildbotTesterQueueView.prototype._popoverContentForLayoutTestRegressions): Build
a popover for layout test regressions when we have the data loaded on demand.
We have test paths, special indicators for crashes/timeouts, and links to test history
at flakiness dashboard.
(BuildbotTesterQueueView.prototype._presentPopoverForLayoutTestRegressions): Show
the popover for layout test regressions. Just shows &quot;Loading...&quot; until the data is
loaded.
(BuildbotTesterQueueView.prototype._presentPopoverForMultipleFailureKinds): List
types of failures if there are multiple. There is a lot of similarity with
appendBuilderQueueStatus(), but I couldn't find a good way to share the code.

* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Initialization.js:
Create a global test history object, which is used for links in layout test popover.

* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Popover.js:
Changed the API to be more like WebInspector again, allowing for changing content
of an existing popover. As the size of a popover can change, making the mouse pointer
enter it without a mousenter event, install a handler for mousewheel instead, and block
document scrolling from this event handler when needed.

* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/StatusLineView.js:
(StatusLineView.prototype.get statusBubbleElement): Added an accessor for status
bubble element, making it possible to install a popover on it.

* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Utilities.js:
(JSON.load): Added the ability to load JSONP by providing an optional callback name.

* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/WebKitBuildbot.js:
(WebKitBuildbot.prototype.layoutTestResultsDirectoryURLForIteration): Switched from
building a complete results URL to only building one for root results path. This is
the part that depends on specific buildbot installation, everything relative to it
is the same.

* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/WebKitTestHistory.js: Added.
Build a path to test history page. In the future, we may consider adding code to
load the data and display it inline.

* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Styles/QueueView.css:
Added styles for this new popover.

* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/index.html: Added
a new file, WebKitTestHistory.js.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkToolsBuildSlaveSupportbuildwebkitorgconfigpublic_htmldashboardScriptsBuildbotjs">trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Buildbot.js</a></li>
<li><a href="#trunkToolsBuildSlaveSupportbuildwebkitorgconfigpublic_htmldashboardScriptsBuildbotIterationjs">trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/BuildbotIteration.js</a></li>
<li><a href="#trunkToolsBuildSlaveSupportbuildwebkitorgconfigpublic_htmldashboardScriptsBuildbotQueueViewjs">trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/BuildbotQueueView.js</a></li>
<li><a href="#trunkToolsBuildSlaveSupportbuildwebkitorgconfigpublic_htmldashboardScriptsBuildbotTesterQueueViewjs">trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/BuildbotTesterQueueView.js</a></li>
<li><a href="#trunkToolsBuildSlaveSupportbuildwebkitorgconfigpublic_htmldashboardScriptsInitializationjs">trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Initialization.js</a></li>
<li><a href="#trunkToolsBuildSlaveSupportbuildwebkitorgconfigpublic_htmldashboardScriptsPopoverjs">trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Popover.js</a></li>
<li><a href="#trunkToolsBuildSlaveSupportbuildwebkitorgconfigpublic_htmldashboardScriptsStatusLineViewjs">trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/StatusLineView.js</a></li>
<li><a href="#trunkToolsBuildSlaveSupportbuildwebkitorgconfigpublic_htmldashboardScriptsUtilitiesjs">trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Utilities.js</a></li>
<li><a href="#trunkToolsBuildSlaveSupportbuildwebkitorgconfigpublic_htmldashboardScriptsWebKitBuildbotjs">trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/WebKitBuildbot.js</a></li>
<li><a href="#trunkToolsBuildSlaveSupportbuildwebkitorgconfigpublic_htmldashboardStylesQueueViewcss">trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Styles/QueueView.css</a></li>
<li><a href="#trunkToolsBuildSlaveSupportbuildwebkitorgconfigpublic_htmldashboardindexhtml">trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/index.html</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkToolsBuildSlaveSupportbuildwebkitorgconfigpublic_htmldashboardScriptsWebKitTestHistoryjs">trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/WebKitTestHistory.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkToolsBuildSlaveSupportbuildwebkitorgconfigpublic_htmldashboardScriptsBuildbotjs"></a>
<div class="modfile"><h4>Modified: trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Buildbot.js (161272 => 161273)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Buildbot.js        2014-01-03 19:13:38 UTC (rev 161272)
+++ trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Buildbot.js        2014-01-03 19:32:11 UTC (rev 161273)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -84,5 +84,21 @@
</span><span class="cx">     bindingsTestResultsURLForIteration: function(iteration)
</span><span class="cx">     {
</span><span class="cx">         return this.baseURL + &quot;builders/&quot; + encodeURIComponent(iteration.queue.id) + &quot;/builds/&quot; + iteration.id + &quot;/steps/bindings-generation-tests/logs/stdio&quot;;
</span><ins>+    },
+
+    layoutTestResultsURLForIteration: function(iteration)
+    {
+        return this.layoutTestResultsDirectoryURLForIteration(iteration) + &quot;/results.html&quot;;
+    },
+
+    layoutTestFullResultsURLForIteration: function(iteration)
+    {
+        return this.layoutTestResultsDirectoryURLForIteration(iteration) + &quot;/full_results.json&quot;;
+    },
+
+    layoutTestCrashLogForIteration: function(iteration, testPath)
+    {
+        var crashLogPath = testPath.replace(/^(.*)\.(?:.*)$/, &quot;$1-crash-log.txt&quot;);
+        return this.layoutTestResultsDirectoryURLForIteration(iteration) + &quot;/&quot; + crashLogPath;
</ins><span class="cx">     }
</span><span class="cx"> };
</span></span></pre></div>
<a id="trunkToolsBuildSlaveSupportbuildwebkitorgconfigpublic_htmldashboardScriptsBuildbotIterationjs"></a>
<div class="modfile"><h4>Modified: trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/BuildbotIteration.js (161272 => 161273)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/BuildbotIteration.js        2014-01-03 19:13:38 UTC (rev 161272)
+++ trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/BuildbotIteration.js        2014-01-03 19:32:11 UTC (rev 161273)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -189,5 +189,71 @@
</span><span class="cx"> 
</span><span class="cx">             this.dispatchEventToListeners(BuildbotIteration.Event.Updated);
</span><span class="cx">         }.bind(this));
</span><ins>+    },
+
+    loadLayoutTestResults: function(callback)
+    {
+        function collectResults(subtree, predicate)
+        {
+            // Results object is a trie:
+            // directory
+            //   subdirectory
+            //     test1.html
+            //       expected:&quot;PASS&quot;
+            //       actual: &quot;IMAGE&quot;
+            //       report: &quot;REGRESSION&quot;
+            //     test2.html
+            //       expected:&quot;FAIL&quot;
+            //       actual:&quot;TEXT&quot;
+
+            var result = [];
+            for (var key in subtree) {
+                var value = subtree[key];
+                console.assert(typeof value === &quot;object&quot;);
+                var isIndividualTest = value.hasOwnProperty(&quot;actual&quot;) &amp;&amp; value.hasOwnProperty(&quot;expected&quot;);
+                if (isIndividualTest) {
+                    // Possible values for actual and expected keys: PASS, FAIL, AUDIO, IMAGE, TEXT, IMAGE+TEXT, TIMEOUT, CRASH, MISSING.
+                    // Both actual and expected can be space separated lists. Actual contains two values when retrying a failed test
+                    // gives a different result (retrying may be disabled in tester configuration).
+                    // Possible values for report key (when present): REGRESSION, MISSING, FLAKY.
+
+                    if (predicate(value)) {
+                        var item = {path: key};
+                        if (value.actual.contains(&quot;CRASH&quot;))
+                            item.crash = true;
+                        if (value.actual.contains(&quot;TIMEOUT&quot;))
+                            item.timeout = true;
+                        result.push(item);
+                    }
+
+                } else {
+                    var nestedTests = collectResults(value, predicate);
+                    for (var i = 0, end = nestedTests.length; i &lt; end; ++i)
+                        nestedTests[i].path = key + &quot;/&quot; + nestedTests[i].path;
+                    result = result.concat(nestedTests);
+                }
+            }
+
+            return result;
+        }
+
+        JSON.load(this.queue.buildbot.layoutTestFullResultsURLForIteration(this), function(data) {
+            if (data.error) {
+                console.log(data.error);
+                callback();
+                return;
+            }
+
+            this.layoutTestResults.regressions = collectResults(data.tests, function(info) { return info[&quot;report&quot;] === &quot;REGRESSION&quot; });
+            console.assert(data.num_regressions === this.layoutTestResults.regressions.length);
+
+            this.layoutTestResults.flakyTests = collectResults(data.tests, function(info) { return info[&quot;report&quot;] === &quot;FLAKY&quot; });
+            console.assert(data.num_flaky === this.layoutTestResults.flakyTests.length);
+
+            this.layoutTestResults.testsWithMissingResults = collectResults(data.tests, function(info) { return info[&quot;report&quot;] === &quot;MISSING&quot; });
+            console.assert(data.num_missing === this.layoutTestResults.testsWithMissingResults.length);
+
+            callback();
+        }.bind(this), &quot;ADD_RESULTS&quot;);
</ins><span class="cx">     }
</span><span class="cx"> };
</span></span></pre></div>
<a id="trunkToolsBuildSlaveSupportbuildwebkitorgconfigpublic_htmldashboardScriptsBuildbotQueueViewjs"></a>
<div class="modfile"><h4>Modified: trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/BuildbotQueueView.js (161272 => 161273)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/BuildbotQueueView.js        2014-01-03 19:13:38 UTC (rev 161272)
+++ trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/BuildbotQueueView.js        2014-01-03 19:32:11 UTC (rev 161273)
</span><span class="lines">@@ -176,7 +176,8 @@
</span><span class="cx">             content.appendChild(linesForInternal[i]);
</span><span class="cx"> 
</span><span class="cx">         var rect = Dashboard.Rect.rectFromClientRect(element.getBoundingClientRect());
</span><del>-        popover.present(rect, content, [Dashboard.RectEdge.MIN_Y, Dashboard.RectEdge.MAX_Y, Dashboard.RectEdge.MAX_X, Dashboard.RectEdge.MIN_X]);
</del><ins>+        popover.content = content;
+        popover.present(rect, [Dashboard.RectEdge.MIN_Y, Dashboard.RectEdge.MAX_Y, Dashboard.RectEdge.MAX_X, Dashboard.RectEdge.MIN_X]);
</ins><span class="cx"> 
</span><span class="cx">         return true;
</span><span class="cx">     },
</span><span class="lines">@@ -194,7 +195,8 @@
</span><span class="cx">             content.appendChild(linesForCommits[i]);
</span><span class="cx"> 
</span><span class="cx">         var rect = Dashboard.Rect.rectFromClientRect(element.getBoundingClientRect());
</span><del>-        popover.present(rect, content, [Dashboard.RectEdge.MIN_Y, Dashboard.RectEdge.MAX_Y, Dashboard.RectEdge.MAX_X, Dashboard.RectEdge.MIN_X]);
</del><ins>+        popover.content = content;
+        popover.present(rect, [Dashboard.RectEdge.MIN_Y, Dashboard.RectEdge.MAX_Y, Dashboard.RectEdge.MAX_X, Dashboard.RectEdge.MIN_X]);
</ins><span class="cx"> 
</span><span class="cx">         return true;
</span><span class="cx">     },
</span></span></pre></div>
<a id="trunkToolsBuildSlaveSupportbuildwebkitorgconfigpublic_htmldashboardScriptsBuildbotTesterQueueViewjs"></a>
<div class="modfile"><h4>Modified: trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/BuildbotTesterQueueView.js (161272 => 161273)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/BuildbotTesterQueueView.js        2014-01-03 19:13:38 UTC (rev 161272)
+++ trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/BuildbotTesterQueueView.js        2014-01-03 19:32:11 UTC (rev 161273)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -68,6 +68,9 @@
</span><span class="cx">                 if (!iteration.failed) {
</span><span class="cx">                     var status = new StatusLineView(messageElement, StatusLineView.Status.Good, &quot;all tests passed&quot;);
</span><span class="cx">                     limit = 0;
</span><ins>+                } else if (!iteration.productive) {
+                    var url = iteration.queue.buildbot.buildPageURLForIteration(iteration);
+                    var status = new StatusLineView(messageElement, StatusLineView.Status.Danger, iteration.text, undefined, url);
</ins><span class="cx">                 } else if (!layoutTestResults.failureCount &amp;&amp; !javascriptTestResults.failureCount &amp;&amp; !apiTestResults.failureCount &amp;&amp; !pythonTestResults.failureCount &amp;&amp; !perlTestResults.failureCount &amp;&amp; !bindingTestResults.errorOccurred) {
</span><span class="cx">                     // Something wrong happened, but it was not a test failure.
</span><span class="cx">                     var url = iteration.queue.buildbot.buildPageURLForIteration(iteration);
</span><span class="lines">@@ -75,6 +78,7 @@
</span><span class="cx">                 } else if (layoutTestResults.failureCount &amp;&amp; !javascriptTestResults.failureCount &amp;&amp; !apiTestResults.failureCount &amp;&amp; !pythonTestResults.failureCount &amp;&amp; !perlTestResults.failureCount &amp;&amp; !bindingTestResults.errorOccurred) {
</span><span class="cx">                     var url = iteration.queue.buildbot.layoutTestResultsURLForIteration(iteration);
</span><span class="cx">                     var status = new StatusLineView(messageElement, StatusLineView.Status.Bad, layoutTestResults.failureCount === 1 ? &quot;layout test failure&quot; : &quot;layout test failures&quot;, layoutTestResults.tooManyFailures ? layoutTestResults.failureCount + &quot;\uff0b&quot; : layoutTestResults.failureCount, url);
</span><ins>+                    new PopoverTracker(status.statusBubbleElement, this._presentPopoverForLayoutTestRegressions.bind(this), iteration);
</ins><span class="cx">                 } else if (!layoutTestResults.failureCount &amp;&amp; javascriptTestResults.failureCount &amp;&amp; !apiTestResults.failureCount &amp;&amp; !pythonTestResults.failureCount &amp;&amp; !perlTestResults.failureCount &amp;&amp; !bindingTestResults.errorOccurred) {
</span><span class="cx">                     var url = iteration.queue.buildbot.javascriptTestResultsURLForIteration(iteration);
</span><span class="cx">                     var status = new StatusLineView(messageElement, StatusLineView.Status.Bad, javascriptTestResults.failureCount === 1 ? &quot;javascript test failure&quot; : &quot;javascript test failures&quot;, javascriptTestResults.failureCount, url);
</span><span class="lines">@@ -94,6 +98,7 @@
</span><span class="cx">                     var url = iteration.queue.buildbot.buildPageURLForIteration(iteration);
</span><span class="cx">                     var totalFailures = layoutTestResults.failureCount + javascriptTestResults.failureCount + apiTestResults.failureCount + pythonTestResults.failureCount + perlTestResults.failureCount + bindingTestResults.errorOccurred;
</span><span class="cx">                     var status = new StatusLineView(messageElement, StatusLineView.Status.Bad, totalFailures === 1 ? &quot;test failure&quot; : &quot;test failures&quot;, totalFailures, url);
</span><ins>+                    new PopoverTracker(status.statusBubbleElement, this._presentPopoverForMultipleFailureKinds.bind(this), iteration);
</ins><span class="cx">                 }
</span><span class="cx"> 
</span><span class="cx">                 this.element.appendChild(status.element);
</span><span class="lines">@@ -123,4 +128,141 @@
</span><span class="cx">         appendBuild.call(this, this.releaseQueues, &quot;Release&quot;);
</span><span class="cx">         appendBuild.call(this, this.debugQueues, &quot;Debug&quot;);
</span><span class="cx">     },
</span><ins>+
+    _popoverContentForLayoutTestRegressions: function(iteration)
+    {
+        var hasTestHistory = typeof testHistory !== &quot;undefined&quot;;
+
+        var content = document.createElement(&quot;div&quot;);
+        content.className = &quot;test-results-popover&quot;;
+
+        if (!iteration.layoutTestResults.regressions) {
+            var message = document.createElement(&quot;div&quot;);
+            message.className = &quot;loading-failure&quot;;
+            message.textContent = &quot;Test results couldn\u2019t be loaded&quot;;
+            content.appendChild(message);
+            return content;
+        }
+
+        var sortedRegressions = iteration.layoutTestResults.regressions.slice().sort(function(a, b) { return (a.path === b.path) ? 0 : (a.path &gt; b.path) ? 1 : -1; });
+
+        for (var i = 0, end = sortedRegressions.length; i != end; ++i) {
+            var test = sortedRegressions[i];
+
+            var rowElement = document.createElement(&quot;div&quot;);
+
+            var testPathElement = document.createElement(&quot;span&quot;);
+            testPathElement.className = &quot;test-path&quot;;
+            testPathElement.textContent = test.path;
+            rowElement.appendChild(testPathElement);
+
+            if (test.crash) {
+                var failureKindElement = document.createElement(&quot;a&quot;);
+                failureKindElement.className = &quot;failure-kind-indicator&quot;
+                failureKindElement.textContent = &quot;crash&quot;;
+                failureKindElement.href = iteration.queue.buildbot.layoutTestCrashLogForIteration(iteration, test.path);
+                failureKindElement.target = &quot;_blank&quot;;
+                rowElement.appendChild(failureKindElement);
+            }
+
+            if (test.timeout) {
+                var failureKindElement = document.createElement(&quot;span&quot;);
+                failureKindElement.className = &quot;failure-kind-indicator&quot;
+                failureKindElement.textContent = &quot;timeout&quot;;
+                rowElement.appendChild(failureKindElement);
+            }
+
+            if (hasTestHistory) {
+                var testHistoryLink = document.createElement(&quot;a&quot;);
+                testHistoryLink.className = &quot;test-history-link&quot;;
+                testHistoryLink.textContent = &quot;history&quot;;
+                testHistoryLink.href = testHistory.historyPageURLForTest(test.path);
+                testHistoryLink.target = &quot;_blank&quot;;
+                rowElement.appendChild(testHistoryLink);
+            }
+
+            content.appendChild(rowElement);
+        }
+
+        return content;
+    },
+
+    _presentPopoverForLayoutTestRegressions: function(element, popover, iteration)
+    {
+        if (iteration.layoutTestResults.regressions)
+            var content = this._popoverContentForLayoutTestRegressions(iteration);
+        else {
+            var content = document.createElement(&quot;div&quot;);
+            content.className = &quot;test-results-popover&quot;;
+
+            var loadingIndicator = document.createElement(&quot;div&quot;);
+            loadingIndicator.className = &quot;loading-indicator&quot;;
+            loadingIndicator.textContent = &quot;Loading\u2026&quot;;
+            content.appendChild(loadingIndicator);
+
+            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;
+    },
+
+    _presentPopoverForMultipleFailureKinds: function(element, popover, iteration)
+    {
+        function addResultKind(message, url) {
+            var line = document.createElement(&quot;a&quot;);
+            line.className = &quot;failing-test-kind-summary&quot;;
+            line.href = url;
+            line.textContent = message;
+            line.target = &quot;_blank&quot;;
+            content.appendChild(line);            
+        }
+
+        var layoutTestResults = iteration.layoutTestResults || {failureCount: 0};
+        var javascriptTestResults = iteration.javascriptTestResults || {failureCount: 0};
+        var apiTestResults = iteration.apiTestResults || {failureCount: 0};
+        var pythonTestResults = iteration.pythonTestResults || {failureCount: 0};
+        var perlTestResults = iteration.perlTestResults || {failureCount: 0};
+        var bindingTestResults = iteration.bindingTestResults || {errorOccurred: false};
+
+        var content = document.createElement(&quot;div&quot;);
+        content.className = &quot;test-results-popover&quot;;
+
+        if (layoutTestResults.failureCount) {
+            var message = (layoutTestResults.tooManyFailures ? layoutTestResults.failureCount + &quot;\uff0b&quot; : layoutTestResults.failureCount) + &quot;\u00a0&quot; +
+                (layoutTestResults.failureCount === 1 ? &quot;layout test failure&quot; : &quot;layout test failures&quot;);
+            addResultKind(message, iteration.queue.buildbot.layoutTestResultsURLForIteration(iteration));
+        }
+
+        if (javascriptTestResults.failureCount) {
+            var message = javascriptTestResults.failureCount + &quot;\u00a0&quot; + (javascriptTestResults.failureCount === 1 ? &quot;javascript test failure&quot; : &quot;javascript test failures&quot;);
+            addResultKind(message, iteration.queue.buildbot.javascriptTestResultsURLForIteration(iteration));
+        }
+
+        if (apiTestResults.failureCount) {
+            var message = apiTestResults.failureCount + &quot;\u00a0&quot; + (apiTestResults.failureCount === 1 ? &quot;api test failure&quot; : &quot;api test failures&quot;);
+            addResultKind(message, iteration.queue.buildbot.apiTestResultsURLForIteration(iteration));
+        }
+
+        if (pythonTestResults.failureCount) {
+            var message = pythonTestResults.failureCount + &quot;\u00a0&quot; + (pythonTestResults.failureCount === 1 ? &quot;webkitpy test failure&quot; : &quot;webkitpy test failures&quot;);
+            addResultKind(message, iteration.queue.buildbot.bindingsTestResultsURLForIteration(iteration));
+        }
+
+        if (perlTestResults.failureCount) {
+            var message = perlTestResults.failureCount + &quot;\u00a0&quot; + (perlTestResults.failureCount === 1 ? &quot;webkitperl test failure&quot; : &quot;webkitperl test failures&quot;);
+            addResultKind(message, iteration.queue.buildbot.webkitperlTestResultsURLForIteration(iteration));
+        }
+
+        if (bindingTestResults.errorOccurred)
+            addResultKind(&quot;bindings tests failed&quot;, iteration.queue.buildbot.bindingsTestResultsURLForIteration(iteration));
+
+        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;
+    }
</ins><span class="cx"> };
</span></span></pre></div>
<a id="trunkToolsBuildSlaveSupportbuildwebkitorgconfigpublic_htmldashboardScriptsInitializationjs"></a>
<div class="modfile"><h4>Modified: trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Initialization.js (161272 => 161273)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Initialization.js        2014-01-03 19:13:38 UTC (rev 161272)
+++ trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Initialization.js        2014-01-03 19:32:11 UTC (rev 161273)
</span><span class="lines">@@ -27,3 +27,4 @@
</span><span class="cx"> var buildbot = new WebKitBuildbot;
</span><span class="cx"> var webkitTrac = new Trac(&quot;http://trac.webkit.org/&quot;);
</span><span class="cx"> var ews = new EWS;
</span><ins>+var testHistory = new TestHistory;
</ins></span></pre></div>
<a id="trunkToolsBuildSlaveSupportbuildwebkitorgconfigpublic_htmldashboardScriptsPopoverjs"></a>
<div class="modfile"><h4>Modified: trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Popover.js (161272 => 161273)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Popover.js        2014-01-03 19:13:38 UTC (rev 161272)
+++ trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Popover.js        2014-01-03 19:32:11 UTC (rev 161273)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -34,6 +34,8 @@
</span><span class="cx">     this._targetFrame = new Dashboard.Rect;
</span><span class="cx">     this._preferredEdges = null;
</span><span class="cx"> 
</span><ins>+    this._contentNeedsUpdate = false;
+
</ins><span class="cx">     this._element = document.createElement(&quot;div&quot;);
</span><span class="cx">     this._element.className = Dashboard.Popover.StyleClassName;
</span><span class="cx">     this._canvasId = &quot;popover-&quot; + (Dashboard.Popover.canvasId++);
</span><span class="lines">@@ -92,19 +94,52 @@
</span><span class="cx">             &amp;&amp; !this._element.classList.contains(Dashboard.Popover.StepInClassName);
</span><span class="cx">     },
</span><span class="cx"> 
</span><ins>+    get potentiallyVisible()
+    {
+        return this._element.parentNode === document.body;
+    },
+
+    set content(content)
+    {
+        if (content === this._content)
+            return;
+
+        console.assert(content);
+
+        this._content = content;
+
+        this._contentNeedsUpdate = true;
+
+        if (this.potentiallyVisible)
+            this._update();
+    },
+
+    update: function()
+    {
+        if (!this.potentiallyVisible)
+            return;
+
+        var previouslyFocusedElement = document.activeElement;
+
+        this._contentNeedsUpdate = true;
+        this._update();
+
+        if (previouslyFocusedElement)
+            previouslyFocusedElement.focus();
+    },
+
</ins><span class="cx">     /**
</span><span class="cx">      * @param {Dashboard.Rect} targetFrame
</span><span class="cx">      * @param {Element} content
</span><span class="cx">      * @param {Dashboard.RectEdge}[] preferredEdges
</span><span class="cx">      */
</span><del>-    present: function(targetFrame, content, preferredEdges)
</del><ins>+    present: function(targetFrame, preferredEdges)
</ins><span class="cx">     {
</span><del>-        console.assert(!this._content)
-
</del><span class="cx">         this._targetFrame = targetFrame;
</span><del>-        this._content = content;
</del><span class="cx">         this._preferredEdges = preferredEdges;
</span><span class="cx"> 
</span><ins>+        console.assert(this._content);
+
</ins><span class="cx">         window.addEventListener(&quot;mousedown&quot;, this, true);
</span><span class="cx">         window.addEventListener(&quot;scroll&quot;, this, true);
</span><span class="cx"> 
</span><span class="lines">@@ -112,11 +147,8 @@
</span><span class="cx"> 
</span><span class="cx">         this._element.classList.add(Dashboard.Popover.StepInClassName);
</span><span class="cx"> 
</span><del>-        // Scrolling inside a popover should not cascade to document when reaching a bound, because that would make it disappear unexpectedly.
-        if (this._container.offsetHeight &lt; this._container.scrollHeight) {
-            this._element.addEventListener(&quot;mouseenter&quot;, this, true);
-            this._element.addEventListener(&quot;mouseleave&quot;, this, true);
-        }
</del><ins>+        this._element.addEventListener(&quot;mousewheel&quot;, this, true);
+        this._element.addEventListener(&quot;mouseleave&quot;, this, true);
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     makeVisibleImmediately: function()
</span><span class="lines">@@ -156,8 +188,11 @@
</span><span class="cx">             else if (this._element.classList.contains(Dashboard.Popover.FadeOutClassName))
</span><span class="cx">                 this._finalizeDismissal();
</span><span class="cx">             break;
</span><del>-        case &quot;mouseenter&quot;:
-            document.body.classList.add(Dashboard.Popover.PreventDocumentScrollingClassName);
</del><ins>+        case &quot;mousewheel&quot;:
+            // Scrolling inside a popover should not cascade to document when reaching a bound, because that would make it disappear unexpectedly.
+            // FIXME: We should use mouseenter for better performance once it works reliably, see &lt;https://bugs.webkit.org/show_bug.cgi?id=120786&gt;.
+            if (this._container.offsetHeight &lt; this._container.scrollHeight)
+                document.body.classList.add(Dashboard.Popover.PreventDocumentScrollingClassName);
</ins><span class="cx">             break;
</span><span class="cx">         case &quot;mouseleave&quot;:
</span><span class="cx">             if (!this._element.isSelfOrAncestor(event.toElement))
</span><span class="lines">@@ -180,20 +215,22 @@
</span><span class="cx">         else
</span><span class="cx">             this._element.classList.remove(Dashboard.Popover.FadeOutClassName);
</span><span class="cx"> 
</span><del>-        // Reset CSS properties on element so that the element may be sized to fit its content.
-        this._element.style.removeProperty(&quot;left&quot;);
-        this._element.style.removeProperty(&quot;top&quot;);
-        this._element.style.removeProperty(&quot;width&quot;);
-        this._element.style.removeProperty(&quot;height&quot;);
-        if (this._edge !== null)
-            this._element.classList.remove(this._cssClassNameForEdge());
</del><ins>+        if (this._contentNeedsUpdate) {
+            // Reset CSS properties on element so that the element may be sized to fit its content.
+            this._element.style.removeProperty(&quot;left&quot;);
+            this._element.style.removeProperty(&quot;top&quot;);
+            this._element.style.removeProperty(&quot;width&quot;);
+            this._element.style.removeProperty(&quot;height&quot;);
+            if (this._edge !== null)
+                this._element.classList.remove(this._cssClassNameForEdge());
</ins><span class="cx"> 
</span><del>-        // Add the content in place of the wrapper to get the raw metrics.
-        this._element.replaceChild(this._content, this._container);
</del><ins>+            // Add the content in place of the wrapper to get the raw metrics.
+            this._element.replaceChild(this._content, this._container);
</ins><span class="cx"> 
</span><del>-        // Get the ideal size for the popover to fit its content.
-        var popoverBounds = this._element.getBoundingClientRect();
-        this._preferredSize = new Dashboard.Size(Math.ceil(popoverBounds.width), Math.ceil(popoverBounds.height));
</del><ins>+            // Get the ideal size for the popover to fit its content.
+            var popoverBounds = this._element.getBoundingClientRect();
+            this._preferredSize = new Dashboard.Size(Math.ceil(popoverBounds.width), Math.ceil(popoverBounds.height));
+        }
</ins><span class="cx"> 
</span><span class="cx">         // The frame of the window with a little inset to make sure we have room for shadows.
</span><span class="cx">         var containerFrame = new Dashboard.Rect(0, 0, window.innerWidth, window.innerHeight);
</span><span class="lines">@@ -267,9 +304,13 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         // Wrap the content in the container so that it's located correctly.
</span><del>-        this._container.textContent = &quot;&quot;;
-        this._element.replaceChild(this._container, this._content);
-        this._container.appendChild(this._content);
</del><ins>+        if (this._contentNeedsUpdate) {
+            this._container.textContent = &quot;&quot;;
+            this._element.replaceChild(this._container, this._content);
+            this._container.appendChild(this._content);
+        }
+
+        this._contentNeedsUpdate = false;
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     _cssClassNameForEdge: function()
</span></span></pre></div>
<a id="trunkToolsBuildSlaveSupportbuildwebkitorgconfigpublic_htmldashboardScriptsStatusLineViewjs"></a>
<div class="modfile"><h4>Modified: trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/StatusLineView.js (161272 => 161273)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/StatusLineView.js        2014-01-03 19:13:38 UTC (rev 161272)
+++ trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/StatusLineView.js        2014-01-03 19:32:11 UTC (rev 161273)
</span><span class="lines">@@ -160,5 +160,10 @@
</span><span class="cx">         } else {
</span><span class="cx">             this._messageElement.textContent = x;
</span><span class="cx">         }
</span><ins>+    },
+
+    get statusBubbleElement()
+    {
+        return this._statusBubbleElement;
</ins><span class="cx">     }
</span><span class="cx"> };
</span></span></pre></div>
<a id="trunkToolsBuildSlaveSupportbuildwebkitorgconfigpublic_htmldashboardScriptsUtilitiesjs"></a>
<div class="modfile"><h4>Modified: trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Utilities.js (161272 => 161273)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Utilities.js        2014-01-03 19:13:38 UTC (rev 161272)
+++ trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Utilities.js        2014-01-03 19:32:11 UTC (rev 161273)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -23,7 +23,7 @@
</span><span class="cx">  * THE POSSIBILITY OF SUCH DAMAGE.
</span><span class="cx">  */
</span><span class="cx"> 
</span><del>-JSON.load = function(url, callback)
</del><ins>+JSON.load = function(url, callback, jsonpCallbackName)
</ins><span class="cx"> {
</span><span class="cx">     console.assert(url);
</span><span class="cx"> 
</span><span class="lines">@@ -36,7 +36,10 @@
</span><span class="cx">             return;
</span><span class="cx"> 
</span><span class="cx">         try {
</span><del>-            var data = JSON.parse(request.responseText);
</del><ins>+            var responseText = request.responseText;
+            if (jsonpCallbackName)
+                responseText = responseText.replace(new RegExp(&quot;^&quot; + jsonpCallbackName + &quot;\\((.*)\\);?$&quot;), &quot;$1&quot;);
+            var data = JSON.parse(responseText);
</ins><span class="cx">         } catch (e) {
</span><span class="cx">             var data = {error: e.message};
</span><span class="cx">         }
</span></span></pre></div>
<a id="trunkToolsBuildSlaveSupportbuildwebkitorgconfigpublic_htmldashboardScriptsWebKitBuildbotjs"></a>
<div class="modfile"><h4>Modified: trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/WebKitBuildbot.js (161272 => 161273)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/WebKitBuildbot.js        2014-01-03 19:13:38 UTC (rev 161272)
+++ trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/WebKitBuildbot.js        2014-01-03 19:32:11 UTC (rev 161273)
</span><span class="lines">@@ -64,8 +64,8 @@
</span><span class="cx">         return this.baseURL + &quot;builders/&quot; + encodeURIComponent(iteration.queue.id) + &quot;/builds/&quot; + iteration.id + &quot;/steps/compile-webkit/logs/stdio/text&quot;;
</span><span class="cx">     },
</span><span class="cx"> 
</span><del>-    layoutTestResultsURLForIteration: function(iteration)
</del><ins>+    layoutTestResultsDirectoryURLForIteration: function(iteration)
</ins><span class="cx">     {
</span><del>-        return this.baseURL + &quot;results/&quot; + encodeURIComponent(iteration.queue.id) + &quot;/&quot; + encodeURIComponent(&quot;r&quot; + iteration.openSourceRevision + &quot; (&quot; + iteration.id + &quot;)&quot;) + &quot;/results.html&quot;;
</del><ins>+        return this.baseURL + &quot;results/&quot; + encodeURIComponent(iteration.queue.id) + &quot;/&quot; + encodeURIComponent(&quot;r&quot; + iteration.openSourceRevision + &quot; (&quot; + iteration.id + &quot;)&quot;);
</ins><span class="cx">     }
</span><span class="cx"> };
</span></span></pre></div>
<a id="trunkToolsBuildSlaveSupportbuildwebkitorgconfigpublic_htmldashboardScriptsWebKitTestHistoryjs"></a>
<div class="addfile"><h4>Added: trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/WebKitTestHistory.js (0 => 161273)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/WebKitTestHistory.js                                (rev 0)
+++ trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/WebKitTestHistory.js        2014-01-03 19:32:11 UTC (rev 161273)
</span><span class="lines">@@ -0,0 +1,41 @@
</span><ins>+/*
+ * Copyright (C) 2014 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.
+ */
+
+TestHistory = function()
+{
+    this._baseURL = &quot;http://webkit-test-results.appspot.com/dashboards/flakiness_dashboard.html&quot;;
+};
+
+BaseObject.addConstructorFunctions(TestHistory);
+
+TestHistory.prototype = {
+    constructor: TestHistory,
+    __proto__: BaseObject.prototype,
+
+    historyPageURLForTest: function(path)
+    {
+        return this._baseURL + &quot;#showAllRuns=true&amp;tests=&quot; + encodeURIComponent(path);
+    }
+};
</ins><span class="cx">Property changes on: trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/WebKitTestHistory.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnmimetype"></a>
<div class="addfile"><h4>Added: svn:mime-type</h4></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<a id="trunkToolsBuildSlaveSupportbuildwebkitorgconfigpublic_htmldashboardStylesQueueViewcss"></a>
<div class="modfile"><h4>Modified: trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Styles/QueueView.css (161272 => 161273)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Styles/QueueView.css        2014-01-03 19:13:38 UTC (rev 161272)
+++ trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Styles/QueueView.css        2014-01-03 19:32:11 UTC (rev 161273)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -62,3 +62,31 @@
</span><span class="cx"> .commit-history-popover &gt; .divider {
</span><span class="cx">     height: 7px;
</span><span class="cx"> }
</span><ins>+
+.test-results-popover {
+    font-family: &quot;HelveticaNeue-Light&quot;, &quot;Helvetica Neue&quot;, sans-serif;
+    color: rgb(145, 135, 95);
+    font-size: 12px;
+    text-align: left;
+    padding: 1px 6px 1px 6px;
+}
+
+.test-results-popover .failing-test-kind-summary {
+    display: block;
+}
+
+.test-results-popover .test-path {
+    color: black;
+    -webkit-user-select: auto;
+    cursor: text;
+}
+
+.test-results-popover .failure-kind-indicator {
+    color: rgb(191, 67, 41);
+    padding: 0px 0px 0px 7px;
+}
+
+.test-results-popover .test-history-link {
+    color: rgb(145, 135, 95);
+    padding: 0px 0px 0px 7px;
+}
</ins></span></pre></div>
<a id="trunkToolsBuildSlaveSupportbuildwebkitorgconfigpublic_htmldashboardindexhtml"></a>
<div class="modfile"><h4>Modified: trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/index.html (161272 => 161273)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/index.html        2014-01-03 19:13:38 UTC (rev 161272)
+++ trunk/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/index.html        2014-01-03 19:32:11 UTC (rev 161273)
</span><span class="lines">@@ -53,6 +53,7 @@
</span><span class="cx">     &lt;script src=&quot;Scripts/StatusLineView.js&quot;&gt;&lt;/script&gt;
</span><span class="cx">     &lt;script src=&quot;Scripts/Settings.js&quot;&gt;&lt;/script&gt;
</span><span class="cx">     &lt;script src=&quot;Scripts/Trac.js&quot;&gt;&lt;/script&gt;
</span><ins>+    &lt;script src=&quot;Scripts/WebKitTestHistory.js&quot;&gt;&lt;/script&gt;
</ins><span class="cx">     &lt;script src=&quot;Scripts/Initialization.js&quot;&gt;&lt;/script&gt;
</span><span class="cx">     &lt;script src=&quot;Scripts/Main.js&quot;&gt;&lt;/script&gt;
</span><span class="cx"> &lt;/head&gt;
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (161272 => 161273)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog        2014-01-03 19:13:38 UTC (rev 161272)
+++ trunk/Tools/ChangeLog        2014-01-03 19:32:11 UTC (rev 161273)
</span><span class="lines">@@ -1,3 +1,78 @@
</span><ins>+2014-01-03  Alexey Proskuryakov  &lt;ap@apple.com&gt;
+
+        Please add a way to quick peek at failing tests at build.webkit.org/dashboard
+        https://bugs.webkit.org/show_bug.cgi?id=122181
+
+        Reviewed by Timothy Hatcher and Timothy Horton.
+
+        Detailed results are saved by run-webkit-tests to full_results.json (which is actually
+        JSONP). Dashboard will load them on demand.
+
+        * BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Buildbot.js:
+        (Buildbot.prototype.layoutTestResultsURLForIteration): Moved from WebKitBuildbot.js
+        and made it use a function from WebKitBuildbot that builds results directory path.
+        (Buildbot.prototype.layoutTestFullResultsURLForIteration): Added a function that builds
+        a URL for full_results.json.
+        (Buildbot.prototype.layoutTestCrashLogForIteration): Added a function that builds
+        a URL for a crash log.
+
+        * BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/BuildbotIteration.js:
+        (BuildbotIteration.prototype.loadLayoutTestResults): Load and cache layout test results for
+        the iteration.
+
+        * BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/BuildbotQueueView.js:        
+        (BuildbotQueueView.prototype._presentPopoverForPendingCommits): Updated for changed
+        popover API (see below).
+        (BuildbotQueueView.prototype._presentPopoverForRevisionRange): Ditto.
+
+        * BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/BuildbotTesterQueueView.js:
+        (BuildbotTesterQueueView.prototype.update.appendBuilderQueueStatus): Added a check
+        for iterations that were interrupted (previously, they were displayed incorrectly,
+        often as passes). Install popover trackers for failure bubbles for which we can currently
+        display something useful.
+        (BuildbotTesterQueueView.prototype._popoverContentForLayoutTestRegressions): Build
+        a popover for layout test regressions when we have the data loaded on demand.
+        We have test paths, special indicators for crashes/timeouts, and links to test history
+        at flakiness dashboard.
+        (BuildbotTesterQueueView.prototype._presentPopoverForLayoutTestRegressions): Show
+        the popover for layout test regressions. Just shows &quot;Loading...&quot; until the data is
+        loaded.
+        (BuildbotTesterQueueView.prototype._presentPopoverForMultipleFailureKinds): List
+        types of failures if there are multiple. There is a lot of similarity with
+        appendBuilderQueueStatus(), but I couldn't find a good way to share the code.
+
+        * BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Initialization.js:
+        Create a global test history object, which is used for links in layout test popover.
+
+        * BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Popover.js:
+        Changed the API to be more like WebInspector again, allowing for changing content
+        of an existing popover. As the size of a popover can change, making the mouse pointer
+        enter it without a mousenter event, install a handler for mousewheel instead, and block
+        document scrolling from this event handler when needed.
+
+        * BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/StatusLineView.js:
+        (StatusLineView.prototype.get statusBubbleElement): Added an accessor for status
+        bubble element, making it possible to install a popover on it.
+
+        * BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Utilities.js:
+        (JSON.load): Added the ability to load JSONP by providing an optional callback name.
+
+        * BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/WebKitBuildbot.js:
+        (WebKitBuildbot.prototype.layoutTestResultsDirectoryURLForIteration): Switched from
+        building a complete results URL to only building one for root results path. This is
+        the part that depends on specific buildbot installation, everything relative to it
+        is the same.
+
+        * BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/WebKitTestHistory.js: Added.
+        Build a path to test history page. In the future, we may consider adding code to
+        load the data and display it inline.
+
+        * BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Styles/QueueView.css:
+        Added styles for this new popover.
+
+        * BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/index.html: Added
+        a new file, WebKitTestHistory.js.
+
</ins><span class="cx"> 2014-01-03  Carlos Garcia Campos  &lt;cgarcia@igalia.com&gt;
</span><span class="cx"> 
</span><span class="cx">         REGRESSION(r161214): [GTK] WebKit2 C API tests fail to run after r161214
</span></span></pre>
</div>
</div>

</body>
</html>