Bug 652501 - Part 1: Allow reftests to clean up plugin and IPC process crash dumps. r=roc

This commit is contained in:
Cameron McCormack 2011-04-26 15:02:38 +12:00
Родитель 68454aca67
Коммит 76f0cc3edd
3 изменённых файлов: 140 добавлений и 2 удалений

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

@ -396,6 +396,7 @@ so 60/zoom is an integer.
Printing Tests
==============
Now that the patch for bug 374050 has landed
(https://bugzilla.mozilla.org/show_bug.cgi?id=374050), it is possible to
create reftests that run in a paginated context.
@ -421,3 +422,23 @@ doesn't use exactly the same codepath as real print preview/print. In
particular, scripting and frames are likely to cause problems; it is untested,
though. That said, it should be sufficient for testing layout issues related
to pagination.
Plugin and IPC Process Crash Tests
==================================
If you are running a test that causes an out-of-process plugin or IPC process
under Electrolysis to crash as part of a reftest, this will cause process
crash minidump files to be left in the profile directory. The test
infrastructure that runs the reftests will notice these minidump files and
dump out information from them, and these additional error messages in the logs
can end up erroneously being associated with other errors from the reftest run.
They are also confusing, since the appearance of "PROCESS-CRASH" messages in
the test run output can seem like a real problem, when in fact it is the
expected behavior.
To indicate to the reftest framework that a test is expecting a plugin or
IPC process crash, have the test include "reftest-expect-process-crash" as
one of the root element's classes by the time the test has finished. This will
cause any minidump files that are generated while running the test to be removed
and they won't cause any error messages in the test run output.

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

@ -464,6 +464,7 @@ function WaitForTestEnd(contentRootElement, inPrintMode) {
state = STATE_COMPLETED;
gFailureReason = "timed out while taking snapshot (bug in harness?)";
RemoveListeners();
CheckForProcessCrashExpectation();
setTimeout(RecordResult, 0);
return;
}
@ -527,6 +528,7 @@ function OnDocumentLoad(event)
// Go into reftest-wait mode belatedly.
WaitForTestEnd(contentRootElement, inPrintMode);
} else {
CheckForProcessCrashExpectation();
RecordResult();
}
}
@ -555,6 +557,17 @@ function OnDocumentLoad(event)
}
}
function CheckForProcessCrashExpectation()
{
var contentRootElement = content.document.documentElement;
if (contentRootElement &&
contentRootElement.hasAttribute('class') &&
contentRootElement.getAttribute('class').split(/\s+/)
.indexOf("reftest-expect-process-crash") != -1) {
SendExpectProcessCrash();
}
}
function RecordResult()
{
LogInfo("RecordResult fired");
@ -764,11 +777,16 @@ function SendInitCanvasWithSnapshot()
}
function SendScriptResults(runtimeMs, error, results)
{
{
sendAsyncMessage("reftest:ScriptResults",
{ runtimeMs: runtimeMs, error: error, results: results });
}
function SendExpectProcessCrash(runtimeMs)
{
sendAsyncMessage("reftest:ExpectProcessCrash");
}
function SendTestDone(runtimeMs)
{
sendAsyncMessage("reftest:TestDone", { runtimeMs: runtimeMs });

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

@ -57,6 +57,10 @@ const NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX =
"@mozilla.org/network/protocol;1?name=";
const NS_XREAPPINFO_CONTRACTID =
"@mozilla.org/xre/app-info;1";
const NS_DIRECTORY_SERVICE_CONTRACTID =
"@mozilla.org/file/directory_service;1";
const NS_OBSERVER_SERVICE_CONTRACTID =
"@mozilla.org/observer-service;1";
var gLoadTimeout = 0;
var gTimeoutHook = null;
@ -115,6 +119,11 @@ var gSlowestTestURL;
var gDrawWindowFlags;
var gExpectingProcessCrash = false;
var gExpectedCrashDumpFiles = [];
var gUnexpectedCrashDumpFiles = { };
var gCrashDumpDir;
const TYPE_REFTEST_EQUAL = '==';
const TYPE_REFTEST_NOTEQUAL = '!=';
const TYPE_LOAD = 'load'; // test without a reference (just test that it does
@ -205,6 +214,11 @@ function IDForEventTarget(event)
function OnRefTestLoad()
{
gCrashDumpDir = CC[NS_DIRECTORY_SERVICE_CONTRACTID]
.getService(CI.nsIProperties)
.get("ProfD", CI.nsIFile);
gCrashDumpDir.append("minidumps");
var prefs = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefBranch2);
try {
@ -279,6 +293,8 @@ function InitAndStartRefTests()
gIOService = CC[IO_SERVICE_CONTRACTID].getService(CI.nsIIOService);
gDebug = CC[DEBUG_CONTRACTID].getService(CI.nsIDebug2);
RegisterProcessCrashObservers();
if (gRemote) {
gServer = null;
} else {
@ -1141,6 +1157,7 @@ function RecordResult(testRunTime, errorMsg, scriptResults)
// First document has been loaded.
// Proceed to load the second document.
CleanUpCrashDumpFiles();
StartCurrentURI(2);
break;
case 2:
@ -1201,6 +1218,7 @@ function RecordResult(testRunTime, errorMsg, scriptResults)
UpdateCanvasCache(gURLs[0].url1, gCanvas1);
UpdateCanvasCache(gURLs[0].url2, gCanvas2);
CleanUpCrashDumpFiles();
FinishTestItem();
break;
default:
@ -1217,6 +1235,55 @@ function LoadFailed(why)
FinishTestItem();
}
function RemoveExpectedCrashDumpFiles()
{
if (gExpectingProcessCrash) {
for each (let crashFilename in gExpectedCrashDumpFiles) {
let file = gCrashDumpDir.clone();
file.append(crashFilename);
if (file.exists()) {
file.remove(false);
}
}
}
gExpectedCrashDumpFiles.length = 0;
}
function FindUnexpectedCrashDumpFiles()
{
if (!gCrashDumpDir.exists()) {
return;
}
let entries = gCrashDumpDir.directoryEntries;
if (!entries) {
return;
}
let foundCrashDumpFile = false;
while (entries.hasMoreElements()) {
let file = entries.getNext().QueryInterface(CI.nsIFile);
let path = String(file.path);
if (path.match(/\.(dmp|extra)$/) && !gUnexpectedCrashDumpFiles[path]) {
if (!foundCrashDumpFile) {
foundCrashDumpFile = true;
gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gCurrentURL +
" | This test left crash dumps behind, but we weren't expecting it to!\n");
}
gDumpLog("REFTEST INFO | Found unexpected crash dump file" + path +
".\n");
gUnexpectedCrashDumpFiles[path] = true;
}
}
}
function CleanUpCrashDumpFiles()
{
RemoveExpectedCrashDumpFiles();
FindUnexpectedCrashDumpFiles();
gExpectingProcessCrash = false;
}
function FinishTestItem()
{
// Replace document with BLANK_URL_FOR_CLEARING in case there are
@ -1316,6 +1383,10 @@ function RegisterMessageListenersAndLoadContentScript()
"reftest:UpdateCanvasForInvalidation",
function (m) { RecvUpdateCanvasForInvalidation(m.json.rects); }
);
gBrowserMessageManager.addMessageListener(
"reftest:ExpectProcessCrash",
function (m) { RecvExpectProcessCrash(); }
);
gBrowserMessageManager.loadFrameScript("chrome://reftest/content/reftest-content.js", true);
}
@ -1376,6 +1447,34 @@ function RecvUpdateCanvasForInvalidation(rects)
UpdateCurrentCanvasForInvalidation(rects);
}
function OnProcessCrashed(subject, topic, data)
{
var id;
subject = subject.QueryInterface(CI.nsIPropertyBag2);
if (topic == "plugin-crashed") {
id = subject.getPropertyAsAString("pluginDumpID");
} else if (topic == "ipc:content-shutdown") {
id = subject.getPropertyAsAString("dumpID");
}
if (id) {
gExpectedCrashDumpFiles.push(id + ".dmp");
gExpectedCrashDumpFiles.push(id + ".extra");
}
}
function RegisterProcessCrashObservers()
{
var os = CC[NS_OBSERVER_SERVICE_CONTRACTID]
.getService(CI.nsIObserverService);
os.addObserver(OnProcessCrashed, "plugin-crashed", false);
os.addObserver(OnProcessCrashed, "ipc:content-shutdown", false);
}
function RecvExpectProcessCrash()
{
gExpectingProcessCrash = true;
}
function SendClear()
{
gBrowserMessageManager.sendAsyncMessage("reftest:Clear");