Bug 603517 - Enable mochitest to optionally run in loops without restarting the browser r=ctalbert

This commit is contained in:
Malini Das 2011-07-14 14:39:17 -07:00
Родитель 5ac670aeff
Коммит 26d36b64b7
8 изменённых файлов: 280 добавлений и 40 удалений

Просмотреть файл

@ -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,33 +129,40 @@ Tester.prototype = {
},
finish: function Tester_finish(aSkipSummary) {
this._cs.unregisterListener(this);
this.dumper.dump("\nINFO TEST-START | Shutdown\n");
if (this.tests.length) {
this.dumper.dump("Browser Chrome Test Summary\n");
function sum(a,b) a+b;
var passCount = this.tests.map(function (f) f.passCount).reduce(sum);
var failCount = this.tests.map(function (f) f.failCount).reduce(sum);
var todoCount = this.tests.map(function (f) f.todoCount).reduce(sum);
this.dumper.dump("\tPassed: " + passCount + "\n" +
"\tFailed: " + failCount + "\n" +
"\tTodo: " + todoCount + "\n");
} else {
this.dumper.dump("TEST-UNEXPECTED-FAIL | (browser-test.js) | " +
"No tests to run. Did you pass an invalid --test-path?");
if(this.loops > 0){
--this.loops;
this.currentTestIndex = -1;
this.nextTest();
}
else{
this._cs.unregisterListener(this);
this.dumper.dump("\nINFO TEST-START | Shutdown\n");
if (this.tests.length) {
this.dumper.dump("Browser Chrome Test Summary\n");
function sum(a,b) a+b;
var passCount = this.tests.map(function (f) f.passCount).reduce(sum);
var failCount = this.tests.map(function (f) f.failCount).reduce(sum);
var todoCount = this.tests.map(function (f) f.todoCount).reduce(sum);
this.dumper.dump("\tPassed: " + passCount + "\n" +
"\tFailed: " + failCount + "\n" +
"\tTodo: " + todoCount + "\n");
} else {
this.dumper.dump("TEST-UNEXPECTED-FAIL | (browser-test.js) | " +
"No tests to run. Did you pass an invalid --test-path?");
}
this.dumper.dump("\n*** End BrowserChrome Test Results ***\n");
this.dumper.done();
// Tests complete, notify the callback and return
this.callback(this.tests);
this.callback = null;
this.tests = null;
}
this.dumper.dump("\n*** End BrowserChrome Test Results ***\n");
this.dumper.done();
// Tests complete, notify the callback and return
this.callback(this.tests);
this.callback = null;
this.tests = null;
},
observe: function Tester_observe(aConsoleMessage) {

Просмотреть файл

@ -32,7 +32,7 @@ function loadTests()
{
window.removeEventListener("load", loadTests, false);
[links, singleTestPath] = getTestList();
// load server.js in so we can share template functions
var scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
getService(Ci.mozIJSSubScriptLoader);
@ -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,11 +266,27 @@ TestRunner.runNextTest = function() {
TestRunner.log("Passed: " + $("pass-count").innerHTML);
TestRunner.log("Failed: " + $("fail-count").innerHTML);
TestRunner.log("Todo: " + $("todo-count").innerHTML);
TestRunner.log("SimpleTest FINISHED");
// 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 = "";
@ -165,8 +171,7 @@ RunSet.reloadAndRunAll = function(e) {
window.location.href += "&autorun=1";
} 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();
}