forked from mirrors/gecko-dev
This is based on the same rules as for the majority of the rest of mozilla-central. MozReview-Commit-ID: 2O1jH8cNXIj --HG-- extra : rebase_source : b6788a231f70521398ef8783bebce99384a344d9
395 lines
14 KiB
JavaScript
395 lines
14 KiB
JavaScript
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
|
/* Any copyright is dedicated to the Public Domain.
|
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
|
|
"use strict";
|
|
|
|
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
|
|
|
var pcs;
|
|
|
|
// Call |run_next_test| if all functions in |names| are called
|
|
function makeJointSuccess(names) {
|
|
let funcs = {}, successCount = 0;
|
|
names.forEach(function(name) {
|
|
funcs[name] = function() {
|
|
info("got expected: " + name);
|
|
if (++successCount === names.length)
|
|
run_next_test();
|
|
};
|
|
});
|
|
return funcs;
|
|
}
|
|
|
|
function TestDescription(aType, aTcpAddress, aTcpPort) {
|
|
this.type = aType;
|
|
this.tcpAddress = Cc["@mozilla.org/array;1"]
|
|
.createInstance(Ci.nsIMutableArray);
|
|
for (let address of aTcpAddress) {
|
|
let wrapper = Cc["@mozilla.org/supports-cstring;1"]
|
|
.createInstance(Ci.nsISupportsCString);
|
|
wrapper.data = address;
|
|
this.tcpAddress.appendElement(wrapper);
|
|
}
|
|
this.tcpPort = aTcpPort;
|
|
}
|
|
|
|
TestDescription.prototype = {
|
|
QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationChannelDescription]),
|
|
};
|
|
|
|
const CONTROLLER_CONTROL_CHANNEL_PORT = 36777;
|
|
const PRESENTER_CONTROL_CHANNEL_PORT = 36888;
|
|
|
|
var CLOSE_CONTROL_CHANNEL_REASON = Cr.NS_OK;
|
|
var candidate;
|
|
|
|
// presenter's presentation channel description
|
|
const OFFER_ADDRESS = "192.168.123.123";
|
|
const OFFER_PORT = 123;
|
|
|
|
// controller's presentation channel description
|
|
const ANSWER_ADDRESS = "192.168.321.321";
|
|
const ANSWER_PORT = 321;
|
|
|
|
function loopOfferAnser() {
|
|
pcs = Cc["@mozilla.org/presentation/control-service;1"]
|
|
.createInstance(Ci.nsIPresentationControlService);
|
|
pcs.id = "controllerID";
|
|
pcs.listener = {
|
|
onServerReady() {
|
|
testPresentationServer();
|
|
}
|
|
};
|
|
|
|
// First run with TLS enabled.
|
|
pcs.startServer(true, PRESENTER_CONTROL_CHANNEL_PORT);
|
|
}
|
|
|
|
|
|
function testPresentationServer() {
|
|
let yayFuncs = makeJointSuccess(["controllerControlChannelClose",
|
|
"presenterControlChannelClose",
|
|
"controllerControlChannelReconnect",
|
|
"presenterControlChannelReconnect"]);
|
|
let presenterControlChannel;
|
|
|
|
pcs.listener = {
|
|
|
|
onSessionRequest(deviceInfo, url, presentationId, controlChannel) {
|
|
presenterControlChannel = controlChannel;
|
|
Assert.equal(deviceInfo.id, pcs.id, "expected device id");
|
|
Assert.equal(deviceInfo.address, "127.0.0.1", "expected device address");
|
|
Assert.equal(url, "http://example.com", "expected url");
|
|
Assert.equal(presentationId, "testPresentationId", "expected presentation id");
|
|
|
|
presenterControlChannel.listener = {
|
|
status: "created",
|
|
onOffer(aOffer) {
|
|
Assert.equal(this.status, "opened", "1. presenterControlChannel: get offer, send answer");
|
|
this.status = "onOffer";
|
|
|
|
let offer = aOffer.QueryInterface(Ci.nsIPresentationChannelDescription);
|
|
Assert.strictEqual(offer.tcpAddress.queryElementAt(0, Ci.nsISupportsCString).data,
|
|
OFFER_ADDRESS,
|
|
"expected offer address array");
|
|
Assert.equal(offer.tcpPort, OFFER_PORT, "expected offer port");
|
|
try {
|
|
let tcpType = Ci.nsIPresentationChannelDescription.TYPE_TCP;
|
|
let answer = new TestDescription(tcpType, [ANSWER_ADDRESS], ANSWER_PORT);
|
|
presenterControlChannel.sendAnswer(answer);
|
|
} catch (e) {
|
|
Assert.ok(false, "sending answer fails" + e);
|
|
}
|
|
},
|
|
onAnswer(aAnswer) {
|
|
Assert.ok(false, "get answer");
|
|
},
|
|
onIceCandidate(aCandidate) {
|
|
Assert.ok(true, "3. presenterControlChannel: get ice candidate, close channel");
|
|
let recvCandidate = JSON.parse(aCandidate);
|
|
for (let key in recvCandidate) {
|
|
if (typeof(recvCandidate[key]) !== "function") {
|
|
Assert.equal(recvCandidate[key], candidate[key], "key " + key + " should match.");
|
|
}
|
|
}
|
|
presenterControlChannel.disconnect(CLOSE_CONTROL_CHANNEL_REASON);
|
|
},
|
|
notifyConnected() {
|
|
Assert.equal(this.status, "created", "0. presenterControlChannel: opened");
|
|
this.status = "opened";
|
|
},
|
|
notifyDisconnected(aReason) {
|
|
Assert.equal(this.status, "onOffer", "4. presenterControlChannel: closed");
|
|
Assert.equal(aReason, CLOSE_CONTROL_CHANNEL_REASON, "presenterControlChannel notify closed");
|
|
this.status = "closed";
|
|
yayFuncs.controllerControlChannelClose();
|
|
},
|
|
QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationControlChannelListener]),
|
|
};
|
|
},
|
|
onReconnectRequest(deviceInfo, url, presentationId, controlChannel) {
|
|
Assert.equal(url, "http://example.com", "expected url");
|
|
Assert.equal(presentationId, "testPresentationId", "expected presentation id");
|
|
yayFuncs.presenterControlChannelReconnect();
|
|
},
|
|
|
|
QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationControlServerListener]),
|
|
};
|
|
|
|
let presenterDeviceInfo = {
|
|
id: "presentatorID",
|
|
address: "127.0.0.1",
|
|
port: PRESENTER_CONTROL_CHANNEL_PORT,
|
|
certFingerprint: pcs.certFingerprint,
|
|
QueryInterface: ChromeUtils.generateQI([Ci.nsITCPDeviceInfo]),
|
|
};
|
|
|
|
let controllerControlChannel = pcs.connect(presenterDeviceInfo);
|
|
|
|
controllerControlChannel.listener = {
|
|
status: "created",
|
|
onOffer(offer) {
|
|
Assert.ok(false, "get offer");
|
|
},
|
|
onAnswer(aAnswer) {
|
|
Assert.equal(this.status, "opened", "2. controllerControlChannel: get answer, send ICE candidate");
|
|
|
|
let answer = aAnswer.QueryInterface(Ci.nsIPresentationChannelDescription);
|
|
Assert.strictEqual(answer.tcpAddress.queryElementAt(0, Ci.nsISupportsCString).data,
|
|
ANSWER_ADDRESS,
|
|
"expected answer address array");
|
|
Assert.equal(answer.tcpPort, ANSWER_PORT, "expected answer port");
|
|
candidate = {
|
|
candidate: "1 1 UDP 1 127.0.0.1 34567 type host",
|
|
sdpMid: "helloworld",
|
|
sdpMLineIndex: 1
|
|
};
|
|
controllerControlChannel.sendIceCandidate(JSON.stringify(candidate));
|
|
},
|
|
onIceCandidate(aCandidate) {
|
|
Assert.ok(false, "get ICE candidate");
|
|
},
|
|
notifyConnected() {
|
|
Assert.equal(this.status, "created", "0. controllerControlChannel: opened, send offer");
|
|
controllerControlChannel.launch("testPresentationId", "http://example.com");
|
|
this.status = "opened";
|
|
try {
|
|
let tcpType = Ci.nsIPresentationChannelDescription.TYPE_TCP;
|
|
let offer = new TestDescription(tcpType, [OFFER_ADDRESS], OFFER_PORT);
|
|
controllerControlChannel.sendOffer(offer);
|
|
} catch (e) {
|
|
Assert.ok(false, "sending offer fails:" + e);
|
|
}
|
|
},
|
|
notifyDisconnected(aReason) {
|
|
this.status = "closed";
|
|
Assert.equal(aReason, CLOSE_CONTROL_CHANNEL_REASON, "4. controllerControlChannel notify closed");
|
|
yayFuncs.presenterControlChannelClose();
|
|
|
|
let reconnectControllerControlChannel = pcs.connect(presenterDeviceInfo);
|
|
reconnectControllerControlChannel.listener = {
|
|
notifyConnected() {
|
|
reconnectControllerControlChannel.reconnect("testPresentationId", "http://example.com");
|
|
},
|
|
notifyReconnected() {
|
|
yayFuncs.controllerControlChannelReconnect();
|
|
},
|
|
QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationControlChannelListener]),
|
|
};
|
|
},
|
|
QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationControlChannelListener]),
|
|
};
|
|
}
|
|
|
|
function terminateRequest() {
|
|
let yayFuncs = makeJointSuccess(["controllerControlChannelConnected",
|
|
"controllerControlChannelDisconnected",
|
|
"presenterControlChannelDisconnected",
|
|
"terminatedByController",
|
|
"terminatedByReceiver"]);
|
|
let controllerControlChannel;
|
|
let terminatePhase = "controller";
|
|
|
|
pcs.listener = {
|
|
onTerminateRequest(deviceInfo, presentationId, controlChannel, isFromReceiver) {
|
|
Assert.equal(deviceInfo.address, "127.0.0.1", "expected device address");
|
|
Assert.equal(presentationId, "testPresentationId", "expected presentation id");
|
|
controlChannel.terminate(presentationId); // Reply terminate ack.
|
|
|
|
if (terminatePhase === "controller") {
|
|
controllerControlChannel = controlChannel;
|
|
Assert.equal(deviceInfo.id, pcs.id, "expected controller device id");
|
|
Assert.equal(isFromReceiver, false, "expected request from controller");
|
|
yayFuncs.terminatedByController();
|
|
|
|
controllerControlChannel.listener = {
|
|
notifyConnected() {
|
|
Assert.ok(true, "control channel notify connected");
|
|
yayFuncs.controllerControlChannelConnected();
|
|
|
|
terminatePhase = "receiver";
|
|
controllerControlChannel.terminate("testPresentationId");
|
|
},
|
|
notifyDisconnected(aReason) {
|
|
Assert.equal(aReason, CLOSE_CONTROL_CHANNEL_REASON, "controllerControlChannel notify disconncted");
|
|
yayFuncs.controllerControlChannelDisconnected();
|
|
},
|
|
QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationControlChannelListener]),
|
|
};
|
|
} else {
|
|
Assert.equal(deviceInfo.id, presenterDeviceInfo.id, "expected presenter device id");
|
|
Assert.equal(isFromReceiver, true, "expected request from receiver");
|
|
yayFuncs.terminatedByReceiver();
|
|
presenterControlChannel.disconnect(CLOSE_CONTROL_CHANNEL_REASON);
|
|
}
|
|
},
|
|
QueryInterface: ChromeUtils.generateQI([Ci.nsITCPPresentationServerListener]),
|
|
};
|
|
|
|
let presenterDeviceInfo = {
|
|
id: "presentatorID",
|
|
address: "127.0.0.1",
|
|
port: PRESENTER_CONTROL_CHANNEL_PORT,
|
|
certFingerprint: pcs.certFingerprint,
|
|
QueryInterface: ChromeUtils.generateQI([Ci.nsITCPDeviceInfo]),
|
|
};
|
|
|
|
let presenterControlChannel = pcs.connect(presenterDeviceInfo);
|
|
|
|
presenterControlChannel.listener = {
|
|
notifyConnected() {
|
|
presenterControlChannel.terminate("testPresentationId");
|
|
},
|
|
notifyDisconnected(aReason) {
|
|
Assert.equal(aReason, CLOSE_CONTROL_CHANNEL_REASON, "4. presenterControlChannel notify disconnected");
|
|
yayFuncs.presenterControlChannelDisconnected();
|
|
},
|
|
QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationControlChannelListener]),
|
|
};
|
|
}
|
|
|
|
function terminateRequestAbnormal() {
|
|
let yayFuncs = makeJointSuccess(["controllerControlChannelConnected",
|
|
"controllerControlChannelDisconnected",
|
|
"presenterControlChannelDisconnected"]);
|
|
let controllerControlChannel;
|
|
|
|
pcs.listener = {
|
|
onTerminateRequest(deviceInfo, presentationId, controlChannel, isFromReceiver) {
|
|
Assert.equal(deviceInfo.id, pcs.id, "expected controller device id");
|
|
Assert.equal(deviceInfo.address, "127.0.0.1", "expected device address");
|
|
Assert.equal(presentationId, "testPresentationId", "expected presentation id");
|
|
Assert.equal(isFromReceiver, false, "expected request from controller");
|
|
controlChannel.terminate("unmatched-presentationId"); // Reply abnormal terminate ack.
|
|
|
|
controllerControlChannel = controlChannel;
|
|
|
|
controllerControlChannel.listener = {
|
|
notifyConnected() {
|
|
Assert.ok(true, "control channel notify connected");
|
|
yayFuncs.controllerControlChannelConnected();
|
|
},
|
|
notifyDisconnected(aReason) {
|
|
Assert.equal(aReason, Cr.NS_ERROR_FAILURE, "controllerControlChannel notify disconncted with error");
|
|
yayFuncs.controllerControlChannelDisconnected();
|
|
},
|
|
QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationControlChannelListener]),
|
|
};
|
|
},
|
|
QueryInterface: ChromeUtils.generateQI([Ci.nsITCPPresentationServerListener]),
|
|
};
|
|
|
|
let presenterDeviceInfo = {
|
|
id: "presentatorID",
|
|
address: "127.0.0.1",
|
|
port: PRESENTER_CONTROL_CHANNEL_PORT,
|
|
certFingerprint: pcs.certFingerprint,
|
|
QueryInterface: ChromeUtils.generateQI([Ci.nsITCPDeviceInfo]),
|
|
};
|
|
|
|
let presenterControlChannel = pcs.connect(presenterDeviceInfo);
|
|
|
|
presenterControlChannel.listener = {
|
|
notifyConnected() {
|
|
presenterControlChannel.terminate("testPresentationId");
|
|
},
|
|
notifyDisconnected(aReason) {
|
|
Assert.equal(aReason, Cr.NS_ERROR_FAILURE, "4. presenterControlChannel notify disconnected with error");
|
|
yayFuncs.presenterControlChannelDisconnected();
|
|
},
|
|
QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationControlChannelListener]),
|
|
};
|
|
}
|
|
|
|
function setOffline() {
|
|
pcs.listener = {
|
|
onServerReady(aPort, aCertFingerprint) {
|
|
Assert.notEqual(aPort, 0, "TCPPresentationServer port changed and the port should be valid");
|
|
pcs.close();
|
|
run_next_test();
|
|
},
|
|
};
|
|
|
|
// Let the server socket restart automatically.
|
|
Services.io.offline = true;
|
|
Services.io.offline = false;
|
|
}
|
|
|
|
function oneMoreLoop() {
|
|
try {
|
|
pcs.listener = {
|
|
onServerReady() {
|
|
testPresentationServer();
|
|
}
|
|
};
|
|
|
|
// Second run with TLS disabled.
|
|
pcs.startServer(false, PRESENTER_CONTROL_CHANNEL_PORT);
|
|
} catch (e) {
|
|
Assert.ok(false, "TCP presentation init fail:" + e);
|
|
run_next_test();
|
|
}
|
|
}
|
|
|
|
|
|
function shutdown() {
|
|
pcs.listener = {
|
|
onServerReady(aPort, aCertFingerprint) {
|
|
Assert.ok(false, "TCPPresentationServer port changed");
|
|
},
|
|
};
|
|
pcs.close();
|
|
Assert.equal(pcs.port, 0, "TCPPresentationServer closed");
|
|
run_next_test();
|
|
}
|
|
|
|
// Test manually close control channel with NS_ERROR_FAILURE
|
|
function changeCloseReason() {
|
|
CLOSE_CONTROL_CHANNEL_REASON = Cr.NS_ERROR_FAILURE;
|
|
run_next_test();
|
|
}
|
|
|
|
add_test(loopOfferAnser);
|
|
add_test(terminateRequest);
|
|
add_test(terminateRequestAbnormal);
|
|
add_test(setOffline);
|
|
add_test(changeCloseReason);
|
|
add_test(oneMoreLoop);
|
|
add_test(shutdown);
|
|
|
|
function run_test() {
|
|
// Need profile dir to store the key / cert
|
|
do_get_profile();
|
|
// Ensure PSM is initialized
|
|
Cc["@mozilla.org/psm;1"].getService(Ci.nsISupports);
|
|
|
|
Services.prefs.setBoolPref("dom.presentation.tcp_server.debug", true);
|
|
|
|
registerCleanupFunction(() => {
|
|
Services.prefs.clearUserPref("dom.presentation.tcp_server.debug");
|
|
});
|
|
|
|
run_next_test();
|
|
}
|