summaryrefslogtreecommitdiffstats
path: root/devtools/shared/discovery/tests/unit/test_discovery.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/shared/discovery/tests/unit/test_discovery.js')
-rw-r--r--devtools/shared/discovery/tests/unit/test_discovery.js161
1 files changed, 161 insertions, 0 deletions
diff --git a/devtools/shared/discovery/tests/unit/test_discovery.js b/devtools/shared/discovery/tests/unit/test_discovery.js
new file mode 100644
index 000000000..c31340b08
--- /dev/null
+++ b/devtools/shared/discovery/tests/unit/test_discovery.js
@@ -0,0 +1,161 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+var Cu = Components.utils;
+
+const { require } =
+ Cu.import("resource://devtools/shared/Loader.jsm", {});
+const Services = require("Services");
+const promise = require("promise");
+const defer = require("devtools/shared/defer");
+const EventEmitter = require("devtools/shared/event-emitter");
+const discovery = require("devtools/shared/discovery/discovery");
+const { setTimeout, clearTimeout } = require("sdk/timers");
+
+Services.prefs.setBoolPref("devtools.discovery.log", true);
+
+do_register_cleanup(() => {
+ Services.prefs.clearUserPref("devtools.discovery.log");
+});
+
+function log(msg) {
+ do_print("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: function (object, port) {
+ log("Send to " + port + ":\n" + JSON.stringify(object, null, 2));
+ if (!gTestTransports[port]) {
+ log("No listener on port " + port);
+ return;
+ }
+ let message = JSON.stringify(object);
+ gTestTransports[port].onPacketReceived(null, message);
+ },
+
+ destroy: function () {
+ delete gTestTransports[this.port];
+ },
+
+ // nsIUDPSocketListener
+
+ onPacketReceived: function (socket, message) {
+ let object = JSON.parse(message);
+ object.from = "localhost";
+ log("Recv on " + this.port + ":\n" + JSON.stringify(object, null, 2));
+ this.emit("message", object);
+ },
+
+ onStopListening: function (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: function () {
+ return "test-device";
+ }
+});
+
+function run_test() {
+ run_next_test();
+}
+
+add_task(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"), []);
+
+ yield scanForChange("devtools", "added");
+
+ // Now we see the new service
+ deepEqual(discovery.getRemoteDevicesWithService("devtools"), ["test-device"]);
+ deepEqual(discovery.getRemoteDevicesWithService("penguins"), []);
+
+ discovery.addService("penguins", { tux: true });
+ yield 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");
+ yield scanForChange("devtools", "removed");
+
+ discovery.addService("penguins", { tux: false });
+ yield scanForChange("penguins", "updated");
+
+ // Scan again, but nothing should be removed
+ yield scanForNoChange("penguins", "removed");
+
+ // Split the scanning side from the service side to simulate the machine with
+ // the service becoming unreachable
+ gTestTransports = {};
+
+ discovery.removeService("penguins");
+ yield scanForChange("penguins", "removed");
+});
+
+function scanForChange(service, changeType) {
+ let deferred = defer();
+ let timer = setTimeout(() => {
+ deferred.reject(new Error("Reply never arrived"));
+ }, discovery.replyTimeout + 500);
+ discovery.on(service + "-device-" + changeType, function onChange() {
+ discovery.off(service + "-device-" + changeType, onChange);
+ clearTimeout(timer);
+ deferred.resolve();
+ });
+ discovery.scan();
+ return deferred.promise;
+}
+
+function scanForNoChange(service, changeType) {
+ let deferred = defer();
+ let timer = setTimeout(() => {
+ deferred.resolve();
+ }, discovery.replyTimeout + 500);
+ discovery.on(service + "-device-" + changeType, function onChange() {
+ discovery.off(service + "-device-" + changeType, onChange);
+ clearTimeout(timer);
+ deferred.reject(new Error("Unexpected change occurred"));
+ });
+ discovery.scan();
+ return deferred.promise;
+}