Commit 75c0d2f7 authored by Quinten Yearsley's avatar Quinten Yearsley Committed by Commit Bot

Remove webkit-patch layout-tests-server.

Now webkit-patch rebaseline-server is removed in
https://crrev.com/c/847641.

layout-tests-server is likely also unused, and it would
be good to reduce the surface area and quantity of code
in webkitpy if possible.

Bug: 704384
Change-Id: I518153ae01c36d1e34433dc38c5ebea9b87cc869
Reviewed-on: https://chromium-review.googlesource.com/883613Reviewed-by: default avatarDirk Pranke <dpranke@chromium.org>
Commit-Queue: Quinten Yearsley <qyearsley@chromium.org>
Cr-Commit-Position: refs/heads/master@{#531963}
parent 9aa4d2ce
# Copyright (c) 2010 Google Inc. All rights reserved.
# Copyright (c) 2014 Samsung Electronics. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * 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.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
# OWNER OR 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.
"""Starts a local HTTP server which can run layout tests (given a list of layout tests to be run)"""
from webkitpy.tool.commands.abstract_local_server_command import AbstractLocalServerCommand
from webkitpy.tool.servers.layout_tests_server import LayoutTestsHTTPServer
class LayoutTestsServer(AbstractLocalServerCommand):
name = 'layout-test-server'
help_text = __doc__
show_in_main_help = True
server = LayoutTestsHTTPServer
def _prepare_config(self, options, args, tool):
options.show_results = False
options.httpd_port = 9630
# Required for Python to search this directory for module files
<!DOCTYPE html>
<!--
Copyright (c) 2010 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:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* 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.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
OWNER OR 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.
-->
<html>
<head>
<title>Layout Test Rebaseline Server</title>
<link rel="stylesheet" href="/main.css" type="text/css">
<script src="/util.js"></script>
<script src="/loupe.js"></script>
<script src="/main.js"></script>
<script src="/queue.js"></script>
</head>
<body class="loading">
<pre id="log" style="display: none"></pre>
<div id="queue" style="display: none">
Queue:
<select id="queue-select" size="10"></select>
<button id="remove-queue-selection">Remove selection</button>
<button id="rebaseline-queue">Rebaseline queue</button>
</div>
<div id="header">
<div id="controls">
<!-- Add a dummy <select> node so that this lines up with the text on the left -->
<select style="visibility: hidden"></select>
<span id="toggle-sort" class="link">Sort tests by metric</span>
<span class="divider">|</span>
<span id="toggle-log" class="link">Log</span>
<span class="divider">|</span>
<a href="/quitquitquit">Exit</a>
</div>
<span id="selectors">
<label>
Failure type:
<select id="failure-type-selector"></select>
</label>
<label>
Directory:
<select id="directory-selector"></select>
</label>
<label>
Test:
<select id="test-selector"></select>
</label>
</span>
<a id="test-link" target="_blank">View test</a>
<span id="nav-buttons">
<button id="previous-test">&laquo;</button>
<span id="test-index"></span> of <span id="test-count"></span>
<button id="next-test">&raquo;</button>
</span>
</div>
<table id="test-output">
<thead id="labels">
<tr>
<th>Expected</th>
<th>Actual</th>
<th>Diff</th>
</tr>
</thead>
<tbody id="image-outputs" style="display: none">
<tr>
<td colspan="3"><h2>Image</h2></td>
</tr>
<tr>
<td><img id="expected-image"></td>
<td><img id="actual-image"></td>
<td>
<canvas id="diff-canvas" width="800" height="600"></canvas>
<div id="diff-checksum" style="display: none">
<h3>Checksum mismatch</h3>
Expected: <span id="expected-checksum"></span><br>
Actual: <span id="actual-checksum"></span>
</div>
</td>
</tr>
</tbody>
<tbody id="text-outputs" style="display: none">
<tr>
<td colspan="3"><h2>Text</h2></td>
</tr>
<tr>
<td><pre id="expected-text" class="text-output"></pre></td>
<td><pre id="actual-text" class="text-output"></pre></td>
<td><div id="diff-text-pretty" class="text-output"></div></td>
</tr>
</tbody>
</table>
<div id="footer">
<label>State: <span id="state"></span></label>
<label>Existing baselines: <span id="current-baselines"></span></label>
<label>
Baseline target:
<select id="baseline-target"></select>
</label>
<label>
Move current baselines to:
<select id="baseline-move-to">
<option value="none">Nowhere (replace)</option>
</select>
</label>
<!-- Add a dummy <button> node so that this lines up with the text on the right -->
<button style="visibility: hidden; padding-left: 0; padding-right: 0;"></button>
<div id="action-buttons">
<span id="toggle-queue" class="link">Queue</span>
<button id="add-to-rebaseline-queue">Add to rebaseline queue</button>
</div>
</div>
<table id="loupe" style="display: none">
<tr>
<td colspan="3" id="loupe-info">
<span id="loupe-close" class="link">Close</span>
<label>Coordinate: <span id="loupe-coordinate"></span></label>
</td>
</tr>
<tr>
<td>
<div class="loupe-container">
<canvas id="expected-loupe" width="210" height="210"></canvas>
<div class="center-highlight"></div>
</div>
</td>
<td>
<div class="loupe-container">
<canvas id="actual-loupe" width="210" height="210"></canvas>
<div class="center-highlight"></div>
</div>
</td>
<td>
<div class="loupe-container">
<canvas id="diff-loupe" width="210" height="210"></canvas>
<div class="center-highlight"></div>
</div>
</td>
</tr>
<tr id="loupe-colors">
<td><label>Exp. color: <span id="expected-loupe-color"></span></label></td>
<td><label>Actual color: <span id="actual-loupe-color"></span></label></td>
<td><label>Diff color: <span id="diff-loupe-color"></span></label></td>
</tr>
</table>
</body>
</html>
/*
* Copyright (c) 2010 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:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
* OWNER OR 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 LOUPE_MAGNIFICATION_FACTOR = 10;
function Loupe()
{
this._node = $('loupe');
this._currentCornerX = -1;
this._currentCornerY = -1;
var self = this;
function handleOutputClick(event) { self._handleOutputClick(event); }
$('expected-image').addEventListener('click', handleOutputClick);
$('actual-image').addEventListener('click', handleOutputClick);
$('diff-canvas').addEventListener('click', handleOutputClick);
function handleLoupeClick(event) { self._handleLoupeClick(event); }
$('expected-loupe').addEventListener('click', handleLoupeClick);
$('actual-loupe').addEventListener('click', handleLoupeClick);
$('diff-loupe').addEventListener('click', handleLoupeClick);
function hide(event) { self.hide(); }
$('loupe-close').addEventListener('click', hide);
}
Loupe.prototype._handleOutputClick = function(event)
{
// The -1 compensates for the border around the image/canvas.
this._showFor(event.offsetX - 1, event.offsetY - 1);
};
Loupe.prototype._handleLoupeClick = function(event)
{
var deltaX = Math.floor(event.offsetX/LOUPE_MAGNIFICATION_FACTOR);
var deltaY = Math.floor(event.offsetY/LOUPE_MAGNIFICATION_FACTOR);
this._showFor(
this._currentCornerX + deltaX, this._currentCornerY + deltaY);
}
Loupe.prototype.hide = function()
{
this._node.style.display = 'none';
};
Loupe.prototype._showFor = function(x, y)
{
this._fillFromImage(x, y, 'expected', $('expected-image'));
this._fillFromImage(x, y, 'actual', $('actual-image'));
this._fillFromCanvas(x, y, 'diff', $('diff-canvas'));
this._node.style.display = '';
};
Loupe.prototype._fillFromImage = function(x, y, type, sourceImage)
{
var tempCanvas = document.createElement('canvas');
tempCanvas.width = sourceImage.width;
tempCanvas.height = sourceImage.height;
var tempContext = tempCanvas.getContext('2d');
tempContext.drawImage(sourceImage, 0, 0);
this._fillFromCanvas(x, y, type, tempCanvas);
};
Loupe.prototype._fillFromCanvas = function(x, y, type, canvas)
{
var context = canvas.getContext('2d');
var sourceImageData =
context.getImageData(0, 0, canvas.width, canvas.height);
var targetCanvas = $(type + '-loupe');
var targetContext = targetCanvas.getContext('2d');
targetContext.fillStyle = 'rgba(255, 255, 255, 1)';
targetContext.fillRect(0, 0, targetCanvas.width, targetCanvas.height);
var sourceXOffset = (targetCanvas.width/LOUPE_MAGNIFICATION_FACTOR - 1)/2;
var sourceYOffset = (targetCanvas.height/LOUPE_MAGNIFICATION_FACTOR - 1)/2;
function readPixelComponent(x, y, component) {
var offset = (y * sourceImageData.width + x) * 4 + component;
return sourceImageData.data[offset];
}
for (var i = -sourceXOffset; i <= sourceXOffset; i++) {
for (var j = -sourceYOffset; j <= sourceYOffset; j++) {
var sourceX = x + i;
var sourceY = y + j;
var sourceR = readPixelComponent(sourceX, sourceY, 0);
var sourceG = readPixelComponent(sourceX, sourceY, 1);
var sourceB = readPixelComponent(sourceX, sourceY, 2);
var sourceA = readPixelComponent(sourceX, sourceY, 3)/255;
sourceA = Math.round(sourceA * 10)/10;
var targetX = (i + sourceXOffset) * LOUPE_MAGNIFICATION_FACTOR;
var targetY = (j + sourceYOffset) * LOUPE_MAGNIFICATION_FACTOR;
var colorString =
sourceR + ', ' + sourceG + ', ' + sourceB + ', ' + sourceA;
targetContext.fillStyle = 'rgba(' + colorString + ')';
targetContext.fillRect(
targetX, targetY,
LOUPE_MAGNIFICATION_FACTOR, LOUPE_MAGNIFICATION_FACTOR);
if (i == 0 && j == 0) {
$('loupe-coordinate').textContent = sourceX + ', ' + sourceY;
$(type + '-loupe-color').textContent = colorString;
}
}
}
this._currentCornerX = x - sourceXOffset;
this._currentCornerY = y - sourceYOffset;
};
/*
* Copyright (c) 2010 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:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
* OWNER OR 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.
*/
body {
font-size: 12px;
font-family: Helvetica, Arial, sans-serif;
padding: 0;
margin: 0;
}
.loading {
opacity: 0.5;
}
div {
margin: 0;
}
a, .link {
color: #aaf;
text-decoration: underline;
cursor: pointer;
}
.link.selected {
color: #fff;
font-weight: bold;
text-decoration: none;
}
#log,
#queue {
padding: .25em 0 0 .25em;
position: absolute;
right: 0;
height: 200px;
overflow: auto;
background: #fff;
-webkit-box-shadow: 1px 1px 5px rgba(0, 0, 0, .5);
}
#log {
top: 2em;
width: 500px;
}
#queue {
bottom: 3em;
width: 400px;
}
#queue-select {
display: block;
width: 390px;
}
#header,
#footer {
padding: .5em 1em;
background: #333;
color: #fff;
-webkit-box-shadow: 0 1px 5px rgba(0, 0, 0, 0.5);
}
#header {
margin-bottom: 1em;
}
#header .divider,
#footer .divider {
opacity: .3;
padding: 0 .5em;
}
#header label,
#footer label {
padding-right: 1em;
color: #ccc;
}
#test-link {
margin-right: 1em;
}
#header label span,
#footer label span {
color: #fff;
font-weight: bold;
}
#nav-buttons {
white-space: nowrap;
}
#nav-buttons button {
background: #fff;
border: 0;
border-radius: 10px;
}
#nav-buttons button:active {
-webkit-box-shadow: 0 0 5px #33f inset;
background: #aaa;
}
#nav-buttons button[disabled] {
opacity: .5;
}
#controls {
float: right;
}
.disabled-control {
color: #888;
}
#test-output {
border-spacing: 0;
border-collapse: collapse;
margin: 0 auto;
width: 100%;
}
#test-output td,
#test-output th {
padding: 0;
vertical-align: top;
}
#image-outputs img,
#image-outputs canvas,
#image-outputs #diff-checksum {
width: 800px;
height: 600px;
border: solid 1px #ddd;
-webkit-user-select: none;
-webkit-user-drag: none;
}
#image-outputs img,
#image-outputs canvas {
cursor: crosshair;
}
#image-outputs img.loading,
#image-outputs canvas.loading {
opacity: .5;
}
#image-outputs #actual-image {
margin: 0 1em;
}
#test-output #labels th {
text-align: center;
color: #666;
}
#text-outputs .text-output {
height: 600px;
width: 800px;
overflow: auto;
}
#test-output h2 {
border-bottom: solid 1px #ccc;
font-weight: bold;
margin: 0;
background: #eee;
}
#footer {
position: absolute;
bottom: 0;
left: 0;
right: 0;
margin-top: 1em;
}
#state.needs_rebaseline {
color: yellow;
}
#state.rebaseline_failed {
color: red;
}
#state.rebaseline_succeeded {
color: green;
}
#state.in_queue {
color: gray;
}
#current-baselines {
font-weight: normal !important;
}
#current-baselines .platform {
font-weight: bold;
}
#current-baselines a {
color: #ddf;
}
#current-baselines .was-used-for-test {
color: #aaf;
font-weight: bold;
}
#action-buttons {
float: right;
}
#action-buttons .link {
margin-right: 1em;
}
#footer button {
padding: 1em;
}
#loupe {
-webkit-box-shadow: 2px 2px 5px rgba(0, 0, 0, .5);
position: absolute;
width: 634px;
top: 50%;
left: 50%;
margin-left: -151px;
margin-top: -50px;
background: #fff;
border-spacing: 0;
border-collapse: collapse;
}
#loupe td {
padding: 0;
border: solid 1px #ccc;
}
#loupe label {
color: #999;
padding-right: 1em;
}
#loupe span {
color: #000;
font-weight: bold;
}
#loupe canvas {
cursor: crosshair;
}
#loupe #loupe-close {
float: right;
}
#loupe #loupe-info {
background: #eee;
padding: .3em .5em;
}
#loupe #loupe-colors td {
text-align: center;
}
#loupe .loupe-container {
position: relative;
width: 210px;
height: 210px;
}
#loupe .center-highlight {
position: absolute;
width: 10px;
height: 10px;
top: 50%;
left: 50%;
margin-left: -5px;
margin-top: -5px;
outline: solid 1px #999;
}
/*
* Copyright (c) 2010 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:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
* OWNER OR 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 RebaselineQueue()
{
this._selectNode = $('queue-select');
this._rebaselineButtonNode = $('rebaseline-queue');
this._toggleNode = $('toggle-queue');
this._removeSelectionButtonNode = $('remove-queue-selection');
this._inProgressRebaselineCount = 0;
var self = this;
$('add-to-rebaseline-queue').addEventListener(
'click', function() { self.addCurrentTest(); });
this._selectNode.addEventListener('change', updateState);
this._removeSelectionButtonNode.addEventListener(
'click', function() { self._removeSelection(); });
this._rebaselineButtonNode.addEventListener(
'click', function() { self.rebaseline(); });
this._toggleNode.addEventListener(
'click', function() { toggle('queue'); });
}
RebaselineQueue.prototype.updateState = function()
{
var testName = getSelectedTest();
var state = results.tests[testName].state;
$('add-to-rebaseline-queue').disabled = state != STATE_NEEDS_REBASELINE;
var queueLength = this._selectNode.options.length;
if (this._inProgressRebaselineCount > 0) {
this._rebaselineButtonNode.disabled = true;
this._rebaselineButtonNode.textContent =
'Rebaseline in progress (' + this._inProgressRebaselineCount +
' tests left)';
} else if (queueLength == 0) {
this._rebaselineButtonNode.disabled = true;
this._rebaselineButtonNode.textContent = 'Rebaseline queue';
this._toggleNode.textContent = 'Queue';
} else {
this._rebaselineButtonNode.disabled = false;
this._rebaselineButtonNode.textContent =
'Rebaseline queue (' + queueLength + ' tests)';
this._toggleNode.textContent = 'Queue (' + queueLength + ' tests)';
}
this._removeSelectionButtonNode.disabled =
this._selectNode.selectedIndex == -1;
};
RebaselineQueue.prototype.addCurrentTest = function()
{
var testName = getSelectedTest();
var test = results.tests[testName];
if (test.state != STATE_NEEDS_REBASELINE) {
log('Cannot add test with state "' + test.state + '" to queue.',
log.WARNING);
return;
}
var queueOption = document.createElement('option');
queueOption.value = testName;
queueOption.textContent = testName;
this._selectNode.appendChild(queueOption);
test.state = STATE_IN_QUEUE;
updateState();
};
RebaselineQueue.prototype.removeCurrentTest = function()
{
this._removeTest(getSelectedTest());
};
RebaselineQueue.prototype._removeSelection = function()
{
if (this._selectNode.selectedIndex == -1)
return;
this._removeTest(
this._selectNode.options[this._selectNode.selectedIndex].value);
};
RebaselineQueue.prototype._removeTest = function(testName)
{
var queueOption = this._selectNode.firstChild;
while (queueOption && queueOption.value != testName) {
queueOption = queueOption.nextSibling;
}
if (!queueOption)
return;
this._selectNode.removeChild(queueOption);
var test = results.tests[testName];
test.state = STATE_NEEDS_REBASELINE;
updateState();
};
RebaselineQueue.prototype.rebaseline = function()
{
var testNames = [];
for (var queueOption = this._selectNode.firstChild;
queueOption;
queueOption = queueOption.nextSibling) {
testNames.push(queueOption.value);
}
this._inProgressRebaselineCount = testNames.length;
updateState();
testNames.forEach(this._rebaselineTest, this);
};
RebaselineQueue.prototype._rebaselineTest = function(testName)
{
var baselineTarget = getSelectValue('baseline-target');
var baselineMoveTo = getSelectValue('baseline-move-to');
var xhr = new XMLHttpRequest();
xhr.open('POST',
'/rebaseline?test=' + encodeURIComponent(testName) +
'&baseline-target=' + encodeURIComponent(baselineTarget) +
'&baseline-move-to=' + encodeURIComponent(baselineMoveTo));
var self = this;
function handleResponse(logType, newState) {
log(xhr.responseText, logType);
self._removeTest(testName);
self._inProgressRebaselineCount--;
results.tests[testName].state = newState;
updateState();
// If we're done with a set of rebaselines, regenerate the test menu
// (which is grouped by state) since test states have changed.
if (self._inProgressRebaselineCount == 0) {
selectDirectory();
}
}
function handleSuccess() {
handleResponse(log.SUCCESS, STATE_REBASELINE_SUCCEEDED);
}
function handleFailure() {
handleResponse(log.ERROR, STATE_REBASELINE_FAILED);
}
xhr.addEventListener('load', function() {
if (xhr.status < 400) {
handleSuccess();
} else {
handleFailure();
}
});
xhr.addEventListener('error', handleFailure);
xhr.send();
};
/*
* Copyright (c) 2010 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:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
* OWNER OR 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 results;
var testsByFailureType = {};
var testsByDirectory = {};
var selectedTests = [];
function $(id)
{
return document.getElementById(id);
}
function getSelectValue(id)
{
var select = $(id);
if (select.selectedIndex == -1) {
return null;
} else {
return select.options[select.selectedIndex].value;
}
}
function loadText(url, callback)
{
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.addEventListener('load', function() { callback(xhr.responseText); });
xhr.send();
}
function log(text, type)
{
var node = $('log');
if (type) {
var typeNode = document.createElement('span');
typeNode.textContent = type.text;
typeNode.style.color = type.color;
node.appendChild(typeNode);
}
node.appendChild(document.createTextNode(text + '\n'));
node.scrollTop = node.scrollHeight;
}
log.WARNING = {text: 'Warning: ', color: '#aa3'};
log.SUCCESS = {text: 'Success: ', color: 'green'};
log.ERROR = {text: 'Error: ', color: 'red'};
function toggle(id)
{
var element = $(id);
var toggler = $('toggle-' + id);
if (element.style.display == 'none') {
element.style.display = '';
toggler.className = 'link selected';
} else {
element.style.display = 'none';
toggler.className = 'link';
}
}
function getTracUrl(layoutTestPath)
{
return 'http://trac.webkit.org/browser/trunk/LayoutTests/' + layoutTestPath;
}
function getSortedKeys(obj)
{
var keys = [];
for (var key in obj) {
keys.push(key);
}
keys.sort();
return keys;
}
\ No newline at end of file
# Copyright (c) 2010 Google Inc. All rights reserved.
# Copyright (C) 2014 Samsung Electronics. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * 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.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
# OWNER OR 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.
import time
import json
import BaseHTTPServer
import subprocess
from subprocess import STDOUT
from webkitpy.common.path_finder import PathFinder
from webkitpy.common.system.filesystem import FileSystem
from webkitpy.tool.servers.reflection_handler import ReflectionHandler
class LayoutTestsHTTPServer(BaseHTTPServer.HTTPServer):
def __init__(self, httpd_port, _):
server_address = ('', httpd_port)
BaseHTTPServer.HTTPServer.__init__(self, server_address, LayoutTestsServerHTTPRequestHandler)
class LayoutTestsServerHTTPRequestHandler(ReflectionHandler):
def do_POST(self):
json_raw_data = self.rfile.read(int(self.headers.getheader('content-length')))
json_data = json.loads(json_raw_data)
test_list = ''
for each in json_data['tests']:
test_list += each + ' '
filesystem = FileSystem()
path_finder = PathFinder(filesystem)
script_dir = path_finder.path_from_tools_scripts()
executable_path = script_dir + '/run-webkit-tests'
cmd = 'python ' + executable_path + ' --no-show-results '
cmd += test_list
process = subprocess.Popen(cmd, shell=True, cwd=script_dir, env=None, stdout=subprocess.PIPE, stderr=STDOUT)
self.send_response(200)
self.send_header('Access-Control-Allow-Origin', '*')
self.send_header('Content-type', 'text/html')
self.end_headers()
while process.poll() is None:
html_output = '<br>' + str(process.stdout.readline())
self.wfile.write(html_output)
self.wfile.flush()
time.sleep(0.05)
process.wait()
def do_OPTIONS(self):
self.send_response(200, 'ok')
self.send_header('Access-Control-Allow-Origin', '*')
self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
self.send_header('Access-Control-Allow-Headers', 'Content-type')
# 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:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * 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.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
# OWNER OR 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.
import BaseHTTPServer
import cgi
import codecs
import datetime
import json
import mimetypes
import os.path
import shutil
import threading
import time
import wsgiref.handlers
class ReflectionHandler(BaseHTTPServer.BaseHTTPRequestHandler):
STATIC_FILE_EXTENSIONS = ['.js', '.css', '.html']
# Subclasses should override.
STATIC_FILE_DIRECTORY = None
# Setting this flag to True causes the server to send
# Access-Control-Allow-Origin: *
# with every response.
allow_cross_origin_requests = False
def do_GET(self):
self._handle_request()
def do_POST(self):
self._handle_request()
def do_HEAD(self):
self._handle_request()
def read_entity_body(self):
length = int(self.headers.getheader('content-length'))
return self.rfile.read(length)
def _handle_request(self):
# The query attribute is used in subclasses. If we want to set it in the constructor,
# we have to override the superclass constructor, although the docs
# (https://docs.python.org/2/library/basehttpserver.html) say "Subclasses should
# not need to override or extend the __init__() method."
# pylint: disable=attribute-defined-outside-init
if '?' in self.path:
path, query_string = self.path.split('?', 1)
self.query = cgi.parse_qs(query_string)
else:
path = self.path
self.query = {}
function_or_file_name = path[1:] or 'index.html'
_, extension = os.path.splitext(function_or_file_name)
if extension in self.STATIC_FILE_EXTENSIONS:
self._serve_static_file(function_or_file_name)
return
function_name = function_or_file_name.replace('.', '_')
if not hasattr(self, function_name):
self.send_error(404, 'Unknown function %s' % function_name)
return
if function_name[0] == '_':
self.send_error(401, 'Not allowed to invoke private or protected methods')
return
function = getattr(self, function_name)
function()
def _serve_static_file(self, static_path):
self._serve_file(os.path.join(self.STATIC_FILE_DIRECTORY, static_path))
def quitquitquit(self):
self._serve_text('Server quit.\n')
# Shutdown has to happen on another thread from the server's thread,
# otherwise there's a deadlock.
threading.Thread(target=self.server.shutdown).start()
def _send_access_control_header(self):
if self.allow_cross_origin_requests:
self.send_header('Access-Control-Allow-Origin', '*')
def _serve_text(self, text):
self.send_response(200)
self._send_access_control_header()
self.send_header('Content-type', 'text/plain')
self.end_headers()
self.wfile.write(text)
def _serve_json(self, json_object):
self.send_response(200)
self._send_access_control_header()
self.send_header('Content-type', 'application/json')
self.end_headers()
json.dump(json_object, self.wfile)
def _serve_file(self, file_path, cacheable_seconds=0, headers_only=False):
if not os.path.exists(file_path):
self.send_error(404, 'File not found')
return
with codecs.open(file_path, 'rb') as static_file:
self.send_response(200)
self._send_access_control_header()
self.send_header('Content-Length', os.path.getsize(file_path))
mime_type, _ = mimetypes.guess_type(file_path)
if mime_type:
self.send_header('Content-type', mime_type)
if cacheable_seconds:
expires_time = (datetime.datetime.now() +
datetime.timedelta(0, cacheable_seconds))
expires_formatted = wsgiref.handlers.format_date_time(
time.mktime(expires_time.timetuple()))
self.send_header('Expires', expires_formatted)
self.end_headers()
if not headers_only:
shutil.copyfileobj(static_file, self.wfile)
def _serve_xml(self, xml):
self.send_response(200)
self._send_access_control_header()
self.send_header('Content-type', 'text/xml')
self.end_headers()
xml = xml.encode('utf-8')
self.wfile.write(xml)
# 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:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * 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.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
# OWNER OR 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.
import unittest
from webkitpy.tool.servers.reflection_handler import ReflectionHandler
class TestReflectionHandler(ReflectionHandler):
STATIC_FILE_DIRECTORY = '/'
def __init__(self): # pylint: disable=super-init-not-called
self.static_files_served = set()
self.errors_sent = set()
self.functions_run = set()
self.path = None
def _serve_static_file(self, name):
self.static_files_served.add(name)
def send_error(self, code, message=None):
self.errors_sent.add(code)
def function_one(self):
self.functions_run.add('function_one')
def some_html(self):
self.functions_run.add('some_html')
class WriteConvertingLogger(object):
def __init__(self):
self.data = ''
def write(self, data):
# If data is still in ASCII, this will throw an exception.
self.data = str(data)
class TestReflectionHandlerServeXML(ReflectionHandler):
def __init__(self): # pylint: disable=super-init-not-called
self.requestline = False
self.client_address = '127.0.0.1'
self.request_version = '1'
self.wfile = WriteConvertingLogger()
def serve_xml(self, data):
self._serve_xml(data)
def log_message(self, _format, *_args):
pass
class ReflectionHandlerTest(unittest.TestCase):
def assert_handler_response(self, requests, expected_static_files, expected_errors, expected_functions):
handler = TestReflectionHandler()
for request in requests:
handler.path = request
handler._handle_request()
self.assertEqual(handler.static_files_served, expected_static_files)
self.assertEqual(handler.errors_sent, expected_errors)
self.assertEqual(handler.functions_run, expected_functions)
def test_static_content_or_function_switch(self):
self.assert_handler_response(['/test.js'], set(['test.js']), set(), set())
self.assert_handler_response(['/test.js', '/test.css', '/test.html'],
set(['test.js', 'test.html', 'test.css']), set(), set())
self.assert_handler_response(['/test.js', '/test.exe', '/testhtml'], set(['test.js']), set([404]), set())
self.assert_handler_response(['/test.html', '/function.one'], set(['test.html']), set(), set(['function_one']))
self.assert_handler_response(['/some.html'], set(['some.html']), set(), set())
......@@ -46,7 +46,6 @@ from webkitpy.tool.commands.command import HelpPrintingOptionParser
from webkitpy.tool.commands.copy_existing_baselines import CopyExistingBaselines
from webkitpy.tool.commands.flaky_tests import FlakyTests
from webkitpy.tool.commands.help_command import HelpCommand
from webkitpy.tool.commands.layout_tests_server import LayoutTestsServer
from webkitpy.tool.commands.optimize_baselines import OptimizeBaselines
from webkitpy.tool.commands.pretty_diff import PrettyDiff
from webkitpy.tool.commands.queries import CrashLog
......@@ -82,7 +81,6 @@ class WebKitPatch(Host):
CopyExistingBaselines(),
CrashLog(),
FlakyTests(),
LayoutTestsServer(),
OptimizeBaselines(),
PrettyDiff(),
PrintBaselines(),
......
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