зеркало из https://github.com/mozilla/gecko-dev.git
Bug 603517 - Enable mochitest to optionally run in loops without restarting the browser r=ctalbert
This commit is contained in:
Родитель
5ac670aeff
Коммит
26d36b64b7
|
@ -100,6 +100,7 @@ _SERV_FILES = \
|
|||
$(topsrcdir)/netwerk/test/httpserver/httpd.js \
|
||||
mozprefs.js \
|
||||
pywebsocket_wrapper.py \
|
||||
plain-loop.html \
|
||||
$(NULL)
|
||||
|
||||
_PYWEBSOCKET_FILES = \
|
||||
|
|
|
@ -58,6 +58,7 @@ Tester.prototype = {
|
|||
EventUtils: {},
|
||||
SimpleTest: {},
|
||||
|
||||
loops: 0,
|
||||
checker: null,
|
||||
currentTestIndex: -1,
|
||||
lastStartTime: null,
|
||||
|
@ -69,6 +70,10 @@ Tester.prototype = {
|
|||
},
|
||||
|
||||
start: function Tester_start() {
|
||||
//if testOnLoad was not called, then gConfig is not defined
|
||||
if(!gConfig)
|
||||
gConfig = readConfig();
|
||||
this.loops = gConfig.loops;
|
||||
this.dumper.dump("*** Start BrowserChrome Test Results ***\n");
|
||||
this._cs.registerListener(this);
|
||||
|
||||
|
@ -124,6 +129,12 @@ Tester.prototype = {
|
|||
},
|
||||
|
||||
finish: function Tester_finish(aSkipSummary) {
|
||||
if(this.loops > 0){
|
||||
--this.loops;
|
||||
this.currentTestIndex = -1;
|
||||
this.nextTest();
|
||||
}
|
||||
else{
|
||||
this._cs.unregisterListener(this);
|
||||
|
||||
this.dumper.dump("\nINFO TEST-START | Shutdown\n");
|
||||
|
@ -151,6 +162,7 @@ Tester.prototype = {
|
|||
this.callback(this.tests);
|
||||
this.callback = null;
|
||||
this.tests = null;
|
||||
}
|
||||
},
|
||||
|
||||
observe: function Tester_observe(aConsoleMessage) {
|
||||
|
|
|
@ -49,10 +49,13 @@ function loadTests()
|
|||
}
|
||||
gTestList = eval(srvScope.jsonArrayOfTestFiles(links));
|
||||
populate();
|
||||
hookup();
|
||||
|
||||
if (singleTestPath)
|
||||
window.location.href = singleTestPath;
|
||||
if (singleTestPath) {
|
||||
TestRunner.loopTest(singleTestPath);
|
||||
} else {
|
||||
hookup();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
window.addEventListener("load", loadTests, false);
|
||||
|
@ -63,6 +66,7 @@ function loadTests()
|
|||
<button label="Run Chrome Tests" id="runtests" flex="1"/>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml" id="xulharness">
|
||||
<!--TODO: this should be separated into a file that both this file and server.js uses-->
|
||||
<div class="container">
|
||||
<p style="float:right;">
|
||||
<small>Based on the MochiKit unit tests.</small>
|
||||
|
@ -98,6 +102,12 @@ function loadTests()
|
|||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<br/>
|
||||
<table cellpadding="0" cellspacing="0" border="1" bordercolor="red">
|
||||
<!-- tbody needed to avoid bug 494546 causing performance problems -->
|
||||
<tbody id="fail-table">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="/static/harness.css" />
|
||||
<script type="text/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/TestRunner.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/MozillaFileLogger.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/setup.js"></script>
|
||||
</head>
|
||||
<script type="text/javascript">
|
||||
|
||||
function loadTests()
|
||||
{
|
||||
var links = {};
|
||||
var params = {};
|
||||
if (window.parseQueryString) {
|
||||
params = parseQueryString(location.search.substring(1), true);
|
||||
}
|
||||
|
||||
var table = $("test-table");
|
||||
var row = table.rows[1];
|
||||
row.id = 'tr-' + params.testname;
|
||||
row.cells[3].innerHTML= "<a href=" + params.testname + ">" + params.testname + "</a>";
|
||||
|
||||
TestRunner.loopTest(params.testname);
|
||||
}
|
||||
</script>
|
||||
|
||||
<body onload="loadTests()">
|
||||
<!--TODO: this should be separated into a file that both this file and server.js uses-->
|
||||
<div class="container">
|
||||
<p style="float:right;">
|
||||
<small>Based on the MochiKit unit tests.</small>
|
||||
</p>
|
||||
<div class="status">
|
||||
<h1 id="indicator">Status</h1>
|
||||
<h2 id="pass">Passed: <span id="pass-count">0</span></h2>
|
||||
<h2 id="fail">Failed: <span id="fail-count">0</span></h2>
|
||||
<h2 id="fail">Todo: <span id="todo-count">0</span></h2>
|
||||
</div>
|
||||
<div class="clear"></div>
|
||||
<div id="current-test">
|
||||
<b>Currently Executing: <span id="current-test-path">_</span></b>
|
||||
</div>
|
||||
<div class="clear"></div>
|
||||
<div class="frameholder">
|
||||
<iframe type="content" scrolling="no" id="testframe" width="550" height="350"></iframe>
|
||||
</div>
|
||||
<div class="clear"></div>
|
||||
<div class="toggle">
|
||||
<a href="#" id="toggleNonTests">Show Non-Tests</a>
|
||||
<br />
|
||||
</div>
|
||||
<div id="wrapper">
|
||||
<table cellpadding="0" cellspacing="0">
|
||||
<!-- tbody needed to avoid bug 494546 causing performance problems -->
|
||||
<tbody id="test-table">
|
||||
<tr>
|
||||
<td>Passed</td>
|
||||
<td>Failed</td>
|
||||
<td>Todo</td>
|
||||
<td>Test Files</td>
|
||||
</tr>
|
||||
<tr class="dir">
|
||||
<td>0</td>
|
||||
<td>0</td>
|
||||
<td>0</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<br/>
|
||||
<table cellpadding="0" cellspacing="0" border="1" bordercolor="red">
|
||||
<!-- tbody needed to avoid bug 494546 causing performance problems -->
|
||||
<tbody id="fail-table">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -232,6 +232,13 @@ class MochitestOptions(optparse.OptionParser):
|
|||
"inside a VMware Workstation 7.0 or later VM")
|
||||
defaults["vmwareRecording"] = False
|
||||
|
||||
self.add_option("--loops",
|
||||
action = "store", type = "int",
|
||||
dest = "loops", metavar = "LOOPS",
|
||||
help = "repeats the test or set of tests the given number of times "
|
||||
"without restarting the browser (given number > 0)")
|
||||
defaults["loops"] = 0
|
||||
|
||||
# -h, --help are automatically handled by OptionParser
|
||||
|
||||
self.set_defaults(**defaults)
|
||||
|
@ -405,6 +412,7 @@ class Mochitest(object):
|
|||
# Path to the test script on the server
|
||||
TEST_PATH = "/tests/"
|
||||
CHROME_PATH = "/redirect.html";
|
||||
PLAIN_LOOP_PATH = "/plain-loop.html";
|
||||
urlOpts = []
|
||||
runSSLTunnel = True
|
||||
vmwareHelper = None
|
||||
|
@ -433,6 +441,8 @@ class Mochitest(object):
|
|||
""" Build the url path to the specific test harness and test file or directory """
|
||||
testHost = "http://mochi.test:8888"
|
||||
testURL = testHost + self.TEST_PATH + options.testPath
|
||||
if os.path.isfile(self.oldcwd + self.TEST_PATH + options.testPath) and options.loops > 0:
|
||||
testURL = testHost + self.PLAIN_LOOP_PATH
|
||||
if options.chrome or options.a11y:
|
||||
testURL = testHost + self.CHROME_PATH
|
||||
elif options.browserChrome:
|
||||
|
@ -537,6 +547,7 @@ class Mochitest(object):
|
|||
totalChunks -- how many chunks to split tests into
|
||||
thisChunk -- which chunk to run
|
||||
timeout -- per-test timeout in seconds
|
||||
loops -- How many times to run the test
|
||||
"""
|
||||
|
||||
# allow relative paths for logFile
|
||||
|
@ -563,6 +574,10 @@ class Mochitest(object):
|
|||
self.urlOpts.append("chunkByDir=%d" % options.chunkByDir)
|
||||
if options.shuffle:
|
||||
self.urlOpts.append("shuffle=1")
|
||||
if options.loops:
|
||||
self.urlOpts.append("loops=%d" % options.loops)
|
||||
if os.path.isfile(self.oldcwd + self.TEST_PATH + options.testPath) and options.loops > 0:
|
||||
self.urlOpts.append("testname=%s" % (self.TEST_PATH + options.testPath))
|
||||
|
||||
def cleanup(self, manifest, options):
|
||||
""" remove temporary files and profile """
|
||||
|
|
|
@ -662,6 +662,11 @@ function testListing(metadata, response)
|
|||
TR(TD("Passed"), TD("Failed"), TD("Todo"), TD("Test Files")),
|
||||
linksToTableRows(links, 0)
|
||||
),
|
||||
|
||||
BR(),
|
||||
TABLE({cellpadding: 0, cellspacing: 0, border: 1, bordercolor: "red", id: "fail-table"}
|
||||
),
|
||||
|
||||
DIV({class: "clear"})
|
||||
)
|
||||
)
|
||||
|
|
|
@ -37,6 +37,7 @@ var TestRunner = {};
|
|||
TestRunner.logEnabled = false;
|
||||
TestRunner._currentTest = 0;
|
||||
TestRunner.currentTestURL = "";
|
||||
TestRunner.originalTestURL = "";
|
||||
TestRunner._urls = [];
|
||||
|
||||
TestRunner.timeout = 5 * 60 * 1000; // 5 minutes.
|
||||
|
@ -85,6 +86,12 @@ TestRunner.requestLongerTimeout = function(factor) {
|
|||
TestRunner._timeoutFactor = factor;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is used to loop tests
|
||||
**/
|
||||
TestRunner.loops = 0;
|
||||
TestRunner._currentLoop = 0;
|
||||
|
||||
/**
|
||||
* This function is called after generating the summary.
|
||||
**/
|
||||
|
@ -124,7 +131,6 @@ TestRunner._toggle = function(el) {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates the iframe that contains a test
|
||||
**/
|
||||
|
@ -163,6 +169,7 @@ TestRunner._makeIframe = function (url, retry) {
|
|||
**/
|
||||
TestRunner.runTests = function (/*url...*/) {
|
||||
TestRunner.log("SimpleTest START");
|
||||
TestRunner.originalTestURL = $("current-test").innerHTML;
|
||||
|
||||
SpecialPowers.registerProcessCrashObservers();
|
||||
|
||||
|
@ -174,6 +181,49 @@ TestRunner.runTests = function (/*url...*/) {
|
|||
TestRunner.runNextTest();
|
||||
};
|
||||
|
||||
/**
|
||||
* Used for running a set of tests in a loop for debugging purposes
|
||||
* Takes an array of URLs
|
||||
**/
|
||||
TestRunner.resetTests = function(listURLs) {
|
||||
TestRunner._currentTest = 0;
|
||||
// Reset our "Current-test" line - functionality depends on it
|
||||
$("current-test").innerHTML = TestRunner.originalTestURL;
|
||||
if (TestRunner.logEnabled)
|
||||
TestRunner.log("SimpleTest START Loop " + TestRunner._currentLoop);
|
||||
|
||||
TestRunner._urls = listURLs;
|
||||
$('testframe').src="";
|
||||
TestRunner._checkForHangs();
|
||||
window.focus();
|
||||
$('testframe').focus();
|
||||
TestRunner.runNextTest();
|
||||
}
|
||||
|
||||
/*
|
||||
* Used to run a single test in a loop and update the UI with the results
|
||||
*/
|
||||
TestRunner.loopTest = function(testPath){
|
||||
var numLoops = TestRunner.loops;
|
||||
while(numLoops >= 0){
|
||||
//must set the following line so that TestHarness.updateUI finds the right div to update
|
||||
$("current-test-path").innerHTML = testPath;
|
||||
function checkComplete() {
|
||||
var testWindow = window.open(testPath, 'test window');
|
||||
if (testWindow.document.readyState == "complete") {
|
||||
TestRunner.currentTestURL = testPath;
|
||||
TestRunner.updateUI(testWindow.SimpleTest._tests);
|
||||
testWindow.close();
|
||||
} else {
|
||||
setTimeout(checkComplete, 1000);
|
||||
}
|
||||
}
|
||||
checkComplete();
|
||||
numLoops--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Run the next test. If no test remains, calls onComplete().
|
||||
**/
|
||||
|
@ -216,9 +266,25 @@ TestRunner.runNextTest = function() {
|
|||
TestRunner.log("Passed: " + $("pass-count").innerHTML);
|
||||
TestRunner.log("Failed: " + $("fail-count").innerHTML);
|
||||
TestRunner.log("Todo: " + $("todo-count").innerHTML);
|
||||
// If we are looping, don't send this cause it closes the log file
|
||||
if (TestRunner.loops == 0)
|
||||
TestRunner.log("SimpleTest FINISHED");
|
||||
|
||||
if (TestRunner.onComplete) {
|
||||
if (TestRunner.loops == 0 && TestRunner.onComplete) {
|
||||
TestRunner.onComplete();
|
||||
}
|
||||
|
||||
if (TestRunner._currentLoop < TestRunner.loops){
|
||||
TestRunner._currentLoop++;
|
||||
TestRunner.resetTests(TestRunner._urls);
|
||||
} else {
|
||||
// Loops are finished
|
||||
if (TestRunner.logEnabled) {
|
||||
TestRunner.log("TEST-INFO | Ran " + TestRunner._currentLoop + " Loops");
|
||||
TestRunner.log("SimpleTest FINISHED");
|
||||
}
|
||||
|
||||
if (TestRunner.onComplete)
|
||||
TestRunner.onComplete();
|
||||
}
|
||||
}
|
||||
|
@ -292,6 +358,47 @@ TestRunner.countResults = function(tests) {
|
|||
return {"OK": nOK, "notOK": nNotOK, "todo": nTodo};
|
||||
}
|
||||
|
||||
/**
|
||||
* Print out table of any error messages found during looped run
|
||||
*/
|
||||
TestRunner.displayLoopErrors = function(tableName, tests) {
|
||||
if(TestRunner.countResults(tests).notOK >0){
|
||||
var table = $(tableName);
|
||||
var curtest;
|
||||
if (table.rows.length == 0) {
|
||||
//if table headers are not yet generated, make them
|
||||
var row = table.insertRow(table.rows.length);
|
||||
var cell = row.insertCell(0);
|
||||
var textNode = document.createTextNode("Test File Name:");
|
||||
cell.appendChild(textNode);
|
||||
cell = row.insertCell(1);
|
||||
textNode = document.createTextNode("Test:");
|
||||
cell.appendChild(textNode);
|
||||
cell = row.insertCell(2);
|
||||
textNode = document.createTextNode("Error message:");
|
||||
cell.appendChild(textNode);
|
||||
}
|
||||
|
||||
//find the broken test
|
||||
for (var testnum in tests){
|
||||
curtest = tests[testnum];
|
||||
if( !((curtest.todo && !curtest.result) || (curtest.result && !curtest.todo)) ){
|
||||
//this is a failed test or the result of todo test. Display the related message
|
||||
row = table.insertRow(table.rows.length);
|
||||
cell = row.insertCell(0);
|
||||
textNode = document.createTextNode(TestRunner.currentTestURL);
|
||||
cell.appendChild(textNode);
|
||||
cell = row.insertCell(1);
|
||||
textNode = document.createTextNode(curtest.name);
|
||||
cell.appendChild(textNode);
|
||||
cell = row.insertCell(2);
|
||||
textNode = document.createTextNode((curtest.diag ? curtest.diag : "" ));
|
||||
cell.appendChild(textNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TestRunner.updateUI = function(tests) {
|
||||
var results = TestRunner.countResults(tests);
|
||||
var passCount = parseInt($("pass-count").innerHTML) + results.OK;
|
||||
|
@ -319,9 +426,14 @@ TestRunner.updateUI = function(tests) {
|
|||
var row = $(trID);
|
||||
var tds = row.getElementsByTagName("td");
|
||||
tds[0].style.backgroundColor = "#0d0";
|
||||
tds[0].innerHTML = results.OK;
|
||||
tds[0].innerHTML = parseInt(tds[0].innerHTML) + parseInt(results.OK);
|
||||
tds[1].style.backgroundColor = results.notOK > 0 ? "red" : "#0d0";
|
||||
tds[1].innerHTML = results.notOK;
|
||||
tds[1].innerHTML = parseInt(tds[1].innerHTML) + parseInt(results.notOK);
|
||||
tds[2].style.backgroundColor = results.todo > 0 ? "orange" : "#0d0";
|
||||
tds[2].innerHTML = results.todo;
|
||||
tds[2].innerHTML = parseInt(tds[2].innerHTML) + parseInt(results.todo);
|
||||
|
||||
//if we ran in a loop, display any found errors
|
||||
if(TestRunner.loops > 0){
|
||||
TestRunner.displayLoopErrors('fail-table', tests);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,6 +69,11 @@ if (params.timeout) {
|
|||
var fileLevel = params.fileLevel || null;
|
||||
var consoleLevel = params.consoleLevel || null;
|
||||
|
||||
// loop tells us how many times to run the tests
|
||||
if (params.loops) {
|
||||
TestRunner.loops = params.loops;
|
||||
}
|
||||
|
||||
// closeWhenDone tells us to call quit.js when complete
|
||||
if (params.closeWhenDone) {
|
||||
TestRunner.onComplete = goQuitApplication;
|
||||
|
@ -154,6 +159,7 @@ RunSet.runall = function(e) {
|
|||
}
|
||||
TestRunner.runTests(my_tests);
|
||||
}
|
||||
|
||||
RunSet.reloadAndRunAll = function(e) {
|
||||
e.preventDefault();
|
||||
//window.location.hash = "";
|
||||
|
@ -166,7 +172,6 @@ RunSet.reloadAndRunAll = function(e) {
|
|||
} else {
|
||||
window.location.href += "?autorun=1";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// UI Stuff
|
||||
|
@ -205,7 +210,7 @@ function toggleNonTests (e) {
|
|||
function hookup() {
|
||||
connect("runtests", "onclick", RunSet, "reloadAndRunAll");
|
||||
connect("toggleNonTests", "onclick", toggleNonTests);
|
||||
// run automatically if
|
||||
// run automatically if autorun specified
|
||||
if (params.autorun) {
|
||||
RunSet.runall();
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче