"use strict"; /** * Tests the FX_TAB_SWITCH_SPINNER_VISIBLE_MS and * FX_TAB_SWITCH_SPINNER_VISIBLE_LONG_MS telemetry probes */ const MIN_HANG_TIME = 500; // ms const MAX_HANG_TIME = 5 * 1000; // ms /** * Returns the sum of all values in an array. * @param {Array} aArray An array of integers * @return {Number} The sum of the integers in the array */ function sum(aArray) { return aArray.reduce(function (previousValue, currentValue) { return previousValue + currentValue; }); } /** * Causes the content process for a remote to run * some busy JS for aMs milliseconds. * * @param {} browser * The browser that's running in the content process that we're * going to hang. * @param {int} aMs * The amount of time, in milliseconds, to hang the content process. * * @return {Promise} * Resolves once the hang is done. */ function hangContentProcess(browser, aMs) { return ContentTask.spawn(browser, aMs, function (ms) { let then = Date.now(); while (Date.now() - then < ms) { // Let's burn some CPU... } }); } /** * A generator intended to be run as a Task. It tests one of the tab spinner * telemetry probes. * @param {String} aProbe The probe to test. Should be one of: * - FX_TAB_SWITCH_SPINNER_VISIBLE_MS * - FX_TAB_SWITCH_SPINNER_VISIBLE_LONG_MS */ async function testProbe(aProbe) { info(`Testing probe: ${aProbe}`); let histogram = Services.telemetry.getHistogramById(aProbe); let delayTime = MIN_HANG_TIME + 1; // Pick a bucket arbitrarily // The tab spinner does not show up instantly. We need to hang for a little // bit of extra time to account for the tab spinner delay. delayTime += gBrowser.selectedTab.linkedBrowser .getTabBrowser() ._getSwitcher().TAB_SWITCH_TIMEOUT; // In order for a spinner to be shown, the tab must have presented before. let origTab = gBrowser.selectedTab; let hangTab = await BrowserTestUtils.openNewForegroundTab(gBrowser); let hangBrowser = hangTab.linkedBrowser; ok(hangBrowser.isRemoteBrowser, "New tab should be remote."); ok(hangBrowser.frameLoader.remoteTab.hasPresented, "New tab has presented."); // Now switch back to the original tab and set up our hang. await BrowserTestUtils.switchTab(gBrowser, origTab); let tabHangPromise = hangContentProcess(hangBrowser, delayTime); histogram.clear(); let hangTabSwitch = BrowserTestUtils.switchTab(gBrowser, hangTab); await tabHangPromise; await hangTabSwitch; // Now we should have a hang in our histogram. let snapshot = histogram.snapshot(); BrowserTestUtils.removeTab(hangTab); ok( sum(Object.values(snapshot.values)) > 0, `Spinner probe should now have a value in some bucket` ); } add_setup(async function () { await SpecialPowers.pushPrefEnv({ set: [ ["dom.ipc.processCount", 1], // We can interrupt JS to paint now, which is great for // users, but bad for testing spinners. We temporarily // disable that feature for this test so that we can // easily get ourselves into a predictable tab spinner // state. ["browser.tabs.remote.force-paint", false], ], }); }); add_task(testProbe.bind(null, "FX_TAB_SWITCH_SPINNER_VISIBLE_MS")); add_task(testProbe.bind(null, "FX_TAB_SWITCH_SPINNER_VISIBLE_LONG_MS"));