diff options
Diffstat (limited to 'devtools/shared/discovery/tests/unit/test_discovery.js')
-rw-r--r-- | devtools/shared/discovery/tests/unit/test_discovery.js | 161 |
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; +} |