1 /* Any copyright is dedicated to the Public Domain.
2 http://creativecommons.org/publicdomain/zero/1.0/ */
4 if (SpecialPowers.useRemoteSubframes) {
5 requestLongerTimeout(2);
8 const DEFAULT_PROCESS_COUNT = Services.prefs
9 .getDefaultBranch(null)
10 .getIntPref("dom.ipc.processCount");
13 * A test that checks whether any preference getter from the given list
14 * of stats was called more often than the max parameter.
16 * @param {Array} stats - an array of [prefName, accessCount] tuples
17 * @param {Number} max - the maximum number of times any of the prefs should
19 * @param {Object} knownProblematicPrefs (optional) - an object that defines
20 * prefs that should be exempt from checking the
21 * maximum access. It looks like the following:
24 * min: [Number] the minimum amount of times this should have
25 * been called (to avoid keeping around dead items)
26 * max: [Number] the maximum amount of times this should have
27 * been called (to avoid this creeping up further)
30 function checkPrefGetters(stats, max, knownProblematicPrefs = {}) {
31 let getterStats = Object.entries(stats).sort(
32 ([, val1], [, val2]) => val2 - val1
35 // Clone the list to be able to delete entries to check if we
36 // forgot any later on.
37 knownProblematicPrefs = Object.assign({}, knownProblematicPrefs);
39 for (let [pref, count] of getterStats) {
40 let prefLimits = knownProblematicPrefs[pref];
45 `${pref} should not be accessed more than ${max} times.`
48 // Still record how much this pref was accessed even if we don't do any real assertions.
49 if (!prefLimits.min && !prefLimits.max) {
51 `${pref} should not be accessed more than ${max} times and was accessed ${count} times.`
59 `${pref} should be accessed at least ${prefLimits.min} times.`
66 `${pref} should be accessed at most ${prefLimits.max} times.`
69 delete knownProblematicPrefs[pref];
73 // This pref will be accessed by mozJSComponentLoader when loading modules,
74 // which fails TV runs since they run the test multiple times without restarting.
75 // We just ignore this pref, since it's for testing only anyway.
76 if (knownProblematicPrefs["browser.startup.record"]) {
77 delete knownProblematicPrefs["browser.startup.record"];
80 let unusedPrefs = Object.keys(knownProblematicPrefs);
84 `Should have accessed all known problematic prefs. Remaining: ${unusedPrefs}`
89 * A helper function to read preference access data
90 * using the Services.prefs.readStats() function.
92 function getPreferenceStats() {
94 Services.prefs.readStats((key, value) => (stats[key] = value));
98 add_task(async function debug_only() {
99 ok(AppConstants.DEBUG, "You need to run this test on a debug build.");
102 // Just checks how many prefs were accessed during startup.
103 add_task(async function startup() {
106 let knownProblematicPrefs = {
107 "browser.startup.record": {
108 // This pref is accessed in Nighly and debug builds only.
112 "network.loadinfo.skip_type_assertion": {
113 // This is accessed in debug only.
115 "chrome.override_package.global": {
121 let startupRecorder = Cc["@mozilla.org/test/startuprecorder;1"].getService()
123 await startupRecorder.done;
125 ok(startupRecorder.data.prefStats, "startupRecorder has prefStats");
127 checkPrefGetters(startupRecorder.data.prefStats, max, knownProblematicPrefs);
130 // This opens 10 tabs and checks pref getters.
131 add_task(async function open_10_tabs() {
132 // This is somewhat arbitrary. When we had a default of 4 content processes
133 // the value was 15. We need to scale it as we increase the number of
134 // content processes so we approximate with 4 * process_count.
135 const max = 4 * DEFAULT_PROCESS_COUNT;
137 let knownProblematicPrefs = {
138 "browser.startup.record": {
141 "browser.tabs.remote.logSwitchTiming": {
144 "network.loadinfo.skip_type_assertion": {
145 // This is accessed in debug only.
149 Services.prefs.resetStats();
152 while (tabs.length < 10) {
154 await BrowserTestUtils.openNewForegroundTab(
156 "http://example.com",
163 for (let tab of tabs) {
164 await BrowserTestUtils.removeTab(tab);
167 checkPrefGetters(getPreferenceStats(), max, knownProblematicPrefs);
170 // This navigates to 50 sites and checks pref getters.
171 add_task(async function navigate_around() {
172 await SpecialPowers.pushPrefEnv({
174 // Disable bfcache so that we can measure more accurately the number of
175 // pref accesses in the child processes.
176 // If bfcache is enabled on Fission
177 // dom.ipc.keepProcessesAlive.webIsolated.perOrigin and
178 // security.sandbox.content.force-namespace are accessed only a couple of
180 ["browser.sessionhistory.max_total_viewers", 0],
186 let knownProblematicPrefs = {
187 "network.loadinfo.skip_type_assertion": {
188 // This is accessed in debug only.
192 if (AppConstants.NIGHTLY_BUILD) {
193 knownProblematicPrefs["toolkit.telemetry.cachedClientID"] = {
194 // Bug 1712391: Only an issue in tests where pref is not populated early on
195 // in startup. Code path is only accessed in Nightly builds.
199 if (SpecialPowers.useRemoteSubframes) {
200 // We access this when considering starting a new content process.
201 // Because there is no complete list of content process types,
202 // caching this is not trivial. Opening 50 different content
203 // processes and throwing them away immediately is a bit artificial;
204 // we're more likely to keep some around so this shouldn't be quite
205 // this bad in practice. Fixing this is
206 // https://bugzilla.mozilla.org/show_bug.cgi?id=1600266
207 knownProblematicPrefs["dom.ipc.processCount.webIsolated"] = {
211 // This pref is only accessed in automation to speed up tests.
212 knownProblematicPrefs[
213 "dom.ipc.keepProcessesAlive.webIsolated.perOrigin"
218 if (AppConstants.platform == "linux") {
219 // The following sandbox pref is covered by
220 // https://bugzilla.mozilla.org/show_bug.cgi?id=1600189
221 knownProblematicPrefs["security.sandbox.content.force-namespace"] = {
225 // This was previously being read in the content process, but
226 // bug 1725573 moved it into the parent process. We also block
227 // the main thread on requests to the X server, which is likely
228 // more problematic than the pref read. These issues are covered
229 // by https://bugzilla.mozilla.org/show_bug.cgi?id=1729080
230 knownProblematicPrefs["gfx.color_management.display_profile"] = {
234 } else if (AppConstants.platform == "win") {
235 // The following 2 graphics prefs are covered by
236 // https://bugzilla.mozilla.org/show_bug.cgi?id=1639497
237 knownProblematicPrefs["gfx.canvas.azure.backends"] = {
241 knownProblematicPrefs["gfx.content.azure.backends"] = {
245 // The following 2 sandbox prefs are covered by
246 // https://bugzilla.mozilla.org/show_bug.cgi?id=1639494
247 knownProblematicPrefs["security.sandbox.content.read_path_whitelist"] = {
251 knownProblematicPrefs["security.sandbox.logging.enabled"] = {
258 Services.prefs.resetStats();
260 let tab = await BrowserTestUtils.openNewForegroundTab(
262 "http://example.com",
268 "http://example.com/",
269 "https://example.com/",
270 "http://example.org/",
271 "https://example.org/",
274 for (let i = 0; i < 50; i++) {
275 let url = urls[i % urls.length];
276 info(`Navigating to ${url}...`);
277 BrowserTestUtils.loadURI(tab.linkedBrowser, url);
278 await BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, url);
279 info(`Loaded ${url}.`);
282 await BrowserTestUtils.removeTab(tab);
284 checkPrefGetters(getPreferenceStats(), max, knownProblematicPrefs);