summaryrefslogtreecommitdiffstats
path: root/remote/test/browser/browser_agent.js
blob: 1578aaa6878011a21293dfd16dce5e1bc567c6d4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/ */

"use strict";

const { Preferences } = ChromeUtils.import(
  "resource://gre/modules/Preferences.jsm"
);

// To fully test the Remote Agent's capabilities an instance of the interface
// needs to be used. This refers to the Rust specific implementation.
const remoteAgentInstance = Cc["@mozilla.org/remote/agent;1"].createInstance(
  Ci.nsIRemoteAgent
);

const URL = "http://localhost:0";

// set up test conditions and clean up
function add_agent_task(originalTask) {
  const task = async function() {
    try {
      await RemoteAgent.close();
      await originalTask();
    } finally {
      Preferences.reset("remote.enabled");
      Preferences.reset("remote.force-local");
    }
  };
  Object.defineProperty(task, "name", {
    value: originalTask.name,
    writable: false,
  });
  add_plain_task(task);
}

add_agent_task(async function debuggerAddress() {
  const port = getNonAtomicFreePort();

  await RemoteAgent.listen(`http://localhost:${port}`);
  is(
    remoteAgentInstance.debuggerAddress,
    `localhost:${port}`,
    "debuggerAddress set"
  );
});

add_agent_task(async function listening() {
  is(remoteAgentInstance.listening, false, "Agent is not listening");
  await RemoteAgent.listen(URL);
  is(remoteAgentInstance.listening, true, "Agent is listening");
});

add_agent_task(async function listen() {
  const port = getNonAtomicFreePort();

  let boundURL;
  function observer(subject, topic, data) {
    Services.obs.removeObserver(observer, topic);
    boundURL = Services.io.newURI(data);
  }
  Services.obs.addObserver(observer, "remote-listening");

  await RemoteAgent.listen("http://localhost:" + port);
  isnot(boundURL, undefined, "remote-listening observer notified");
  is(
    boundURL.port,
    port,
    `expected default port ${port}, got ${boundURL.port}`
  );
});

add_agent_task(async function listenWhenDisabled() {
  Preferences.set("remote.enabled", false);
  try {
    await RemoteAgent.listen(URL);
    fail("listen() did not return exception");
  } catch (e) {
    is(e.result, Cr.NS_ERROR_NOT_AVAILABLE);
    is(e.message, "Disabled by preference");
  }
});

// TODO(ato): https://bugzil.la/1590829
add_agent_task(async function listenTakesString() {
  await RemoteAgent.listen("http://localhost:0");
  await RemoteAgent.close();
});

// TODO(ato): https://bugzil.la/1590829
add_agent_task(async function listenNonURL() {
  try {
    await RemoteAgent.listen("foobar");
    fail("listen() did not reject non-URL");
  } catch (e) {
    is(e.result, Cr.NS_ERROR_MALFORMED_URI);
  }
});

add_agent_task(async function listenRestrictedToLoopbackDevice() {
  try {
    await RemoteAgent.listen("http://0.0.0.0:0");
    fail("listen() did not reject non-loopback device");
  } catch (e) {
    is(e.result, Cr.NS_ERROR_ILLEGAL_VALUE);
    is(e.message, "Restricted to loopback devices");
  }
});

add_agent_task(async function listenNonLoopbackDevice() {
  Preferences.set("remote.force-local", false);
  await RemoteAgent.listen("http://0.0.0.0:0");
});

add_agent_task(async function test_close() {
  await RemoteAgent.listen(URL);
  await RemoteAgent.close();
  // no-op when not listening
  await RemoteAgent.close();
});

function getNonAtomicFreePort() {
  const so = Cc["@mozilla.org/network/server-socket;1"].createInstance(
    Ci.nsIServerSocket
  );
  try {
    so.init(-1, true /* aLoopbackOnly */, -1 /* aBackLog */);
    return so.port;
  } finally {
    so.close();
  }
}