summaryrefslogtreecommitdiffstats
path: root/toolkit/components/perfmonitoring/tests/browser/browser_AddonWatcher.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/perfmonitoring/tests/browser/browser_AddonWatcher.js')
-rw-r--r--toolkit/components/perfmonitoring/tests/browser/browser_AddonWatcher.js151
1 files changed, 151 insertions, 0 deletions
diff --git a/toolkit/components/perfmonitoring/tests/browser/browser_AddonWatcher.js b/toolkit/components/perfmonitoring/tests/browser/browser_AddonWatcher.js
new file mode 100644
index 000000000..b4e80faa7
--- /dev/null
+++ b/toolkit/components/perfmonitoring/tests/browser/browser_AddonWatcher.js
@@ -0,0 +1,151 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests for AddonWatcher.jsm
+
+"use strict";
+
+requestLongerTimeout(2);
+
+Cu.import("resource://gre/modules/Promise.jsm", this);
+Cu.import("resource://gre/modules/AddonManager.jsm", this);
+Cu.import("resource://gre/modules/Services.jsm", this);
+
+const ADDON_URL = "http://example.com/browser/toolkit/components/perfmonitoring/tests/browser/browser_Addons_sample.xpi";
+const ADDON_ID = "addonwatcher-test@mozilla.com";
+
+add_task(function* init() {
+ info("Installing test add-on");
+ let installer = yield new Promise(resolve => AddonManager.getInstallForURL(ADDON_URL, resolve, "application/x-xpinstall"));
+ if (installer.error) {
+ throw installer.error;
+ }
+ let installed = new Promise((resolve, reject) => installer.addListener({
+ onInstallEnded: (_, addon) => resolve(addon),
+ onInstallFailed: reject,
+ onDownloadFailed: reject
+ }));
+
+ // We also need to wait for the add-on to report that it's ready
+ // to be used in the test.
+ let ready = TestUtils.topicObserved("test-addonwatcher-ready");
+ installer.install();
+
+ info("Waiting for installation to terminate");
+ let addon = yield installed;
+
+ yield ready;
+
+ registerCleanupFunction(() => {
+ info("Uninstalling test add-on");
+ addon.uninstall()
+ });
+
+ Preferences.set("browser.addon-watch.warmup-ms", 0);
+ Preferences.set("browser.addon-watch.freeze-threshold-micros", 0);
+ Preferences.set("browser.addon-watch.jank-threshold-micros", 0);
+ Preferences.set("browser.addon-watch.occurrences-between-alerts", 0);
+ Preferences.set("browser.addon-watch.delay-between-alerts-ms", 0);
+ Preferences.set("browser.addon-watch.delay-between-freeze-alerts-ms", 0);
+ Preferences.set("browser.addon-watch.max-simultaneous-reports", 10000);
+ Preferences.set("browser.addon-watch.deactivate-after-idle-ms", 100000000);
+ registerCleanupFunction(() => {
+ for (let k of [
+ "browser.addon-watch.warmup-ms",
+ "browser.addon-watch.freeze-threshold-micros",
+ "browser.addon-watch.jank-threshold-micros",
+ "browser.addon-watch.occurrences-between-alerts",
+ "browser.addon-watch.delay-between-alerts-ms",
+ "browser.addon-watch.delay-between-freeze-alerts-ms",
+ "browser.addon-watch.max-simultaneous-reports",
+ "browser.addon-watch.deactivate-after-idle-ms"
+ ]) {
+ Preferences.reset(k);
+ }
+ });
+
+ let oldCanRecord = Services.telemetry.canRecordExtended;
+ Services.telemetry.canRecordExtended = true;
+ AddonWatcher.init();
+
+ registerCleanupFunction(function () {
+ AddonWatcher.paused = true;
+ Services.telemetry.canRecordExtended = oldCanRecord;
+ });
+});
+
+// Utility function to burn some resource, trigger a reaction of the add-on watcher
+// and check both its notification and telemetry.
+let burn_rubber = Task.async(function*({histogramName, topic, expectedMinSum}) {
+ let detected = false;
+ let observer = (_, topic, id) => {
+ Assert.equal(id, ADDON_ID, "The add-on watcher has detected the misbehaving addon");
+ detected = true;
+ };
+
+ try {
+ info("Preparing add-on watcher");
+
+ Services.obs.addObserver(observer, AddonWatcher.TOPIC_SLOW_ADDON_DETECTED, false);
+
+ let histogram = Services.telemetry.getKeyedHistogramById(histogramName);
+ histogram.clear();
+ let snap1 = histogram.snapshot(ADDON_ID);
+ Assert.equal(snap1.sum, 0, `Histogram ${histogramName} is initially empty for the add-on`);
+
+ let histogramUpdated = false;
+ do {
+ info(`Burning some CPU with ${topic}. This should cause an add-on watcher notification`);
+ yield new Promise(resolve => setTimeout(resolve, 100));
+ Services.obs.notifyObservers(null, topic, "");
+ yield new Promise(resolve => setTimeout(resolve, 100));
+
+ let snap2 = histogram.snapshot(ADDON_ID);
+ histogramUpdated = snap2.sum > 0;
+ info(`For the moment, histogram ${histogramName} shows ${snap2.sum} => ${histogramUpdated}`);
+ info(`For the moment, we have ${detected?"":"NOT "}detected the slow add-on`);
+ } while (!histogramUpdated || !detected);
+
+ let snap3 = histogram.snapshot(ADDON_ID);
+ Assert.ok(snap3.sum >= expectedMinSum, `Histogram ${histogramName} recorded a gravity of ${snap3.sum}, expecting at least ${expectedMinSum}.`);
+ } finally {
+ Services.obs.removeObserver(observer, AddonWatcher.TOPIC_SLOW_ADDON_DETECTED);
+ }
+});
+
+// Test that burning CPU will cause the add-on watcher to notice that
+// the add-on is misbehaving.
+add_task(function* test_burn_CPU() {
+ yield burn_rubber({
+ histogramName: "PERF_MONITORING_SLOW_ADDON_JANK_US",
+ topic: "test-addonwatcher-burn-some-cpu",
+ expectedMinSum: 7,
+ });
+});
+
+// Test that burning content CPU will cause the add-on watcher to notice that
+// the add-on is misbehaving.
+/*
+Blocked by bug 1227283.
+add_task(function* test_burn_content_CPU() {
+ yield burn_rubber({
+ histogramName: "PERF_MONITORING_SLOW_ADDON_JANK_US",
+ topic: "test-addonwatcher-burn-some-content-cpu",
+ expectedMinSum: 7,
+ });
+});
+*/
+
+// Test that burning CPOW will cause the add-on watcher to notice that
+// the add-on is misbehaving.
+add_task(function* test_burn_CPOW() {
+ if (!gMultiProcessBrowser) {
+ info("This is a single-process Firefox, we can't test for CPOW");
+ return;
+ }
+ yield burn_rubber({
+ histogramName: "PERF_MONITORING_SLOW_ADDON_CPOW_US",
+ topic: "test-addonwatcher-burn-some-cpow",
+ expectedMinSum: 400,
+ });
+});