tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

browser_remoteness_flip_on_restore.js (9199B)


      1 "use strict";
      2 
      3 /**
      4 * This set of tests checks that the remoteness is properly
      5 * set for each browser in a window when that window has
      6 * session state loaded into it.
      7 */
      8 
      9 /**
     10 * Takes a SessionStore window state object for a single
     11 * window, sets the selected tab for it, and then returns
     12 * the object to be passed to SessionStore.setWindowState.
     13 *
     14 * @param state (object)
     15 *        The state to prepare to be sent to a window. This is
     16 *        state should just be for a single window.
     17 * @param selected (int)
     18 *        The 1-based index of the selected tab. Note that
     19 *        If this is 0, then the selected tab will not change
     20 *        from what's already selected in the window that we're
     21 *        sending state to.
     22 * @returns (object)
     23 *        The JSON encoded string to call
     24 *        SessionStore.setWindowState with.
     25 */
     26 function prepareState(state, selected) {
     27  // We'll create a copy so that we don't accidentally
     28  // modify the caller's selected property.
     29  let copy = {};
     30  Object.assign(copy, state);
     31  copy.selected = selected;
     32 
     33  return {
     34    windows: [copy],
     35  };
     36 }
     37 
     38 const SIMPLE_STATE = {
     39  tabs: [
     40    {
     41      entries: [
     42        {
     43          url: "http://example.com/",
     44          triggeringPrincipal_base64,
     45          title: "title",
     46        },
     47      ],
     48    },
     49    {
     50      entries: [
     51        {
     52          url: "http://example.com/",
     53          triggeringPrincipal_base64,
     54          title: "title",
     55        },
     56      ],
     57    },
     58    {
     59      entries: [
     60        {
     61          url: "http://example.com/",
     62          triggeringPrincipal_base64,
     63          title: "title",
     64        },
     65      ],
     66    },
     67  ],
     68  title: "",
     69  _closedTabs: [],
     70 };
     71 
     72 const PINNED_STATE = {
     73  tabs: [
     74    {
     75      entries: [
     76        {
     77          url: "http://example.com/",
     78          triggeringPrincipal_base64,
     79          title: "title",
     80        },
     81      ],
     82      pinned: true,
     83    },
     84    {
     85      entries: [
     86        {
     87          url: "http://example.com/",
     88          triggeringPrincipal_base64,
     89          title: "title",
     90        },
     91      ],
     92      pinned: true,
     93    },
     94    {
     95      entries: [
     96        {
     97          url: "http://example.com/",
     98          triggeringPrincipal_base64,
     99          title: "title",
    100        },
    101      ],
    102    },
    103  ],
    104  title: "",
    105  _closedTabs: [],
    106 };
    107 
    108 /**
    109 * This is where most of the action is happening. This function takes
    110 * an Array of "test scenario" Objects and runs them. For each scenario, a
    111 * window is opened, put into some state, and then a new state is
    112 * loaded into that window. We then check to make sure that the
    113 * right things have happened in that window wrt remoteness flips.
    114 *
    115 * The schema for a testing scenario Object is as follows:
    116 *
    117 * initialRemoteness:
    118 *   an Array that represents the starting window. Each bool
    119 *   in the Array represents the window tabs in order. A "true"
    120 *   indicates that that tab should be remote. "false" if the tab
    121 *   should be non-remote.
    122 *
    123 * initialSelectedTab:
    124 *   The 1-based index of the tab that we want to select for the
    125 *   restored window. This is 1-based to avoid confusion with the
    126 *   selectedTab property described down below, though you probably
    127 *   want to set this to be greater than 0, since the initial window
    128 *   needs to have a defined initial selected tab. Because of this,
    129 *   the test will throw if initialSelectedTab is 0.
    130 *
    131 * stateToRestore:
    132 *   A JS Object for the state to send down to the window.
    133 *
    134 * selectedTab:
    135 *   The 1-based index of the tab that we want to select for the
    136 *   restored window. Leave this at 0 if you don't want to change
    137 *   the selection from the initial window state.
    138 *
    139 * expectedRemoteness:
    140 *   an Array that represents the window that we end up with after
    141 *   restoring state. Each bool in the Array represents the window
    142 *   tabs in order. A "true" indicates that the tab be remote, and
    143 *   a "false" indicates that the tab should be "non-remote". We
    144 *   need this Array in order to test pinned tabs which will also
    145 *   be loaded by default, and therefore should end up remote.
    146 *
    147 */
    148 async function runScenarios(scenarios) {
    149  for (let [scenarioIndex, scenario] of scenarios.entries()) {
    150    info("Running scenario " + scenarioIndex);
    151    Assert.greater(
    152      scenario.initialSelectedTab,
    153      0,
    154      "You must define an initially selected tab"
    155    );
    156 
    157    // First, we need to create the initial conditions, so we
    158    // open a new window to put into our starting state...
    159    let win = await BrowserTestUtils.openNewBrowserWindow();
    160    let tabbrowser = win.gBrowser;
    161    Assert.ok(
    162      tabbrowser.selectedBrowser.isRemoteBrowser,
    163      "The initial browser should be remote."
    164    );
    165    // Now put the window into the expected initial state.
    166    for (let i = 0; i < scenario.initialRemoteness.length; ++i) {
    167      let tab;
    168      if (i > 0) {
    169        // The window starts with one tab, so we need to create
    170        // any of the additional ones required by this test.
    171        info("Opening a new tab");
    172        tab = await BrowserTestUtils.openNewForegroundTab(tabbrowser);
    173      } else {
    174        info("Using the selected tab");
    175        tab = tabbrowser.selectedTab;
    176      }
    177      let browser = tab.linkedBrowser;
    178      let remotenessState = scenario.initialRemoteness[i]
    179        ? E10SUtils.DEFAULT_REMOTE_TYPE
    180        : E10SUtils.NOT_REMOTE;
    181      tabbrowser.updateBrowserRemoteness(browser, {
    182        remoteType: remotenessState,
    183      });
    184    }
    185 
    186    // And select the requested tab.
    187    let tabToSelect = tabbrowser.tabs[scenario.initialSelectedTab - 1];
    188    if (tabbrowser.selectedTab != tabToSelect) {
    189      await BrowserTestUtils.switchTab(tabbrowser, tabToSelect);
    190    }
    191 
    192    // Okay, time to test!
    193    let state = prepareState(scenario.stateToRestore, scenario.selectedTab);
    194 
    195    await setWindowState(win, state, true);
    196 
    197    for (let i = 0; i < scenario.expectedRemoteness.length; ++i) {
    198      let expectedRemoteness = scenario.expectedRemoteness[i];
    199      let tab = tabbrowser.tabs[i];
    200 
    201      Assert.equal(
    202        tab.linkedBrowser.isRemoteBrowser,
    203        expectedRemoteness,
    204        "Should have gotten the expected remoteness " +
    205          `for the tab at index ${i}`
    206      );
    207    }
    208 
    209    await BrowserTestUtils.closeWindow(win);
    210  }
    211 }
    212 
    213 /**
    214 * Tests that if we restore state to browser windows with
    215 * a variety of initial remoteness states. For this particular
    216 * set of tests, we assume that tabs are restoring on demand.
    217 */
    218 add_task(async function () {
    219  // This test opens and closes windows, which might bog down
    220  // a debug build long enough to time out the test, so we
    221  // extend the tolerance on timeouts.
    222  requestLongerTimeout(5);
    223 
    224  await SpecialPowers.pushPrefEnv({
    225    set: [["browser.sessionstore.restore_on_demand", true]],
    226  });
    227 
    228  const TEST_SCENARIOS = [
    229    // Only one tab in the new window, and it's remote. This
    230    // is the common case, since this is how restoration occurs
    231    // when the restored window is being opened.
    232    {
    233      initialRemoteness: [true],
    234      initialSelectedTab: 1,
    235      stateToRestore: SIMPLE_STATE,
    236      selectedTab: 3,
    237      // All tabs should now be remote.
    238      expectedRemoteness: [true, true, true],
    239    },
    240 
    241    // A single remote tab, and this is the one that's going
    242    // to be selected once state is restored.
    243    {
    244      initialRemoteness: [true],
    245      initialSelectedTab: 1,
    246      stateToRestore: SIMPLE_STATE,
    247      selectedTab: 1,
    248      // All tabs should now be remote.
    249      expectedRemoteness: [true, true, true],
    250    },
    251 
    252    // A single remote tab which starts selected. We set the
    253    // selectedTab to 0 which is equivalent to "don't change
    254    // the tab selection in the window".
    255    {
    256      initialRemoteness: [true],
    257      initialSelectedTab: 1,
    258      stateToRestore: SIMPLE_STATE,
    259      selectedTab: 0,
    260      // All tabs should now be remote.
    261      expectedRemoteness: [true, true, true],
    262    },
    263 
    264    // An initially remote tab, but we're going to load
    265    // some pinned tabs now, and the pinned tabs should load
    266    // right away.
    267    {
    268      initialRemoteness: [true],
    269      initialSelectedTab: 1,
    270      stateToRestore: PINNED_STATE,
    271      selectedTab: 3,
    272      // Both pinned tabs and the selected tabs should all
    273      // end up being remote.
    274      expectedRemoteness: [true, true, true],
    275    },
    276 
    277    // A single non-remote tab.
    278    {
    279      initialRemoteness: [false],
    280      initialSelectedTab: 1,
    281      stateToRestore: SIMPLE_STATE,
    282      selectedTab: 2,
    283      // All tabs should now be remote.
    284      expectedRemoteness: [true, true, true],
    285    },
    286 
    287    // A mixture of remote and non-remote tabs.
    288    {
    289      initialRemoteness: [true, false, true],
    290      initialSelectedTab: 1,
    291      stateToRestore: SIMPLE_STATE,
    292      selectedTab: 3,
    293      // All tabs should now be remote.
    294      expectedRemoteness: [true, true, true],
    295    },
    296 
    297    // An initially non-remote tab, but we're going to load
    298    // some pinned tabs now, and the pinned tabs should load
    299    // right away.
    300    {
    301      initialRemoteness: [false],
    302      initialSelectedTab: 1,
    303      stateToRestore: PINNED_STATE,
    304      selectedTab: 3,
    305      // All tabs should now be remote.
    306      expectedRemoteness: [true, true, true],
    307    },
    308  ];
    309 
    310  await runScenarios(TEST_SCENARIOS);
    311 });