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