/* Any copyright is dedicated to the public domain. http://creativecommons.org/publicdomain/zero/1.0/ */ // Helpers for managing the browser frame preferences. "use strict"; function _getPath() { return window.location.pathname .substring(0, window.location.pathname.lastIndexOf('/')) .replace("/priority", ""); } const browserElementTestHelpers = { _getBoolPref: function(pref) { try { return SpecialPowers.getBoolPref(pref); } catch (e) { return undefined; } }, _setPref: function(pref, value) { this.lockTestReady(); if (value !== undefined && value !== null) { SpecialPowers.pushPrefEnv({'set': [[pref, value]]}, this.unlockTestReady.bind(this)); } else { SpecialPowers.pushPrefEnv({'clear': [[pref]]}, this.unlockTestReady.bind(this)); } }, _setPrefs: function() { this.lockTestReady(); SpecialPowers.pushPrefEnv({'set': Array.slice(arguments)}, this.unlockTestReady.bind(this)); }, _testReadyLockCount: 0, _firedTestReady: false, lockTestReady: function() { this._testReadyLockCount++; }, unlockTestReady: function() { this._testReadyLockCount--; if (this._testReadyLockCount == 0 && !this._firedTestReady) { this._firedTestReady = true; dispatchEvent(new Event("testready")); } }, enableProcessPriorityManager: function() { this._setPrefs( ['dom.ipc.processPriorityManager.testMode', true], ['dom.ipc.processPriorityManager.enabled', true], ['dom.ipc.processPriorityManager.backgroundLRUPoolLevels', 2] ); }, setEnabledPref: function(value) { this._setPref('dom.mozBrowserFramesEnabled', value); }, setSelectionChangeEnabledPref: function(value) { this._setPref('selectioncaret.enabled', value); }, getOOPByDefaultPref: function() { return this._getBoolPref("dom.ipc.browser_frames.oop_by_default"); }, addPermission: function() { this.lockTestReady(); SpecialPowers.pushPermissions( [{'type': "browser", 'allow': 1, 'context': document}], this.unlockTestReady.bind(this)); }, _observers: [], // This function is a wrapper which lets you register an observer to one of // the process priority manager's test-only topics. observerFn should be a // function which takes (subject, topic, data). // // We'll clean up any observers you add at the end of the test. addProcessPriorityObserver: function(processPriorityTopic, observerFn) { var topic = "process-priority-manager:TEST-ONLY:" + processPriorityTopic; // SpecialPowers appears to require that the observer be an object, not a // function. var observer = { observe: observerFn }; SpecialPowers.addObserver(observer, topic, /* weak = */ false); this._observers.push([observer, topic]); }, cleanUp: function() { for (var i = 0; i < this._observers.length; i++) { SpecialPowers.removeObserver(this._observers[i][0], this._observers[i][1]); } }, // Some basically-empty pages from different domains you can load. 'emptyPage1': 'http://example.com' + _getPath() + '/file_empty.html', 'emptyPage2': 'http://example.org' + _getPath() + '/file_empty.html', 'emptyPage3': 'http://test1.example.org' + _getPath() + '/file_empty.html', 'focusPage': 'http://example.org' + _getPath() + '/file_focus.html', }; // Returns a promise which is resolved when a subprocess is created. The // argument to resolve() is the childID of the subprocess. function expectProcessCreated(/* optional */ initialPriority, /* optional */ initialCPUPriority) { return new Promise(function(resolve, reject) { var observed = false; browserElementTestHelpers.addProcessPriorityObserver( "process-created", function(subject, topic, data) { // Don't run this observer twice, so we don't ok(true) twice. (It's fine // to resolve a promise twice; the second resolve() call does nothing.) if (observed) { return; } observed = true; var childID = parseInt(data); ok(true, 'Got new process, id=' + childID); if (initialPriority) { expectPriorityChange(childID, initialPriority, initialCPUPriority).then(function() { resolve(childID); }); } else { resolve(childID); } } ); }); } // Just like expectProcessCreated(), except we'll call ok(false) if a second // process is created. function expectOnlyOneProcessCreated(/* optional */ initialPriority, /* optional */ initialCPUPriority) { var p = expectProcessCreated(initialPriority, initialCPUPriority); p.then(function() { expectProcessCreated().then(function(childID) { ok(false, 'Got unexpected process creation, childID=' + childID); }); }); return p; } // Returns a promise which is resolved or rejected the next time the process // childID changes its priority. We resolve if the (priority, CPU priority) // tuple matches (expectedPriority, expectedCPUPriority) and we reject // otherwise. // // expectedCPUPriority is an optional argument; if it's not specified, we // resolve if priority matches expectedPriority. function expectPriorityChange(childID, expectedPriority, /* optional */ expectedCPUPriority) { return new Promise(function(resolve, reject) { var observed = false; browserElementTestHelpers.addProcessPriorityObserver( 'process-priority-set', function(subject, topic, data) { if (observed) { return; } var [id, priority, cpuPriority] = data.split(":"); if (id != childID) { return; } // Make sure we run the is() calls in this observer only once, otherwise // we'll expect /every/ priority change to match expectedPriority. observed = true; is(priority, expectedPriority, 'Expected priority of childID ' + childID + ' to change to ' + expectedPriority); if (expectedCPUPriority) { is(cpuPriority, expectedCPUPriority, 'Expected CPU priority of childID ' + childID + ' to change to ' + expectedCPUPriority); } if (priority == expectedPriority && (!expectedCPUPriority || expectedCPUPriority == cpuPriority)) { resolve(); } else { reject(); } } ); }); } // Returns a promise which is resolved or rejected the next time the background // process childID changes its priority. We resolve if the backgroundLRU // matches expectedBackgroundLRU and we reject otherwise. function expectPriorityWithBackgroundLRUSet(childID, expectedBackgroundLRU) { return new Promise(function(resolve, reject) { browserElementTestHelpers.addProcessPriorityObserver( 'process-priority-with-background-LRU-set', function(subject, topic, data) { var [id, priority, cpuPriority, backgroundLRU] = data.split(":"); if (id != childID) { return; } is(backgroundLRU, expectedBackgroundLRU, 'Expected backgroundLRU ' + backgroundLRU + ' of childID ' + childID + ' to change to ' + expectedBackgroundLRU); if (backgroundLRU == expectedBackgroundLRU) { resolve(); } else { reject(); } } ); }); } // Returns a promise which is resolved the first time the given iframe fires // the mozbrowser##eventName event. function expectMozbrowserEvent(iframe, eventName) { return new Promise(function(resolve, reject) { iframe.addEventListener('mozbrowser' + eventName, function handler(e) { iframe.removeEventListener('mozbrowser' + eventName, handler); resolve(e); }); }); } // Set some prefs: // // * browser.pagethumbnails.capturing_disabled: true // // Disable tab view; it seriously messes us up. // // * dom.ipc.browser_frames.oop_by_default // // Enable or disable OOP-by-default depending on the test's filename. You // can still force OOP on or off with