зеркало из https://github.com/mozilla/pjs.git
bug 510505 - add unit tests for breakpad exception handler. r=bsmedberg
This commit is contained in:
Родитель
078429ef66
Коммит
ec60db8584
|
@ -70,6 +70,11 @@ TEST_HARNESS_COMPONENTS := \
|
|||
httpd.js \
|
||||
$(NULL)
|
||||
|
||||
ifdef MOZ_CRASHREPORTER
|
||||
#XXX: should find a better way to do this
|
||||
TEST_HARNESS_COMPONENTS += crashreporter_test.xpt
|
||||
endif
|
||||
|
||||
# Rules for staging the necessary harness bits for a test package
|
||||
PKG_STAGE = $(DIST)/test-package-stage
|
||||
|
||||
|
|
|
@ -110,7 +110,7 @@ CPPSRCS = \
|
|||
FORCE_STATIC_LIB = 1
|
||||
|
||||
ifdef ENABLE_TESTS
|
||||
DIRS += test
|
||||
TOOL_DIRS = test
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -43,9 +43,23 @@ relativesrcdir = toolkit/crashreporter/test
|
|||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = crashreporter
|
||||
MODULE = crashreporter_test
|
||||
XPCSHELL_TESTS = unit
|
||||
|
||||
LIBRARY_NAME = testcrasher
|
||||
IS_COMPONENT = 1
|
||||
USE_STATIC_LIBS = 1
|
||||
|
||||
XPIDLSRCS = nsITestCrasher.idl
|
||||
|
||||
CPPSRCS = \
|
||||
nsTestCrasher.cpp \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DSO_LIBS += xpcom
|
||||
EXTRA_DSO_LDOPTS += $(LIBS_DIR) $(MOZ_COMPONENT_LIBS) $(XPCOM_GLUE_LDOPTS)
|
||||
LOCAL_INCLUDES += -I$(XPIDL_GEN_DIR)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
_BROWSER_FILES = \
|
||||
|
@ -58,3 +72,6 @@ _BROWSER_FILES = \
|
|||
|
||||
libs:: $(_BROWSER_FILES)
|
||||
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)/browser
|
||||
$(NSINSTALL) -D $(DEPTH)/_tests/xpcshell/$(MODULE)/unit/components
|
||||
$(INSTALL) $(SHARED_LIBRARY) \
|
||||
$(DEPTH)/_tests/xpcshell/$(MODULE)/unit/components
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
#include "nsISupports.idl"
|
||||
|
||||
[scriptable, uuid(95464a04-6949-46cb-b621-d167790704a0)]
|
||||
interface nsITestCrasher : nsISupports
|
||||
{
|
||||
void crash();
|
||||
};
|
|
@ -0,0 +1,44 @@
|
|||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIGenericFactory.h"
|
||||
#include "nsITestCrasher.h"
|
||||
|
||||
class nsTestCrasher : public nsITestCrasher
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSITESTCRASHER
|
||||
|
||||
nsTestCrasher() {}
|
||||
|
||||
private:
|
||||
~nsTestCrasher() {};
|
||||
};
|
||||
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsTestCrasher, nsITestCrasher)
|
||||
|
||||
/* void crash (); */
|
||||
NS_IMETHODIMP nsTestCrasher::Crash()
|
||||
{
|
||||
volatile int* foo = (int*)0x42;
|
||||
*foo = 0;
|
||||
// not reached
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// 54afce51-38d7-4df0-9750-2f90f9ffbca2
|
||||
#define NS_TESTCRASHER_CID \
|
||||
{ 0x54afce51, 0x38d7, 0x4df0, {0x97, 0x50, 0x2f, 0x90, 0xf9, 0xff, 0xbc, 0xa2} }
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsTestCrasher)
|
||||
|
||||
static const nsModuleComponentInfo components[] = {
|
||||
{ "Test Crasher",
|
||||
NS_TESTCRASHER_CID,
|
||||
"@mozilla.org/testcrasher;1",
|
||||
nsTestCrasherConstructor
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMPL_NSGETMODULE(nsTestCrasherModule, components)
|
|
@ -0,0 +1,9 @@
|
|||
// enable crash reporting first
|
||||
let cwd = Components.classes["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Components.interfaces.nsIProperties)
|
||||
.get("CurWorkD", Components.interfaces.nsILocalFile);
|
||||
let crashReporter =
|
||||
Components.classes["@mozilla.org/toolkit/crash-reporter;1"]
|
||||
.getService(Components.interfaces.nsICrashReporter);
|
||||
crashReporter.enabled = true;
|
||||
crashReporter.minidumpPath = cwd;
|
|
@ -0,0 +1,7 @@
|
|||
// now actually crash
|
||||
let cd = cwd.clone();
|
||||
cd.append("components");
|
||||
Components.manager instanceof Components.interfaces.nsIComponentRegistrar;
|
||||
Components.manager.autoRegister(cd);
|
||||
let crasher = Components.classes["@mozilla.org/testcrasher;1"].createInstance(Components.interfaces.nsITestCrasher);
|
||||
crasher.crash();
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Run an xpcshell subprocess and crash it.
|
||||
*
|
||||
* @param setup
|
||||
* A string of JavaScript code to execute in the subprocess
|
||||
* before crashing. If this is a function and not a string,
|
||||
* it will have .toSource() called on it, and turned into
|
||||
* a call to itself. (for programmer convenience)
|
||||
* This code will be evaluted between crasher_subprocess_head.js
|
||||
* and crasher_subprocess_tail.js, so it will have access
|
||||
* to everything defined in crasher_subprocess_head.js,
|
||||
* which includes "crashReporter", a variable holding
|
||||
* the crash reporter service.
|
||||
*
|
||||
* @param callback
|
||||
* A JavaScript function to be called after the subprocess
|
||||
* crashes. It will be passed (minidump, extra), where
|
||||
* minidump is an nsILocalFile of the minidump file produced,
|
||||
* and extra is an object containing the key,value pairs from
|
||||
* the .extra file.
|
||||
*/
|
||||
function do_crash(setup, callback)
|
||||
{
|
||||
// get current process filename (xpcshell)
|
||||
let ds = Components.classes["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Components.interfaces.nsIProperties);
|
||||
let bin = ds.get("CurProcD", Components.interfaces.nsILocalFile);
|
||||
bin.append("xpcshell");
|
||||
if (!bin.exists()) {
|
||||
bin.leafName = "xpcshell.exe";
|
||||
do_check_true(bin.exists());
|
||||
if (!bin.exists())
|
||||
// weird, can't find xpcshell binary?
|
||||
do_throw("Can't find xpcshell binary!");
|
||||
}
|
||||
// get Gre dir (GreD)
|
||||
let greD = ds.get("GreD", Components.interfaces.nsILocalFile);
|
||||
let headfile = do_get_file("crasher_subprocess_head.js");
|
||||
let tailfile = do_get_file("crasher_subprocess_tail.js");
|
||||
// run xpcshell -g GreD -f head -e "some setup code" -f tail
|
||||
let process = Components.classes["@mozilla.org/process/util;1"]
|
||||
.createInstance(Components.interfaces.nsIProcess);
|
||||
process.init(bin);
|
||||
let args = ['-g', greD.path,
|
||||
'-f', headfile.path];
|
||||
if (setup) {
|
||||
if (typeof(setup) == "function")
|
||||
// funky, but convenient
|
||||
setup = "("+setup.toSource()+")();";
|
||||
args.push('-e', setup);
|
||||
}
|
||||
args.push('-f', tailfile.path);
|
||||
try {
|
||||
process.run(true, args, args.length);
|
||||
}
|
||||
catch(ex) {} // on Windows we exit with a -1 status when crashing.
|
||||
|
||||
// should exit with an error (should have crashed)
|
||||
do_check_neq(process.exitValue, 0);
|
||||
// find minidump
|
||||
let minidump = null;
|
||||
let en = do_get_cwd().directoryEntries;
|
||||
while (en.hasMoreElements()) {
|
||||
let f = en.getNext().QueryInterface(Components.interfaces.nsILocalFile);
|
||||
if (f.leafName.substr(-4) == ".dmp") {
|
||||
minidump = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (minidump == null)
|
||||
do_throw("No minidump found!");
|
||||
|
||||
let extrafile = minidump.clone();
|
||||
extrafile.leafName = extrafile.leafName.slice(0, -4) + ".extra";
|
||||
do_check_true(extrafile.exists());
|
||||
let extra = parseKeyValuePairsFromFile(extrafile);
|
||||
|
||||
if (callback)
|
||||
callback(minidump, extra);
|
||||
|
||||
if (minidump.exists())
|
||||
minidump.remove(false);
|
||||
if (extrafile.exists())
|
||||
extrafile.remove(false);
|
||||
}
|
||||
|
||||
// Utility functions for parsing .extra files
|
||||
function parseKeyValuePairs(text) {
|
||||
var lines = text.split('\n');
|
||||
var data = {};
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
if (lines[i] == '')
|
||||
continue;
|
||||
|
||||
// can't just .split() because the value might contain = characters
|
||||
let eq = lines[i].indexOf('=');
|
||||
if (eq != -1) {
|
||||
let [key, value] = [lines[i].substring(0, eq),
|
||||
lines[i].substring(eq + 1)];
|
||||
if (key && value)
|
||||
data[key] = value.replace("\\n", "\n", "g").replace("\\\\", "\\", "g");
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
function parseKeyValuePairsFromFile(file) {
|
||||
var fstream = Components.classes["@mozilla.org/network/file-input-stream;1"].
|
||||
createInstance(Components.interfaces.nsIFileInputStream);
|
||||
fstream.init(file, -1, 0, 0);
|
||||
var is = Components.classes["@mozilla.org/intl/converter-input-stream;1"].
|
||||
createInstance(Components.interfaces.nsIConverterInputStream);
|
||||
is.init(fstream, "UTF-8", 1024, Components.interfaces.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
|
||||
var str = {};
|
||||
var contents = '';
|
||||
while (is.readString(4096, str) != 0) {
|
||||
contents += str.value;
|
||||
}
|
||||
is.close();
|
||||
fstream.close();
|
||||
return parseKeyValuePairs(contents);
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
function run_test()
|
||||
{
|
||||
if (!("@mozilla.org/toolkit/crash-reporter;1" in Components.classes)) {
|
||||
dump("INFO | test_crashreporter.js | Can't test crashreporter in a non-libxul build.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// try a basic crash
|
||||
do_crash(null, function(mdump, extra) {
|
||||
do_check_true(mdump.exists());
|
||||
do_check_true(mdump.fileSize > 0);
|
||||
do_check_true('StartupTime' in extra);
|
||||
do_check_true('CrashTime' in extra);
|
||||
});
|
||||
|
||||
// check setting some basic data
|
||||
do_crash(function() {
|
||||
crashReporter.annotateCrashReport("TestKey", "TestValue");
|
||||
crashReporter.appendAppNotesToCrashReport("Junk");
|
||||
crashReporter.appendAppNotesToCrashReport("MoreJunk");
|
||||
},
|
||||
function(mdump, extra) {
|
||||
do_check_eq(extra.TestKey, "TestValue");
|
||||
do_check_eq(extra.Notes, "JunkMoreJunk");
|
||||
});
|
||||
}
|
Загрузка…
Ссылка в новой задаче