tor-browser

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

testactors.js (7812B)


      1 /* Any copyright is dedicated to the Public Domain.
      2   http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 const {
      7  LazyPool,
      8  createExtraActors,
      9 } = require("resource://devtools/shared/protocol/lazy-pool.js");
     10 const { RootActor } = require("resource://devtools/server/actors/root.js");
     11 const {
     12  WatcherActor,
     13 } = require("resource://devtools/server/actors/watcher.js");
     14 const { ThreadActor } = require("resource://devtools/server/actors/thread.js");
     15 const {
     16  DevToolsServer,
     17 } = require("resource://devtools/server/devtools-server.js");
     18 const {
     19  ActorRegistry,
     20 } = require("resource://devtools/server/actors/utils/actor-registry.js");
     21 const {
     22  SourcesManager,
     23 } = require("resource://devtools/server/actors/utils/sources-manager.js");
     24 const makeDebugger = require("resource://devtools/server/actors/utils/make-debugger.js");
     25 const protocol = require("resource://devtools/shared/protocol.js");
     26 const {
     27  windowGlobalTargetSpec,
     28 } = require("resource://devtools/shared/specs/targets/window-global.js");
     29 const {
     30  tabDescriptorSpec,
     31 } = require("resource://devtools/shared/specs/descriptors/tab.js");
     32 const Targets = require("resource://devtools/server/actors/targets/index.js");
     33 const {
     34  createContentProcessSessionContext,
     35 } = require("resource://devtools/server/actors/watcher/session-context.js");
     36 const { TargetActorRegistry } = ChromeUtils.importESModule(
     37  "resource://devtools/server/actors/targets/target-actor-registry.sys.mjs",
     38  { global: "shared" }
     39 );
     40 const {
     41  BaseTargetActor,
     42 } = require("resource://devtools/server/actors/targets/base-target-actor.js");
     43 const Resources = require("resource://devtools/server/actors/resources/index.js");
     44 
     45 var gTestGlobals = new Set();
     46 DevToolsServer.addTestGlobal = function (global) {
     47  gTestGlobals.add(global);
     48 };
     49 DevToolsServer.removeTestGlobal = function (global) {
     50  gTestGlobals.delete(global);
     51 };
     52 
     53 DevToolsServer.getTestGlobal = function (name) {
     54  for (const g of gTestGlobals) {
     55    if (g.title == name) {
     56      return g;
     57    }
     58  }
     59 
     60  return null;
     61 };
     62 
     63 var gAllowNewThreadGlobals = false;
     64 DevToolsServer.allowNewThreadGlobals = function () {
     65  gAllowNewThreadGlobals = true;
     66 };
     67 DevToolsServer.disallowNewThreadGlobals = function () {
     68  gAllowNewThreadGlobals = false;
     69 };
     70 
     71 // A mock tab list, for use by tests. This simply presents each global in
     72 // gTestGlobals as a tab, and the list is fixed: it never calls its
     73 // onListChanged handler.
     74 //
     75 // As implemented now, we consult gTestGlobals when we're constructed, not
     76 // when we're iterated over, so tests have to add their globals before the
     77 // root actor is created.
     78 class TestTabList {
     79  constructor(connection) {
     80    this.conn = connection;
     81 
     82    // An array of actors for each global added with
     83    // DevToolsServer.addTestGlobal.
     84    this._descriptorActors = [];
     85 
     86    // A pool mapping those actors' names to the actors.
     87    this._descriptorActorPool = new LazyPool(connection);
     88 
     89    for (const global of gTestGlobals) {
     90      const actor = new TestTargetActor(connection, global);
     91      this._descriptorActorPool.manage(actor);
     92 
     93      // Register the target actor, so that the Watcher actor can have access to it.
     94      TargetActorRegistry.registerXpcShellTargetActor(actor);
     95 
     96      const descriptorActor = new TestDescriptorActor(connection, actor);
     97      this._descriptorActorPool.manage(descriptorActor);
     98 
     99      this._descriptorActors.push(descriptorActor);
    100    }
    101  }
    102  destroy() {}
    103  getList() {
    104    return Promise.resolve([...this._descriptorActors]);
    105  }
    106  // Helper method only available for the xpcshell implementation of tablist.
    107  getTargetActorForTab(title) {
    108    const descriptorActor = this._descriptorActors.find(d => d.title === title);
    109    if (!descriptorActor) {
    110      return null;
    111    }
    112    return descriptorActor._targetActor;
    113  }
    114 }
    115 
    116 exports.createRootActor = function createRootActor(connection) {
    117  ActorRegistry.registerModule("devtools/server/actors/webconsole", {
    118    prefix: "console",
    119    constructor: "WebConsoleActor",
    120    type: { target: true },
    121  });
    122  const root = new RootActor(connection, {
    123    tabList: new TestTabList(connection),
    124    globalActorFactories: ActorRegistry.globalActorFactories,
    125  });
    126 
    127  root.applicationType = "xpcshell-tests";
    128  return root;
    129 };
    130 
    131 class TestDescriptorActor extends protocol.Actor {
    132  constructor(conn, targetActor) {
    133    super(conn, tabDescriptorSpec);
    134    this._targetActor = targetActor;
    135  }
    136 
    137  // We don't exercise the selected tab in xpcshell tests.
    138  get selected() {
    139    return false;
    140  }
    141 
    142  get title() {
    143    return this._targetActor.title;
    144  }
    145 
    146  form() {
    147    const form = {
    148      actor: this.actorID,
    149      traits: {
    150        watcher: true,
    151      },
    152      selected: this.selected,
    153      title: this._targetActor.title,
    154      url: this._targetActor.url,
    155    };
    156 
    157    return form;
    158  }
    159 
    160  getWatcher() {
    161    const sessionContext = {
    162      type: "all",
    163      supportedTargets: {},
    164      supportedResources: [
    165        Resources.TYPES.SOURCE,
    166        Resources.TYPES.CONSOLE_MESSAGE,
    167        Resources.TYPES.THREAD_STATE,
    168      ],
    169    };
    170    const watcherActor = new WatcherActor(this.conn, sessionContext);
    171    return watcherActor;
    172  }
    173 
    174  getFavicon() {
    175    return "";
    176  }
    177 
    178  getTarget() {
    179    return this._targetActor.form();
    180  }
    181 }
    182 
    183 class TestTargetActor extends BaseTargetActor {
    184  constructor(conn, global) {
    185    super(conn, Targets.TYPES.FRAME, windowGlobalTargetSpec);
    186 
    187    this.sessionContext = createContentProcessSessionContext();
    188    this._global = global;
    189    try {
    190      this._global.wrappedJSObject = Cu.unwaiveXrays(global);
    191    } catch (e) {}
    192    this.threadActor = new ThreadActor(this, this._global);
    193    this.conn.addActor(this.threadActor);
    194    this._extraActors = {};
    195    // This is a hack in order to enable threadActor to be accessed from getFront
    196    this._extraActors.threadActor = this.threadActor;
    197    this.makeDebugger = makeDebugger.bind(null, {
    198      findDebuggees: () => [this._global],
    199      shouldAddNewGlobalAsDebuggee: () => gAllowNewThreadGlobals,
    200    });
    201    this.dbg = this.makeDebugger();
    202    this.notifyResources = this.notifyResources.bind(this);
    203  }
    204 
    205  targetType = Targets.TYPES.FRAME;
    206 
    207  // This is still used by the web console startListeners method
    208  get window() {
    209    return this._global;
    210  }
    211 
    212  get targetGlobal() {
    213    return this._global;
    214  }
    215 
    216  // Both title and url point to this._global.title
    217  get title() {
    218    return this._global.document.title;
    219  }
    220 
    221  get url() {
    222    return this._global.title;
    223  }
    224 
    225  get sourcesManager() {
    226    if (!this._sourcesManager) {
    227      this._sourcesManager = new SourcesManager(this.threadActor);
    228    }
    229    return this._sourcesManager;
    230  }
    231 
    232  form() {
    233    const response = {
    234      actor: this.actorID,
    235      title: this.title,
    236      threadActor: this.threadActor.actorID,
    237      targetType: this.targetType,
    238    };
    239 
    240    // Walk over target-scoped actors and add them to a new LazyPool.
    241    const actorPool = new LazyPool(this.conn);
    242    const actors = createExtraActors(
    243      ActorRegistry.targetScopedActorFactories,
    244      actorPool,
    245      this
    246    );
    247    if (actorPool?._poolMap.size > 0) {
    248      this._descriptorActorPool = actorPool;
    249      this.conn.addActorPool(this._descriptorActorPool);
    250    }
    251 
    252    return { ...response, ...actors };
    253  }
    254 
    255  detach() {
    256    this.threadActor.destroy();
    257    return { type: "detached" };
    258  }
    259 
    260  reload() {
    261    this.sourcesManager.reset();
    262    this.threadActor.clearDebuggees();
    263    this.threadActor.dbg.addDebuggees();
    264    return {};
    265  }
    266 
    267  removeActorByName(name) {
    268    const actor = this._extraActors[name];
    269    if (this._descriptorActorPool) {
    270      this._descriptorActorPool.removeActor(actor);
    271    }
    272    delete this._extraActors[name];
    273  }
    274 
    275  notifyResources(updateType, resourceType, resources) {
    276    this.emit(`resources-${updateType}-array`, [[resourceType, resources]]);
    277  }
    278 }