mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-08 08:17:31 +09:00
Issue #439 - Remove tests from toolkit/
This commit is contained in:
parent
3210cc7d95
commit
e5bacc6f6e
2362 changed files with 95 additions and 246993 deletions
|
|
@ -4,10 +4,16 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['tests/browser/browser.ini']
|
||||
|
||||
XPIDL_MODULE = 'toolkit_perfmonitoring'
|
||||
|
||||
XPIDL_SOURCES += ['nsIPerformanceStats.idl']
|
||||
|
||||
EXPORTS += ['nsPerformanceStats.h']
|
||||
|
||||
LOCAL_INCLUDES += ['/dom/base']
|
||||
|
||||
UNIFIED_SOURCES += ['nsPerformanceStats.cpp']
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'AddonWatcher.jsm',
|
||||
'PerformanceStats-content.js',
|
||||
|
|
@ -16,20 +22,4 @@ EXTRA_JS_MODULES += [
|
|||
'PerformanceWatcher.jsm',
|
||||
]
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIPerformanceStats.idl',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'nsPerformanceStats.cpp'
|
||||
]
|
||||
|
||||
EXPORTS += [
|
||||
'nsPerformanceStats.h'
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/dom/base',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
|
|
|||
|
|
@ -1,7 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"../../../../../testing/mochitest/browser.eslintrc.js"
|
||||
]
|
||||
};
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
[DEFAULT]
|
||||
head = head.js
|
||||
tags = addons
|
||||
support-files =
|
||||
browser_Addons_sample.xpi
|
||||
browser_compartments.html
|
||||
browser_compartments_frame.html
|
||||
browser_compartments_script.js
|
||||
|
||||
[browser_AddonWatcher.js]
|
||||
[browser_compartments.js]
|
||||
skip-if = os == "linux" && !debug && e10s # Bug 1230018
|
||||
[browser_addonPerformanceAlerts.js]
|
||||
[browser_addonPerformanceAlerts_2.js]
|
||||
[browser_webpagePerformanceAlerts.js]
|
||||
|
|
@ -1,151 +0,0 @@
|
|||
/* 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,
|
||||
});
|
||||
});
|
||||
Binary file not shown.
|
|
@ -1,105 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Sample for browser_AddonWatcher.js
|
||||
|
||||
"use strict";
|
||||
|
||||
const {utils: Cu, classes: Cc, interfaces: Ci} = Components;
|
||||
|
||||
const TOPIC_BURNCPU = "test-addonwatcher-burn-some-cpu";
|
||||
const TOPIC_BURNCPOW = "test-addonwatcher-burn-some-cpow";
|
||||
const TOPIC_BURNCONTENTCPU = "test-addonwatcher-burn-some-content-cpu";
|
||||
const TOPIC_READY = "test-addonwatcher-ready";
|
||||
|
||||
const MESSAGE_BURNCPOW = "test-addonwatcher-cpow:init";
|
||||
const URL_FRAMESCRIPT = "chrome://addonwatcher-test/content/framescript.js";
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm", this);
|
||||
const { setTimeout } = Cu.import("resource://gre/modules/Timer.jsm", {});
|
||||
Cu.import("resource://gre/modules/Task.jsm", this);
|
||||
|
||||
let globalMM = Cc["@mozilla.org/globalmessagemanager;1"]
|
||||
.getService(Ci.nsIMessageListenerManager);
|
||||
|
||||
/**
|
||||
* Spend some time using CPU.
|
||||
*/
|
||||
function burnCPU() {
|
||||
let ignored = [];
|
||||
let start = Date.now();
|
||||
let i = 0;
|
||||
while (Date.now() - start < 1000) {
|
||||
ignored[i++ % 2] = i;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Spend some time in CPOW.
|
||||
*/
|
||||
function burnCPOW() {
|
||||
gBurnCPOW();
|
||||
}
|
||||
let gBurnCPOW = null;
|
||||
|
||||
function burnContentCPU() {
|
||||
setTimeout(() => { try {
|
||||
gBurnContentCPU()
|
||||
} catch (ex) {
|
||||
dump(`test-addon error: ${ex}\n`);
|
||||
} }, 0);
|
||||
}
|
||||
let gBurnContentCPU = null;
|
||||
|
||||
let gTab = null;
|
||||
let gTabBrowser = null;
|
||||
|
||||
function startup() {
|
||||
Services.obs.addObserver(burnCPU, TOPIC_BURNCPU, false);
|
||||
Services.obs.addObserver(burnCPOW, TOPIC_BURNCPOW, false);
|
||||
Services.obs.addObserver(burnContentCPU, TOPIC_BURNCONTENTCPU, false);
|
||||
|
||||
let windows = Services.wm.getEnumerator("navigator:browser");
|
||||
let win = windows.getNext();
|
||||
gTabBrowser = win.gBrowser;
|
||||
gTab = gTabBrowser.addTab("about:robots");
|
||||
gBurnContentCPU = function() {
|
||||
gTab.linkedBrowser.messageManager.sendAsyncMessage("test-addonwatcher-burn-some-content-cpu", {});
|
||||
}
|
||||
|
||||
gTab.linkedBrowser.messageManager.loadFrameScript(URL_FRAMESCRIPT, false);
|
||||
globalMM.loadFrameScript(URL_FRAMESCRIPT, false);
|
||||
|
||||
if (Services.appinfo.browserTabsRemoteAutostart) {
|
||||
// This profile has e10s enabled, which means we'll want to
|
||||
// test CPOW traffic.
|
||||
globalMM.addMessageListener("test-addonwatcher-cpow:init", function waitForCPOW(msg) {
|
||||
if (Components.utils.isCrossProcessWrapper(msg.objects.burnCPOW)) {
|
||||
gBurnCPOW = msg.objects.burnCPOW;
|
||||
globalMM.removeMessageListener("test-addonwatcher-cpow:init", waitForCPOW);
|
||||
Services.obs.notifyObservers(null, TOPIC_READY, null);
|
||||
} else {
|
||||
Cu.reportError("test-addonwatcher-cpow:init didn't give us a CPOW! Expect timeouts.");
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// e10s is not enabled, so a CPOW is not necessary - we can report ready
|
||||
// right away.
|
||||
Services.obs.notifyObservers(null, TOPIC_READY, null);
|
||||
}
|
||||
}
|
||||
|
||||
function shutdown() {
|
||||
Services.obs.removeObserver(burnCPU, TOPIC_BURNCPU);
|
||||
Services.obs.removeObserver(burnCPOW, TOPIC_BURNCPOW);
|
||||
Services.obs.removeObserver(burnContentCPU, TOPIC_BURNCONTENTCPU);
|
||||
gTabBrowser.removeTab(gTab);
|
||||
}
|
||||
|
||||
function install() {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
function uninstall() {
|
||||
// Nothing to do
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
echo "Rebuilding browser_Addons_sample.xpi..."
|
||||
zip -r ../browser_Addons_sample.xpi .
|
||||
echo "
|
||||
Done! Don't forget to sign it: https://wiki.mozilla.org/EngineeringProductivity/HowTo/SignExtensions"
|
||||
|
|
@ -1 +0,0 @@
|
|||
content addonwatcher-test content/
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
function burnCPOW(msg) {
|
||||
dump(`Addon: content burnCPU start ${Math.sin(Math.random())}\n`);
|
||||
let start = content.performance.now();
|
||||
let ignored = [];
|
||||
while (content.performance.now() - start < 5000) {
|
||||
ignored[ignored.length % 2] = ignored.length;
|
||||
}
|
||||
dump(`Addon: content burnCPU done: ${content.performance.now() - start}\n`);
|
||||
}
|
||||
|
||||
if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
|
||||
sendAsyncMessage("test-addonwatcher-cpow:init", {}, {burnCPOW});
|
||||
}
|
||||
|
||||
addMessageListener("test-addonwatcher-burn-some-content-cpu", burnCPOW);
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
|
||||
<Description about="urn:mozilla:install-manifest">
|
||||
<em:id>addonwatcher-test@mozilla.com</em:id>
|
||||
<em:version>1.1</em:version>
|
||||
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
|
||||
<em:minVersion>0.3</em:minVersion>
|
||||
<em:maxVersion>*</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>toolkit@mozilla.org</em:id>
|
||||
<em:minVersion>1</em:minVersion>
|
||||
<em:maxVersion>*</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
|
||||
<em:bootstrap>true</em:bootstrap>
|
||||
|
||||
<em:name>Sample for browser_AddonWatcher.js</em:name>
|
||||
|
||||
</Description>
|
||||
</RDF>
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
/**
|
||||
* Tests for PerformanceWatcher watching slow addons.
|
||||
*/
|
||||
|
||||
add_task(function* init() {
|
||||
// Get rid of buffering.
|
||||
let service = Cc["@mozilla.org/toolkit/performance-stats-service;1"].getService(
|
||||
Ci.nsIPerformanceStatsService);
|
||||
let oldDelay = service.jankAlertBufferingDelay;
|
||||
|
||||
service.jankAlertBufferingDelay = 0 /* ms */;
|
||||
registerCleanupFunction(() => {
|
||||
info("Cleanup");
|
||||
service.jankAlertBufferingDelay = oldDelay;
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function* test_install_addon_then_watch_it() {
|
||||
for (let topic of ["burnCPU", "promiseBurnContentCPU", "promiseBurnCPOW"]) {
|
||||
info(`Starting subtest ${topic}`);
|
||||
info("Spawning fake add-on, making sure that the compartment is initialized");
|
||||
let addon = new AddonBurner();
|
||||
yield addon.promiseInitialized;
|
||||
addon.burnCPU();
|
||||
|
||||
info(`Check that burning CPU triggers the real listener, but not the fake listener ${topic}`);
|
||||
let realListener = new AddonListener(addon.addonId, (group, details) => {
|
||||
if (group.addonId == addon.addonId) {
|
||||
return details.highestJank;
|
||||
}
|
||||
throw new Error(`I shouldn't have been called with addon ${group.addonId}`);
|
||||
});
|
||||
let fakeListener = new AddonListener(addon.addonId + "-fake-" + Math.random(), group => true); // This listener should never be triggered.
|
||||
let universalListener = new AddonListener("*", alerts => {
|
||||
info(`AddonListener: received alerts ${JSON.stringify(alerts)}`);
|
||||
let alert = alerts.find(({source}) => {
|
||||
return source.addonId == addon.addonId;
|
||||
});
|
||||
if (alert) {
|
||||
info(`AddonListener: I found an alert for ${addon.addonId}`);
|
||||
return alert.details.highestJank;
|
||||
}
|
||||
info(`AddonListener: I didn't find any alert for ${addon.addonId}`);
|
||||
return null;
|
||||
});
|
||||
|
||||
// Waiting a little – listeners are buffered.
|
||||
yield new Promise(resolve => setTimeout(resolve, 100));
|
||||
yield addon.run(topic, 10, realListener);
|
||||
// Waiting a little – listeners are buffered.
|
||||
yield new Promise(resolve => setTimeout(resolve, 100));
|
||||
|
||||
Assert.ok(realListener.triggered, `1. The real listener was triggered ${topic}`);
|
||||
Assert.ok(universalListener.triggered, `1. The universal listener was triggered ${topic}`);
|
||||
Assert.ok(!fakeListener.triggered, `1. The fake listener was not triggered ${topic}`);
|
||||
Assert.ok(realListener.result >= addon.jankThreshold, `1. jank is at least ${addon.jankThreshold/1000}ms (${realListener.result/1000}ms) ${topic}`);
|
||||
|
||||
info(`Attempting to remove a performance listener incorrectly, check that this does not hurt our real listener ${topic}`);
|
||||
Assert.throws(() => PerformanceWatcher.removePerformanceListener({addonId: addon.addonId}, () => {}));
|
||||
Assert.throws(() => PerformanceWatcher.removePerformanceListener({addonId: addon.addonId + "-unbound-id-" + Math.random()}, realListener.listener));
|
||||
|
||||
yield addon.run(topic, 10, realListener);
|
||||
// Waiting a little – listeners are buffered.
|
||||
yield new Promise(resolve => setTimeout(resolve, 300));
|
||||
|
||||
Assert.ok(realListener.triggered, `2. The real listener was triggered ${topic}`);
|
||||
Assert.ok(universalListener.triggered, `2. The universal listener was triggered ${topic}`);
|
||||
Assert.ok(!fakeListener.triggered, `2. The fake listener was not triggered ${topic}`);
|
||||
Assert.ok(realListener.result >= 200000, `2. jank is at least 300ms (${realListener.result/1000}ms) ${topic}`);
|
||||
|
||||
info(`Attempting to remove correctly, check if the listener is still triggered ${topic}`);
|
||||
realListener.unregister();
|
||||
yield addon.run(topic, 3, realListener);
|
||||
Assert.ok(!realListener.triggered, `3. After being unregistered, the real listener was not triggered ${topic}`);
|
||||
Assert.ok(universalListener.triggered, `3. The universal listener is still triggered ${topic}`);
|
||||
|
||||
info("Unregistering universal listener");
|
||||
// Waiting a little – listeners are buffered.
|
||||
yield new Promise(resolve => setTimeout(resolve, 100));
|
||||
universalListener.unregister();
|
||||
// Waiting a little – listeners are buffered.
|
||||
yield new Promise(resolve => setTimeout(resolve, 100));
|
||||
yield addon.run(topic, 3, realListener);
|
||||
Assert.ok(!universalListener.triggered, `4. After being unregistered, the universal listener is not triggered ${topic}`);
|
||||
|
||||
fakeListener.unregister();
|
||||
addon.dispose();
|
||||
}
|
||||
});
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
/**
|
||||
* Tests for PerformanceWatcher watching slow addons.
|
||||
*/
|
||||
|
||||
add_task(function* test_watch_addon_then_install_it() {
|
||||
for (let topic of ["burnCPU", "promiseBurnContentCPU", "promiseBurnCPOW"]) {
|
||||
let addonId = "addon:test_watch_addons_before_installing" + Math.random();
|
||||
let realListener = new AddonListener(addonId, (group, details) => {
|
||||
if (group.addonId == addonId) {
|
||||
return details.highestJank;
|
||||
}
|
||||
throw new Error(`I shouldn't have been called with addon ${group.addonId}`);
|
||||
});
|
||||
|
||||
info("Now install the add-on, *after* having installed the listener");
|
||||
let addon = new AddonBurner(addonId);
|
||||
|
||||
Assert.ok((yield addon.run(topic, 10, realListener)), `5. The real listener was triggered ${topic}`);
|
||||
Assert.ok(realListener.result >= addon.jankThreshold, `5. jank is at least ${addon.jankThreshold/1000}ms (${realListener.result}µs) ${topic}`);
|
||||
realListener.unregister();
|
||||
addon.dispose();
|
||||
}
|
||||
});
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
Main frame for test browser_compartments.js
|
||||
</title>
|
||||
</head>
|
||||
<body>
|
||||
Main frame.
|
||||
|
||||
<iframe src="browser_compartments_frame.html?frame=1">
|
||||
Subframe 1
|
||||
</iframe>
|
||||
|
||||
<iframe src="browser_compartments_frame.html?frame=2">
|
||||
Subframe 2.
|
||||
</iframe>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,312 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Test that we see jank that takes place in a webpage,
|
||||
* and that jank from several iframes are actually charged
|
||||
* to the top window.
|
||||
*/
|
||||
Cu.import("resource://gre/modules/PerformanceStats.jsm", this);
|
||||
Cu.import("resource://gre/modules/Services.jsm", this);
|
||||
Cu.import("resource://testing-common/ContentTask.jsm", this);
|
||||
|
||||
|
||||
const URL = "http://example.com/browser/toolkit/components/perfmonitoring/tests/browser/browser_compartments.html?test=" + Math.random();
|
||||
const PARENT_TITLE = `Main frame for test browser_compartments.js ${Math.random()}`;
|
||||
const FRAME_TITLE = `Subframe for test browser_compartments.js ${Math.random()}`;
|
||||
|
||||
const PARENT_PID = Services.appinfo.processID;
|
||||
|
||||
// This function is injected as source as a frameScript
|
||||
function frameScript() {
|
||||
try {
|
||||
"use strict";
|
||||
|
||||
const { utils: Cu, classes: Cc, interfaces: Ci } = Components;
|
||||
Cu.import("resource://gre/modules/PerformanceStats.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
// Make sure that the stopwatch is now active.
|
||||
let monitor = PerformanceStats.getMonitor(["jank", "cpow", "ticks", "compartments"]);
|
||||
|
||||
addMessageListener("compartments-test:getStatistics", () => {
|
||||
try {
|
||||
monitor.promiseSnapshot().then(snapshot => {
|
||||
sendAsyncMessage("compartments-test:getStatistics", {snapshot, pid: Services.appinfo.processID});
|
||||
});
|
||||
} catch (ex) {
|
||||
Cu.reportError("Error in content (getStatistics): " + ex);
|
||||
Cu.reportError(ex.stack);
|
||||
}
|
||||
});
|
||||
|
||||
addMessageListener("compartments-test:setTitles", titles => {
|
||||
try {
|
||||
content.document.title = titles.data.parent;
|
||||
for (let i = 0; i < content.frames.length; ++i) {
|
||||
content.frames[i].postMessage({title: titles.data.frames}, "*");
|
||||
}
|
||||
console.log("content", "Done setting titles", content.document.title);
|
||||
sendAsyncMessage("compartments-test:setTitles");
|
||||
} catch (ex) {
|
||||
Cu.reportError("Error in content (setTitles): " + ex);
|
||||
Cu.reportError(ex.stack);
|
||||
}
|
||||
});
|
||||
} catch (ex) {
|
||||
Cu.reportError("Error in content (setup): " + ex);
|
||||
Cu.reportError(ex.stack);
|
||||
}
|
||||
}
|
||||
|
||||
// A variant of `Assert` that doesn't spam the logs
|
||||
// in case of success.
|
||||
var SilentAssert = {
|
||||
equal: function(a, b, msg) {
|
||||
if (a == b) {
|
||||
return;
|
||||
}
|
||||
Assert.equal(a, b, msg);
|
||||
},
|
||||
notEqual: function(a, b, msg) {
|
||||
if (a != b) {
|
||||
return;
|
||||
}
|
||||
Assert.notEqual(a, b, msg);
|
||||
},
|
||||
ok: function(a, msg) {
|
||||
if (a) {
|
||||
return;
|
||||
}
|
||||
Assert.ok(a, msg);
|
||||
},
|
||||
leq: function(a, b, msg) {
|
||||
this.ok(a <= b, `${msg}: ${a} <= ${b}`);
|
||||
}
|
||||
};
|
||||
|
||||
var isShuttingDown = false;
|
||||
function monotinicity_tester(source, testName) {
|
||||
// In the background, check invariants:
|
||||
// - numeric data can only ever increase;
|
||||
// - the name, addonId, isSystem of a component never changes;
|
||||
// - the name, addonId, isSystem of the process data;
|
||||
// - there is at most one component with a combination of `name` and `addonId`;
|
||||
// - types, etc.
|
||||
let previous = {
|
||||
processData: null,
|
||||
componentsMap: new Map(),
|
||||
};
|
||||
|
||||
let sanityCheck = function(prev, next) {
|
||||
if (prev == null) {
|
||||
return;
|
||||
}
|
||||
for (let k of ["groupId", "addonId", "isSystem"]) {
|
||||
SilentAssert.equal(prev[k], next[k], `Sanity check (${testName}): ${k} hasn't changed (${prev.name}).`);
|
||||
}
|
||||
for (let [probe, k] of [
|
||||
["jank", "totalUserTime"],
|
||||
["jank", "totalSystemTime"],
|
||||
["cpow", "totalCPOWTime"],
|
||||
["ticks", "ticks"]
|
||||
]) {
|
||||
SilentAssert.equal(typeof next[probe][k], "number", `Sanity check (${testName}): ${k} is a number.`);
|
||||
SilentAssert.leq(prev[probe][k], next[probe][k], `Sanity check (${testName}): ${k} is monotonic.`);
|
||||
SilentAssert.leq(0, next[probe][k], `Sanity check (${testName}): ${k} is >= 0.`)
|
||||
}
|
||||
SilentAssert.equal(prev.jank.durations.length, next.jank.durations.length);
|
||||
for (let i = 0; i < next.jank.durations.length; ++i) {
|
||||
SilentAssert.ok(typeof next.jank.durations[i] == "number" && next.jank.durations[i] >= 0,
|
||||
`Sanity check (${testName}): durations[${i}] is a non-negative number.`);
|
||||
SilentAssert.leq(prev.jank.durations[i], next.jank.durations[i],
|
||||
`Sanity check (${testName}): durations[${i}] is monotonic.`);
|
||||
}
|
||||
for (let i = 0; i < next.jank.durations.length - 1; ++i) {
|
||||
SilentAssert.leq(next.jank.durations[i + 1], next.jank.durations[i],
|
||||
`Sanity check (${testName}): durations[${i}] >= durations[${i + 1}].`)
|
||||
}
|
||||
};
|
||||
let iteration = 0;
|
||||
let frameCheck = Task.async(function*() {
|
||||
if (isShuttingDown) {
|
||||
window.clearInterval(interval);
|
||||
return;
|
||||
}
|
||||
let name = `${testName}: ${iteration++}`;
|
||||
let result = yield source();
|
||||
if (!result) {
|
||||
// This can happen at the end of the test when we attempt
|
||||
// to communicate too late with the content process.
|
||||
window.clearInterval(interval);
|
||||
return;
|
||||
}
|
||||
let {pid, snapshot} = result;
|
||||
|
||||
// Sanity check on the process data.
|
||||
sanityCheck(previous.processData, snapshot.processData);
|
||||
SilentAssert.equal(snapshot.processData.isSystem, true);
|
||||
SilentAssert.equal(snapshot.processData.name, "<process>");
|
||||
SilentAssert.equal(snapshot.processData.addonId, "");
|
||||
SilentAssert.equal(snapshot.processData.processId, pid);
|
||||
previous.procesData = snapshot.processData;
|
||||
|
||||
// Sanity check on components data.
|
||||
let map = new Map();
|
||||
for (let item of snapshot.componentsData) {
|
||||
for (let [probe, k] of [
|
||||
["jank", "totalUserTime"],
|
||||
["jank", "totalSystemTime"],
|
||||
["cpow", "totalCPOWTime"]
|
||||
]) {
|
||||
// Note that we cannot expect components data to be always smaller
|
||||
// than process data, as `getrusage` & co are not monotonic.
|
||||
SilentAssert.leq(item[probe][k], 3 * snapshot.processData[probe][k],
|
||||
`Sanity check (${name}): ${k} of component is not impossibly larger than that of process`);
|
||||
}
|
||||
|
||||
let isCorrectPid = (item.processId == pid && !item.isChildProcess)
|
||||
|| (item.processId != pid && item.isChildProcess);
|
||||
SilentAssert.ok(isCorrectPid, `Pid check (${name}): the item comes from the right process`);
|
||||
|
||||
let key = item.groupId;
|
||||
if (map.has(key)) {
|
||||
let old = map.get(key);
|
||||
Assert.ok(false, `Component ${key} has already been seen. Latest: ${item.addonId||item.name}, previous: ${old.addonId||old.name}`);
|
||||
}
|
||||
map.set(key, item);
|
||||
}
|
||||
for (let item of snapshot.componentsData) {
|
||||
if (!item.parentId) {
|
||||
continue;
|
||||
}
|
||||
let parent = map.get(item.parentId);
|
||||
SilentAssert.ok(parent, `The parent exists ${item.parentId}`);
|
||||
|
||||
for (let [probe, k] of [
|
||||
["jank", "totalUserTime"],
|
||||
["jank", "totalSystemTime"],
|
||||
["cpow", "totalCPOWTime"]
|
||||
]) {
|
||||
// Note that we cannot expect components data to be always smaller
|
||||
// than parent data, as `getrusage` & co are not monotonic.
|
||||
SilentAssert.leq(item[probe][k], 2 * parent[probe][k],
|
||||
`Sanity check (${testName}): ${k} of component is not impossibly larger than that of parent`);
|
||||
}
|
||||
}
|
||||
for (let [key, item] of map) {
|
||||
sanityCheck(previous.componentsMap.get(key), item);
|
||||
previous.componentsMap.set(key, item);
|
||||
}
|
||||
});
|
||||
let interval = window.setInterval(frameCheck, 300);
|
||||
registerCleanupFunction(() => {
|
||||
window.clearInterval(interval);
|
||||
});
|
||||
}
|
||||
|
||||
add_task(function* test() {
|
||||
let monitor = PerformanceStats.getMonitor(["jank", "cpow", "ticks"]);
|
||||
|
||||
info("Extracting initial state");
|
||||
let stats0 = yield monitor.promiseSnapshot();
|
||||
Assert.notEqual(stats0.componentsData.length, 0, "There is more than one component");
|
||||
Assert.ok(!stats0.componentsData.find(stat => stat.name.indexOf(URL) != -1),
|
||||
"The url doesn't appear yet");
|
||||
|
||||
let newTab = gBrowser.addTab();
|
||||
let browser = newTab.linkedBrowser;
|
||||
// Setup monitoring in the tab
|
||||
info("Setting up monitoring in the tab");
|
||||
yield ContentTask.spawn(newTab.linkedBrowser, null, frameScript);
|
||||
|
||||
info("Opening URL");
|
||||
newTab.linkedBrowser.loadURI(URL);
|
||||
|
||||
if (Services.sysinfo.getPropertyAsAString("name") == "Windows_NT") {
|
||||
info("Deactivating sanity checks under Windows (bug 1151240)");
|
||||
} else {
|
||||
info("Setting up sanity checks");
|
||||
monotinicity_tester(() => monitor.promiseSnapshot().then(snapshot => ({snapshot, pid: PARENT_PID})), "parent process");
|
||||
monotinicity_tester(() => promiseContentResponseOrNull(browser, "compartments-test:getStatistics", null), "content process" );
|
||||
}
|
||||
|
||||
let skipTotalUserTime = hasLowPrecision();
|
||||
|
||||
|
||||
while (true) {
|
||||
yield new Promise(resolve => setTimeout(resolve, 100));
|
||||
|
||||
// We may have race conditions with DOM loading.
|
||||
// Don't waste too much brainpower here, let's just ask
|
||||
// repeatedly for the title to be changed, until this works.
|
||||
info("Setting titles");
|
||||
yield promiseContentResponse(browser, "compartments-test:setTitles", {
|
||||
parent: PARENT_TITLE,
|
||||
frames: FRAME_TITLE
|
||||
});
|
||||
info("Titles set");
|
||||
|
||||
let {snapshot: stats} = (yield promiseContentResponse(browser, "compartments-test:getStatistics", null));
|
||||
|
||||
// Attach titles to components.
|
||||
let titles = [];
|
||||
let map = new Map();
|
||||
let windows = Services.wm.getEnumerator("navigator:browser");
|
||||
while (windows.hasMoreElements()) {
|
||||
let window = windows.getNext();
|
||||
let tabbrowser = window.gBrowser;
|
||||
for (let browser of tabbrowser.browsers) {
|
||||
let id = browser.outerWindowID; // May be `null` if the browser isn't loaded yet
|
||||
if (id != null) {
|
||||
map.set(id, browser);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (let stat of stats.componentsData) {
|
||||
if (!stat.windowId) {
|
||||
continue;
|
||||
}
|
||||
let browser = map.get(stat.windowId);
|
||||
if (!browser) {
|
||||
continue;
|
||||
}
|
||||
let title = browser.contentTitle;
|
||||
if (title) {
|
||||
stat.title = title;
|
||||
titles.push(title);
|
||||
}
|
||||
}
|
||||
|
||||
// While the webpage consists in three compartments, we should see only
|
||||
// one `PerformanceData` in `componentsData`. Its `name` is undefined
|
||||
// (could be either the main frame or one of its subframes), but its
|
||||
// `title` should be the title of the main frame.
|
||||
info(`Searching for frame title '${FRAME_TITLE}' in ${JSON.stringify(titles)} (I hope not to find it)`);
|
||||
Assert.ok(!titles.includes(FRAME_TITLE), "Searching by title, the frames don't show up in the list of components");
|
||||
|
||||
info(`Searching for window title '${PARENT_TITLE}' in ${JSON.stringify(titles)} (I hope to find it)`);
|
||||
let parent = stats.componentsData.find(x => x.title == PARENT_TITLE);
|
||||
if (!parent) {
|
||||
info("Searching by title, we didn't find the main frame");
|
||||
continue;
|
||||
}
|
||||
info("Found the main frame");
|
||||
|
||||
if (skipTotalUserTime) {
|
||||
info("Not looking for total user time on this platform, we're done");
|
||||
break;
|
||||
} else if (parent.jank.totalUserTime > 1000) {
|
||||
info("Enough CPU time detected, we're done");
|
||||
break;
|
||||
} else {
|
||||
info(`Not enough CPU time detected: ${parent.jank.totalUserTime}`);
|
||||
}
|
||||
}
|
||||
isShuttingDown = true;
|
||||
|
||||
// Cleanup
|
||||
gBrowser.removeTab(newTab, {skipPermitUnload: true});
|
||||
});
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
Subframe for test browser_compartments.html (do not change this title)
|
||||
</title>
|
||||
<script src="browser_compartments_script.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
Subframe loaded.
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
|
||||
var carryOn = true;
|
||||
|
||||
window.addEventListener("message", e => {
|
||||
console.log("frame content", "message", e);
|
||||
if ("title" in e.data) {
|
||||
document.title = e.data.title;
|
||||
}
|
||||
if ("stop" in e.data) {
|
||||
carryOn = false;
|
||||
}
|
||||
});
|
||||
|
||||
// Use some CPU.
|
||||
var interval = window.setInterval(() => {
|
||||
if (!carryOn) {
|
||||
window.clearInterval(interval);
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute an arbitrary value, print it out to make sure that the JS
|
||||
// engine doesn't discard all our computation.
|
||||
var date = Date.now();
|
||||
var array = [];
|
||||
var i = 0;
|
||||
while (Date.now() - date <= 100) {
|
||||
array[i%2] = i++;
|
||||
}
|
||||
}, 300);
|
||||
|
|
@ -1,111 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
/**
|
||||
* Tests for PerformanceWatcher watching slow web pages.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Simulate a slow webpage.
|
||||
*/
|
||||
function WebpageBurner() {
|
||||
CPUBurner.call(this, "http://example.com/browser/toolkit/components/perfmonitoring/tests/browser/browser_compartments.html?test=" + Math.random(), 300000);
|
||||
}
|
||||
WebpageBurner.prototype = Object.create(CPUBurner.prototype);
|
||||
WebpageBurner.prototype.promiseBurnContentCPU = function() {
|
||||
return promiseContentResponse(this._browser, "test-performance-watcher:burn-content-cpu", {});
|
||||
};
|
||||
|
||||
function WebpageListener(windowId, accept) {
|
||||
info(`Creating WebpageListener for ${windowId}`);
|
||||
AlertListener.call(this, accept, {
|
||||
register: () => PerformanceWatcher.addPerformanceListener({windowId}, this.listener),
|
||||
unregister: () => PerformanceWatcher.removePerformanceListener({windowId}, this.listener)
|
||||
});
|
||||
}
|
||||
WebpageListener.prototype = Object.create(AlertListener.prototype);
|
||||
|
||||
add_task(function* init() {
|
||||
// Get rid of buffering.
|
||||
let service = Cc["@mozilla.org/toolkit/performance-stats-service;1"].getService(
|
||||
Ci.nsIPerformanceStatsService);
|
||||
let oldDelay = service.jankAlertBufferingDelay;
|
||||
|
||||
service.jankAlertBufferingDelay = 0 /* ms */;
|
||||
registerCleanupFunction(() => {
|
||||
info("Cleanup");
|
||||
service.jankAlertBufferingDelay = oldDelay;
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function* test_open_window_then_watch_it() {
|
||||
let burner = new WebpageBurner();
|
||||
yield burner.promiseInitialized;
|
||||
yield burner.promiseBurnContentCPU();
|
||||
|
||||
info(`Check that burning CPU triggers the real listener, but not the fake listener`);
|
||||
let realListener = new WebpageListener(burner.windowId, (group, details) => {
|
||||
info(`test: realListener for ${burner.tab.linkedBrowser.outerWindowID}: ${group}, ${details}\n`);
|
||||
Assert.equal(group.windowId, burner.windowId, "We should not receive data meant for another group");
|
||||
return details;
|
||||
}); // This listener should be triggered.
|
||||
|
||||
info(`Creating fake burner`);
|
||||
let otherTab = gBrowser.addTab();
|
||||
yield BrowserTestUtils.browserLoaded(otherTab.linkedBrowser);
|
||||
info(`Check that burning CPU triggers the real listener, but not the fake listener`);
|
||||
let fakeListener = new WebpageListener(otherTab.linkedBrowser.outerWindowID, group => group.windowId == burner.windowId); // This listener should never be triggered.
|
||||
let universalListener = new WebpageListener(0, alerts =>
|
||||
alerts.find(alert => alert.source.windowId == burner.windowId)
|
||||
);
|
||||
|
||||
// Waiting a little – listeners are buffered.
|
||||
yield new Promise(resolve => setTimeout(resolve, 100));
|
||||
|
||||
yield burner.run("promiseBurnContentCPU", 20, realListener);
|
||||
Assert.ok(realListener.triggered, `1. The real listener was triggered`);
|
||||
Assert.ok(universalListener.triggered, `1. The universal listener was triggered`);
|
||||
Assert.ok(!fakeListener.triggered, `1. The fake listener was not triggered`);
|
||||
|
||||
if (realListener.result) {
|
||||
Assert.ok(realListener.result.highestJank >= 300, `1. jank is at least 300ms (${realListener.result.highestJank}ms)`);
|
||||
}
|
||||
|
||||
info(`Attempting to remove a performance listener incorrectly, check that this does not hurt our real listener`);
|
||||
Assert.throws(() => PerformanceWatcher.removePerformanceListener({addonId: addon.addonId}, () => {}));
|
||||
Assert.throws(() => PerformanceWatcher.removePerformanceListener({addonId: addon.addonId + "-unbound-id-" + Math.random()}, realListener.listener));
|
||||
|
||||
// Waiting a little – listeners are buffered.
|
||||
yield new Promise(resolve => setTimeout(resolve, 100));
|
||||
yield burner.run("promiseBurnContentCPU", 20, realListener);
|
||||
// Waiting a little – listeners are buffered.
|
||||
yield new Promise(resolve => setTimeout(resolve, 100));
|
||||
|
||||
Assert.ok(realListener.triggered, `2. The real listener was triggered`);
|
||||
Assert.ok(universalListener.triggered, `2. The universal listener was triggered`);
|
||||
Assert.ok(!fakeListener.triggered, `2. The fake listener was not triggered`);
|
||||
if (realListener.result) {
|
||||
Assert.ok(realListener.result.highestJank >= 300, `2. jank is at least 300ms (${realListener.jank}ms)`);
|
||||
}
|
||||
|
||||
info(`Attempting to remove correctly, check if the listener is still triggered`);
|
||||
// Waiting a little – listeners are buffered.
|
||||
yield new Promise(resolve => setTimeout(resolve, 100));
|
||||
realListener.unregister();
|
||||
|
||||
// Waiting a little – listeners are buffered.
|
||||
yield new Promise(resolve => setTimeout(resolve, 100));
|
||||
yield burner.run("promiseBurnContentCPU", 3, realListener);
|
||||
Assert.ok(!realListener.triggered, `3. After being unregistered, the real listener was not triggered`);
|
||||
Assert.ok(universalListener.triggered, `3. The universal listener is still triggered`);
|
||||
|
||||
universalListener.unregister();
|
||||
|
||||
// Waiting a little – listeners are buffered.
|
||||
yield new Promise(resolve => setTimeout(resolve, 100));
|
||||
yield burner.run("promiseBurnContentCPU", 3, realListener);
|
||||
Assert.ok(!universalListener.triggered, `4. After being unregistered, the universal listener is not triggered`);
|
||||
|
||||
fakeListener.unregister();
|
||||
burner.dispose();
|
||||
gBrowser.removeTab(otherTab);
|
||||
});
|
||||
|
|
@ -1,287 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
var { utils: Cu, interfaces: Ci, classes: Cc } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Promise.jsm", this);
|
||||
Cu.import("resource://gre/modules/AddonManager.jsm", this);
|
||||
Cu.import("resource://gre/modules/AddonWatcher.jsm", this);
|
||||
Cu.import("resource://gre/modules/PerformanceWatcher.jsm", this);
|
||||
Cu.import("resource://gre/modules/Services.jsm", this);
|
||||
Cu.import("resource://testing-common/ContentTaskUtils.jsm", this);
|
||||
|
||||
/**
|
||||
* Base class for simulating slow addons/webpages.
|
||||
*/
|
||||
function CPUBurner(url, jankThreshold) {
|
||||
info(`CPUBurner: Opening tab for ${url}\n`);
|
||||
this.url = url;
|
||||
this.tab = gBrowser.addTab(url);
|
||||
this.jankThreshold = jankThreshold;
|
||||
let browser = this.tab.linkedBrowser;
|
||||
this._browser = browser;
|
||||
ContentTask.spawn(this._browser, null, CPUBurner.frameScript);
|
||||
this.promiseInitialized = BrowserTestUtils.browserLoaded(browser);
|
||||
}
|
||||
CPUBurner.prototype = {
|
||||
get windowId() {
|
||||
return this._browser.outerWindowID;
|
||||
},
|
||||
/**
|
||||
* Burn CPU until it triggers a listener with the specified jank threshold.
|
||||
*/
|
||||
run: Task.async(function*(burner, max, listener) {
|
||||
listener.reset();
|
||||
for (let i = 0; i < max; ++i) {
|
||||
yield new Promise(resolve => setTimeout(resolve, 50));
|
||||
try {
|
||||
yield this[burner]();
|
||||
} catch (ex) {
|
||||
return false;
|
||||
}
|
||||
if (listener.triggered && listener.result >= this.jankThreshold) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}),
|
||||
dispose: function() {
|
||||
info(`CPUBurner: Closing tab for ${this.url}\n`);
|
||||
gBrowser.removeTab(this.tab);
|
||||
}
|
||||
};
|
||||
// This function is injected in all frames
|
||||
CPUBurner.frameScript = function() {
|
||||
try {
|
||||
"use strict";
|
||||
|
||||
const { utils: Cu, classes: Cc, interfaces: Ci } = Components;
|
||||
let sandboxes = new Map();
|
||||
let getSandbox = function(addonId) {
|
||||
let sandbox = sandboxes.get(addonId);
|
||||
if (!sandbox) {
|
||||
sandbox = Components.utils.Sandbox(Services.scriptSecurityManager.getSystemPrincipal(), { addonId });
|
||||
sandboxes.set(addonId, sandbox);
|
||||
}
|
||||
return sandbox;
|
||||
};
|
||||
|
||||
let burnCPU = function() {
|
||||
var start = Date.now();
|
||||
var ignored = [];
|
||||
while (Date.now() - start < 500) {
|
||||
ignored[ignored.length % 2] = ignored.length;
|
||||
}
|
||||
};
|
||||
let burnCPUInSandbox = function(addonId) {
|
||||
let sandbox = getSandbox(addonId);
|
||||
Cu.evalInSandbox(burnCPU.toSource() + "()", sandbox);
|
||||
};
|
||||
|
||||
{
|
||||
let topic = "test-performance-watcher:burn-content-cpu";
|
||||
addMessageListener(topic, function(msg) {
|
||||
try {
|
||||
if (msg.data && msg.data.addonId) {
|
||||
burnCPUInSandbox(msg.data.addonId);
|
||||
} else {
|
||||
burnCPU();
|
||||
}
|
||||
sendAsyncMessage(topic, {});
|
||||
} catch (ex) {
|
||||
dump(`This is the content attempting to burn CPU: error ${ex}\n`);
|
||||
dump(`${ex.stack}\n`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Bind the function to the global context or it might be GC'd during test
|
||||
// causing failures (bug 1230027)
|
||||
this.burnCPOWInSandbox = function(addonId) {
|
||||
try {
|
||||
burnCPUInSandbox(addonId);
|
||||
} catch (ex) {
|
||||
dump(`This is the addon attempting to burn CPOW: error ${ex}\n`);
|
||||
dump(`${ex.stack}\n`);
|
||||
}
|
||||
}
|
||||
|
||||
sendAsyncMessage("test-performance-watcher:cpow-init", {}, {
|
||||
burnCPOWInSandbox: this.burnCPOWInSandbox
|
||||
});
|
||||
|
||||
} catch (ex) {
|
||||
Cu.reportError("This is the addon: error " + ex);
|
||||
Cu.reportError(ex.stack);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Base class for listening to slow group alerts
|
||||
*/
|
||||
function AlertListener(accept, {register, unregister}) {
|
||||
this.listener = (...args) => {
|
||||
if (this._unregistered) {
|
||||
throw new Error("Listener was unregistered");
|
||||
}
|
||||
let result = accept(...args);
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
this.result = result;
|
||||
this.triggered = true;
|
||||
return;
|
||||
};
|
||||
this.triggered = false;
|
||||
this.result = null;
|
||||
this._unregistered = false;
|
||||
this._unregister = unregister;
|
||||
registerCleanupFunction(() => {
|
||||
this.unregister();
|
||||
});
|
||||
register();
|
||||
}
|
||||
AlertListener.prototype = {
|
||||
unregister: function() {
|
||||
this.reset();
|
||||
if (this._unregistered) {
|
||||
info(`head.js: No need to unregister, we're already unregistered.\n`);
|
||||
return;
|
||||
}
|
||||
info(`head.js: Unregistering listener.\n`);
|
||||
this._unregistered = true;
|
||||
this._unregister();
|
||||
info(`head.js: Unregistration complete.\n`);
|
||||
},
|
||||
reset: function() {
|
||||
this.triggered = false;
|
||||
this.result = null;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Simulate a slow add-on.
|
||||
*/
|
||||
function AddonBurner(addonId = "fake add-on id: " + Math.random()) {
|
||||
this.jankThreshold = 200000;
|
||||
CPUBurner.call(this, `http://example.com/?uri=${addonId}`, this.jankThreshold);
|
||||
this._addonId = addonId;
|
||||
this._sandbox = Components.utils.Sandbox(Services.scriptSecurityManager.getSystemPrincipal(), { addonId: this._addonId });
|
||||
this._CPOWBurner = null;
|
||||
|
||||
this._promiseCPOWBurner = new Promise(resolve => {
|
||||
this._browser.messageManager.addMessageListener("test-performance-watcher:cpow-init", msg => {
|
||||
// Note that we cannot resolve Promises with CPOWs now that they
|
||||
// have been outlawed in bug 1233497, so we stash it in the
|
||||
// AddonBurner instance instead.
|
||||
this._CPOWBurner = msg.objects.burnCPOWInSandbox;
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
AddonBurner.prototype = Object.create(CPUBurner.prototype);
|
||||
Object.defineProperty(AddonBurner.prototype, "addonId", {
|
||||
get: function() {
|
||||
return this._addonId;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Simulate slow code being executed by the add-on in the chrome.
|
||||
*/
|
||||
AddonBurner.prototype.burnCPU = function() {
|
||||
Cu.evalInSandbox(AddonBurner.burnCPU.toSource() + "()", this._sandbox);
|
||||
};
|
||||
|
||||
/**
|
||||
* Simulate slow code being executed by the add-on in a CPOW.
|
||||
*/
|
||||
AddonBurner.prototype.promiseBurnCPOW = Task.async(function*() {
|
||||
yield this._promiseCPOWBurner;
|
||||
ok(this._CPOWBurner, "Got the CPOW burner");
|
||||
let burner = this._CPOWBurner;
|
||||
info("Parent: Preparing to burn CPOW");
|
||||
try {
|
||||
yield burner(this._addonId);
|
||||
info("Parent: Done burning CPOW");
|
||||
} catch (ex) {
|
||||
info(`Parent: Error burning CPOW: ${ex}\n`);
|
||||
info(ex.stack + "\n");
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Simulate slow code being executed by the add-on in the content.
|
||||
*/
|
||||
AddonBurner.prototype.promiseBurnContentCPU = function() {
|
||||
return promiseContentResponse(this._browser, "test-performance-watcher:burn-content-cpu", {addonId: this._addonId});
|
||||
};
|
||||
AddonBurner.burnCPU = function() {
|
||||
var start = Date.now();
|
||||
var ignored = [];
|
||||
while (Date.now() - start < 500) {
|
||||
ignored[ignored.length % 2] = ignored.length;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function AddonListener(addonId, accept) {
|
||||
let target = {addonId};
|
||||
AlertListener.call(this, accept, {
|
||||
register: () => {
|
||||
info(`AddonListener: registering ${JSON.stringify(target, null, "\t")}`);
|
||||
PerformanceWatcher.addPerformanceListener({addonId}, this.listener);
|
||||
},
|
||||
unregister: () => {
|
||||
info(`AddonListener: unregistering ${JSON.stringify(target, null, "\t")}`);
|
||||
PerformanceWatcher.removePerformanceListener({addonId}, this.listener);
|
||||
}
|
||||
});
|
||||
}
|
||||
AddonListener.prototype = Object.create(AlertListener.prototype);
|
||||
|
||||
function promiseContentResponse(browser, name, message) {
|
||||
let mm = browser.messageManager;
|
||||
let promise = new Promise(resolve => {
|
||||
function removeListener() {
|
||||
mm.removeMessageListener(name, listener);
|
||||
}
|
||||
|
||||
function listener(msg) {
|
||||
removeListener();
|
||||
resolve(msg.data);
|
||||
}
|
||||
|
||||
mm.addMessageListener(name, listener);
|
||||
registerCleanupFunction(removeListener);
|
||||
});
|
||||
mm.sendAsyncMessage(name, message);
|
||||
return promise;
|
||||
}
|
||||
function promiseContentResponseOrNull(browser, name, message) {
|
||||
if (!browser.messageManager) {
|
||||
return null;
|
||||
}
|
||||
return promiseContentResponse(browser, name, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* `true` if we are running an OS in which the OS performance
|
||||
* clock has a low precision and might unpredictably
|
||||
* never be updated during the execution of the test.
|
||||
*/
|
||||
function hasLowPrecision() {
|
||||
let [sysName, sysVersion] = [Services.sysinfo.getPropertyAsAString("name"), Services.sysinfo.getPropertyAsDouble("version")];
|
||||
info(`Running ${sysName} version ${sysVersion}`);
|
||||
|
||||
if (sysName == "Windows_NT" && sysVersion < 6) {
|
||||
info("Running old Windows, need to deactivate tests due to bad precision.");
|
||||
return true;
|
||||
}
|
||||
if (sysName == "Linux" && sysVersion <= 2.6) {
|
||||
info("Running old Linux, need to deactivate tests due to bad precision.");
|
||||
return true;
|
||||
}
|
||||
info("This platform has good precision.")
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
|
||||
<Description about="urn:mozilla:install-manifest">
|
||||
<em:id>addonwatcher-test@mozilla.com</em:id>
|
||||
<em:version>1.0</em:version>
|
||||
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
|
||||
<em:minVersion>0.3</em:minVersion>
|
||||
<em:maxVersion>*</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>toolkit@mozilla.org</em:id>
|
||||
<em:minVersion>1</em:minVersion>
|
||||
<em:maxVersion>*</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
|
||||
<em:bootstrap>true</em:bootstrap>
|
||||
|
||||
<em:name>Sample for browser_AddonWatcher.js</em:name>
|
||||
|
||||
</Description>
|
||||
</RDF>
|
||||
Loading…
Add table
Add a link
Reference in a new issue