зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1566855
- Submit incomplete crashes by synthesizing a minimal .extra file with sensible crash annotations r=mconley
Differential Revision: https://phabricator.services.mozilla.com/D42575 --HG-- rename : toolkit/crashreporter/test/browser/browser_aboutCrashesResubmit.js => toolkit/crashreporter/test/browser/browser_aboutCrashesIncomplete.js extra : moz-landing-system : lando
This commit is contained in:
Родитель
6faa60ff7c
Коммит
303c5ce8d0
|
@ -9,6 +9,9 @@ const { FileUtils } = ChromeUtils.import(
|
|||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
const { AppConstants } = ChromeUtils.import(
|
||||
"resource://gre/modules/AppConstants.jsm"
|
||||
);
|
||||
const {
|
||||
parseKeyValuePairs,
|
||||
parseKeyValuePairsFromFileAsync,
|
||||
|
@ -125,6 +128,37 @@ function getPendingMinidump(id) {
|
|||
});
|
||||
}
|
||||
|
||||
async function synthesizeExtraFile(extra) {
|
||||
let data =
|
||||
"ServerURL=https://crash-reports.mozilla.com/submit?id=" +
|
||||
Services.appinfo.ID +
|
||||
"&version=" +
|
||||
Services.appinfo.version +
|
||||
"&buildid=" +
|
||||
Services.appinfo.appBuildID +
|
||||
"\n" +
|
||||
"Vendor=" +
|
||||
Services.appinfo.vendor +
|
||||
"\n" +
|
||||
"ProductName=" +
|
||||
Services.appinfo.name +
|
||||
"\n" +
|
||||
"ProductID=" +
|
||||
Services.appinfo.ID +
|
||||
"\n" +
|
||||
"Version=" +
|
||||
Services.appinfo.version +
|
||||
"\n" +
|
||||
"BuildID=" +
|
||||
Services.appinfo.appBuildID +
|
||||
"\n" +
|
||||
"ReleaseChannel=" +
|
||||
AppConstants.MOZ_UPDATE_CHANNEL +
|
||||
"\n";
|
||||
|
||||
await OS.File.writeAtomic(extra, data, { encoding: "utf-8" });
|
||||
}
|
||||
|
||||
async function writeSubmittedReportAsync(crashID, viewURL) {
|
||||
let strings = await getL10nStrings();
|
||||
let data = strings.crashid.replace("%s", crashID);
|
||||
|
@ -343,12 +377,16 @@ Submitter.prototype = {
|
|||
OS.File.exists(memory),
|
||||
]);
|
||||
|
||||
if (!dumpExists || !extraExists) {
|
||||
if (!dumpExists) {
|
||||
this.notifyStatus(FAILED);
|
||||
this.cleanup();
|
||||
return this.submitStatusPromise;
|
||||
}
|
||||
|
||||
if (!extraExists) {
|
||||
await synthesizeExtraFile(extra);
|
||||
}
|
||||
|
||||
this.dump = dump;
|
||||
this.extra = extra;
|
||||
this.memory = memoryExists ? memory : null;
|
||||
|
|
|
@ -3,6 +3,7 @@ support-files =
|
|||
head.js
|
||||
|
||||
[browser_aboutCrashes.js]
|
||||
[browser_aboutCrashesIncomplete.js]
|
||||
[browser_aboutCrashesResubmit.js]
|
||||
[browser_bug471404.js]
|
||||
[browser_clearReports.js]
|
||||
|
|
|
@ -13,6 +13,18 @@ add_task(async function test() {
|
|||
info("about:crashes loaded");
|
||||
return ContentTask.spawn(browser, crashes, crashes => {
|
||||
const doc = content.document;
|
||||
|
||||
const submitted = doc.getElementById("reportListSubmitted");
|
||||
Assert.ok(
|
||||
!submitted.classList.contains("hidden"),
|
||||
"the submitted crash list is visible"
|
||||
);
|
||||
const unsubmitted = doc.getElementById("reportListUnsubmitted");
|
||||
Assert.ok(
|
||||
unsubmitted.classList.contains("hidden"),
|
||||
"the unsubmitted crash list is hidden"
|
||||
);
|
||||
|
||||
const crashIds = doc.getElementsByClassName("crash-id");
|
||||
Assert.equal(
|
||||
crashIds.length,
|
||||
|
@ -30,5 +42,41 @@ add_task(async function test() {
|
|||
}
|
||||
);
|
||||
|
||||
clear_fake_crashes(crD, crashes);
|
||||
const pendingCrash = addPendingCrashreport(crD, Date.now(), { foo: "bar" });
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: "about:crashes" },
|
||||
browser => {
|
||||
info("about:crashes loaded");
|
||||
return ContentTask.spawn(browser, pendingCrash, pendingCrash => {
|
||||
const doc = content.document;
|
||||
|
||||
const submitted = doc.getElementById("reportListSubmitted");
|
||||
Assert.ok(
|
||||
submitted.classList.contains("hidden"),
|
||||
"the submitted crash list is hidden"
|
||||
);
|
||||
const unsubmitted = doc.getElementById("reportListUnsubmitted");
|
||||
Assert.ok(
|
||||
!unsubmitted.classList.contains("hidden"),
|
||||
"the unsubmitted crash list is visible"
|
||||
);
|
||||
|
||||
const crashIds = doc.getElementsByClassName("crash-id");
|
||||
Assert.equal(
|
||||
crashIds.length,
|
||||
1,
|
||||
"about:crashes lists correct number of crash reports"
|
||||
);
|
||||
const pendingRow = doc.getElementById(pendingCrash.id);
|
||||
Assert.equal(
|
||||
pendingRow.cells[0].textContent,
|
||||
pendingCrash.id,
|
||||
"about:crashes lists pending crash IDs correctly"
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
cleanup_fake_appdir();
|
||||
});
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
const SERVER_URL =
|
||||
"http://example.com/browser/toolkit/crashreporter/test/browser/crashreport.sjs";
|
||||
var oldServerUrl = null;
|
||||
|
||||
function set_fake_crashreporter_url() {
|
||||
let env = Cc["@mozilla.org/process/environment;1"].getService(
|
||||
Ci.nsIEnvironment
|
||||
);
|
||||
oldServerUrl = env.get("MOZ_CRASHREPORTER_URL");
|
||||
env.set("MOZ_CRASHREPORTER_URL", SERVER_URL);
|
||||
}
|
||||
|
||||
function reset_fake_crashreporter_url() {
|
||||
let env = Cc["@mozilla.org/process/environment;1"].getService(
|
||||
Ci.nsIEnvironment
|
||||
);
|
||||
env.set("MOZ_CRASHREPORTER_URL", oldServerUrl);
|
||||
}
|
||||
|
||||
function cleanup_and_finish() {
|
||||
try {
|
||||
cleanup_fake_appdir();
|
||||
} catch (ex) {}
|
||||
Services.prefs.clearUserPref("breakpad.reportURL");
|
||||
BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
reset_fake_crashreporter_url();
|
||||
finish();
|
||||
}
|
||||
|
||||
/*
|
||||
* check_submit_incomplete
|
||||
*
|
||||
* Check that crash reports that are missing the .extra file can be submitted.
|
||||
* This will check if the submission process works by clicking on the "Submit"
|
||||
* button in the about:crashes page and then verifies that the submission
|
||||
* received on the server side contains the minimum set of crash annotations
|
||||
* required by a valid report.
|
||||
*/
|
||||
function check_submit_incomplete(tab, crash) {
|
||||
let crashReportPromise = TestUtils.topicObserved(
|
||||
"crash-report-status",
|
||||
(subject, data) => {
|
||||
return data == "success";
|
||||
}
|
||||
);
|
||||
crashReportPromise.then(result => {
|
||||
let crashData = convertPropertyBag(result[0]);
|
||||
|
||||
ok(crashData.serverCrashID, "Should have a serverCrashID set.");
|
||||
ok(crashData.extra.ProductName, "Should have a ProductName field.");
|
||||
ok(crashData.extra.ReleaseChannel, "Should have a ReleaseChannel field.");
|
||||
ok(crashData.extra.Vendor, "Should have a Vendor field.");
|
||||
ok(crashData.extra.Version, "Should have a Version field.");
|
||||
ok(crashData.extra.BuildID, "Should have a BuildID field.");
|
||||
ok(crashData.extra.ProductID, "Should have a ProductID field.");
|
||||
|
||||
cleanup_and_finish();
|
||||
});
|
||||
|
||||
const browser = gBrowser.getBrowserForTab(tab);
|
||||
function csp_onsuccess() {
|
||||
browser.removeEventListener("CrashSubmitSucceeded", csp_onsuccess, true);
|
||||
ok(true, "the crash report was submitted successfully");
|
||||
}
|
||||
function csp_fail() {
|
||||
browser.removeEventListener("CrashSubmitFailed", csp_fail, true);
|
||||
ok(false, "failed to submit crash report!");
|
||||
}
|
||||
browser.addEventListener("CrashSubmitSucceeded", csp_onsuccess, true);
|
||||
browser.addEventListener("CrashSubmitFailed", csp_fail, true);
|
||||
|
||||
ContentTask.spawn(browser, crash.id, id => {
|
||||
const submitButton = content.document
|
||||
.getElementById(id)
|
||||
.getElementsByClassName("submit-button")[0];
|
||||
submitButton.click();
|
||||
});
|
||||
}
|
||||
|
||||
function convertPropertyBag(aBag) {
|
||||
let result = {};
|
||||
for (let { name, value } of aBag.enumerator) {
|
||||
if (value instanceof Ci.nsIPropertyBag) {
|
||||
value = convertPropertyBag(value);
|
||||
}
|
||||
result[name] = value;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
set_fake_crashreporter_url();
|
||||
const appD = make_fake_appdir();
|
||||
const crD = appD.clone();
|
||||
crD.append("Crash Reports");
|
||||
let crash = addIncompletePendingCrashreport(crD, Date.now());
|
||||
|
||||
BrowserTestUtils.openNewForegroundTab(gBrowser, "about:crashes").then(tab => {
|
||||
check_submit_incomplete(tab, crash);
|
||||
});
|
||||
}
|
|
@ -10,6 +10,15 @@ function create_subdir(dir, subdirname) {
|
|||
return subdir;
|
||||
}
|
||||
|
||||
function generate_uuid() {
|
||||
let uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].getService(
|
||||
Ci.nsIUUIDGenerator
|
||||
);
|
||||
let uuid = uuidGenerator.generateUUID().toString();
|
||||
// ditch the {}
|
||||
return uuid.substring(1, uuid.length - 1);
|
||||
}
|
||||
|
||||
// need to hold on to this to unregister for cleanup
|
||||
var _provider = null;
|
||||
|
||||
|
@ -70,18 +79,13 @@ function cleanup_fake_appdir() {
|
|||
|
||||
function add_fake_crashes(crD, count) {
|
||||
let results = [];
|
||||
let uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].getService(
|
||||
Ci.nsIUUIDGenerator
|
||||
);
|
||||
let submitdir = crD.clone();
|
||||
submitdir.append("submitted");
|
||||
// create them from oldest to newest, to ensure that about:crashes
|
||||
// displays them in the correct order
|
||||
let date = Date.now() - count * 60000;
|
||||
for (let i = 0; i < count; i++) {
|
||||
let uuid = uuidGenerator.generateUUID().toString();
|
||||
// ditch the {}
|
||||
uuid = "bp-" + uuid.substring(1, uuid.length - 2);
|
||||
let uuid = "bp-" + generate_uuid();
|
||||
let fn = uuid + ".txt";
|
||||
let file = submitdir.clone();
|
||||
file.append(fn);
|
||||
|
@ -97,6 +101,17 @@ function add_fake_crashes(crD, count) {
|
|||
return results;
|
||||
}
|
||||
|
||||
function clear_fake_crashes(crD, crashes) {
|
||||
let submitdir = crD.clone();
|
||||
submitdir.append("submitted");
|
||||
for (let i of crashes) {
|
||||
let fn = i.id + ".txt";
|
||||
let file = submitdir.clone();
|
||||
file.append(fn);
|
||||
file.remove(false);
|
||||
}
|
||||
}
|
||||
|
||||
function writeDataToFile(file, data) {
|
||||
var fstream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(
|
||||
Ci.nsIFileOutputStream
|
||||
|
@ -112,30 +127,45 @@ function writeDataToFile(file, data) {
|
|||
fstream.close();
|
||||
}
|
||||
|
||||
function writeCrashReportFile(dir, uuid, suffix, date, data) {
|
||||
let file = dir.clone();
|
||||
file.append(uuid + suffix);
|
||||
writeDataToFile(file, data);
|
||||
file.lastModifiedTime = date;
|
||||
}
|
||||
|
||||
function writeMinidumpFile(dir, uuid, date) {
|
||||
// that's the start of a valid minidump, anyway
|
||||
writeCrashReportFile(dir, uuid, ".dmp", date, "MDMP");
|
||||
}
|
||||
|
||||
function writeExtraFile(dir, uuid, date, data) {
|
||||
let extradata = "";
|
||||
for (let x in data) {
|
||||
extradata += x + "=" + data[x] + "\n";
|
||||
}
|
||||
writeCrashReportFile(dir, uuid, ".extra", date, extradata);
|
||||
}
|
||||
|
||||
function writeMemoryReport(dir, uuid, date) {
|
||||
let data = "Let's pretend this is a memory report";
|
||||
writeCrashReportFile(dir, uuid, ".memory.json.gz", date, data);
|
||||
}
|
||||
|
||||
function addPendingCrashreport(crD, date, extra) {
|
||||
let pendingdir = crD.clone();
|
||||
pendingdir.append("pending");
|
||||
let uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].getService(
|
||||
Ci.nsIUUIDGenerator
|
||||
);
|
||||
let uuid = uuidGenerator.generateUUID().toString();
|
||||
// ditch the {}
|
||||
uuid = uuid.substring(1, uuid.length - 1);
|
||||
let dumpfile = pendingdir.clone();
|
||||
dumpfile.append(uuid + ".dmp");
|
||||
writeDataToFile(dumpfile, "MDMP"); // that's the start of a valid minidump, anyway
|
||||
let extrafile = pendingdir.clone();
|
||||
extrafile.append(uuid + ".extra");
|
||||
let extradata = "";
|
||||
for (let x in extra) {
|
||||
extradata += x + "=" + extra[x] + "\n";
|
||||
}
|
||||
writeDataToFile(extrafile, extradata);
|
||||
let memoryfile = pendingdir.clone();
|
||||
memoryfile.append(uuid + ".memory.json.gz");
|
||||
writeDataToFile(memoryfile, "Let's pretend this is a memory report");
|
||||
dumpfile.lastModifiedTime = date;
|
||||
extrafile.lastModifiedTime = date;
|
||||
memoryfile.lastModifiedTime = date;
|
||||
let uuid = generate_uuid();
|
||||
writeMinidumpFile(pendingdir, uuid, date);
|
||||
writeExtraFile(pendingdir, uuid, date, extra);
|
||||
writeMemoryReport(pendingdir, uuid, date);
|
||||
return { id: uuid, date, pending: true, extra };
|
||||
}
|
||||
|
||||
function addIncompletePendingCrashreport(crD, date) {
|
||||
let pendingdir = crD.clone();
|
||||
pendingdir.append("pending");
|
||||
let uuid = generate_uuid();
|
||||
writeMinidumpFile(pendingdir, uuid, date);
|
||||
return { id: uuid, date, pending: true };
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче