fune/devtools/shared/discovery/tests/unit/test_discovery.js

161 lines
4.8 KiB
JavaScript

/* 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;
}