summaryrefslogtreecommitdiffstats
path: root/devtools/shared/transport/tests/xpcshell/test_dbgsocket.js
blob: c210a80d84a92355923975e6cb99632258822868 (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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/* Any copyright is dedicated to the Public Domain.
   http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";

/* global structuredClone */

var gPort;
var gExtraListener;

function run_test() {
  info("Starting test at " + new Date().toTimeString());
  initTestDevToolsServer();

  add_task(test_socket_conn);
  add_task(test_socket_shutdown);
  add_test(test_pipe_conn);

  run_next_test();
}

const { Actor } = require("resource://devtools/shared/protocol/Actor.js");
class EchoTestActor extends Actor {
  constructor(conn) {
    super(conn, { typeName: "EchoTestActor", methods: [] });

    this.requestTypes = {
      echo: EchoTestActor.prototype.onEcho,
    };
  }

  onEcho(request) {
    /*
     * Request packets are frozen. Copy request, so that
     * DevToolsServerConnection.onPacket can attach a 'from' property.
     */
    return structuredClone(request);
  }
}

async function test_socket_conn() {
  Assert.equal(DevToolsServer.listeningSockets, 0);
  const AuthenticatorType = DevToolsServer.Authenticators.get("PROMPT");
  const authenticator = new AuthenticatorType.Server();
  authenticator.allowConnection = () => {
    return DevToolsServer.AuthenticationResult.ALLOW;
  };
  const socketOptions = {
    authenticator,
    portOrPath: -1,
  };
  const listener = new SocketListener(DevToolsServer, socketOptions);
  Assert.ok(listener);
  listener.open();
  Assert.equal(DevToolsServer.listeningSockets, 1);
  gPort = DevToolsServer._listeners[0].port;
  info("DevTools server port is " + gPort);
  // Open a second, separate listener
  gExtraListener = new SocketListener(DevToolsServer, socketOptions);
  gExtraListener.open();
  Assert.equal(DevToolsServer.listeningSockets, 2);
  Assert.ok(!DevToolsServer.hasConnection());

  info("Starting long and unicode tests at " + new Date().toTimeString());
  // We can't use EventEmitter.once as this is the second argument we care about...
  const onConnectionChange = new Promise(res => {
    DevToolsServer.once("connectionchange", (type, conn) => res(conn));
  });

  const transport = await DevToolsClient.socketConnect({
    host: "127.0.0.1",
    port: gPort,
  });
  Assert.ok(DevToolsServer.hasConnection());
  info("Wait for server connection");
  const conn = await onConnectionChange;

  // Register a custom actor to do echo requests
  const actor = new EchoTestActor(conn);
  actor.actorID = "echo-actor";
  conn.addActor(actor);

  // Assert that connection settings are available on transport object
  const settings = transport.connectionSettings;
  Assert.equal(settings.host, "127.0.0.1");
  Assert.equal(settings.port, gPort);

  const onDebuggerConnectionClosed = DevToolsServer.once("connectionchange");
  const unicodeString = "(╯°□°)╯︵ ┻━┻";
  await new Promise(resolve => {
    transport.hooks = {
      onPacket(packet) {
        this.onPacket = function ({ unicode }) {
          Assert.equal(unicode, unicodeString);
          transport.close();
        };
        // Verify that things work correctly when bigger than the output
        // transport buffers and when transporting unicode...
        transport.send({
          to: "echo-actor",
          type: "echo",
          reallylong: really_long(),
          unicode: unicodeString,
        });
        Assert.equal(packet.from, "root");
      },
      onTransportClosed() {
        resolve();
      },
    };
    transport.ready();
  });
  const type = await onDebuggerConnectionClosed;
  Assert.equal(type, "closed");
  Assert.ok(!DevToolsServer.hasConnection());
}

async function test_socket_shutdown() {
  Assert.equal(DevToolsServer.listeningSockets, 2);
  gExtraListener.close();
  Assert.equal(DevToolsServer.listeningSockets, 1);
  Assert.ok(DevToolsServer.closeAllSocketListeners());
  Assert.equal(DevToolsServer.listeningSockets, 0);
  // Make sure closing the listener twice does nothing.
  Assert.ok(!DevToolsServer.closeAllSocketListeners());
  Assert.equal(DevToolsServer.listeningSockets, 0);

  info("Connecting to a server socket at " + new Date().toTimeString());
  try {
    await DevToolsClient.socketConnect({
      host: "127.0.0.1",
      port: gPort,
    });
  } catch (e) {
    if (
      e.result == Cr.NS_ERROR_CONNECTION_REFUSED ||
      e.result == Cr.NS_ERROR_NET_TIMEOUT
    ) {
      // The connection should be refused here, but on slow or overloaded
      // machines it may just time out.
      Assert.ok(true);
      return;
    }
    throw e;
  }

  // Shouldn't reach this, should never connect.
  Assert.ok(false);
}

function test_pipe_conn() {
  const transport = DevToolsServer.connectPipe();
  transport.hooks = {
    onPacket(packet) {
      Assert.equal(packet.from, "root");
      transport.close();
    },
    onTransportClosed() {
      run_next_test();
    },
  };

  transport.ready();
}