Bug 983313 - Write crash events for plugin crashes and hangs (part 1: main changes). r=bsmedberg

This commit is contained in:
Drew Willcoxon 2014-05-12 11:58:18 -07:00
parent a2a44f7315
commit 86906537f1
19 changed files with 710 additions and 191 deletions

View File

@ -773,6 +773,7 @@ bin/libfreebl_32int64_3.so
#ifdef MOZ_CRASHREPORTER
@BINPATH@/components/CrashService.manifest
@BINPATH@/components/CrashService.js
@BINPATH@/components/toolkit_crashservice.xpt
#ifdef XP_MACOSX
@BINPATH@/crashreporter.app/
#else

View File

@ -10,6 +10,7 @@
#ifdef MOZ_CRASHREPORTER
#include "nsExceptionHandler.h"
#include "nsICrashService.h"
#endif
using namespace base;
@ -133,8 +134,37 @@ CrashReporterParent::GenerateChildData(const AnnotationTable* processNotes)
ret = CrashReporter::AppendExtraData(mChildDumpID, *processNotes);
if (!ret)
NS_WARNING("problem appending child data to .extra");
NotifyCrashService();
return ret;
}
void
CrashReporterParent::NotifyCrashService()
{
nsCOMPtr<nsICrashService> crashService =
do_GetService("@mozilla.org/crashservice;1");
if (!crashService) {
return;
}
if (mProcessType == GeckoProcessType_Content) {
crashService->AddCrash(nsICrashService::PROCESS_TYPE_CONTENT,
nsICrashService::CRASH_TYPE_CRASH,
mChildDumpID);
}
else if (mProcessType == GeckoProcessType_Plugin) {
nsAutoCString val;
int32_t crashType = nsICrashService::CRASH_TYPE_CRASH;
if (mNotes.Get(NS_LITERAL_CSTRING("PluginHang"), &val) &&
val.Equals(NS_LITERAL_CSTRING("1"))) {
crashType = nsICrashService::CRASH_TYPE_HANG;
}
crashService->AddCrash(nsICrashService::PROCESS_TYPE_PLUGIN, crashType,
mChildDumpID);
}
}
#endif
} // namespace dom

View File

@ -90,6 +90,11 @@ public:
CloneProtocol(Channel* aChannel,
mozilla::ipc::ProtocolCloneContext *aCtx) MOZ_OVERRIDE;
#ifdef MOZ_CRASHREPORTER
void
NotifyCrashService();
#endif
#ifdef MOZ_CRASHREPORTER
AnnotationTable mNotes;
#endif

View File

@ -4,8 +4,7 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'cocoa':
TEST_DIRS += ['tests']
TEST_DIRS += ['tests']
EXPORTS += [
'nsICachedFileDescriptorListener.h',

View File

@ -3,3 +3,6 @@ run-if = toolkit == 'gonk'
[test_NuwaProcessDeadlock.html]
run-if = toolkit == 'gonk'
[test_child_docshell.html]
run-if = toolkit != 'cocoa' # disabled due to hangs, see changeset 6852e7c47edf
[test_CrashService_crash.html]
run-if = crashreporter && !e10s && (toolkit == 'gtk2' || toolkit == 'gtk3' || toolkit == 'cocoa' || toolkit == 'windows') && (buildapp != 'b2g' || toolkit == 'gonk')

View File

@ -0,0 +1,93 @@
<!DOCTYPE HTML>
<html>
<!--
Ensures that content crashes are reported to the crash service
(nsICrashService and CrashManager.jsm).
-->
<head>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="application/javascript;version=1.7">
"use strict";
SimpleTest.waitForExplicitFinish();
SpecialPowers.addPermission("browser", true, document);
SpecialPowers.pushPrefEnv({'set':[
["dom.mozBrowserFramesEnabled", true],
["dom.ipc.tabs.disabled", false]
]}, function () {
var iframe = document.createElementNS('http://www.w3.org/1999/xhtml', 'iframe');
iframe.setAttribute("remote", "true");
SpecialPowers.wrap(iframe).mozbrowser = true;
document.documentElement.appendChild(iframe);
SimpleTest.expectChildProcessCrash();
var crashMan =
SpecialPowers.Cu.import("resource://gre/modules/Services.jsm").
Services.crashmanager;
// First, clear the crash record store.
info("Waiting for pruneOldCrashes");
var future = new Date(Date.now() + 1000 * 60 * 60 * 24);
crashMan.pruneOldCrashes(future).then(function () {
var crashDateMS = Date.now();
// Inject a frame script that crashes the content process.
var mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
mm.loadFrameScript('data:,new ' + function ContentScriptScope() {
let Cu = Components.utils;
Cu.import("resource://gre/modules/ctypes.jsm");
let crash = function() {
let zero = new ctypes.intptr_t(8);
let badptr = ctypes.cast(zero, ctypes.PointerType(ctypes.int32_t));
badptr.contents;
};
privateNoteIntentionalCrash();
crash();
}, false);
// Finally, poll for the new crash record.
function tryGetCrash() {
info("Waiting for getCrashes");
crashMan.getCrashes().then(function (crashes) {
if (crashes.length) {
is(crashes.length, 1, "There should be only one record");
var crash = SpecialPowers.wrap(crashes[0]);
ok(crash.isOfType(crashMan.PROCESS_TYPE_CONTENT,
crashMan.CRASH_TYPE_CRASH),
"Record should be a content crash");
ok(!!crash.id, "Record should have an ID");
ok(!!crash.crashDate, "Record should have a crash date");
var dateMS = crash.crashDate.valueOf();
var twoMin = 1000 * 60 * 2;
ok(crashDateMS - twoMin <= dateMS &&
dateMS <= crashDateMS + twoMin,
"Record's crash date should be nowish: " +
"now=" + crashDateMS + " recordDate=" + dateMS);
SimpleTest.finish();
}
else {
setTimeout(tryGetCrash, 1000);
}
}, function (err) {
ok(false, "Error getting crashes: " + err);
SimpleTest.finish();
});
}
setTimeout(tryGetCrash, 1000);
}, function () {
ok(false, "pruneOldCrashes error");
SimpleTest.finish();
});
});
</script>
</body>
</html>

View File

@ -55,6 +55,10 @@ skip-if = (toolkit != "gtk2") && (toolkit != "gtk3")
skip-if = !crashreporter
[test_crashing2.html]
skip-if = (!crashreporter) || true # Bug 566049
[test_CrashService_crash.html]
skip-if = !crashreporter || e10s
[test_CrashService_hang.html]
skip-if = !crashreporter || e10s
[test_defaultValue.html]
[test_enumerate.html]
[test_fullpage.html]

View File

@ -0,0 +1,28 @@
<head>
<title>nsICrashService plugin crash</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="utils.js"></script>
<body>
<script class="testbody" type="application/javascript">
SimpleTest.waitForExplicitFinish();
setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
window.frameLoaded = function frameLoaded_toCrash() {
if (!SimpleTest.testPluginIsOOP()) {
ok(true, "Skipping this test when test plugin is not OOP.");
SimpleTest.finish();
return;
}
SimpleTest.expectChildProcessCrash();
crashAndGetCrashServiceRecord("crash", function (cm, crash) {
ok(crash.isOfType(cm.PROCESS_TYPE_PLUGIN, cm.CRASH_TYPE_CRASH),
"Record should be a plugin crash");
SimpleTest.finish();
});
}
</script>
<iframe id="iframe1" src="crashing_subpage.html" width="600" height="600"></iframe>

View File

@ -0,0 +1,31 @@
<head>
<title>nsICrashService plugin hang</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="utils.js"></script>
<body>
<script class="testbody" type="application/javascript">
SimpleTest.waitForExplicitFinish();
setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
window.frameLoaded = function frameLoaded_toCrash() {
if (!SimpleTest.testPluginIsOOP()) {
ok(true, "Skipping this test when test plugin is not OOP.");
SimpleTest.finish();
return;
}
SimpleTest.expectChildProcessCrash();
// the default timeout is annoying high for mochitest runs
var timeoutPref = "dom.ipc.plugins.timeoutSecs";
SpecialPowers.setIntPref(timeoutPref, 5);
crashAndGetCrashServiceRecord("hang", function (cm, crash) {
ok(crash.isOfType(cm.PROCESS_TYPE_PLUGIN, cm.CRASH_TYPE_HANG),
"Record should be a plugin hang");
SimpleTest.finish();
});
}
</script>
<iframe id="iframe1" src="crashing_subpage.html" width="600" height="600"></iframe>

View File

@ -42,3 +42,59 @@ function setTestPluginEnabledState(newEnabledState, pluginName) {
getTestPlugin(pluginName).enabledState = oldEnabledState;
});
}
function crashAndGetCrashServiceRecord(crashMethodName, callback) {
var crashMan =
SpecialPowers.Cu.import("resource://gre/modules/Services.jsm").
Services.crashmanager;
// First, clear the crash record store.
info("Waiting for pruneOldCrashes");
var future = new Date(Date.now() + 1000 * 60 * 60 * 24);
crashMan.pruneOldCrashes(future).then(function () {
var iframe = document.getElementById("iframe1");
var p = iframe.contentDocument.getElementById("plugin1");
var crashDateMS = Date.now();
try {
p[crashMethodName]();
ok(false, "p." + crashMethodName + "() should throw an exception");
}
catch (e) {
ok(true, "p." + crashMethodName + "() should throw an exception");
}
// The crash record store is written and read back asyncly, so poll for
// the new record.
function tryGetCrash() {
info("Waiting for getCrashes");
crashMan.getCrashes().then(function (crashes) {
if (crashes.length) {
is(crashes.length, 1, "There should be only one record");
var crash = SpecialPowers.wrap(crashes[0]);
ok(!!crash.id, "Record should have an ID");
ok(!!crash.crashDate, "Record should have a crash date");
var dateMS = crash.crashDate.valueOf();
var twoMin = 1000 * 60 * 2;
ok(crashDateMS - twoMin <= dateMS &&
dateMS <= crashDateMS + twoMin,
"Record's crash date should be nowish: " +
"now=" + crashDateMS + " recordDate=" + dateMS);
callback(crashMan, crash);
}
else {
setTimeout(tryGetCrash, 1000);
}
}, function (err) {
ok(false, "Error getting crashes: " + err);
SimpleTest.finish();
});
}
setTimeout(tryGetCrash, 1000);
}, function () {
ok(false, "pruneOldCrashes error");
SimpleTest.finish();
});
}

View File

@ -47,15 +47,12 @@ add_task(function* test_collect() {
let day1 = new Date(2014, 0, 1, 0, 0, 0);
let day2 = new Date(2014, 0, 3, 0, 0, 0);
// FUTURE Bug 982836 CrashManager will grow public APIs for adding crashes.
// Switch to that here.
let store = yield manager._getStore();
store.addMainProcessCrash("id1", day1);
store.addMainProcessCrash("id2", day1);
store.addMainProcessCrash("id3", day2);
// Flush changes (this may not be needed but it doesn't hurt).
yield store.save();
yield manager.addCrash(manager.PROCESS_TYPE_MAIN, manager.CRASH_TYPE_CRASH,
"id1", day1);
yield manager.addCrash(manager.PROCESS_TYPE_MAIN, manager.CRASH_TYPE_CRASH,
"id2", day1);
yield manager.addCrash(manager.PROCESS_TYPE_MAIN, manager.CRASH_TYPE_CRASH,
"id3", day2);
yield provider.collectDailyData();
@ -73,9 +70,8 @@ add_task(function* test_collect() {
do_check_eq(value.get("mainCrash"), 1);
// Check that adding a new crash increments counter on next collect.
store = yield manager._getStore();
store.addMainProcessCrash("id4", day2);
yield store.save();
yield manager.addCrash(manager.PROCESS_TYPE_MAIN, manager.CRASH_TYPE_CRASH,
"id4", day2);
yield provider.collectDailyData();
values = yield m.getValues();

View File

@ -121,6 +121,21 @@ this.CrashManager = function (options) {
};
this.CrashManager.prototype = Object.freeze({
// A crash in the main process.
PROCESS_TYPE_MAIN: "main",
// A crash in a content process.
PROCESS_TYPE_CONTENT: "content",
// A crash in a plugin process.
PROCESS_TYPE_PLUGIN: "plugin",
// A real crash.
CRASH_TYPE_CRASH: "crash",
// A hang.
CRASH_TYPE_HANG: "hang",
DUMP_REGEX: /^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.dmp$/i,
SUBMITTED_REGEX: /^bp-(?:hr-)?([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.txt$/i,
ALL_REGEX: /^(.*)$/,
@ -323,6 +338,28 @@ this.CrashManager.prototype = Object.freeze({
return deferred.promise;
},
/**
* Record the occurrence of a crash.
*
* This method skips event files altogether and writes directly and
* immediately to the manager's data store.
*
* @param processType (string) One of the PROCESS_TYPE constants.
* @param crashType (string) One of the CRASH_TYPE constants.
* @param id (string) Crash ID. Likely a UUID.
* @param date (Date) When the crash occurred.
*
* @return promise<null> Resolved when the store has been saved.
*/
addCrash: function (processType, crashType, id, date) {
return Task.spawn(function* () {
let store = yield this._getStore();
if (store.addCrash(processType, crashType, id, date)) {
yield store.save();
}
}.bind(this));
},
/**
* Obtain the paths of all unprocessed events files.
*
@ -389,10 +426,9 @@ this.CrashManager.prototype = Object.freeze({
// Do not change the format of an existing type. Instead, invent a new
// type.
// type in event file => [processType, crashType]
let eventMap = {
"crash.main.1": "addMainProcessCrash",
"crash.plugin.1": "addPluginCrash",
"hang.plugin.1": "addPluginHang",
"crash.main.1": ["main", "crash"],
};
if (type in eventMap) {
@ -403,7 +439,7 @@ this.CrashManager.prototype = Object.freeze({
return this.EVENT_FILE_ERROR_MALFORMED;
}
store[eventMap[type]](payload, date);
store.addCrash(...eventMap[type], payload, date);
return this.EVENT_FILE_SUCCESS;
}
@ -573,15 +609,6 @@ function CrashStore(storeDir, telemetrySizeKey) {
}
CrashStore.prototype = Object.freeze({
// A crash that occurred in the main process.
TYPE_MAIN_CRASH: "main-crash",
// A crash in a plugin process.
TYPE_PLUGIN_CRASH: "plugin-crash",
// A hang in a plugin process.
TYPE_PLUGIN_HANG: "plugin-hang",
// Maximum number of events to store per day. This establishes a
// ceiling on the per-type/per-day records that will be stored.
HIGH_WATER_DAILY_THRESHOLD: 100,
@ -841,23 +868,33 @@ CrashStore.prototype = Object.freeze({
* Returns the crash record if we're allowed to store it or null
* if we've hit the high water mark.
*
* @param processType
* (string) One of the PROCESS_TYPE constants.
* @param crashType
* (string) One of the CRASH_TYPE constants.
* @param id
* (string) The crash ID.
* @param type
* (string) One of the this.TYPE_* constants describing the crash type.
* @param date
* (Date) When this crash occurred.
*
* @return null | object crash record
*/
_ensureCrashRecord: function (id, type, date) {
_ensureCrashRecord: function (processType, crashType, id, date) {
if (!id) {
// Crashes are keyed on ID, so it's not really helpful to store crashes
// without IDs.
return null;
}
let day = dateToDays(date);
this._ensureCountsForDay(day);
let type = processType + "-" + crashType;
let count = (this._countsByDay.get(day).get(type) || 0) + 1;
this._countsByDay.get(day).set(type, count);
if (count > this.HIGH_WATER_DAILY_THRESHOLD && type != this.TYPE_MAIN_CRASH) {
if (count > this.HIGH_WATER_DAILY_THRESHOLD &&
processType != CrashManager.prototype.PROCESS_TYPE_MAIN) {
return null;
}
@ -877,61 +914,23 @@ CrashStore.prototype = Object.freeze({
},
/**
* Record the occurrence of a crash in the main process.
* Record the occurrence of a crash.
*
* @param processType (string) One of the PROCESS_TYPE constants.
* @param crashType (string) One of the CRASH_TYPE constants.
* @param id (string) Crash ID. Likely a UUID.
* @param date (Date) When the crash occurred.
*/
addMainProcessCrash: function (id, date) {
this._ensureCrashRecord(id, this.TYPE_MAIN_CRASH, date);
},
/**
* Record the occurrence of a crash in a plugin process.
*
* @param id (string) Crash ID. Likely a UUID.
* @param date (Date) When the crash occurred.
* @return boolean True if the crash was recorded and false if not.
*/
addPluginCrash: function (id, date) {
this._ensureCrashRecord(id, this.TYPE_PLUGIN_CRASH, date);
addCrash: function (processType, crashType, id, date) {
return !!this._ensureCrashRecord(processType, crashType, id, date);
},
/**
* Record the occurrence of a hang in a plugin process.
*
* @param id (string) Crash ID. Likely a UUID.
* @param date (Date) When the hang was reported.
*/
addPluginHang: function (id, date) {
this._ensureCrashRecord(id, this.TYPE_PLUGIN_HANG, date);
},
get mainProcessCrashes() {
getCrashesOfType: function (processType, crashType) {
let crashes = [];
for (let crash of this.crashes) {
if (crash.isMainProcessCrash) {
crashes.push(crash);
}
}
return crashes;
},
get pluginCrashes() {
let crashes = [];
for (let crash of this.crashes) {
if (crash.isPluginCrash) {
crashes.push(crash);
}
}
return crashes;
},
get pluginHangs() {
let crashes = [];
for (let crash of this.crashes) {
if (crash.isPluginHang) {
if (crash.isOfType(processType, crashType)) {
crashes.push(crash);
}
}
@ -984,16 +983,8 @@ CrashRecord.prototype = Object.freeze({
return this._o.type;
},
get isMainProcessCrash() {
return this._o.type == CrashStore.prototype.TYPE_MAIN_CRASH;
},
get isPluginCrash() {
return this._o.type == CrashStore.prototype.TYPE_PLUGIN_CRASH;
},
get isPluginHang() {
return this._o.type == CrashStore.prototype.TYPE_PLUGIN_HANG;
isOfType: function (processType, crashType) {
return processType + "-" + crashType == this.type;
},
});

View File

@ -18,7 +18,39 @@ this.CrashService = function () {};
CrashService.prototype = Object.freeze({
classID: Components.ID("{92668367-1b17-4190-86b2-1061b2179744}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
QueryInterface: XPCOMUtils.generateQI([
Ci.nsICrashService,
Ci.nsIObserver,
]),
addCrash: function (processType, crashType, id) {
switch (processType) {
case Ci.nsICrashService.PROCESS_TYPE_MAIN:
processType = Services.crashmanager.PROCESS_TYPE_MAIN;
break;
case Ci.nsICrashService.PROCESS_TYPE_CONTENT:
processType = Services.crashmanager.PROCESS_TYPE_CONTENT;
break;
case Ci.nsICrashService.PROCESS_TYPE_PLUGIN:
processType = Services.crashmanager.PROCESS_TYPE_PLUGIN;
break;
default:
throw new Error("Unrecognized PROCESS_TYPE: " + processType);
}
switch (crashType) {
case Ci.nsICrashService.CRASH_TYPE_CRASH:
crashType = Services.crashmanager.CRASH_TYPE_CRASH;
break;
case Ci.nsICrashService.CRASH_TYPE_HANG:
crashType = Services.crashmanager.CRASH_TYPE_HANG;
break;
default:
throw new Error("Unrecognized CRASH_TYPE: " + crashType);
}
Services.crashmanager.addCrash(processType, crashType, id, new Date());
},
observe: function (subject, topic, data) {
switch (topic) {

View File

@ -60,6 +60,11 @@ Each subsection documents the different types of crash events that may be
produced. Each section name corresponds to the first line of the crash
event file.
Currently only main process crashes produce event files. Because crashes and
hangs in child processes can be easily recorded by the main process, we do not
foresee the need for writing event files for child processes, design
considerations below notwithstanding.
crash.main.1
^^^^^^^^^^^^
@ -69,20 +74,6 @@ The payload of this event is the string crash ID, very likely a UUID.
There should be ``UUID.dmp`` and ``UUID.extra`` files on disk, saved by
Breakpad.
crash.plugin.1
^^^^^^^^^^^^^^
This event is produced when a plugin process crashes.
The payload is identical to ``crash.main.1``'s.
hang.plugin.1
^^^^^^^^^^^^^
This event is produced when a plugin process hangs.
The payload is identical to ``crash.main.1``'s.
Aggregated Event Log
====================

View File

@ -16,3 +16,9 @@ EXTRA_JS_MODULES += [
]
XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell/xpcshell.ini']
XPIDL_MODULE = 'toolkit_crashservice'
XPIDL_SOURCES += [
'nsICrashService.idl',
]

View File

@ -0,0 +1,28 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
[scriptable, uuid(a1845b69-28f4-43db-be6e-02eb15a45481)]
interface nsICrashService : nsISupports
{
/**
* Records the occurrence of a crash.
*
* @param processType
* One of the PROCESS_TYPE constants defined below.
* @param crashType
* One of the CRASH_TYPE constants defined below.
* @param id
* Crash ID. Likely a UUID.
*/
void addCrash(in long processType, in long crashType, in AString id);
const long PROCESS_TYPE_MAIN = 0;
const long PROCESS_TYPE_CONTENT = 1;
const long PROCESS_TYPE_PLUGIN = 2;
const long CRASH_TYPE_CRASH = 0;
const long CRASH_TYPE_HANG = 1;
};

View File

@ -166,7 +166,7 @@ add_task(function* test_prune_old() {
let oldDate = new Date(Date.now() - 86400000);
let newDate = new Date(Date.now() - 10000);
yield m.createEventsFile("1", "crash.main.1", oldDate, "id1");
yield m.createEventsFile("2", "crash.plugin.1", newDate, "id2");
yield m.addCrash(m.PROCESS_TYPE_PLUGIN, m.CRASH_TYPE_CRASH, "id2", newDate);
yield m.aggregateEventsFiles();
@ -225,39 +225,7 @@ add_task(function* test_multiline_crash_id_rejected() {
Assert.equal(crashes.length, 0);
});
add_task(function* test_plugin_crash_event_file() {
let m = yield getManager();
yield m.createEventsFile("1", "crash.plugin.1", DUMMY_DATE, "id1");
let count = yield m.aggregateEventsFiles();
Assert.equal(count, 1);
let crashes = yield m.getCrashes();
Assert.equal(crashes.length, 1);
Assert.equal(crashes[0].id, "id1");
Assert.equal(crashes[0].type, "plugin-crash");
Assert.deepEqual(crashes[0].crashDate, DUMMY_DATE);
count = yield m.aggregateEventsFiles();
Assert.equal(count, 0);
});
add_task(function* test_plugin_hang_event_file() {
let m = yield getManager();
yield m.createEventsFile("1", "hang.plugin.1", DUMMY_DATE, "id1");
let count = yield m.aggregateEventsFiles();
Assert.equal(count, 1);
let crashes = yield m.getCrashes();
Assert.equal(crashes.length, 1);
Assert.equal(crashes[0].id, "id1");
Assert.equal(crashes[0].type, "plugin-hang");
Assert.deepEqual(crashes[0].crashDate, DUMMY_DATE);
count = yield m.aggregateEventsFiles();
Assert.equal(count, 0);
});
// Excessive amounts of files should be processed properly.
// Main process crashes should be remembered beyond the high water mark.
add_task(function* test_high_water_mark() {
let m = yield getManager();
@ -265,15 +233,74 @@ add_task(function* test_high_water_mark() {
for (let i = 0; i < store.HIGH_WATER_DAILY_THRESHOLD + 1; i++) {
yield m.createEventsFile("m" + i, "crash.main.1", DUMMY_DATE, "m" + i);
yield m.createEventsFile("pc" + i, "crash.plugin.1", DUMMY_DATE, "pc" + i);
yield m.createEventsFile("ph" + i, "hang.plugin.1", DUMMY_DATE, "ph" + i);
}
let count = yield m.aggregateEventsFiles();
Assert.equal(count, 3 * bsp.CrashStore.prototype.HIGH_WATER_DAILY_THRESHOLD + 3);
Assert.equal(count, bsp.CrashStore.prototype.HIGH_WATER_DAILY_THRESHOLD + 1);
// Need to fetch again in case the first one was garbage collected.
store = yield m._getStore();
// +1 is for preserved main process crash.
Assert.equal(store.crashesCount, 3 * store.HIGH_WATER_DAILY_THRESHOLD + 1);
Assert.equal(store.crashesCount, store.HIGH_WATER_DAILY_THRESHOLD + 1);
});
add_task(function* test_addCrash() {
let m = yield getManager();
let crashes = yield m.getCrashes();
Assert.equal(crashes.length, 0);
yield m.addCrash(m.PROCESS_TYPE_MAIN, m.CRASH_TYPE_CRASH,
"main-crash", DUMMY_DATE);
yield m.addCrash(m.PROCESS_TYPE_MAIN, m.CRASH_TYPE_HANG,
"main-hang", DUMMY_DATE);
yield m.addCrash(m.PROCESS_TYPE_CONTENT, m.CRASH_TYPE_CRASH,
"content-crash", DUMMY_DATE);
yield m.addCrash(m.PROCESS_TYPE_CONTENT, m.CRASH_TYPE_HANG,
"content-hang", DUMMY_DATE);
yield m.addCrash(m.PROCESS_TYPE_PLUGIN, m.CRASH_TYPE_CRASH,
"plugin-crash", DUMMY_DATE);
yield m.addCrash(m.PROCESS_TYPE_PLUGIN, m.CRASH_TYPE_HANG,
"plugin-hang", DUMMY_DATE);
crashes = yield m.getCrashes();
Assert.equal(crashes.length, 6);
let map = new Map(crashes.map(crash => [crash.id, crash]));
let crash = map.get("main-crash");
Assert.ok(!!crash);
Assert.equal(crash.crashDate, DUMMY_DATE);
Assert.equal(crash.type, m.PROCESS_TYPE_MAIN + "-" + m.CRASH_TYPE_CRASH);
Assert.ok(crash.isOfType(m.PROCESS_TYPE_MAIN, m.CRASH_TYPE_CRASH));
crash = map.get("main-hang");
Assert.ok(!!crash);
Assert.equal(crash.crashDate, DUMMY_DATE);
Assert.equal(crash.type, m.PROCESS_TYPE_MAIN + "-" + m.CRASH_TYPE_HANG);
Assert.ok(crash.isOfType(m.PROCESS_TYPE_MAIN, m.CRASH_TYPE_HANG));
crash = map.get("content-crash");
Assert.ok(!!crash);
Assert.equal(crash.crashDate, DUMMY_DATE);
Assert.equal(crash.type, m.PROCESS_TYPE_CONTENT + "-" + m.CRASH_TYPE_CRASH);
Assert.ok(crash.isOfType(m.PROCESS_TYPE_CONTENT, m.CRASH_TYPE_CRASH));
crash = map.get("content-hang");
Assert.ok(!!crash);
Assert.equal(crash.crashDate, DUMMY_DATE);
Assert.equal(crash.type, m.PROCESS_TYPE_CONTENT + "-" + m.CRASH_TYPE_HANG);
Assert.ok(crash.isOfType(m.PROCESS_TYPE_CONTENT, m.CRASH_TYPE_HANG));
crash = map.get("plugin-crash");
Assert.ok(!!crash);
Assert.equal(crash.crashDate, DUMMY_DATE);
Assert.equal(crash.type, m.PROCESS_TYPE_PLUGIN + "-" + m.CRASH_TYPE_CRASH);
Assert.ok(crash.isOfType(m.PROCESS_TYPE_PLUGIN, m.CRASH_TYPE_CRASH));
crash = map.get("plugin-hang");
Assert.ok(!!crash);
Assert.equal(crash.crashDate, DUMMY_DATE);
Assert.equal(crash.type, m.PROCESS_TYPE_PLUGIN + "-" + m.CRASH_TYPE_HANG);
Assert.ok(crash.isOfType(m.PROCESS_TYPE_PLUGIN, m.CRASH_TYPE_HANG));
});

View File

@ -13,6 +13,14 @@ let bsp = Cu.import("resource://gre/modules/CrashManager.jsm", this);
Cu.import("resource://gre/modules/osfile.jsm", this);
Cu.import("resource://gre/modules/Task.jsm", this);
const {
PROCESS_TYPE_MAIN,
PROCESS_TYPE_CONTENT,
PROCESS_TYPE_PLUGIN,
CRASH_TYPE_CRASH,
CRASH_TYPE_HANG,
} = CrashManager.prototype;
const CrashStore = bsp.CrashStore;
let STORE_DIR_COUNT = 0;
@ -45,7 +53,7 @@ add_task(function test_add_crash() {
Assert.equal(s.crashesCount, 0);
let d = new Date(Date.now() - 5000);
s.addMainProcessCrash("id1", d);
Assert.ok(s.addCrash(PROCESS_TYPE_MAIN, CRASH_TYPE_CRASH, "id1", d));
Assert.equal(s.crashesCount, 1);
@ -56,7 +64,9 @@ add_task(function test_add_crash() {
Assert.equal(c.id, "id1", "ID set properly.");
Assert.equal(c.crashDate.getTime(), d.getTime(), "Date set.");
s.addMainProcessCrash("id2", new Date());
Assert.ok(
s.addCrash(PROCESS_TYPE_MAIN, CRASH_TYPE_CRASH, "id2", new Date())
);
Assert.equal(s.crashesCount, 2);
});
@ -67,8 +77,10 @@ add_task(function test_save_load() {
let d1 = new Date();
let d2 = new Date(d1.getTime() - 10000);
s.addMainProcessCrash("id1", d1);
s.addMainProcessCrash("id2", d2);
Assert.ok(
s.addCrash(PROCESS_TYPE_MAIN, CRASH_TYPE_CRASH, "id1", d1) &&
s.addCrash(PROCESS_TYPE_MAIN, CRASH_TYPE_CRASH, "id2", d2)
);
yield s.save();
@ -101,72 +113,179 @@ add_task(function test_corrupt_json() {
add_task(function* test_add_main_crash() {
let s = yield getStore();
s.addMainProcessCrash("id1", new Date());
Assert.ok(
s.addCrash(PROCESS_TYPE_MAIN, CRASH_TYPE_CRASH, "id1", new Date())
);
Assert.equal(s.crashesCount, 1);
let c = s.crashes[0];
Assert.ok(c.crashDate);
Assert.equal(c.type, bsp.CrashStore.prototype.TYPE_MAIN_CRASH);
Assert.ok(c.isMainProcessCrash);
Assert.equal(c.type, PROCESS_TYPE_MAIN + "-" + CRASH_TYPE_CRASH);
Assert.ok(c.isOfType(PROCESS_TYPE_MAIN, CRASH_TYPE_CRASH));
s.addMainProcessCrash("id2", new Date());
Assert.ok(
s.addCrash(PROCESS_TYPE_MAIN, CRASH_TYPE_CRASH, "id2", new Date())
);
Assert.equal(s.crashesCount, 2);
// Duplicate.
s.addMainProcessCrash("id1", new Date());
Assert.ok(
s.addCrash(PROCESS_TYPE_MAIN, CRASH_TYPE_CRASH, "id1", new Date())
);
Assert.equal(s.crashesCount, 2);
Assert.equal(s.mainProcessCrashes.length, 2);
let crashes = s.getCrashesOfType(PROCESS_TYPE_MAIN, CRASH_TYPE_CRASH);
Assert.equal(crashes.length, 2);
});
add_task(function* test_add_main_hang() {
let s = yield getStore();
Assert.ok(
s.addCrash(PROCESS_TYPE_MAIN, CRASH_TYPE_HANG, "id1", new Date())
);
Assert.equal(s.crashesCount, 1);
let c = s.crashes[0];
Assert.ok(c.crashDate);
Assert.equal(c.type, PROCESS_TYPE_MAIN + "-" + CRASH_TYPE_HANG);
Assert.ok(c.isOfType(PROCESS_TYPE_MAIN, CRASH_TYPE_HANG));
Assert.ok(
s.addCrash(PROCESS_TYPE_MAIN, CRASH_TYPE_HANG, "id2", new Date())
);
Assert.equal(s.crashesCount, 2);
Assert.ok(
s.addCrash(PROCESS_TYPE_MAIN, CRASH_TYPE_HANG, "id1", new Date())
);
Assert.equal(s.crashesCount, 2);
let crashes = s.getCrashesOfType(PROCESS_TYPE_MAIN, CRASH_TYPE_HANG);
Assert.equal(crashes.length, 2);
});
add_task(function* test_add_content_crash() {
let s = yield getStore();
Assert.ok(
s.addCrash(PROCESS_TYPE_CONTENT, CRASH_TYPE_CRASH, "id1", new Date())
);
Assert.equal(s.crashesCount, 1);
let c = s.crashes[0];
Assert.ok(c.crashDate);
Assert.equal(c.type, PROCESS_TYPE_CONTENT + "-" + CRASH_TYPE_CRASH);
Assert.ok(c.isOfType(PROCESS_TYPE_CONTENT, CRASH_TYPE_CRASH));
Assert.ok(
s.addCrash(PROCESS_TYPE_CONTENT, CRASH_TYPE_CRASH, "id2", new Date())
);
Assert.equal(s.crashesCount, 2);
Assert.ok(
s.addCrash(PROCESS_TYPE_CONTENT, CRASH_TYPE_CRASH, "id1", new Date())
);
Assert.equal(s.crashesCount, 2);
let crashes = s.getCrashesOfType(PROCESS_TYPE_CONTENT, CRASH_TYPE_CRASH);
Assert.equal(crashes.length, 2);
});
add_task(function* test_add_content_hang() {
let s = yield getStore();
Assert.ok(
s.addCrash(PROCESS_TYPE_CONTENT, CRASH_TYPE_HANG, "id1", new Date())
);
Assert.equal(s.crashesCount, 1);
let c = s.crashes[0];
Assert.ok(c.crashDate);
Assert.equal(c.type, PROCESS_TYPE_CONTENT + "-" + CRASH_TYPE_HANG);
Assert.ok(c.isOfType(PROCESS_TYPE_CONTENT, CRASH_TYPE_HANG));
Assert.ok(
s.addCrash(PROCESS_TYPE_CONTENT, CRASH_TYPE_HANG, "id2", new Date())
);
Assert.equal(s.crashesCount, 2);
Assert.ok(
s.addCrash(PROCESS_TYPE_CONTENT, CRASH_TYPE_HANG, "id1", new Date())
);
Assert.equal(s.crashesCount, 2);
let crashes = s.getCrashesOfType(PROCESS_TYPE_CONTENT, CRASH_TYPE_HANG);
Assert.equal(crashes.length, 2);
});
add_task(function* test_add_plugin_crash() {
let s = yield getStore();
s.addPluginCrash("id1", new Date());
Assert.ok(
s.addCrash(PROCESS_TYPE_PLUGIN, CRASH_TYPE_CRASH, "id1", new Date())
);
Assert.equal(s.crashesCount, 1);
let c = s.crashes[0];
Assert.ok(c.crashDate);
Assert.equal(c.type, bsp.CrashStore.prototype.TYPE_PLUGIN_CRASH);
Assert.ok(c.isPluginCrash);
Assert.equal(c.type, PROCESS_TYPE_PLUGIN + "-" + CRASH_TYPE_CRASH);
Assert.ok(c.isOfType(PROCESS_TYPE_PLUGIN, CRASH_TYPE_CRASH));
s.addPluginCrash("id2", new Date());
Assert.ok(
s.addCrash(PROCESS_TYPE_PLUGIN, CRASH_TYPE_CRASH, "id2", new Date())
);
Assert.equal(s.crashesCount, 2);
s.addPluginCrash("id1", new Date());
Assert.ok(
s.addCrash(PROCESS_TYPE_PLUGIN, CRASH_TYPE_CRASH, "id1", new Date())
);
Assert.equal(s.crashesCount, 2);
Assert.equal(s.pluginCrashes.length, 2);
let crashes = s.getCrashesOfType(PROCESS_TYPE_PLUGIN, CRASH_TYPE_CRASH);
Assert.equal(crashes.length, 2);
});
add_task(function* test_add_plugin_hang() {
let s = yield getStore();
s.addPluginHang("id1", new Date());
Assert.ok(
s.addCrash(PROCESS_TYPE_PLUGIN, CRASH_TYPE_HANG, "id1", new Date())
);
Assert.equal(s.crashesCount, 1);
let c = s.crashes[0];
Assert.ok(c.crashDate);
Assert.equal(c.type, bsp.CrashStore.prototype.TYPE_PLUGIN_HANG);
Assert.ok(c.isPluginHang);
Assert.equal(c.type, PROCESS_TYPE_PLUGIN + "-" + CRASH_TYPE_HANG);
Assert.ok(c.isOfType(PROCESS_TYPE_PLUGIN, CRASH_TYPE_HANG));
s.addPluginHang("id2", new Date());
Assert.ok(
s.addCrash(PROCESS_TYPE_PLUGIN, CRASH_TYPE_HANG, "id2", new Date())
);
Assert.equal(s.crashesCount, 2);
s.addPluginHang("id1", new Date());
Assert.ok(
s.addCrash(PROCESS_TYPE_PLUGIN, CRASH_TYPE_HANG, "id1", new Date())
);
Assert.equal(s.crashesCount, 2);
Assert.equal(s.pluginHangs.length, 2);
let crashes = s.getCrashesOfType(PROCESS_TYPE_PLUGIN, CRASH_TYPE_HANG);
Assert.equal(crashes.length, 2);
});
add_task(function* test_add_mixed_types() {
let s = yield getStore();
s.addMainProcessCrash("main", new Date());
s.addPluginCrash("pcrash", new Date());
s.addPluginHang("phang", new Date());
Assert.ok(
s.addCrash(PROCESS_TYPE_MAIN, CRASH_TYPE_CRASH, "mcrash", new Date()) &&
s.addCrash(PROCESS_TYPE_MAIN, CRASH_TYPE_HANG, "mhang", new Date()) &&
s.addCrash(PROCESS_TYPE_CONTENT, CRASH_TYPE_CRASH, "ccrash", new Date()) &&
s.addCrash(PROCESS_TYPE_CONTENT, CRASH_TYPE_HANG, "chang", new Date()) &&
s.addCrash(PROCESS_TYPE_PLUGIN, CRASH_TYPE_CRASH, "pcrash", new Date()) &&
s.addCrash(PROCESS_TYPE_PLUGIN, CRASH_TYPE_HANG, "phang", new Date())
);
Assert.equal(s.crashesCount, 3);
Assert.equal(s.crashesCount, 6);
yield s.save();
@ -175,11 +294,20 @@ add_task(function* test_add_mixed_types() {
yield s.load();
Assert.equal(s.crashesCount, 3);
Assert.equal(s.crashesCount, 6);
Assert.equal(s.mainProcessCrashes.length, 1);
Assert.equal(s.pluginCrashes.length, 1);
Assert.equal(s.pluginHangs.length, 1);
let crashes = s.getCrashesOfType(PROCESS_TYPE_MAIN, CRASH_TYPE_CRASH);
Assert.equal(crashes.length, 1);
crashes = s.getCrashesOfType(PROCESS_TYPE_MAIN, CRASH_TYPE_HANG);
Assert.equal(crashes.length, 1);
crashes = s.getCrashesOfType(PROCESS_TYPE_CONTENT, CRASH_TYPE_CRASH);
Assert.equal(crashes.length, 1);
crashes = s.getCrashesOfType(PROCESS_TYPE_CONTENT, CRASH_TYPE_HANG);
Assert.equal(crashes.length, 1);
crashes = s.getCrashesOfType(PROCESS_TYPE_PLUGIN, CRASH_TYPE_CRASH);
Assert.equal(crashes.length, 1);
crashes = s.getCrashesOfType(PROCESS_TYPE_PLUGIN, CRASH_TYPE_HANG);
Assert.equal(crashes.length, 1);
});
// Crashes added beyond the high water mark behave properly.
@ -189,32 +317,87 @@ add_task(function* test_high_water() {
let d1 = new Date(2014, 0, 1, 0, 0, 0);
let d2 = new Date(2014, 0, 2, 0, 0, 0);
for (let i = 0; i < s.HIGH_WATER_DAILY_THRESHOLD + 1; i++) {
s.addMainProcessCrash("m1" + i, d1);
s.addMainProcessCrash("m2" + i, d2);
s.addPluginCrash("pc1" + i, d1);
s.addPluginCrash("pc2" + i, d2);
s.addPluginHang("ph1" + i, d1);
s.addPluginHang("ph2" + i, d2);
let i = 0;
for (; i < s.HIGH_WATER_DAILY_THRESHOLD; i++) {
Assert.ok(
s.addCrash(PROCESS_TYPE_MAIN, CRASH_TYPE_CRASH, "mc1" + i, d1) &&
s.addCrash(PROCESS_TYPE_MAIN, CRASH_TYPE_CRASH, "mc2" + i, d2) &&
s.addCrash(PROCESS_TYPE_MAIN, CRASH_TYPE_HANG, "mh1" + i, d1) &&
s.addCrash(PROCESS_TYPE_MAIN, CRASH_TYPE_HANG, "mh2" + i, d2) &&
s.addCrash(PROCESS_TYPE_CONTENT, CRASH_TYPE_CRASH, "cc1" + i, d1) &&
s.addCrash(PROCESS_TYPE_CONTENT, CRASH_TYPE_CRASH, "cc2" + i, d2) &&
s.addCrash(PROCESS_TYPE_CONTENT, CRASH_TYPE_HANG, "ch1" + i, d1) &&
s.addCrash(PROCESS_TYPE_CONTENT, CRASH_TYPE_HANG, "ch2" + i, d2) &&
s.addCrash(PROCESS_TYPE_PLUGIN, CRASH_TYPE_CRASH, "pc1" + i, d1) &&
s.addCrash(PROCESS_TYPE_PLUGIN, CRASH_TYPE_CRASH, "pc2" + i, d2) &&
s.addCrash(PROCESS_TYPE_PLUGIN, CRASH_TYPE_HANG, "ph1" + i, d1) &&
s.addCrash(PROCESS_TYPE_PLUGIN, CRASH_TYPE_HANG, "ph2" + i, d2)
);
}
// We preserve main process crashes. Plugin crashes and hangs beyond should
// be discarded.
Assert.equal(s.crashesCount, 6 * s.HIGH_WATER_DAILY_THRESHOLD + 2);
Assert.equal(s.mainProcessCrashes.length, 2 * s.HIGH_WATER_DAILY_THRESHOLD + 2);
Assert.equal(s.pluginCrashes.length, 2 * s.HIGH_WATER_DAILY_THRESHOLD);
Assert.equal(s.pluginHangs.length, 2 * s.HIGH_WATER_DAILY_THRESHOLD);
Assert.ok(
s.addCrash(PROCESS_TYPE_MAIN, CRASH_TYPE_CRASH, "mc1" + i, d1) &&
s.addCrash(PROCESS_TYPE_MAIN, CRASH_TYPE_CRASH, "mc2" + i, d2) &&
s.addCrash(PROCESS_TYPE_MAIN, CRASH_TYPE_HANG, "mh1" + i, d1) &&
s.addCrash(PROCESS_TYPE_MAIN, CRASH_TYPE_HANG, "mh2" + i, d2)
);
Assert.ok(!s.addCrash(PROCESS_TYPE_CONTENT, CRASH_TYPE_CRASH, "cc1" + i, d1));
Assert.ok(!s.addCrash(PROCESS_TYPE_CONTENT, CRASH_TYPE_CRASH, "cc2" + i, d2));
Assert.ok(!s.addCrash(PROCESS_TYPE_CONTENT, CRASH_TYPE_HANG, "ch1" + i, d1));
Assert.ok(!s.addCrash(PROCESS_TYPE_CONTENT, CRASH_TYPE_HANG, "ch2" + i, d2));
Assert.ok(!s.addCrash(PROCESS_TYPE_PLUGIN, CRASH_TYPE_CRASH, "pc1" + i, d1));
Assert.ok(!s.addCrash(PROCESS_TYPE_PLUGIN, CRASH_TYPE_CRASH, "pc2" + i, d2));
Assert.ok(!s.addCrash(PROCESS_TYPE_PLUGIN, CRASH_TYPE_HANG, "ph1" + i, d1));
Assert.ok(!s.addCrash(PROCESS_TYPE_PLUGIN, CRASH_TYPE_HANG, "ph2" + i, d2));
// We preserve main process crashes and hangs. Content and plugin crashes and
// hangs beyond should be discarded.
Assert.equal(s.crashesCount, 12 * s.HIGH_WATER_DAILY_THRESHOLD + 4);
let crashes = s.getCrashesOfType(PROCESS_TYPE_MAIN, CRASH_TYPE_CRASH);
Assert.equal(crashes.length, 2 * s.HIGH_WATER_DAILY_THRESHOLD + 2);
crashes = s.getCrashesOfType(PROCESS_TYPE_MAIN, CRASH_TYPE_HANG);
Assert.equal(crashes.length, 2 * s.HIGH_WATER_DAILY_THRESHOLD + 2);
crashes = s.getCrashesOfType(PROCESS_TYPE_CONTENT, CRASH_TYPE_CRASH);
Assert.equal(crashes.length, 2 * s.HIGH_WATER_DAILY_THRESHOLD);
crashes = s.getCrashesOfType(PROCESS_TYPE_CONTENT, CRASH_TYPE_HANG);
Assert.equal(crashes.length, 2 * s.HIGH_WATER_DAILY_THRESHOLD);
crashes = s.getCrashesOfType(PROCESS_TYPE_PLUGIN, CRASH_TYPE_CRASH);
Assert.equal(crashes.length, 2 * s.HIGH_WATER_DAILY_THRESHOLD);
crashes = s.getCrashesOfType(PROCESS_TYPE_PLUGIN, CRASH_TYPE_HANG);
Assert.equal(crashes.length, 2 * s.HIGH_WATER_DAILY_THRESHOLD);
// But raw counts should be preserved.
let day1 = bsp.dateToDays(d1);
let day2 = bsp.dateToDays(d2);
Assert.ok(s._countsByDay.has(day1));
Assert.ok(s._countsByDay.has(day2));
Assert.equal(s._countsByDay.get(day1).get(s.TYPE_MAIN_CRASH),
Assert.equal(s._countsByDay.get(day1).
get(PROCESS_TYPE_MAIN + "-" + CRASH_TYPE_CRASH),
s.HIGH_WATER_DAILY_THRESHOLD + 1);
Assert.equal(s._countsByDay.get(day1).get(s.TYPE_PLUGIN_CRASH),
Assert.equal(s._countsByDay.get(day1).
get(PROCESS_TYPE_MAIN + "-" + CRASH_TYPE_HANG),
s.HIGH_WATER_DAILY_THRESHOLD + 1);
Assert.equal(s._countsByDay.get(day1).get(s.TYPE_PLUGIN_HANG),
Assert.equal(s._countsByDay.get(day1).
get(PROCESS_TYPE_CONTENT + "-" + CRASH_TYPE_CRASH),
s.HIGH_WATER_DAILY_THRESHOLD + 1);
Assert.equal(s._countsByDay.get(day1).
get(PROCESS_TYPE_CONTENT + "-" + CRASH_TYPE_HANG),
s.HIGH_WATER_DAILY_THRESHOLD + 1);
Assert.equal(s._countsByDay.get(day1).
get(PROCESS_TYPE_PLUGIN + "-" + CRASH_TYPE_CRASH),
s.HIGH_WATER_DAILY_THRESHOLD + 1);
Assert.equal(s._countsByDay.get(day1).
get(PROCESS_TYPE_PLUGIN + "-" + CRASH_TYPE_HANG),
s.HIGH_WATER_DAILY_THRESHOLD + 1);
yield s.save();
@ -222,10 +405,25 @@ add_task(function* test_high_water() {
Assert.ok(s._countsByDay.has(day1));
Assert.ok(s._countsByDay.has(day2));
Assert.equal(s._countsByDay.get(day1).get(s.TYPE_MAIN_CRASH),
Assert.equal(s._countsByDay.get(day1).
get(PROCESS_TYPE_MAIN + "-" + CRASH_TYPE_CRASH),
s.HIGH_WATER_DAILY_THRESHOLD + 1);
Assert.equal(s._countsByDay.get(day1).get(s.TYPE_PLUGIN_CRASH),
Assert.equal(s._countsByDay.get(day1).
get(PROCESS_TYPE_MAIN + "-" + CRASH_TYPE_HANG),
s.HIGH_WATER_DAILY_THRESHOLD + 1);
Assert.equal(s._countsByDay.get(day1).get(s.TYPE_PLUGIN_HANG),
Assert.equal(s._countsByDay.get(day1).
get(PROCESS_TYPE_CONTENT + "-" + CRASH_TYPE_CRASH),
s.HIGH_WATER_DAILY_THRESHOLD + 1);
Assert.equal(s._countsByDay.get(day1).
get(PROCESS_TYPE_CONTENT + "-" + CRASH_TYPE_HANG),
s.HIGH_WATER_DAILY_THRESHOLD + 1);
Assert.equal(s._countsByDay.get(day1).
get(PROCESS_TYPE_PLUGIN + "-" + CRASH_TYPE_CRASH),
s.HIGH_WATER_DAILY_THRESHOLD + 1);
Assert.equal(s._countsByDay.get(day1).
get(PROCESS_TYPE_PLUGIN + "-" + CRASH_TYPE_HANG),
s.HIGH_WATER_DAILY_THRESHOLD + 1);
});

View File

@ -37,6 +37,6 @@ add_task(function* test_main_process_crash() {
let crashes = yield cm.getCrashes();
Assert.equal(crashes.length, 1);
let crash = crashes[0];
Assert.ok(crash.isMainProcessCrash);
Assert.ok(crash.isOfType(cm.PROCESS_TYPE_MAIN, cm.CRASH_TYPE_CRASH));
Assert.equal(crash.id + ".dmp", basename, "ID recorded properly");
});