mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 642175 - Part 2: Allow mochitests to clean up plugin and IPC process crash dumps. r=ted
This commit is contained in:
parent
5135d118cc
commit
5f0489f00f
@ -114,6 +114,7 @@ def checkForCrashes(dumpDir, symbolsPath, testName=None):
|
||||
dumps = glob.glob(os.path.join(dumpDir, '*.dmp'))
|
||||
for d in dumps:
|
||||
log.info("PROCESS-CRASH | %s | application crashed (minidump found)", testName)
|
||||
print "Crash dump filename: " + d
|
||||
if symbolsPath and stackwalkPath and os.path.exists(stackwalkPath):
|
||||
p = subprocess.Popen([stackwalkPath, d, symbolsPath],
|
||||
stdout=subprocess.PIPE,
|
||||
|
@ -64,7 +64,11 @@ SpecialPowersException.prototype.toString = function() {
|
||||
};
|
||||
|
||||
/* XPCOM gunk */
|
||||
function SpecialPowersObserver() {}
|
||||
function SpecialPowersObserver() {
|
||||
this._isFrameScriptLoaded = false;
|
||||
this._messageManager = Cc["@mozilla.org/globalmessagemanager;1"].
|
||||
getService(Ci.nsIChromeFrameMessageManager);
|
||||
}
|
||||
|
||||
SpecialPowersObserver.prototype = {
|
||||
classDescription: "Special powers Observer for use in testing.",
|
||||
@ -72,24 +76,49 @@ SpecialPowersObserver.prototype = {
|
||||
contractID: "@mozilla.org/special-powers-observer;1",
|
||||
QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsIObserver]),
|
||||
_xpcom_categories: [{category: "profile-after-change", service: true }],
|
||||
isFrameScriptLoaded: false,
|
||||
|
||||
observe: function(aSubject, aTopic, aData)
|
||||
{
|
||||
if (aTopic == "profile-after-change") {
|
||||
this.init();
|
||||
} else if (!this.isFrameScriptLoaded &&
|
||||
aTopic == "chrome-document-global-created") {
|
||||
|
||||
var messageManager = Cc["@mozilla.org/globalmessagemanager;1"].
|
||||
getService(Ci.nsIChromeFrameMessageManager);
|
||||
// Register for any messages our API needs us to handle
|
||||
messageManager.addMessageListener("SPPrefService", this);
|
||||
switch (aTopic) {
|
||||
case "profile-after-change":
|
||||
this.init();
|
||||
break;
|
||||
|
||||
messageManager.loadFrameScript(CHILD_SCRIPT, true);
|
||||
this.isFrameScriptLoaded = true;
|
||||
} else if (aTopic == "xpcom-shutdown") {
|
||||
this.uninit();
|
||||
case "chrome-document-global-created":
|
||||
if (!this._isFrameScriptLoaded) {
|
||||
// Register for any messages our API needs us to handle
|
||||
this._messageManager.addMessageListener("SPPrefService", this);
|
||||
this._messageManager.addMessageListener("SPProcessCrashService", this);
|
||||
this._messageManager.addMessageListener("SPPingService", this);
|
||||
|
||||
this._messageManager.loadFrameScript(CHILD_SCRIPT, true);
|
||||
this._isFrameScriptLoaded = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case "xpcom-shutdown":
|
||||
this.uninit();
|
||||
break;
|
||||
|
||||
case "plugin-crashed":
|
||||
case "ipc:content-shutdown":
|
||||
function addDumpIDToMessage(propertyName) {
|
||||
var id = aSubject.getPropertyAsAString(propertyName);
|
||||
if (id) {
|
||||
message.dumpIDs.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
var message = { type: "crash-observed", dumpIDs: [] };
|
||||
aSubject = aSubject.QueryInterface(Ci.nsIPropertyBag2);
|
||||
if (aTopic == "plugin-crashed") {
|
||||
addDumpIDToMessage("pluginDumpID");
|
||||
addDumpIDToMessage("browserDumpID");
|
||||
} else { // ipc:content-shutdown
|
||||
addDumpIDToMessage("dumpID");
|
||||
}
|
||||
this._messageManager.sendAsyncMessage("SPProcessCrashService", message);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
@ -104,8 +133,76 @@ SpecialPowersObserver.prototype = {
|
||||
{
|
||||
var obs = Services.obs;
|
||||
obs.removeObserver(this, "chrome-document-global-created", false);
|
||||
this.removeProcessCrashObservers();
|
||||
},
|
||||
|
||||
addProcessCrashObservers: function() {
|
||||
if (this._processCrashObserversRegistered) {
|
||||
return;
|
||||
}
|
||||
|
||||
Services.obs.addObserver(this, "plugin-crashed", false);
|
||||
Services.obs.addObserver(this, "ipc:content-shutdown", false);
|
||||
this._processCrashObserversRegistered = true;
|
||||
},
|
||||
|
||||
removeProcessCrashObservers: function() {
|
||||
if (!this._processCrashObserversRegistered) {
|
||||
return;
|
||||
}
|
||||
|
||||
Services.obs.removeObserver(this, "plugin-crashed");
|
||||
Services.obs.removeObserver(this, "ipc:content-shutdown");
|
||||
this._processCrashObserversRegistered = false;
|
||||
},
|
||||
|
||||
getCrashDumpDir: function() {
|
||||
if (!this._crashDumpDir) {
|
||||
var directoryService = Cc["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Ci.nsIProperties);
|
||||
this._crashDumpDir = directoryService.get("ProfD", Ci.nsIFile);
|
||||
this._crashDumpDir.append("minidumps");
|
||||
}
|
||||
return this._crashDumpDir;
|
||||
},
|
||||
|
||||
deleteCrashDumpFiles: function(aFilenames) {
|
||||
var crashDumpDir = this.getCrashDumpDir();
|
||||
if (!crashDumpDir.exists()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var success = aFilenames.length != 0;
|
||||
aFilenames.forEach(function(crashFilename) {
|
||||
var file = crashDumpDir.clone();
|
||||
file.append(crashFilename);
|
||||
if (file.exists()) {
|
||||
file.remove(false);
|
||||
} else {
|
||||
success = false;
|
||||
}
|
||||
});
|
||||
return success;
|
||||
},
|
||||
|
||||
findCrashDumpFiles: function(aToIgnore) {
|
||||
var crashDumpDir = this.getCrashDumpDir();
|
||||
var entries = crashDumpDir.exists() && crashDumpDir.directoryEntries;
|
||||
if (!entries) {
|
||||
return [];
|
||||
}
|
||||
|
||||
var crashDumpFiles = [];
|
||||
while (entries.hasMoreElements()) {
|
||||
var file = entries.getNext().QueryInterface(Ci.nsIFile);
|
||||
var path = String(file.path);
|
||||
if (path.match(/\.(dmp|extra)$/) && !aToIgnore[path]) {
|
||||
crashDumpFiles.push(path);
|
||||
}
|
||||
}
|
||||
return crashDumpFiles.concat();
|
||||
},
|
||||
|
||||
/**
|
||||
* messageManager callback function
|
||||
* This will get requests from our API in the window and process them in chrome for it
|
||||
@ -159,6 +256,34 @@ SpecialPowersObserver.prototype = {
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case "SPProcessCrashService":
|
||||
switch (aMessage.json.op) {
|
||||
case "register-observer":
|
||||
this.addProcessCrashObservers();
|
||||
break;
|
||||
case "unregister-observer":
|
||||
this.removeProcessCrashObservers();
|
||||
break;
|
||||
case "delete-crash-dump-files":
|
||||
return this.deleteCrashDumpFiles(aMessage.json.filenames);
|
||||
case "find-crash-dump-files":
|
||||
return this.findCrashDumpFiles(aMessage.json.crashDumpFilesToIgnore);
|
||||
default:
|
||||
throw new SpecialPowersException("Invalid operation for SPProcessCrashService");
|
||||
}
|
||||
break;
|
||||
|
||||
case "SPPingService":
|
||||
if (aMessage.json.op == "ping") {
|
||||
aMessage.target
|
||||
.QueryInterface(Ci.nsIFrameLoaderOwner)
|
||||
.frameLoader
|
||||
.messageManager
|
||||
.sendAsyncMessage("SPPingService", { op: "pong" });
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new SpecialPowersException("Unrecognized Special Powers API");
|
||||
}
|
||||
|
@ -44,6 +44,12 @@ var Cc = Components.classes;
|
||||
function SpecialPowers(window) {
|
||||
this.window = window;
|
||||
bindDOMWindowUtils(this, window);
|
||||
this._encounteredCrashDumpFiles = [];
|
||||
this._unexpectedCrashDumpFiles = { };
|
||||
this._crashDumpDir = null;
|
||||
this._pongHandlers = [];
|
||||
this._messageListener = this._messageReceived.bind(this);
|
||||
addMessageListener("SPPingService", this._messageListener);
|
||||
}
|
||||
|
||||
function bindDOMWindowUtils(sp, window) {
|
||||
@ -214,6 +220,77 @@ SpecialPowers.prototype = {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
registerProcessCrashObservers: function() {
|
||||
addMessageListener("SPProcessCrashService", this._messageListener);
|
||||
sendSyncMessage("SPProcessCrashService", { op: "register-observer" });
|
||||
},
|
||||
|
||||
_messageReceived: function(aMessage) {
|
||||
switch (aMessage.name) {
|
||||
case "SPProcessCrashService":
|
||||
if (aMessage.json.type == "crash-observed") {
|
||||
var self = this;
|
||||
aMessage.json.dumpIDs.forEach(function(id) {
|
||||
self._encounteredCrashDumpFiles.push(id + ".dmp");
|
||||
self._encounteredCrashDumpFiles.push(id + ".extra");
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
case "SPPingService":
|
||||
if (aMessage.json.op == "pong") {
|
||||
var handler = this._pongHandlers.shift();
|
||||
if (handler) {
|
||||
handler();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
removeExpectedCrashDumpFiles: function(aExpectingProcessCrash) {
|
||||
var success = true;
|
||||
if (aExpectingProcessCrash) {
|
||||
var message = {
|
||||
op: "delete-crash-dump-files",
|
||||
filenames: this._encounteredCrashDumpFiles
|
||||
};
|
||||
if (!sendSyncMessage("SPProcessCrashService", message)[0]) {
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
this._encounteredCrashDumpFiles.length = 0;
|
||||
return success;
|
||||
},
|
||||
|
||||
findUnexpectedCrashDumpFiles: function() {
|
||||
var self = this;
|
||||
var message = {
|
||||
op: "find-crash-dump-files",
|
||||
crashDumpFilesToIgnore: this._unexpectedCrashDumpFiles
|
||||
};
|
||||
var crashDumpFiles = sendSyncMessage("SPProcessCrashService", message)[0];
|
||||
crashDumpFiles.forEach(function(aFilename) {
|
||||
self._unexpectedCrashDumpFiles[aFilename] = true;
|
||||
});
|
||||
return crashDumpFiles;
|
||||
},
|
||||
|
||||
executeAfterFlushingMessageQueue: function(aCallback) {
|
||||
this._pongHandlers.push(aCallback);
|
||||
sendAsyncMessage("SPPingService", { op: "ping" });
|
||||
},
|
||||
|
||||
executeSoon: function(aFunc) {
|
||||
var tm = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
|
||||
tm.mainThread.dispatch({
|
||||
run: function() {
|
||||
aFunc();
|
||||
}
|
||||
}, Ci.nsIThread.DISPATCH_NORMAL);
|
||||
}
|
||||
};
|
||||
|
||||
// Expose everything but internal APIs (starting with underscores) to
|
||||
|
@ -129,6 +129,10 @@ SimpleTest._logResult = function(test, passString, failString) {
|
||||
}
|
||||
};
|
||||
|
||||
SimpleTest._logInfo = function(name, message) {
|
||||
this._logResult({result:true, name:name, diag:message}, "TEST-INFO");
|
||||
};
|
||||
|
||||
/**
|
||||
* Copies of is and isnot with the call to ok replaced by a call to todo.
|
||||
**/
|
||||
@ -330,7 +334,7 @@ SimpleTest.waitForFocus = function (callback, targetWindow, expectBlankPage) {
|
||||
childTargetWindow = childTargetWindow.value;
|
||||
|
||||
function info(msg) {
|
||||
SimpleTest._logResult({result: true, name: msg}, "TEST-INFO");
|
||||
SimpleTest._logInfo("", msg);
|
||||
}
|
||||
|
||||
function debugFocusLog(prefix) {
|
||||
@ -522,6 +526,8 @@ SimpleTest.waitForClipboard = function(aExpectedStringOrValidatorFn, aSetupFn,
|
||||
* working (or finish).
|
||||
*/
|
||||
SimpleTest.executeSoon = function(aFunc) {
|
||||
// Once SpecialPowers is available in chrome mochitests, we can replace the
|
||||
// body of this function with a call to SpecialPowers.executeSoon().
|
||||
if ("Components" in window && "classes" in window.Components) {
|
||||
try {
|
||||
netscape.security.PrivilegeManager
|
||||
@ -556,6 +562,17 @@ SimpleTest.finish = function () {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Indicates to the test framework that the current test expects one or
|
||||
* more crashes (from plugins or IPC documents), and that the minidumps from
|
||||
* those crashes should be removed.
|
||||
*/
|
||||
SimpleTest.expectChildProcessCrash = function () {
|
||||
if (parentRunner) {
|
||||
parentRunner.expectChildProcessCrash();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
addLoadEvent(function() {
|
||||
if (SimpleTest._stopOnLoad) {
|
||||
|
@ -49,6 +49,8 @@ if (typeof SpecialPowers != 'undefined') {
|
||||
TestRunner.ipcMode = false;
|
||||
}
|
||||
|
||||
TestRunner._expectingProcessCrash = false;
|
||||
|
||||
/**
|
||||
* Make sure the tests don't hang indefinitely.
|
||||
**/
|
||||
@ -168,6 +170,10 @@ TestRunner._makeIframe = function (url, retry) {
|
||||
TestRunner.runTests = function (/*url...*/) {
|
||||
TestRunner.log("SimpleTest START");
|
||||
|
||||
if (typeof SpecialPowers != "undefined") {
|
||||
SpecialPowers.registerProcessCrashObservers();
|
||||
}
|
||||
|
||||
TestRunner._urls = flattenArguments(arguments);
|
||||
$('testframe').src="";
|
||||
TestRunner._checkForHangs();
|
||||
@ -226,18 +232,61 @@ TestRunner.runNextTest = function() {
|
||||
}
|
||||
};
|
||||
|
||||
TestRunner.expectChildProcessCrash = function() {
|
||||
if (typeof SpecialPowers == "undefined") {
|
||||
throw "TestRunner.expectChildProcessCrash must only be called from plain mochitests.";
|
||||
}
|
||||
|
||||
TestRunner._expectingProcessCrash = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* This stub is called by SimpleTest when a test is finished.
|
||||
**/
|
||||
TestRunner.testFinished = function(tests) {
|
||||
var runtime = new Date().valueOf() - TestRunner._currentTestStartTime;
|
||||
TestRunner.log("TEST-END | " +
|
||||
TestRunner._urls[TestRunner._currentTest] +
|
||||
" | finished in " + runtime + "ms");
|
||||
function cleanUpCrashDumpFiles() {
|
||||
if (!SpecialPowers.removeExpectedCrashDumpFiles(TestRunner._expectingProcessCrash)) {
|
||||
TestRunner.error("TEST-UNEXPECTED-FAIL | " +
|
||||
TestRunner.currentTestURL +
|
||||
" | This test did not leave any crash dumps behind, but we were expecting some!");
|
||||
tests.push({ result: false });
|
||||
}
|
||||
var unexpectedCrashDumpFiles =
|
||||
SpecialPowers.findUnexpectedCrashDumpFiles();
|
||||
TestRunner._expectingProcessCrash = false;
|
||||
if (unexpectedCrashDumpFiles.length) {
|
||||
TestRunner.error("TEST-UNEXPECTED-FAIL | " +
|
||||
TestRunner.currentTestURL +
|
||||
" | This test left crash dumps behind, but we " +
|
||||
"weren't expecting it to!");
|
||||
tests.push({ result: false });
|
||||
unexpectedCrashDumpFiles.sort().forEach(function(aFilename) {
|
||||
TestRunner.log("TEST-INFO | Found unexpected crash dump file " +
|
||||
aFilename + ".");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
TestRunner.updateUI(tests);
|
||||
TestRunner._currentTest++;
|
||||
TestRunner.runNextTest();
|
||||
function runNextTest() {
|
||||
var runtime = new Date().valueOf() - TestRunner._currentTestStartTime;
|
||||
TestRunner.log("TEST-END | " +
|
||||
TestRunner._urls[TestRunner._currentTest] +
|
||||
" | finished in " + runtime + "ms");
|
||||
TestRunner.log("TEST-INFO | Time is " + Math.floor(Date.now() / 1000));
|
||||
|
||||
TestRunner.updateUI(tests);
|
||||
TestRunner._currentTest++;
|
||||
TestRunner.runNextTest();
|
||||
}
|
||||
|
||||
if (typeof SpecialPowers != 'undefined') {
|
||||
SpecialPowers.executeAfterFlushingMessageQueue(function() {
|
||||
cleanUpCrashDumpFiles();
|
||||
runNextTest();
|
||||
});
|
||||
} else {
|
||||
runNextTest();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user