diff options
Diffstat (limited to '')
3 files changed, 170 insertions, 0 deletions
diff --git a/devtools/shared/discovery/tests/xpcshell/.eslintrc.js b/devtools/shared/discovery/tests/xpcshell/.eslintrc.js new file mode 100644 index 0000000000..7f6b62a9e5 --- /dev/null +++ b/devtools/shared/discovery/tests/xpcshell/.eslintrc.js @@ -0,0 +1,6 @@ +"use strict"; + +module.exports = { + // Extend from the shared list of defined globals for mochitests. + extends: "../../../../.eslintrc.xpcshell.js", +}; diff --git a/devtools/shared/discovery/tests/xpcshell/test_discovery.js b/devtools/shared/discovery/tests/xpcshell/test_discovery.js new file mode 100644 index 0000000000..d2e9c5b6b8 --- /dev/null +++ b/devtools/shared/discovery/tests/xpcshell/test_discovery.js @@ -0,0 +1,158 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ +/* eslint-disable mozilla/no-arbitrary-setTimeout */ + +"use strict"; + +const { require } = ChromeUtils.importESModule( + "resource://devtools/shared/loader/Loader.sys.mjs" +); +const EventEmitter = require("resource://devtools/shared/event-emitter.js"); +const discovery = require("resource://devtools/shared/discovery/discovery.js"); +const { setTimeout, clearTimeout } = ChromeUtils.importESModule( + "resource://gre/modules/Timer.sys.mjs" +); + +Services.prefs.setBoolPref("devtools.discovery.log", true); + +registerCleanupFunction(() => { + Services.prefs.clearUserPref("devtools.discovery.log"); +}); + +function log(msg) { + info("DISCOVERY: " + msg); +} + +// Global map of actively listening ports to TestTransport instances +var gTestTransports = {}; + +/** + * Implements the same API as Transport in discovery.js. Here, no UDP sockets + * are used. Instead, messages are delivered immediately. + */ +function TestTransport(port) { + EventEmitter.decorate(this); + this.port = port; + gTestTransports[this.port] = this; +} + +TestTransport.prototype = { + send(object, port) { + log("Send to " + port + ":\n" + JSON.stringify(object, null, 2)); + if (!gTestTransports[port]) { + log("No listener on port " + port); + return; + } + const message = JSON.stringify(object); + gTestTransports[port].onPacketReceived(null, message); + }, + + destroy() { + delete gTestTransports[this.port]; + }, + + // nsIUDPSocketListener + + onPacketReceived(socket, message) { + const object = JSON.parse(message); + object.from = "localhost"; + log("Recv on " + this.port + ":\n" + JSON.stringify(object, null, 2)); + this.emit("message", object); + }, + + onStopListening(socket, status) {}, +}; + +// Use TestTransport instead of the usual Transport +discovery._factories.Transport = TestTransport; + +// Ignore name generation on b2g and force a fixed value +Object.defineProperty(discovery.device, "name", { + get() { + return "test-device"; + }, +}); + +add_task(async function() { + // At startup, no remote devices are known + deepEqual(discovery.getRemoteDevicesWithService("devtools"), []); + deepEqual(discovery.getRemoteDevicesWithService("penguins"), []); + + discovery.scan(); + + // No services added yet, still empty + deepEqual(discovery.getRemoteDevicesWithService("devtools"), []); + deepEqual(discovery.getRemoteDevicesWithService("penguins"), []); + + discovery.addService("devtools", { port: 1234 }); + + // Changes not visible until next scan + deepEqual(discovery.getRemoteDevicesWithService("devtools"), []); + deepEqual(discovery.getRemoteDevicesWithService("penguins"), []); + + await scanForChange("devtools", "added"); + + // Now we see the new service + deepEqual(discovery.getRemoteDevicesWithService("devtools"), ["test-device"]); + deepEqual(discovery.getRemoteDevicesWithService("penguins"), []); + + discovery.addService("penguins", { tux: true }); + await scanForChange("penguins", "added"); + + deepEqual(discovery.getRemoteDevicesWithService("devtools"), ["test-device"]); + deepEqual(discovery.getRemoteDevicesWithService("penguins"), ["test-device"]); + deepEqual(discovery.getRemoteDevices(), ["test-device"]); + + deepEqual(discovery.getRemoteService("devtools", "test-device"), { + port: 1234, + host: "localhost", + }); + deepEqual(discovery.getRemoteService("penguins", "test-device"), { + tux: true, + host: "localhost", + }); + + discovery.removeService("devtools"); + await scanForChange("devtools", "removed"); + + discovery.addService("penguins", { tux: false }); + await scanForChange("penguins", "updated"); + + // Scan again, but nothing should be removed + await scanForNoChange("penguins", "removed"); + + // Split the scanning side from the service side to simulate the machine with + // the service becoming unreachable + gTestTransports = {}; + + discovery.removeService("penguins"); + await scanForChange("penguins", "removed"); +}); + +function scanForChange(service, changeType) { + return new Promise((resolve, reject) => { + const timer = setTimeout(() => { + reject(new Error("Reply never arrived")); + }, discovery.replyTimeout + 500); + discovery.on(service + "-device-" + changeType, function onChange() { + discovery.off(service + "-device-" + changeType, onChange); + clearTimeout(timer); + resolve(); + }); + discovery.scan(); + }); +} + +function scanForNoChange(service, changeType) { + return new Promise((resolve, reject) => { + const timer = setTimeout(() => { + resolve(); + }, discovery.replyTimeout + 500); + discovery.on(service + "-device-" + changeType, function onChange() { + discovery.off(service + "-device-" + changeType, onChange); + clearTimeout(timer); + reject(new Error("Unexpected change occurred")); + }); + discovery.scan(); + }); +} diff --git a/devtools/shared/discovery/tests/xpcshell/xpcshell.ini b/devtools/shared/discovery/tests/xpcshell/xpcshell.ini new file mode 100644 index 0000000000..145c2d3e2e --- /dev/null +++ b/devtools/shared/discovery/tests/xpcshell/xpcshell.ini @@ -0,0 +1,6 @@ +[DEFAULT] +tags = devtools +head = +firefox-appdir = browser + +[test_discovery.js] |