tor-browser

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

test_discovery.js (4832B)


      1 /* Any copyright is dedicated to the Public Domain.
      2   http://creativecommons.org/publicdomain/zero/1.0/ */
      3 /* eslint-disable mozilla/no-arbitrary-setTimeout */
      4 
      5 "use strict";
      6 
      7 const { require } = ChromeUtils.importESModule(
      8  "resource://devtools/shared/loader/Loader.sys.mjs"
      9 );
     10 const EventEmitter = require("resource://devtools/shared/event-emitter.js");
     11 const discovery = require("resource://devtools/shared/discovery/discovery.js");
     12 const { setTimeout, clearTimeout } = ChromeUtils.importESModule(
     13  "resource://gre/modules/Timer.sys.mjs"
     14 );
     15 
     16 Services.prefs.setBoolPref("devtools.discovery.log", true);
     17 
     18 registerCleanupFunction(() => {
     19  Services.prefs.clearUserPref("devtools.discovery.log");
     20 });
     21 
     22 function log(msg) {
     23  info("DISCOVERY: " + msg);
     24 }
     25 
     26 // Global map of actively listening ports to TestTransport instances
     27 var gTestTransports = {};
     28 
     29 /**
     30 * Implements the same API as Transport in discovery.js.  Here, no UDP sockets
     31 * are used.  Instead, messages are delivered immediately.
     32 */
     33 class TestTransport {
     34  constructor(port) {
     35    EventEmitter.decorate(this);
     36    this.port = port;
     37    gTestTransports[this.port] = this;
     38  }
     39  send(object, port) {
     40    log("Send to " + port + ":\n" + JSON.stringify(object, null, 2));
     41    if (!gTestTransports[port]) {
     42      log("No listener on port " + port);
     43      return;
     44    }
     45    const message = JSON.stringify(object);
     46    gTestTransports[port].onPacketReceived(null, message);
     47  }
     48 
     49  destroy() {
     50    delete gTestTransports[this.port];
     51  }
     52 
     53  // nsIUDPSocketListener
     54  onPacketReceived(socket, message) {
     55    const object = JSON.parse(message);
     56    object.from = "localhost";
     57    log("Recv on " + this.port + ":\n" + JSON.stringify(object, null, 2));
     58    this.emit("message", object);
     59  }
     60 
     61  onStopListening() {}
     62 }
     63 
     64 // Use TestTransport instead of the usual Transport
     65 discovery._factories.Transport = TestTransport;
     66 
     67 // Ignore name generation on b2g and force a fixed value
     68 Object.defineProperty(discovery.device, "name", {
     69  get() {
     70    return "test-device";
     71  },
     72 });
     73 
     74 add_task(async function () {
     75  // At startup, no remote devices are known
     76  deepEqual(discovery.getRemoteDevicesWithService("devtools"), []);
     77  deepEqual(discovery.getRemoteDevicesWithService("penguins"), []);
     78 
     79  discovery.scan();
     80 
     81  // No services added yet, still empty
     82  deepEqual(discovery.getRemoteDevicesWithService("devtools"), []);
     83  deepEqual(discovery.getRemoteDevicesWithService("penguins"), []);
     84 
     85  discovery.addService("devtools", { port: 1234 });
     86 
     87  // Changes not visible until next scan
     88  deepEqual(discovery.getRemoteDevicesWithService("devtools"), []);
     89  deepEqual(discovery.getRemoteDevicesWithService("penguins"), []);
     90 
     91  await scanForChange("devtools", "added");
     92 
     93  // Now we see the new service
     94  deepEqual(discovery.getRemoteDevicesWithService("devtools"), ["test-device"]);
     95  deepEqual(discovery.getRemoteDevicesWithService("penguins"), []);
     96 
     97  discovery.addService("penguins", { tux: true });
     98  await scanForChange("penguins", "added");
     99 
    100  deepEqual(discovery.getRemoteDevicesWithService("devtools"), ["test-device"]);
    101  deepEqual(discovery.getRemoteDevicesWithService("penguins"), ["test-device"]);
    102  deepEqual(discovery.getRemoteDevices(), ["test-device"]);
    103 
    104  deepEqual(discovery.getRemoteService("devtools", "test-device"), {
    105    port: 1234,
    106    host: "localhost",
    107  });
    108  deepEqual(discovery.getRemoteService("penguins", "test-device"), {
    109    tux: true,
    110    host: "localhost",
    111  });
    112 
    113  discovery.removeService("devtools");
    114  await scanForChange("devtools", "removed");
    115 
    116  discovery.addService("penguins", { tux: false });
    117  await scanForChange("penguins", "updated");
    118 
    119  // Scan again, but nothing should be removed
    120  await scanForNoChange("penguins", "removed");
    121 
    122  // Split the scanning side from the service side to simulate the machine with
    123  // the service becoming unreachable
    124  gTestTransports = {};
    125 
    126  discovery.removeService("penguins");
    127  await scanForChange("penguins", "removed");
    128 });
    129 
    130 function scanForChange(service, changeType) {
    131  return new Promise((resolve, reject) => {
    132    const timer = setTimeout(() => {
    133      reject(new Error("Reply never arrived"));
    134    }, discovery.replyTimeout + 500);
    135    discovery.on(service + "-device-" + changeType, function onChange() {
    136      discovery.off(service + "-device-" + changeType, onChange);
    137      clearTimeout(timer);
    138      resolve();
    139    });
    140    discovery.scan();
    141  });
    142 }
    143 
    144 function scanForNoChange(service, changeType) {
    145  return new Promise((resolve, reject) => {
    146    const timer = setTimeout(() => {
    147      resolve();
    148    }, discovery.replyTimeout + 500);
    149    discovery.on(service + "-device-" + changeType, function onChange() {
    150      discovery.off(service + "-device-" + changeType, onChange);
    151      clearTimeout(timer);
    152      reject(new Error("Unexpected change occurred"));
    153    });
    154    discovery.scan();
    155  });
    156 }