summaryrefslogtreecommitdiffstats
path: root/toolkit/components/terminator/tests
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/terminator/tests')
-rw-r--r--toolkit/components/terminator/tests/xpcshell/test_terminator_record.js152
-rw-r--r--toolkit/components/terminator/tests/xpcshell/test_terminator_reload.js88
-rw-r--r--toolkit/components/terminator/tests/xpcshell/xpcshell.ini9
3 files changed, 249 insertions, 0 deletions
diff --git a/toolkit/components/terminator/tests/xpcshell/test_terminator_record.js b/toolkit/components/terminator/tests/xpcshell/test_terminator_record.js
new file mode 100644
index 0000000000..e78c427902
--- /dev/null
+++ b/toolkit/components/terminator/tests/xpcshell/test_terminator_record.js
@@ -0,0 +1,152 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+/* eslint-disable mozilla/no-arbitrary-setTimeout */
+
+"use strict";
+
+// Test that the Shutdown Terminator records durations correctly
+
+const { setTimeout } = ChromeUtils.importESModule(
+ "resource://gre/modules/Timer.sys.mjs"
+);
+
+var PATH;
+var PATH_TMP;
+var terminator;
+
+var HEARTBEAT_MS = 100;
+
+let KEYS = [
+ "quit-application",
+ "profile-change-net-teardown",
+ "profile-change-teardown",
+ "profile-before-change",
+ "profile-before-change-qm",
+ "xpcom-will-shutdown",
+ "xpcom-shutdown",
+ "xpcom-shutdown-threads",
+ "XPCOMShutdownFinal",
+ "CCPostLastCycleCollection",
+];
+
+let DATA = [];
+
+add_task(async function init() {
+ do_get_profile();
+ PATH = PathUtils.join(PathUtils.localProfileDir, "ShutdownDuration.json");
+ PATH_TMP = PATH + ".tmp";
+
+ // Initialize the terminator
+ // (normally, this is done through the manifest file, but xpcshell
+ // doesn't take them into account).
+ info("Initializing the Terminator");
+ terminator = Cc["@mozilla.org/toolkit/shutdown-terminator;1"].createInstance(
+ Ci.nsIObserver
+ );
+});
+
+var promiseShutdownDurationData = async function () {
+ // Wait until PATH exists.
+ // Timeout if it is never created.
+ while (true) {
+ if (await IOUtils.exists(PATH)) {
+ break;
+ }
+
+ // Wait just a very short period to not increase measured values.
+ // Usually the file should appear almost immediately.
+ await new Promise(resolve => setTimeout(resolve, 50));
+ }
+
+ return IOUtils.readJSON(PATH);
+};
+
+var currentPhase = 0;
+
+var advancePhase = async function () {
+ let key = "terminator-test-" + KEYS[currentPhase];
+ let msDuration = 200 + HEARTBEAT_MS * currentPhase;
+
+ info("Advancing shutdown phase to " + KEYS[currentPhase]);
+ terminator.observe(null, key, null);
+ await new Promise(resolve => setTimeout(resolve, msDuration));
+
+ let data = await promiseShutdownDurationData();
+
+ Assert.ok(KEYS[currentPhase] in data, "The file contains the expected key");
+ Assert.equal(
+ Object.keys(data).length,
+ currentPhase + 1,
+ "File does not contain more durations than expected"
+ );
+
+ DATA[currentPhase] = data;
+ currentPhase++;
+ if (currentPhase < KEYS.length) {
+ return true;
+ }
+ return false;
+};
+
+add_task(async function test_record() {
+ info("Collecting duration data for all known phases");
+ let morePhases = true;
+ while (morePhases) {
+ morePhases = await advancePhase();
+
+ await IOUtils.remove(PATH);
+ await IOUtils.remove(PATH_TMP);
+ }
+
+ Assert.equal(DATA.length, KEYS.length, "We have data for each phase");
+
+ for (let i = 0; i < KEYS.length; i++) {
+ let lastDuration = DATA[KEYS.length - 1][KEYS[i]];
+ Assert.equal(
+ typeof lastDuration,
+ "number",
+ "Duration of phase " + i + ":" + KEYS[i] + " is a number"
+ );
+
+ // The durations are only meaningful after we advanced to the next phase.
+ if (i < KEYS.length - 1) {
+ // So we read it from the data written for the following phase.
+ let ticksDuration = DATA[i + 1][KEYS[i]];
+ let msNominalDuration = 200 + HEARTBEAT_MS * i;
+ Assert.lessOrEqual(
+ ticksDuration,
+ Math.ceil(msNominalDuration / HEARTBEAT_MS) + 1,
+ "Duration of phase " + i + ":" + KEYS[i] + " is not too long"
+ );
+ // It seems that the heartbeat based measure is not very accurate
+ // (ticks tend to be less than expected), so we give us some tolerance.
+ // See bug 1768795.
+ let halfNominalTicks = Math.floor(msNominalDuration / 2 / HEARTBEAT_MS);
+ Assert.greaterOrEqual(
+ ticksDuration,
+ halfNominalTicks,
+ "Duration of phase " + i + ":" + KEYS[i] + " is not too short"
+ );
+ }
+ // This check is done only for phases <= xpcom-shutdown-threads
+ // where we have two data points.
+ if (i < KEYS.length - 2) {
+ let ticksDuration = DATA[i + 1][KEYS[i]];
+ Assert.equal(
+ ticksDuration,
+ DATA[KEYS.length - 1][KEYS[i]],
+ "Duration of phase " + i + ":" + KEYS[i] + " hasn't changed"
+ );
+ }
+ }
+
+ // Note that after this check the KEYS array remains sorted, so this
+ // must be the last check to not get confused.
+ Assert.equal(
+ Object.keys(DATA[KEYS.length - 1])
+ .sort()
+ .join(", "),
+ KEYS.sort().join(", "),
+ "The last file contains all expected keys"
+ );
+});
diff --git a/toolkit/components/terminator/tests/xpcshell/test_terminator_reload.js b/toolkit/components/terminator/tests/xpcshell/test_terminator_reload.js
new file mode 100644
index 0000000000..79aecd818b
--- /dev/null
+++ b/toolkit/components/terminator/tests/xpcshell/test_terminator_reload.js
@@ -0,0 +1,88 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that the Shutdown Terminator reloads durations correctly
+
+const HISTOGRAMS = {
+ "quit-application": "SHUTDOWN_PHASE_DURATION_TICKS_QUIT_APPLICATION",
+ "profile-change-net-teardown":
+ "SHUTDOWN_PHASE_DURATION_TICKS_PROFILE_CHANGE_NET_TEARDOWN",
+ "profile-change-teardown":
+ "SHUTDOWN_PHASE_DURATION_TICKS_PROFILE_CHANGE_TEARDOWN",
+ "profile-before-change":
+ "SHUTDOWN_PHASE_DURATION_TICKS_PROFILE_BEFORE_CHANGE",
+ "profile-before-change-qm":
+ "SHUTDOWN_PHASE_DURATION_TICKS_PROFILE_BEFORE_CHANGE_QM",
+ "xpcom-will-shutdown": "SHUTDOWN_PHASE_DURATION_TICKS_XPCOM_WILL_SHUTDOWN",
+ "xpcom-shutdown": "SHUTDOWN_PHASE_DURATION_TICKS_XPCOM_SHUTDOWN",
+};
+
+let PATH;
+
+add_setup(async function init() {
+ do_get_profile();
+ PATH = PathUtils.join(PathUtils.localProfileDir, "ShutdownDuration.json");
+});
+
+add_task(async function test_reload() {
+ info("Forging data");
+ let data = {};
+ let telemetrySnapshots = Services.telemetry.getSnapshotForHistograms(
+ "main",
+ false /* clear */
+ ).parent;
+ let i = 0;
+ for (let k of Object.keys(HISTOGRAMS)) {
+ let id = HISTOGRAMS[k];
+ data[k] = i++;
+ Assert.equal(
+ telemetrySnapshots[id] || undefined,
+ undefined,
+ "Histogram " + id + " is empty"
+ );
+ }
+
+ // Extra fields that nsTerminator reports that we do not have histograms for.
+ data["xpcom-shutdown-threads"] = 123;
+ data.XPCOMShutdownFinal = 456;
+ data.CCPostLastCycleCollection = 789;
+
+ await IOUtils.writeJSON(PATH, data);
+
+ const TOPIC = "shutdown-terminator-telemetry-updated";
+
+ let wait = new Promise(resolve =>
+ Services.obs.addObserver(function observer() {
+ info("Telemetry has been updated");
+ Services.obs.removeObserver(observer, TOPIC);
+ resolve();
+ }, TOPIC)
+ );
+
+ info("Starting nsTerminatorTelemetry");
+ let tt = Cc[
+ "@mozilla.org/toolkit/shutdown-terminator-telemetry;1"
+ ].createInstance(Ci.nsIObserver);
+ tt.observe(null, "profile-after-change", "");
+
+ info("Waiting until telemetry is updated");
+ // Now wait until Telemetry is updated
+ await wait;
+
+ telemetrySnapshots = Services.telemetry.getSnapshotForHistograms(
+ "main",
+ false /* clear */
+ ).parent;
+ for (let k of Object.keys(HISTOGRAMS)) {
+ let id = HISTOGRAMS[k];
+ info("Testing histogram " + id);
+ let snapshot = telemetrySnapshots[id];
+ let count = 0;
+ for (let x of Object.values(snapshot.values)) {
+ count += x;
+ }
+ Assert.equal(count, 1, "We have added one item");
+ }
+});
diff --git a/toolkit/components/terminator/tests/xpcshell/xpcshell.ini b/toolkit/components/terminator/tests/xpcshell/xpcshell.ini
new file mode 100644
index 0000000000..d1594da0db
--- /dev/null
+++ b/toolkit/components/terminator/tests/xpcshell/xpcshell.ini
@@ -0,0 +1,9 @@
+[DEFAULT]
+head=
+
+[test_terminator_record.js]
+skip-if = debug || asan || ccov || tsan # Disabled by bug 1242084, bug 1255484 will enable it again. Bug 1607583 tracks the ccov failure. Bug 1683730 made this timeout for tsan.
+run-sequentially = very high failure rate in parallel
+[test_terminator_reload.js]
+skip-if = os == "android"
+run-sequentially = very high failure rate in parallel