mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-11-11 05:39:41 +02:00
This patch removes the C++ code used to run the minidump analyzer when a content process crashes, and replaces it with JS code within the CrashService object. This removes the need for a separate shutdown blocker in C++ code and allows end-to-end testing of the crash service functionality. Additionally the exception handler code can be simplified since it's now only used to run the crash reporter client. The test added to test_crash_service.js covers computing the minidump SHA256 hash (bug 1322611) and of the minidump analyzer itself (bug 1280477). MozReview-Commit-ID: LO5w839NHev
186 lines
5.3 KiB
JavaScript
186 lines
5.3 KiB
JavaScript
/* 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/. */
|
|
|
|
/*
|
|
* This file provides common and shared functionality to facilitate
|
|
* testing of the Crashes component (CrashManager.jsm).
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
|
|
|
this.EXPORTED_SYMBOLS = [
|
|
"configureLogging",
|
|
"getManager",
|
|
"sleep",
|
|
"TestingCrashManager",
|
|
];
|
|
|
|
Cu.import("resource://gre/modules/CrashManager.jsm", this);
|
|
Cu.import("resource://gre/modules/Log.jsm", this);
|
|
Cu.import("resource://gre/modules/osfile.jsm", this);
|
|
Cu.import("resource://gre/modules/Promise.jsm", this);
|
|
Cu.import("resource://gre/modules/Timer.jsm", this);
|
|
|
|
var loggingConfigured = false;
|
|
|
|
this.configureLogging = function() {
|
|
if (loggingConfigured) {
|
|
return;
|
|
}
|
|
|
|
let log = Log.repository.getLogger("Crashes.CrashManager");
|
|
log.level = Log.Level.All;
|
|
let appender = new Log.DumpAppender();
|
|
appender.level = Log.Level.All;
|
|
log.addAppender(appender);
|
|
loggingConfigured = true;
|
|
};
|
|
|
|
this.sleep = function(wait) {
|
|
return new Promise(resolve => {
|
|
|
|
setTimeout(() => {
|
|
resolve();
|
|
}, wait);
|
|
|
|
});
|
|
};
|
|
|
|
this.TestingCrashManager = function(options) {
|
|
CrashManager.call(this, options);
|
|
}
|
|
|
|
this.TestingCrashManager.prototype = {
|
|
__proto__: CrashManager.prototype,
|
|
|
|
createDummyDump(submitted = false, date = new Date(), hr = false) {
|
|
let uuid = Cc["@mozilla.org/uuid-generator;1"]
|
|
.getService(Ci.nsIUUIDGenerator)
|
|
.generateUUID()
|
|
.toString();
|
|
uuid = uuid.substring(1, uuid.length - 1);
|
|
|
|
let path;
|
|
let mode;
|
|
if (submitted) {
|
|
if (hr) {
|
|
path = OS.Path.join(this._submittedDumpsDir, "bp-hr-" + uuid + ".txt");
|
|
} else {
|
|
path = OS.Path.join(this._submittedDumpsDir, "bp-" + uuid + ".txt");
|
|
}
|
|
mode = OS.Constants.libc.S_IRUSR | OS.Constants.libc.S_IWUSR |
|
|
OS.Constants.libc.S_IRGRP | OS.Constants.libc.S_IROTH;
|
|
} else {
|
|
path = OS.Path.join(this._pendingDumpsDir, uuid + ".dmp");
|
|
mode = OS.Constants.libc.S_IRUSR | OS.Constants.libc.S_IWUSR;
|
|
}
|
|
|
|
return (async function() {
|
|
let f = await OS.File.open(path, {create: true}, {unixMode: mode});
|
|
await f.setDates(date, date);
|
|
await f.close();
|
|
dump("Created fake crash: " + path + "\n");
|
|
|
|
return uuid;
|
|
})();
|
|
},
|
|
|
|
createIgnoredDumpFile(filename, submitted = false) {
|
|
let path;
|
|
if (submitted) {
|
|
path = OS.Path.join(this._submittedDumpsDir, filename);
|
|
} else {
|
|
path = OS.Path.join(this._pendingDumpsDir, filename);
|
|
}
|
|
|
|
return (async function() {
|
|
let mode = OS.Constants.libc.S_IRUSR | OS.Constants.libc.S_IWUSR;
|
|
await OS.File.open(path, {create: true}, {unixMode: mode});
|
|
dump("Create ignored dump file: " + path + "\n");
|
|
})();
|
|
},
|
|
|
|
createEventsFile(filename, type, date, content, index = 0) {
|
|
let path = OS.Path.join(this._eventsDirs[index], filename);
|
|
|
|
let data = type + "\n" +
|
|
Math.floor(date.getTime() / 1000) + "\n" +
|
|
content;
|
|
let encoder = new TextEncoder();
|
|
let array = encoder.encode(data);
|
|
|
|
return (async function() {
|
|
await OS.File.writeAtomic(path, array);
|
|
await OS.File.setDates(path, date, date);
|
|
})();
|
|
},
|
|
|
|
/**
|
|
* Overwrite event file handling to process our test file type.
|
|
*
|
|
* We can probably delete this once we have actual events defined.
|
|
*/
|
|
_handleEventFilePayload(store, entry, type, date, payload) {
|
|
if (type == "test.1") {
|
|
if (payload == "malformed") {
|
|
return this.EVENT_FILE_ERROR_MALFORMED;
|
|
} else if (payload == "success") {
|
|
return this.EVENT_FILE_SUCCESS;
|
|
}
|
|
return this.EVENT_FILE_ERROR_UNKNOWN_EVENT;
|
|
}
|
|
|
|
return CrashManager.prototype._handleEventFilePayload.call(this,
|
|
store,
|
|
entry,
|
|
type,
|
|
date,
|
|
payload);
|
|
},
|
|
};
|
|
|
|
var DUMMY_DIR_COUNT = 0;
|
|
|
|
this.getManager = function() {
|
|
return (async function() {
|
|
const dirMode = OS.Constants.libc.S_IRWXU;
|
|
let baseFile = OS.Constants.Path.profileDir;
|
|
|
|
function makeDir(create = true) {
|
|
return (async function() {
|
|
let path = OS.Path.join(baseFile, "dummy-dir-" + DUMMY_DIR_COUNT++);
|
|
|
|
if (!create) {
|
|
return path;
|
|
}
|
|
|
|
dump("Creating directory: " + path + "\n");
|
|
await OS.File.makeDir(path, {unixMode: dirMode});
|
|
|
|
return path;
|
|
})();
|
|
}
|
|
|
|
let pendingD = await makeDir();
|
|
let submittedD = await makeDir();
|
|
let eventsD1 = await makeDir();
|
|
let eventsD2 = await makeDir();
|
|
|
|
// Store directory is created at run-time if needed. Ensure those code
|
|
// paths are triggered.
|
|
let storeD = await makeDir(false);
|
|
|
|
let m = new TestingCrashManager({
|
|
pendingDumpsDir: pendingD,
|
|
submittedDumpsDir: submittedD,
|
|
eventsDirs: [eventsD1, eventsD2],
|
|
storeDir: storeD,
|
|
telemetryStoreSizeKey: "CRASH_STORE_COMPRESSED_BYTES",
|
|
});
|
|
|
|
return m;
|
|
})();
|
|
};
|