tor-browser

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

helper-mocks.js (9949B)


      1 /* Any copyright is dedicated to the Public Domain.
      2   http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 /* import-globals-from ../../../shared/test/shared-head.js */
      7 
      8 const MOCKS_ROOT = CHROME_URL_ROOT + "mocks/";
      9 /* import-globals-from mocks/helper-adb-mock.js */
     10 Services.scriptloader.loadSubScript(MOCKS_ROOT + "helper-adb-mock.js", this);
     11 /* import-globals-from mocks/helper-client-wrapper-mock.js */
     12 Services.scriptloader.loadSubScript(
     13  MOCKS_ROOT + "helper-client-wrapper-mock.js",
     14  this
     15 );
     16 /* import-globals-from mocks/helper-runtime-client-factory-mock.js */
     17 Services.scriptloader.loadSubScript(
     18  MOCKS_ROOT + "helper-runtime-client-factory-mock.js",
     19  this
     20 );
     21 
     22 const {
     23  RUNTIMES,
     24 } = require("resource://devtools/client/aboutdebugging/src/constants.js");
     25 
     26 /**
     27 * This wrapper around the mocks used in about:debugging tests provides helpers to
     28 * quickly setup mocks for runtime tests involving USB, network or wifi runtimes that can
     29 * are difficult to setup in a test environment.
     30 */
     31 class Mocks {
     32  constructor() {
     33    // Setup the adb mock to rely on internal arrays.
     34    this.adbMock = createAdbMock();
     35    this.adbProcessMock = createAdbProcessMock();
     36    this._usbRuntimes = [];
     37    this._usbDevices = [];
     38    this.adbMock.adb.getRuntimes = () => {
     39      return this._usbRuntimes;
     40    };
     41    this.adbMock.adb.getDevices = () => {
     42      const runtimeDevices = this._usbRuntimes.map(r => {
     43        return { id: r.deviceId, name: r.deviceName };
     44      });
     45      return runtimeDevices.concat(this._usbDevices);
     46    };
     47 
     48    // adb.updateRuntimes should ultimately fire the "runtime-list-updated" event.
     49    this.adbMock.adb.updateRuntimes = () => {
     50      this.emitUSBUpdate();
     51    };
     52 
     53    this.adbMock.adb.isProcessStarted = () => true;
     54 
     55    // Prepare a fake observer to be able to emit events from this mock.
     56    this._observerMock = addObserverMock(this.adbMock.adb);
     57 
     58    // Setup the runtime-client-factory mock to rely on the internal _clients map.
     59    this.runtimeClientFactoryMock = createRuntimeClientFactoryMock();
     60    this._clients = {
     61      [RUNTIMES.NETWORK]: {},
     62      [RUNTIMES.THIS_FIREFOX]: {},
     63      [RUNTIMES.USB]: {},
     64    };
     65    this.runtimeClientFactoryMock.createClientForRuntime = runtime => {
     66      return this._clients[runtime.type][runtime.id];
     67    };
     68 
     69    // Add a client for THIS_FIREFOX, since about:debugging will start on the This Firefox
     70    // page.
     71    this._thisFirefoxClient = createThisFirefoxClientMock();
     72    this._clients[RUNTIMES.THIS_FIREFOX][RUNTIMES.THIS_FIREFOX] =
     73      this._thisFirefoxClient;
     74 
     75    // Enable mocks and remove them after the test.
     76    this.enableMocks();
     77    registerCleanupFunction(() => this.disableMocks());
     78  }
     79 
     80  get thisFirefoxClient() {
     81    return this._thisFirefoxClient;
     82  }
     83 
     84  enableMocks() {
     85    enableAdbMock(this.adbMock);
     86    enableAdbProcessMock(this.adbProcessMock);
     87    enableRuntimeClientFactoryMock(this.runtimeClientFactoryMock);
     88  }
     89 
     90  disableMocks() {
     91    disableAdbMock();
     92    disableAdbProcessMock();
     93    disableRuntimeClientFactoryMock();
     94 
     95    for (const host of Object.keys(this._clients[RUNTIMES.NETWORK])) {
     96      this.removeNetworkRuntime(host);
     97    }
     98  }
     99 
    100  createNetworkRuntime(host, runtimeInfo) {
    101    const {
    102      addNetworkLocation,
    103    } = require("resource://devtools/client/aboutdebugging/src/modules/network-locations.js");
    104    addNetworkLocation(host);
    105 
    106    // Add a valid client that can be returned for this particular runtime id.
    107    const mockNetworkClient = createClientMock();
    108    mockNetworkClient.getDeviceDescription = () => {
    109      return {
    110        name: runtimeInfo.name || "TestBrand",
    111        channel: runtimeInfo.channel || "release",
    112        version: runtimeInfo.version || "1.0",
    113      };
    114    };
    115    this._clients[RUNTIMES.NETWORK][host] = mockNetworkClient;
    116 
    117    return mockNetworkClient;
    118  }
    119 
    120  removeNetworkRuntime(host) {
    121    const {
    122      removeNetworkLocation,
    123    } = require("resource://devtools/client/aboutdebugging/src/modules/network-locations.js");
    124    removeNetworkLocation(host);
    125 
    126    delete this._clients[RUNTIMES.NETWORK][host];
    127  }
    128 
    129  emitUSBUpdate() {
    130    this._observerMock.emit("runtime-list-updated");
    131  }
    132 
    133  /**
    134   * Creates a USB runtime for which a client conenction can be established.
    135   *
    136   * @param {string} id
    137   *        The id of the runtime.
    138   * @param {object} optional object used to create the fake runtime & device
    139   *        - channel: {String} Release channel, for instance "release", "nightly"
    140   *        - clientWrapper: {ClientWrapper} optional ClientWrapper for this runtime
    141   *        - deviceId: {String} Device id
    142   *        - deviceName: {String} Device name
    143   *        - isFenix: {Boolean} set by ADB if the package name matches a Fenix package
    144   *        - name: {String} Application name, for instance "Firefox"
    145   *        - shortName: {String} Short name for the device
    146   *        - socketPath: {String} (should only be used for connecting, so not here)
    147   *        - version: {String} Version, for instance "63.0a"
    148   *        - versionName: {String} Version return by ADB "63.0a"
    149   * @return {object} Returns the mock client created for this runtime so that methods
    150   * can be overridden on it.
    151   */
    152  createUSBRuntime(id, runtimeInfo = {}) {
    153    // Add a new runtime to the list of scanned runtimes.
    154    this._usbRuntimes.push({
    155      deviceId: runtimeInfo.deviceId || "test device id",
    156      deviceName: runtimeInfo.deviceName || "test device name",
    157      id,
    158      isFenix: runtimeInfo.isFenix,
    159      shortName: runtimeInfo.shortName || "testshort",
    160      socketPath: runtimeInfo.socketPath || "test/path",
    161      versionName: runtimeInfo.versionName || "1.0",
    162    });
    163 
    164    // Add a valid client that can be returned for this particular runtime id.
    165    let mockUsbClient = runtimeInfo.clientWrapper;
    166    if (mockUsbClient) {
    167      const originalGetDeviceDescription =
    168        mockUsbClient.getDeviceDescription.bind(mockUsbClient);
    169      mockUsbClient.getDeviceDescription = async () => {
    170        const deviceDescription = await originalGetDeviceDescription();
    171        return {
    172          channel: runtimeInfo.channel || deviceDescription.channel,
    173          name: runtimeInfo.name || deviceDescription.name,
    174          version: runtimeInfo.version || deviceDescription.version,
    175        };
    176      };
    177    } else {
    178      // If no clientWrapper was provided, create a mock client here.
    179      mockUsbClient = createClientMock();
    180      mockUsbClient.getDeviceDescription = () => {
    181        return {
    182          channel: runtimeInfo.channel || "release",
    183          name: runtimeInfo.name || "TestBrand",
    184          version: runtimeInfo.version || "1.0",
    185        };
    186      };
    187    }
    188 
    189    this._clients[RUNTIMES.USB][id] = mockUsbClient;
    190 
    191    return mockUsbClient;
    192  }
    193 
    194  removeUSBRuntime(id) {
    195    this._usbRuntimes = this._usbRuntimes.filter(runtime => runtime.id !== id);
    196    delete this._clients[RUNTIMES.USB][id];
    197  }
    198 
    199  addDevice(deviceId, deviceName) {
    200    this._usbDevices.push({
    201      id: deviceId,
    202      name: deviceName,
    203    });
    204  }
    205 
    206  removeDevice(deviceId) {
    207    this._usbDevices = this._usbDevices.filter(d => {
    208      return d.id !== deviceId;
    209    });
    210  }
    211 
    212  removeRuntime(id) {
    213    if (this._clients[RUNTIMES.USB][id]) {
    214      this.removeUSBRuntime(id);
    215    } else if (this._clients[RUNTIMES.NETWORK][id]) {
    216      this.removeNetworkRuntime(id);
    217    }
    218  }
    219 }
    220 /* exported Mocks */
    221 
    222 const silenceWorkerUpdates = function () {
    223  const {
    224    removeMockedModule,
    225    setMockedModule,
    226  } = require("resource://devtools/shared/loader/browser-loader-mocks.js");
    227 
    228  const mock = {
    229    WorkersListener: () => {
    230      return {
    231        addListener: () => {},
    232        removeListener: () => {},
    233      };
    234    },
    235  };
    236  setMockedModule(mock, "devtools/client/shared/workers-listener");
    237 
    238  registerCleanupFunction(() => {
    239    removeMockedModule("devtools/client/shared/workers-listener");
    240  });
    241 };
    242 /* exported silenceWorkerUpdates */
    243 
    244 async function createLocalClientWrapper() {
    245  info("Create a local DevToolsClient");
    246 
    247  // First, instantiate a DevToolsServer, the same way it is being done when running
    248  // firefox --start-debugger-server
    249  const {
    250    useDistinctSystemPrincipalLoader,
    251    releaseDistinctSystemPrincipalLoader,
    252  } = ChromeUtils.importESModule(
    253    "resource://devtools/shared/loader/DistinctSystemPrincipalLoader.sys.mjs"
    254  );
    255  const requester = {};
    256  const serverLoader = useDistinctSystemPrincipalLoader(requester);
    257  registerCleanupFunction(() => {
    258    releaseDistinctSystemPrincipalLoader(requester);
    259  });
    260  const { DevToolsServer } = serverLoader.require(
    261    "resource://devtools/server/devtools-server.js"
    262  );
    263  DevToolsServer.init();
    264  DevToolsServer.registerAllActors();
    265  DevToolsServer.allowChromeProcess = true;
    266 
    267  // Then spawn a DevToolsClient connected to this new DevToolsServer
    268  const {
    269    DevToolsClient,
    270  } = require("resource://devtools/client/devtools-client.js");
    271  const {
    272    ClientWrapper,
    273  } = require("resource://devtools/client/aboutdebugging/src/modules/client-wrapper.js");
    274 
    275  const client = new DevToolsClient(DevToolsServer.connectPipe());
    276 
    277  await client.connect();
    278  return new ClientWrapper(client);
    279 }
    280 /* exported createLocalClientWrapper */
    281 
    282 // Create a basic mock for this-firefox client, and setup a runtime-client-factory mock
    283 // to return our mock client when needed.
    284 function setupThisFirefoxMock() {
    285  const runtimeClientFactoryMock = createRuntimeClientFactoryMock();
    286  const thisFirefoxClient = createThisFirefoxClientMock();
    287  runtimeClientFactoryMock.createClientForRuntime = runtime => {
    288    if (runtime.id === RUNTIMES.THIS_FIREFOX) {
    289      return thisFirefoxClient;
    290    }
    291    throw new Error("Unexpected runtime id " + runtime.id);
    292  };
    293 
    294  info("Enable mocks");
    295  enableRuntimeClientFactoryMock(runtimeClientFactoryMock);
    296  registerCleanupFunction(() => {
    297    disableRuntimeClientFactoryMock();
    298  });
    299 
    300  return thisFirefoxClient;
    301 }
    302 /* exported setupThisFirefoxMock */