forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			1070 lines
		
	
	
	
		
			30 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			1070 lines
		
	
	
	
		
			30 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/* Any copyright is dedicated to the Public Domain.
 | 
						|
 * http://creativecommons.org/publicdomain/zero/1.0/ */
 | 
						|
 | 
						|
"use strict";
 | 
						|
 | 
						|
const { CrashManager } = ChromeUtils.importESModule(
 | 
						|
  "resource://gre/modules/CrashManager.sys.mjs"
 | 
						|
);
 | 
						|
const { TelemetryArchiveTesting } = ChromeUtils.importESModule(
 | 
						|
  "resource://testing-common/TelemetryArchiveTesting.sys.mjs"
 | 
						|
);
 | 
						|
const { configureLogging, getManager, sleep } = ChromeUtils.importESModule(
 | 
						|
  "resource://testing-common/CrashManagerTest.sys.mjs"
 | 
						|
);
 | 
						|
const { TelemetryEnvironment } = ChromeUtils.importESModule(
 | 
						|
  "resource://gre/modules/TelemetryEnvironment.sys.mjs"
 | 
						|
);
 | 
						|
 | 
						|
const DUMMY_DATE = new Date(Date.now() - 10 * 24 * 60 * 60 * 1000);
 | 
						|
DUMMY_DATE.setMilliseconds(0);
 | 
						|
 | 
						|
const DUMMY_DATE_2 = new Date(Date.now() - 20 * 24 * 60 * 60 * 1000);
 | 
						|
DUMMY_DATE_2.setMilliseconds(0);
 | 
						|
 | 
						|
function run_test() {
 | 
						|
  do_get_profile();
 | 
						|
  configureLogging();
 | 
						|
  TelemetryArchiveTesting.setup();
 | 
						|
  // Initialize FOG for glean tests
 | 
						|
  Services.fog.initializeFOG();
 | 
						|
  run_next_test();
 | 
						|
}
 | 
						|
 | 
						|
add_task(async function test_constructor_ok() {
 | 
						|
  let m = new CrashManager({
 | 
						|
    pendingDumpsDir: "/foo",
 | 
						|
    submittedDumpsDir: "/bar",
 | 
						|
    eventsDirs: [],
 | 
						|
    storeDir: "/baz",
 | 
						|
  });
 | 
						|
  Assert.ok(m, "CrashManager can be created.");
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function test_constructor_invalid() {
 | 
						|
  Assert.throws(() => {
 | 
						|
    new CrashManager({ foo: true });
 | 
						|
  }, /Unknown property in options/);
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function test_get_manager() {
 | 
						|
  let m = await getManager();
 | 
						|
  Assert.ok(m, "CrashManager obtained.");
 | 
						|
 | 
						|
  await m.createDummyDump(true);
 | 
						|
  await m.createDummyDump(false);
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function test_valid_process() {
 | 
						|
  let m = await getManager();
 | 
						|
  Assert.ok(m, "CrashManager obtained.");
 | 
						|
 | 
						|
  Assert.ok(!m.isValidProcessType(42));
 | 
						|
  Assert.ok(!m.isValidProcessType(null));
 | 
						|
  Assert.ok(!m.isValidProcessType("default"));
 | 
						|
 | 
						|
  Assert.ok(m.isValidProcessType("main"));
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function test_process_ping() {
 | 
						|
  let m = await getManager();
 | 
						|
  Assert.ok(m, "CrashManager obtained.");
 | 
						|
 | 
						|
  Assert.ok(!m.isPingAllowed(42));
 | 
						|
  Assert.ok(!m.isPingAllowed(null));
 | 
						|
  Assert.ok(!m.isPingAllowed("default"));
 | 
						|
  Assert.ok(!m.isPingAllowed("ipdlunittest"));
 | 
						|
  Assert.ok(!m.isPingAllowed("tab"));
 | 
						|
 | 
						|
  Assert.ok(m.isPingAllowed("content"));
 | 
						|
  Assert.ok(m.isPingAllowed("forkserver"));
 | 
						|
  Assert.ok(m.isPingAllowed("gmplugin"));
 | 
						|
  Assert.ok(m.isPingAllowed("gpu"));
 | 
						|
  Assert.ok(m.isPingAllowed("main"));
 | 
						|
  Assert.ok(m.isPingAllowed("rdd"));
 | 
						|
  Assert.ok(m.isPingAllowed("sandboxbroker"));
 | 
						|
  Assert.ok(m.isPingAllowed("socket"));
 | 
						|
  Assert.ok(m.isPingAllowed("utility"));
 | 
						|
  Assert.ok(m.isPingAllowed("vr"));
 | 
						|
});
 | 
						|
 | 
						|
// Unsubmitted dump files on disk are detected properly.
 | 
						|
add_task(async function test_pending_dumps() {
 | 
						|
  let m = await getManager();
 | 
						|
  let now = Date.now();
 | 
						|
  let ids = [];
 | 
						|
  const COUNT = 5;
 | 
						|
 | 
						|
  for (let i = 0; i < COUNT; i++) {
 | 
						|
    ids.push(await m.createDummyDump(false, new Date(now - i * 86400000)));
 | 
						|
  }
 | 
						|
  await m.createIgnoredDumpFile("ignored", false);
 | 
						|
 | 
						|
  let entries = await m.pendingDumps();
 | 
						|
  Assert.equal(entries.length, COUNT, "proper number detected.");
 | 
						|
 | 
						|
  for (let entry of entries) {
 | 
						|
    Assert.equal(typeof entry, "object", "entry is an object");
 | 
						|
    Assert.ok("id" in entry, "id in entry");
 | 
						|
    Assert.ok("path" in entry, "path in entry");
 | 
						|
    Assert.ok("date" in entry, "date in entry");
 | 
						|
    Assert.notEqual(ids.indexOf(entry.id), -1, "ID is known");
 | 
						|
  }
 | 
						|
 | 
						|
  for (let i = 0; i < COUNT; i++) {
 | 
						|
    Assert.equal(entries[i].id, ids[COUNT - i - 1], "Entries sorted by mtime");
 | 
						|
  }
 | 
						|
});
 | 
						|
 | 
						|
// Submitted dump files on disk are detected properly.
 | 
						|
add_task(async function test_submitted_dumps() {
 | 
						|
  let m = await getManager();
 | 
						|
  let COUNT = 5;
 | 
						|
 | 
						|
  for (let i = 0; i < COUNT; i++) {
 | 
						|
    await m.createDummyDump(true);
 | 
						|
  }
 | 
						|
  await m.createIgnoredDumpFile("ignored", true);
 | 
						|
 | 
						|
  let entries = await m.submittedDumps();
 | 
						|
  Assert.equal(entries.length, COUNT, "proper number detected.");
 | 
						|
 | 
						|
  let hrID = await m.createDummyDump(true, new Date(), true);
 | 
						|
  entries = await m.submittedDumps();
 | 
						|
  Assert.equal(entries.length, COUNT + 1, "hr- in filename detected.");
 | 
						|
 | 
						|
  let gotIDs = new Set(entries.map(e => e.id));
 | 
						|
  Assert.ok(gotIDs.has(hrID));
 | 
						|
});
 | 
						|
 | 
						|
// The store should expire after inactivity.
 | 
						|
add_task(async function test_store_expires() {
 | 
						|
  let m = await getManager();
 | 
						|
 | 
						|
  Object.defineProperty(m, "STORE_EXPIRATION_MS", {
 | 
						|
    value: 250,
 | 
						|
  });
 | 
						|
 | 
						|
  let store = await m._getStore();
 | 
						|
  Assert.ok(store);
 | 
						|
  Assert.equal(store, m._store);
 | 
						|
 | 
						|
  await sleep(300);
 | 
						|
  Assert.ok(!m._store, "Store has gone away.");
 | 
						|
});
 | 
						|
 | 
						|
// Ensure errors are handled when the events dir is missing.
 | 
						|
add_task(async function test_empty_events_dir() {
 | 
						|
  let m = await getManager();
 | 
						|
  await m.deleteEventsDirs();
 | 
						|
 | 
						|
  let paths = await m._getUnprocessedEventsFiles();
 | 
						|
  Assert.equal(paths.length, 0);
 | 
						|
});
 | 
						|
 | 
						|
// Ensure discovery of unprocessed events files works.
 | 
						|
add_task(async function test_unprocessed_events_files() {
 | 
						|
  let m = await getManager();
 | 
						|
  await m.createEventsFile("1", "test.1", new Date(), "foo", "{}", 0);
 | 
						|
  await m.createEventsFile("2", "test.1", new Date(), "bar", "{}", 0);
 | 
						|
  await m.createEventsFile("1", "test.1", new Date(), "baz", "{}", 1);
 | 
						|
 | 
						|
  let paths = await m._getUnprocessedEventsFiles();
 | 
						|
  Assert.equal(paths.length, 3);
 | 
						|
});
 | 
						|
 | 
						|
// Ensure only 1 aggregateEventsFiles() is allowed at a time.
 | 
						|
add_task(async function test_aggregate_events_locking() {
 | 
						|
  let m = await getManager();
 | 
						|
 | 
						|
  let p1 = m.aggregateEventsFiles();
 | 
						|
  let p2 = m.aggregateEventsFiles();
 | 
						|
 | 
						|
  Assert.strictEqual(p1, p2, "Same promise should be returned.");
 | 
						|
});
 | 
						|
 | 
						|
// Malformed events files should be deleted.
 | 
						|
add_task(async function test_malformed_files_deleted() {
 | 
						|
  let m = await getManager();
 | 
						|
 | 
						|
  await m.createEventsFile("1", "crash.main.1", new Date(), "foo\nbar");
 | 
						|
 | 
						|
  let count = await m.aggregateEventsFiles();
 | 
						|
  Assert.equal(count, 1);
 | 
						|
  let crashes = await m.getCrashes();
 | 
						|
  Assert.equal(crashes.length, 0);
 | 
						|
 | 
						|
  count = await m.aggregateEventsFiles();
 | 
						|
  Assert.equal(count, 0);
 | 
						|
});
 | 
						|
 | 
						|
// Unknown event types should be ignored.
 | 
						|
add_task(async function test_aggregate_ignore_unknown_events() {
 | 
						|
  let m = await getManager();
 | 
						|
 | 
						|
  await m.createEventsFile("1", "crash.main.3", DUMMY_DATE, "id1", "{}");
 | 
						|
  await m.createEventsFile("2", "foobar.1", new Date(), "dummy");
 | 
						|
 | 
						|
  let count = await m.aggregateEventsFiles();
 | 
						|
  Assert.equal(count, 2);
 | 
						|
 | 
						|
  count = await m.aggregateEventsFiles();
 | 
						|
  Assert.equal(count, 1);
 | 
						|
 | 
						|
  count = await m.aggregateEventsFiles();
 | 
						|
  Assert.equal(count, 1);
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function test_prune_old() {
 | 
						|
  let m = await getManager();
 | 
						|
  let oldDate = new Date(Date.now() - 86400000);
 | 
						|
  let newDate = new Date(Date.now() - 10000);
 | 
						|
  await m.createEventsFile("1", "crash.main.3", oldDate, "id1", "{}");
 | 
						|
  await m.addCrash(
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT],
 | 
						|
    m.CRASH_TYPE_CRASH,
 | 
						|
    "id2",
 | 
						|
    newDate
 | 
						|
  );
 | 
						|
 | 
						|
  await m.aggregateEventsFiles();
 | 
						|
 | 
						|
  let crashes = await m.getCrashes();
 | 
						|
  Assert.equal(crashes.length, 2);
 | 
						|
 | 
						|
  await m.pruneOldCrashes(new Date(oldDate.getTime() + 10000));
 | 
						|
 | 
						|
  crashes = await m.getCrashes();
 | 
						|
  Assert.equal(crashes.length, 1, "Old crash has been pruned.");
 | 
						|
 | 
						|
  let c = crashes[0];
 | 
						|
  Assert.equal(c.id, "id2", "Proper crash was pruned.");
 | 
						|
 | 
						|
  // We can't test exact boundary conditions because dates from filesystem
 | 
						|
  // don't have same guarantees as JS dates.
 | 
						|
  await m.pruneOldCrashes(new Date(newDate.getTime() + 5000));
 | 
						|
  crashes = await m.getCrashes();
 | 
						|
  Assert.equal(crashes.length, 0);
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function test_schedule_maintenance() {
 | 
						|
  let m = await getManager();
 | 
						|
  await m.createEventsFile("1", "crash.main.3", DUMMY_DATE, "id1", "{}");
 | 
						|
 | 
						|
  let oldDate = new Date(
 | 
						|
    Date.now() - m.PURGE_OLDER_THAN_DAYS * 2 * 24 * 60 * 60 * 1000
 | 
						|
  );
 | 
						|
  await m.createEventsFile("2", "crash.main.3", oldDate, "id2", "{}");
 | 
						|
 | 
						|
  await m.scheduleMaintenance(25);
 | 
						|
  let crashes = await m.getCrashes();
 | 
						|
  Assert.equal(crashes.length, 1);
 | 
						|
  Assert.equal(crashes[0].id, "id1");
 | 
						|
});
 | 
						|
 | 
						|
const crashId = "3cb67eba-0dc7-6f78-6a569a0e-172287ec";
 | 
						|
const productName = "Firefox";
 | 
						|
const productId = "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}";
 | 
						|
const sha256Hash =
 | 
						|
  "f8410c3ac4496cfa9191a1240f0e365101aef40c7bf34fc5bcb8ec511832ed79";
 | 
						|
const stackTraces = { status: "OK" };
 | 
						|
 | 
						|
add_task(async function test_main_crash_event_file() {
 | 
						|
  let ac = new TelemetryArchiveTesting.Checker();
 | 
						|
  await ac.promiseInit();
 | 
						|
  let theEnvironment = TelemetryEnvironment.currentEnvironment;
 | 
						|
  const sessionId = "be66af2f-2ee5-4330-ae95-44462dfbdf0c";
 | 
						|
 | 
						|
  // To test proper escaping, add data to the environment with an embedded
 | 
						|
  // double-quote
 | 
						|
  theEnvironment.testValue = 'MyValue"';
 | 
						|
 | 
						|
  let m = await getManager();
 | 
						|
  const metadata = JSON.stringify({
 | 
						|
    ProductName: productName,
 | 
						|
    ProductID: productId,
 | 
						|
    TelemetryEnvironment: JSON.stringify(theEnvironment),
 | 
						|
    TelemetrySessionId: sessionId,
 | 
						|
    MinidumpSha256Hash: sha256Hash,
 | 
						|
    StackTraces: stackTraces,
 | 
						|
    ThisShouldNot: "end-up-in-the-ping",
 | 
						|
  });
 | 
						|
 | 
						|
  await m.createEventsFile(
 | 
						|
    crashId,
 | 
						|
    "crash.main.3",
 | 
						|
    DUMMY_DATE,
 | 
						|
    crashId,
 | 
						|
    metadata
 | 
						|
  );
 | 
						|
  let count = await m.aggregateEventsFiles();
 | 
						|
  Assert.equal(count, 1);
 | 
						|
 | 
						|
  let crashes = await m.getCrashes();
 | 
						|
  Assert.equal(crashes.length, 1);
 | 
						|
  Assert.equal(crashes[0].id, crashId);
 | 
						|
  Assert.equal(crashes[0].type, "main-crash");
 | 
						|
  Assert.equal(crashes[0].metadata.ProductName, productName);
 | 
						|
  Assert.equal(crashes[0].metadata.ProductID, productId);
 | 
						|
  Assert.ok(crashes[0].metadata.TelemetryEnvironment);
 | 
						|
  Assert.equal(Object.getOwnPropertyNames(crashes[0].metadata).length, 7);
 | 
						|
  Assert.equal(crashes[0].metadata.TelemetrySessionId, sessionId);
 | 
						|
  Assert.ok(crashes[0].metadata.StackTraces);
 | 
						|
  Assert.deepEqual(crashes[0].crashDate, DUMMY_DATE);
 | 
						|
 | 
						|
  let found = await ac.promiseFindPing("crash", [
 | 
						|
    [["payload", "hasCrashEnvironment"], true],
 | 
						|
    [["payload", "metadata", "ProductName"], productName],
 | 
						|
    [["payload", "metadata", "ProductID"], productId],
 | 
						|
    [["payload", "minidumpSha256Hash"], sha256Hash],
 | 
						|
    [["payload", "crashId"], crashId],
 | 
						|
    [["payload", "stackTraces", "status"], "OK"],
 | 
						|
    [["payload", "sessionId"], sessionId],
 | 
						|
  ]);
 | 
						|
  Assert.ok(found, "Telemetry ping submitted for found crash");
 | 
						|
  Assert.deepEqual(
 | 
						|
    found.environment,
 | 
						|
    theEnvironment,
 | 
						|
    "The saved environment should be present"
 | 
						|
  );
 | 
						|
  Assert.equal(
 | 
						|
    found.payload.metadata.ThisShouldNot,
 | 
						|
    undefined,
 | 
						|
    "Non-allowed fields should be filtered out"
 | 
						|
  );
 | 
						|
 | 
						|
  count = await m.aggregateEventsFiles();
 | 
						|
  Assert.equal(count, 0);
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function test_main_crash_event_file_noenv() {
 | 
						|
  let ac = new TelemetryArchiveTesting.Checker();
 | 
						|
  await ac.promiseInit();
 | 
						|
  const metadata = JSON.stringify({
 | 
						|
    ProductName: productName,
 | 
						|
    ProductID: productId,
 | 
						|
  });
 | 
						|
 | 
						|
  let m = await getManager();
 | 
						|
  await m.createEventsFile(
 | 
						|
    crashId,
 | 
						|
    "crash.main.3",
 | 
						|
    DUMMY_DATE,
 | 
						|
    crashId,
 | 
						|
    metadata
 | 
						|
  );
 | 
						|
  let count = await m.aggregateEventsFiles();
 | 
						|
  Assert.equal(count, 1);
 | 
						|
 | 
						|
  let crashes = await m.getCrashes();
 | 
						|
  Assert.equal(crashes.length, 1);
 | 
						|
  Assert.equal(crashes[0].id, crashId);
 | 
						|
  Assert.equal(crashes[0].type, "main-crash");
 | 
						|
  Assert.deepEqual(crashes[0].metadata, {
 | 
						|
    ProductName: productName,
 | 
						|
    ProductID: productId,
 | 
						|
  });
 | 
						|
  Assert.deepEqual(crashes[0].crashDate, DUMMY_DATE);
 | 
						|
 | 
						|
  let found = await ac.promiseFindPing("crash", [
 | 
						|
    [["payload", "hasCrashEnvironment"], false],
 | 
						|
    [["payload", "metadata", "ProductName"], productName],
 | 
						|
    [["payload", "metadata", "ProductID"], productId],
 | 
						|
  ]);
 | 
						|
  Assert.ok(found, "Telemetry ping submitted for found crash");
 | 
						|
  Assert.ok(found.environment, "There is an environment");
 | 
						|
 | 
						|
  count = await m.aggregateEventsFiles();
 | 
						|
  Assert.equal(count, 0);
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function test_crash_submission_event_file() {
 | 
						|
  let m = await getManager();
 | 
						|
  await m.createEventsFile("1", "crash.main.3", DUMMY_DATE, "crash1", "{}");
 | 
						|
  await m.createEventsFile(
 | 
						|
    "1-submission",
 | 
						|
    "crash.submission.1",
 | 
						|
    DUMMY_DATE_2,
 | 
						|
    "crash1",
 | 
						|
    "false\n"
 | 
						|
  );
 | 
						|
 | 
						|
  // The line below has been intentionally commented out to make sure that
 | 
						|
  // the crash record is created when one does not exist.
 | 
						|
  // yield m.createEventsFile("2", "crash.main.1", DUMMY_DATE, "crash2");
 | 
						|
  await m.createEventsFile(
 | 
						|
    "2-submission",
 | 
						|
    "crash.submission.1",
 | 
						|
    DUMMY_DATE_2,
 | 
						|
    "crash2",
 | 
						|
    "true\nbp-2"
 | 
						|
  );
 | 
						|
  let count = await m.aggregateEventsFiles();
 | 
						|
  Assert.equal(count, 3);
 | 
						|
 | 
						|
  let crashes = await m.getCrashes();
 | 
						|
  Assert.equal(crashes.length, 2);
 | 
						|
 | 
						|
  let map = new Map(crashes.map(crash => [crash.id, crash]));
 | 
						|
 | 
						|
  let crash1 = map.get("crash1");
 | 
						|
  Assert.ok(!!crash1);
 | 
						|
  Assert.equal(crash1.remoteID, null);
 | 
						|
  let crash2 = map.get("crash2");
 | 
						|
  Assert.ok(!!crash2);
 | 
						|
  Assert.equal(crash2.remoteID, "bp-2");
 | 
						|
 | 
						|
  Assert.equal(crash1.submissions.size, 1);
 | 
						|
  let submission = crash1.submissions.values().next().value;
 | 
						|
  Assert.equal(submission.result, m.SUBMISSION_RESULT_FAILED);
 | 
						|
  Assert.equal(submission.requestDate.getTime(), DUMMY_DATE_2.getTime());
 | 
						|
  Assert.equal(submission.responseDate.getTime(), DUMMY_DATE_2.getTime());
 | 
						|
 | 
						|
  Assert.equal(crash2.submissions.size, 1);
 | 
						|
  submission = crash2.submissions.values().next().value;
 | 
						|
  Assert.equal(submission.result, m.SUBMISSION_RESULT_OK);
 | 
						|
  Assert.equal(submission.requestDate.getTime(), DUMMY_DATE_2.getTime());
 | 
						|
  Assert.equal(submission.responseDate.getTime(), DUMMY_DATE_2.getTime());
 | 
						|
 | 
						|
  count = await m.aggregateEventsFiles();
 | 
						|
  Assert.equal(count, 0);
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function test_multiline_crash_id_rejected() {
 | 
						|
  let m = await getManager();
 | 
						|
  await m.createEventsFile("1", "crash.main.1", DUMMY_DATE, "id1\nid2");
 | 
						|
  await m.aggregateEventsFiles();
 | 
						|
  let crashes = await m.getCrashes();
 | 
						|
  Assert.equal(crashes.length, 0);
 | 
						|
});
 | 
						|
 | 
						|
// Main process crashes should be remembered beyond the high water mark.
 | 
						|
add_task(async function test_high_water_mark() {
 | 
						|
  let m = await getManager();
 | 
						|
 | 
						|
  let store = await m._getStore();
 | 
						|
 | 
						|
  for (let i = 0; i < store.HIGH_WATER_DAILY_THRESHOLD + 1; i++) {
 | 
						|
    await m.createEventsFile(
 | 
						|
      "m" + i,
 | 
						|
      "crash.main.3",
 | 
						|
      DUMMY_DATE,
 | 
						|
      "m" + i,
 | 
						|
      "{}"
 | 
						|
    );
 | 
						|
  }
 | 
						|
 | 
						|
  let count = await m.aggregateEventsFiles();
 | 
						|
  Assert.equal(count, store.HIGH_WATER_DAILY_THRESHOLD + 1);
 | 
						|
 | 
						|
  // Need to fetch again in case the first one was garbage collected.
 | 
						|
  store = await m._getStore();
 | 
						|
 | 
						|
  Assert.equal(store.crashesCount, store.HIGH_WATER_DAILY_THRESHOLD + 1);
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function test_addCrash() {
 | 
						|
  let m = await getManager();
 | 
						|
 | 
						|
  let crashes = await m.getCrashes();
 | 
						|
  Assert.equal(crashes.length, 0);
 | 
						|
 | 
						|
  await m.addCrash(
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT],
 | 
						|
    m.CRASH_TYPE_CRASH,
 | 
						|
    "main-crash",
 | 
						|
    DUMMY_DATE
 | 
						|
  );
 | 
						|
  await m.addCrash(
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT],
 | 
						|
    m.CRASH_TYPE_HANG,
 | 
						|
    "main-hang",
 | 
						|
    DUMMY_DATE
 | 
						|
  );
 | 
						|
  await m.addCrash(
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT],
 | 
						|
    m.CRASH_TYPE_CRASH,
 | 
						|
    "content-crash",
 | 
						|
    DUMMY_DATE
 | 
						|
  );
 | 
						|
  await m.addCrash(
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT],
 | 
						|
    m.CRASH_TYPE_HANG,
 | 
						|
    "content-hang",
 | 
						|
    DUMMY_DATE
 | 
						|
  );
 | 
						|
  await m.addCrash(
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_GMPLUGIN],
 | 
						|
    m.CRASH_TYPE_CRASH,
 | 
						|
    "gmplugin-crash",
 | 
						|
    DUMMY_DATE
 | 
						|
  );
 | 
						|
  await m.addCrash(
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_GPU],
 | 
						|
    m.CRASH_TYPE_CRASH,
 | 
						|
    "gpu-crash",
 | 
						|
    DUMMY_DATE
 | 
						|
  );
 | 
						|
  await m.addCrash(
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_VR],
 | 
						|
    m.CRASH_TYPE_CRASH,
 | 
						|
    "vr-crash",
 | 
						|
    DUMMY_DATE
 | 
						|
  );
 | 
						|
  await m.addCrash(
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_RDD],
 | 
						|
    m.CRASH_TYPE_CRASH,
 | 
						|
    "rdd-crash",
 | 
						|
    DUMMY_DATE
 | 
						|
  );
 | 
						|
  await m.addCrash(
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_SOCKET],
 | 
						|
    m.CRASH_TYPE_CRASH,
 | 
						|
    "socket-crash",
 | 
						|
    DUMMY_DATE
 | 
						|
  );
 | 
						|
 | 
						|
  await m.addCrash(
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT],
 | 
						|
    m.CRASH_TYPE_CRASH,
 | 
						|
    "changing-item",
 | 
						|
    DUMMY_DATE
 | 
						|
  );
 | 
						|
  await m.addCrash(
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT],
 | 
						|
    m.CRASH_TYPE_HANG,
 | 
						|
    "changing-item",
 | 
						|
    DUMMY_DATE_2
 | 
						|
  );
 | 
						|
 | 
						|
  crashes = await m.getCrashes();
 | 
						|
  Assert.equal(crashes.length, 10);
 | 
						|
 | 
						|
  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.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT] +
 | 
						|
      "-" +
 | 
						|
      m.CRASH_TYPE_CRASH
 | 
						|
  );
 | 
						|
  Assert.ok(
 | 
						|
    crash.isOfType(
 | 
						|
      m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT],
 | 
						|
      m.CRASH_TYPE_CRASH
 | 
						|
    )
 | 
						|
  );
 | 
						|
 | 
						|
  crash = map.get("main-hang");
 | 
						|
  Assert.ok(!!crash);
 | 
						|
  Assert.equal(crash.crashDate, DUMMY_DATE);
 | 
						|
  Assert.equal(
 | 
						|
    crash.type,
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT] +
 | 
						|
      "-" +
 | 
						|
      m.CRASH_TYPE_HANG
 | 
						|
  );
 | 
						|
  Assert.ok(
 | 
						|
    crash.isOfType(
 | 
						|
      m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT],
 | 
						|
      m.CRASH_TYPE_HANG
 | 
						|
    )
 | 
						|
  );
 | 
						|
 | 
						|
  crash = map.get("content-crash");
 | 
						|
  Assert.ok(!!crash);
 | 
						|
  Assert.equal(crash.crashDate, DUMMY_DATE);
 | 
						|
  Assert.equal(
 | 
						|
    crash.type,
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT] +
 | 
						|
      "-" +
 | 
						|
      m.CRASH_TYPE_CRASH
 | 
						|
  );
 | 
						|
  Assert.ok(
 | 
						|
    crash.isOfType(
 | 
						|
      m.processTypes[Ci.nsIXULRuntime.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.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT] +
 | 
						|
      "-" +
 | 
						|
      m.CRASH_TYPE_HANG
 | 
						|
  );
 | 
						|
  Assert.ok(
 | 
						|
    crash.isOfType(
 | 
						|
      m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT],
 | 
						|
      m.CRASH_TYPE_HANG
 | 
						|
    )
 | 
						|
  );
 | 
						|
 | 
						|
  crash = map.get("gmplugin-crash");
 | 
						|
  Assert.ok(!!crash);
 | 
						|
  Assert.equal(crash.crashDate, DUMMY_DATE);
 | 
						|
  Assert.equal(
 | 
						|
    crash.type,
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_GMPLUGIN] +
 | 
						|
      "-" +
 | 
						|
      m.CRASH_TYPE_CRASH
 | 
						|
  );
 | 
						|
  Assert.ok(
 | 
						|
    crash.isOfType(
 | 
						|
      m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_GMPLUGIN],
 | 
						|
      m.CRASH_TYPE_CRASH
 | 
						|
    )
 | 
						|
  );
 | 
						|
 | 
						|
  crash = map.get("gpu-crash");
 | 
						|
  Assert.ok(!!crash);
 | 
						|
  Assert.equal(crash.crashDate, DUMMY_DATE);
 | 
						|
  Assert.equal(
 | 
						|
    crash.type,
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_GPU] + "-" + m.CRASH_TYPE_CRASH
 | 
						|
  );
 | 
						|
  Assert.ok(
 | 
						|
    crash.isOfType(
 | 
						|
      m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_GPU],
 | 
						|
      m.CRASH_TYPE_CRASH
 | 
						|
    )
 | 
						|
  );
 | 
						|
 | 
						|
  crash = map.get("vr-crash");
 | 
						|
  Assert.ok(!!crash);
 | 
						|
  Assert.equal(crash.crashDate, DUMMY_DATE);
 | 
						|
  Assert.equal(
 | 
						|
    crash.type,
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_VR] + "-" + m.CRASH_TYPE_CRASH
 | 
						|
  );
 | 
						|
  Assert.ok(
 | 
						|
    crash.isOfType(
 | 
						|
      m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_VR],
 | 
						|
      m.CRASH_TYPE_CRASH
 | 
						|
    )
 | 
						|
  );
 | 
						|
 | 
						|
  crash = map.get("rdd-crash");
 | 
						|
  Assert.ok(!!crash);
 | 
						|
  Assert.equal(crash.crashDate, DUMMY_DATE);
 | 
						|
  Assert.equal(
 | 
						|
    crash.type,
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_RDD] + "-" + m.CRASH_TYPE_CRASH
 | 
						|
  );
 | 
						|
  Assert.ok(
 | 
						|
    crash.isOfType(
 | 
						|
      m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_RDD],
 | 
						|
      m.CRASH_TYPE_CRASH
 | 
						|
    )
 | 
						|
  );
 | 
						|
 | 
						|
  crash = map.get("socket-crash");
 | 
						|
  Assert.ok(!!crash);
 | 
						|
  Assert.equal(crash.crashDate, DUMMY_DATE);
 | 
						|
  Assert.equal(
 | 
						|
    crash.type,
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_SOCKET] +
 | 
						|
      "-" +
 | 
						|
      m.CRASH_TYPE_CRASH
 | 
						|
  );
 | 
						|
  Assert.ok(
 | 
						|
    crash.isOfType(
 | 
						|
      m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_SOCKET],
 | 
						|
      m.CRASH_TYPE_CRASH
 | 
						|
    )
 | 
						|
  );
 | 
						|
 | 
						|
  crash = map.get("changing-item");
 | 
						|
  Assert.ok(!!crash);
 | 
						|
  Assert.equal(crash.crashDate, DUMMY_DATE_2);
 | 
						|
  Assert.equal(
 | 
						|
    crash.type,
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT] +
 | 
						|
      "-" +
 | 
						|
      m.CRASH_TYPE_HANG
 | 
						|
  );
 | 
						|
  Assert.ok(
 | 
						|
    crash.isOfType(
 | 
						|
      m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT],
 | 
						|
      m.CRASH_TYPE_HANG
 | 
						|
    )
 | 
						|
  );
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function test_child_process_crash_ping() {
 | 
						|
  let m = await getManager();
 | 
						|
  const EXPECTED_PROCESSES = [
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT],
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT],
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_GMPLUGIN],
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_GPU],
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_VR],
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_RDD],
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_SOCKET],
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_REMOTESANDBOXBROKER],
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_FORKSERVER],
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_UTILITY],
 | 
						|
  ];
 | 
						|
 | 
						|
  const UNEXPECTED_PROCESSES = [
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_IPDLUNITTEST],
 | 
						|
    null,
 | 
						|
    12, // non-string process type
 | 
						|
  ];
 | 
						|
 | 
						|
  let ac = new TelemetryArchiveTesting.Checker();
 | 
						|
  await ac.promiseInit();
 | 
						|
 | 
						|
  // Add a child-process crash for each allowed process type.
 | 
						|
  for (let p of EXPECTED_PROCESSES) {
 | 
						|
    // Generate a ping.
 | 
						|
    const remoteType =
 | 
						|
      p === m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT]
 | 
						|
        ? "web"
 | 
						|
        : undefined;
 | 
						|
    let id = await m.createDummyDump();
 | 
						|
    await m.addCrash(p, m.CRASH_TYPE_CRASH, id, DUMMY_DATE, {
 | 
						|
      RemoteType: remoteType,
 | 
						|
      StackTraces: stackTraces,
 | 
						|
      MinidumpSha256Hash: sha256Hash,
 | 
						|
      ipc_channel_error: "ShutDownKill",
 | 
						|
      ThisShouldNot: "end-up-in-the-ping",
 | 
						|
    });
 | 
						|
    await m._pingPromise;
 | 
						|
 | 
						|
    let found = await ac.promiseFindPing("crash", [
 | 
						|
      [["payload", "crashId"], id],
 | 
						|
      [["payload", "minidumpSha256Hash"], sha256Hash],
 | 
						|
      [["payload", "processType"], p],
 | 
						|
      [["payload", "stackTraces", "status"], "OK"],
 | 
						|
    ]);
 | 
						|
    Assert.ok(found, "Telemetry ping submitted for " + p + " crash");
 | 
						|
 | 
						|
    let hoursOnly = new Date(DUMMY_DATE);
 | 
						|
    hoursOnly.setSeconds(0);
 | 
						|
    hoursOnly.setMinutes(0);
 | 
						|
    Assert.equal(
 | 
						|
      new Date(found.payload.crashTime).getTime(),
 | 
						|
      hoursOnly.getTime()
 | 
						|
    );
 | 
						|
 | 
						|
    Assert.equal(
 | 
						|
      found.payload.metadata.ThisShouldNot,
 | 
						|
      undefined,
 | 
						|
      "Non-allowed fields should be filtered out"
 | 
						|
    );
 | 
						|
    Assert.equal(
 | 
						|
      found.payload.metadata.RemoteType,
 | 
						|
      remoteType,
 | 
						|
      "RemoteType should be allowed for content crashes"
 | 
						|
    );
 | 
						|
    Assert.equal(
 | 
						|
      found.payload.metadata.ipc_channel_error,
 | 
						|
      "ShutDownKill",
 | 
						|
      "ipc_channel_error should be allowed for content crashes"
 | 
						|
    );
 | 
						|
  }
 | 
						|
 | 
						|
  // Check that we don't generate a crash ping for invalid/unexpected process
 | 
						|
  // types.
 | 
						|
  for (let p of UNEXPECTED_PROCESSES) {
 | 
						|
    let id = await m.createDummyDump();
 | 
						|
    await m.addCrash(p, m.CRASH_TYPE_CRASH, id, DUMMY_DATE, {
 | 
						|
      StackTraces: stackTraces,
 | 
						|
      MinidumpSha256Hash: sha256Hash,
 | 
						|
      ThisShouldNot: "end-up-in-the-ping",
 | 
						|
    });
 | 
						|
    await m._pingPromise;
 | 
						|
 | 
						|
    // Check that we didn't receive any new ping.
 | 
						|
    let found = await ac.promiseFindPing("crash", [
 | 
						|
      [["payload", "crashId"], id],
 | 
						|
    ]);
 | 
						|
    Assert.ok(
 | 
						|
      !found,
 | 
						|
      "No telemetry ping must be submitted for invalid process types"
 | 
						|
    );
 | 
						|
  }
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function test_glean_crash_ping() {
 | 
						|
  let m = await getManager();
 | 
						|
 | 
						|
  let id = await m.createDummyDump();
 | 
						|
 | 
						|
  // Test bare minumum (with missing optional fields)
 | 
						|
  let submitted = false;
 | 
						|
  GleanPings.crash.testBeforeNextSubmit(_ => {
 | 
						|
    submitted = true;
 | 
						|
    const MINUTES = new Date(DUMMY_DATE);
 | 
						|
    MINUTES.setSeconds(0);
 | 
						|
    Assert.equal(Glean.crash.time.testGetValue().getTime(), MINUTES.getTime());
 | 
						|
    Assert.equal(
 | 
						|
      Glean.crash.processType.testGetValue(),
 | 
						|
      m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT]
 | 
						|
    );
 | 
						|
    Assert.equal(Glean.crash.startup.testGetValue(), false);
 | 
						|
  });
 | 
						|
 | 
						|
  await m.addCrash(
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT],
 | 
						|
    m.CRASH_TYPE_CRASH,
 | 
						|
    id,
 | 
						|
    DUMMY_DATE,
 | 
						|
    {}
 | 
						|
  );
 | 
						|
 | 
						|
  Assert.ok(submitted);
 | 
						|
 | 
						|
  // Test with additional fields
 | 
						|
  submitted = false;
 | 
						|
  GleanPings.crash.testBeforeNextSubmit(() => {
 | 
						|
    submitted = true;
 | 
						|
    const MINUTES = new Date(DUMMY_DATE_2);
 | 
						|
    MINUTES.setSeconds(0);
 | 
						|
    Assert.equal(Glean.crash.uptime.testGetValue(), 600.1 * 1000);
 | 
						|
    Assert.equal(Glean.crash.time.testGetValue().getTime(), MINUTES.getTime());
 | 
						|
    Assert.equal(
 | 
						|
      Glean.crash.processType.testGetValue(),
 | 
						|
      m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT]
 | 
						|
    );
 | 
						|
    Assert.equal(Glean.crash.startup.testGetValue(), true);
 | 
						|
  });
 | 
						|
 | 
						|
  await m.addCrash(
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT],
 | 
						|
    m.CRASH_TYPE_CRASH,
 | 
						|
    id,
 | 
						|
    DUMMY_DATE_2,
 | 
						|
    {
 | 
						|
      StackTraces: stackTraces,
 | 
						|
      MinidumpSha256Hash: sha256Hash,
 | 
						|
      UptimeTS: "600.1",
 | 
						|
      StartupCrash: "1",
 | 
						|
    }
 | 
						|
  );
 | 
						|
 | 
						|
  Assert.ok(submitted);
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function test_generateSubmissionID() {
 | 
						|
  let m = await getManager();
 | 
						|
 | 
						|
  const SUBMISSION_ID_REGEX =
 | 
						|
    /^(sub-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/i;
 | 
						|
  let id = m.generateSubmissionID();
 | 
						|
  Assert.ok(SUBMISSION_ID_REGEX.test(id));
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function test_addSubmissionAttemptAndResult() {
 | 
						|
  let m = await getManager();
 | 
						|
 | 
						|
  let crashes = await m.getCrashes();
 | 
						|
  Assert.equal(crashes.length, 0);
 | 
						|
 | 
						|
  await m.addCrash(
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT],
 | 
						|
    m.CRASH_TYPE_CRASH,
 | 
						|
    "main-crash",
 | 
						|
    DUMMY_DATE
 | 
						|
  );
 | 
						|
  await m.addSubmissionAttempt("main-crash", "submission", DUMMY_DATE);
 | 
						|
  await m.addSubmissionResult(
 | 
						|
    "main-crash",
 | 
						|
    "submission",
 | 
						|
    DUMMY_DATE_2,
 | 
						|
    m.SUBMISSION_RESULT_OK
 | 
						|
  );
 | 
						|
 | 
						|
  crashes = await m.getCrashes();
 | 
						|
  Assert.equal(crashes.length, 1);
 | 
						|
 | 
						|
  let submissions = crashes[0].submissions;
 | 
						|
  Assert.ok(!!submissions);
 | 
						|
 | 
						|
  let submission = submissions.get("submission");
 | 
						|
  Assert.ok(!!submission);
 | 
						|
  Assert.equal(submission.requestDate.getTime(), DUMMY_DATE.getTime());
 | 
						|
  Assert.equal(submission.responseDate.getTime(), DUMMY_DATE_2.getTime());
 | 
						|
  Assert.equal(submission.result, m.SUBMISSION_RESULT_OK);
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function test_addSubmissionAttemptEarlyCall() {
 | 
						|
  let m = await getManager();
 | 
						|
 | 
						|
  let crashes = await m.getCrashes();
 | 
						|
  Assert.equal(crashes.length, 0);
 | 
						|
 | 
						|
  let p = m
 | 
						|
    .ensureCrashIsPresent("main-crash")
 | 
						|
    .then(() => {
 | 
						|
      return m.addSubmissionAttempt("main-crash", "submission", DUMMY_DATE);
 | 
						|
    })
 | 
						|
    .then(() => {
 | 
						|
      return m.addSubmissionResult(
 | 
						|
        "main-crash",
 | 
						|
        "submission",
 | 
						|
        DUMMY_DATE_2,
 | 
						|
        m.SUBMISSION_RESULT_OK
 | 
						|
      );
 | 
						|
    });
 | 
						|
 | 
						|
  await m.addCrash(
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT],
 | 
						|
    m.CRASH_TYPE_CRASH,
 | 
						|
    "main-crash",
 | 
						|
    DUMMY_DATE
 | 
						|
  );
 | 
						|
 | 
						|
  crashes = await m.getCrashes();
 | 
						|
  Assert.equal(crashes.length, 1);
 | 
						|
 | 
						|
  await p;
 | 
						|
  let submissions = crashes[0].submissions;
 | 
						|
  Assert.ok(!!submissions);
 | 
						|
 | 
						|
  let submission = submissions.get("submission");
 | 
						|
  Assert.ok(!!submission);
 | 
						|
  Assert.equal(submission.requestDate.getTime(), DUMMY_DATE.getTime());
 | 
						|
  Assert.equal(submission.responseDate.getTime(), DUMMY_DATE_2.getTime());
 | 
						|
  Assert.equal(submission.result, m.SUBMISSION_RESULT_OK);
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function test_setCrashClassifications() {
 | 
						|
  let m = await getManager();
 | 
						|
 | 
						|
  await m.addCrash(
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT],
 | 
						|
    m.CRASH_TYPE_CRASH,
 | 
						|
    "main-crash",
 | 
						|
    DUMMY_DATE
 | 
						|
  );
 | 
						|
  await m.setCrashClassifications("main-crash", ["a"]);
 | 
						|
  let classifications = (await m.getCrashes())[0].classifications;
 | 
						|
  Assert.ok(classifications.includes("a"));
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function test_setRemoteCrashID() {
 | 
						|
  let m = await getManager();
 | 
						|
 | 
						|
  await m.addCrash(
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT],
 | 
						|
    m.CRASH_TYPE_CRASH,
 | 
						|
    "main-crash",
 | 
						|
    DUMMY_DATE
 | 
						|
  );
 | 
						|
  await m.setRemoteCrashID("main-crash", "bp-1");
 | 
						|
  Assert.equal((await m.getCrashes())[0].remoteID, "bp-1");
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function test_addCrashWrong() {
 | 
						|
  let m = await getManager();
 | 
						|
 | 
						|
  let crashes = await m.getCrashes();
 | 
						|
  Assert.equal(crashes.length, 0);
 | 
						|
 | 
						|
  await m.addCrash(
 | 
						|
    m.processTypes[-1], // passing a wrong type to force 'undefined', it should
 | 
						|
    m.CRASH_TYPE_CRASH, // fail in the end and not record it
 | 
						|
    "wrong-content-crash",
 | 
						|
    DUMMY_DATE
 | 
						|
  );
 | 
						|
 | 
						|
  crashes = await m.getCrashes();
 | 
						|
  Assert.equal(crashes.length, 0);
 | 
						|
});
 | 
						|
 | 
						|
add_task(async function test_telemetryHistogram() {
 | 
						|
  let Telemetry = Services.telemetry;
 | 
						|
  let h = Telemetry.getKeyedHistogramById("PROCESS_CRASH_SUBMIT_ATTEMPT");
 | 
						|
  h.clear();
 | 
						|
  Telemetry.clearScalars();
 | 
						|
 | 
						|
  let m = await getManager();
 | 
						|
  let processTypes = [];
 | 
						|
  let crashTypes = [];
 | 
						|
 | 
						|
  // Gather all process types
 | 
						|
  for (let field in m.processTypes) {
 | 
						|
    if (m.isPingAllowed(m.processTypes[field])) {
 | 
						|
      processTypes.push(m.processTypes[field]);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // Gather all crash types
 | 
						|
  for (let field in m) {
 | 
						|
    if (field.startsWith("CRASH_TYPE_")) {
 | 
						|
      crashTypes.push(m[field]);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  let keysCount = 0;
 | 
						|
  let keys = [];
 | 
						|
 | 
						|
  for (let processType of processTypes) {
 | 
						|
    for (let crashType of crashTypes) {
 | 
						|
      let key = processType + "-" + crashType;
 | 
						|
 | 
						|
      keys.push(key);
 | 
						|
      h.add(key, 1);
 | 
						|
      keysCount++;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // Ensure that we have generated some crash, otherwise it could indicate
 | 
						|
  // something silently regressing
 | 
						|
  Assert.greater(keysCount, 2);
 | 
						|
 | 
						|
  // Check that we have the expected keys.
 | 
						|
  let snap = h.snapshot();
 | 
						|
  Assert.equal(
 | 
						|
    Object.keys(snap).length,
 | 
						|
    keysCount,
 | 
						|
    "Some crash types have not been recorded, see the list in Histograms.json"
 | 
						|
  );
 | 
						|
  Assert.deepEqual(
 | 
						|
    Object.keys(snap).sort(),
 | 
						|
    keys.sort(),
 | 
						|
    "Some crash types do not match"
 | 
						|
  );
 | 
						|
});
 | 
						|
 | 
						|
// Test that a ping with `CrashPingUUID` in the metadata (as set by the
 | 
						|
// external crash reporter) is sent with Glean but not with Telemetry (because
 | 
						|
// the crash reporter already sends it using Telemetry).
 | 
						|
add_task(async function test_crash_reporter_ping_with_uuid() {
 | 
						|
  let m = await getManager();
 | 
						|
 | 
						|
  let id = await m.createDummyDump();
 | 
						|
 | 
						|
  // Realistically this case will only happen through
 | 
						|
  // `_handleEventFilePayload`, however the `_sendCrashPing` method will check
 | 
						|
  // for it regardless of where it is called.
 | 
						|
  let metadata = { CrashPingUUID: "bff6bde4-f96c-4859-8c56-6b3f40878c26" };
 | 
						|
 | 
						|
  // Glean hooks
 | 
						|
  let glean_submitted = false;
 | 
						|
  GleanPings.crash.testBeforeNextSubmit(_ => {
 | 
						|
    glean_submitted = true;
 | 
						|
  });
 | 
						|
 | 
						|
  await m.addCrash(
 | 
						|
    m.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT],
 | 
						|
    m.CRASH_TYPE_CRASH,
 | 
						|
    id,
 | 
						|
    DUMMY_DATE,
 | 
						|
    metadata
 | 
						|
  );
 | 
						|
 | 
						|
  // Ping promise is only set if the Telemetry ping is submitted.
 | 
						|
  let telemetry_submitted = !!m._pingPromise;
 | 
						|
 | 
						|
  Assert.ok(glean_submitted);
 | 
						|
  Assert.ok(!telemetry_submitted);
 | 
						|
});
 |