/* 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() { AddonWatcher.uninit(); 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 ready = new Promise((resolve, reject) => installer.addListener({ onInstallEnded: (_, addon) => resolve(addon), onInstallFailed: reject, onDownloadFailed: reject })); installer.install(); info("Waiting for installation to terminate"); let addon = yield ready; registerCleanupFunction(() => { info("Uninstalling test add-on"); addon.uninstall() }); Preferences.set("browser.addon-watch.warmup-ms", 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.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.occurrences-between-alerts", "browser.addon-watch.delay-between-alerts-ms", "browser.addon-watch.max-simultaneous-reports" ]) { Preferences.reset(k); } }); let oldCanRecord = Services.telemetry.canRecordExtended; Services.telemetry.canRecordExtended = true; registerCleanupFunction(function () { 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}) { try { info("Preparing add-on watcher"); let detected = false; AddonWatcher.init(id => { Assert.equal(id, ADDON_ID, "The add-on watcher has detected the misbehaving addon"); detected = true; }); 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 { if (typeof AddonWatcher != "undefined") { // If the test fails, we may end up with `AddonWatcher` being undefined // here. Let's not make logs harder to parse. AddonWatcher.uninit(); } } }); // 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, }); });