gecko-dev/dom/presentation/tests/mochitest/PresentationSessionChromeSc...

413 строки
11 KiB
JavaScript

/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
/* eslint-env mozilla/frame-script */
const Cm = Components.manager;
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].getService(
Ci.nsIUUIDGenerator
);
function debug(str) {
// dump('DEBUG -*- PresentationSessionChromeScript1UA -*-: ' + str + '\n');
}
const originalFactoryData = [];
var sessionId; // Store the uuid generated by PresentationRequest.
var triggerControlChannelError = false; // For simulating error during control channel establishment.
// control channel of sender
const mockControlChannelOfSender = {
QueryInterface: ChromeUtils.generateQI(["nsIPresentationControlChannel"]),
set listener(listener) {
// PresentationControllingInfo::SetControlChannel
if (listener) {
debug("set listener for mockControlChannelOfSender without null");
} else {
debug("set listener for mockControlChannelOfSender with null");
}
this._listener = listener;
},
get listener() {
return this._listener;
},
notifyConnected() {
// send offer after notifyConnected immediately
this._listener
.QueryInterface(Ci.nsIPresentationControlChannelListener)
.notifyConnected();
},
notifyReconnected() {
// send offer after notifyOpened immediately
this._listener
.QueryInterface(Ci.nsIPresentationControlChannelListener)
.notifyReconnected();
},
sendOffer(offer) {
Services.tm.dispatchToMainThread(() => {
mockControlChannelOfReceiver.onOffer(offer);
});
},
onAnswer(answer) {
this._listener
.QueryInterface(Ci.nsIPresentationControlChannelListener)
.onAnswer(answer);
},
launch(presentationId, url) {
sessionId = presentationId;
sendAsyncMessage("sender-launch", url);
},
disconnect(reason) {
if (!this._listener) {
return;
}
this._listener
.QueryInterface(Ci.nsIPresentationControlChannelListener)
.notifyDisconnected(reason);
mockControlChannelOfReceiver.disconnect();
},
terminate(presentationId) {
sendAsyncMessage("sender-terminate");
},
reconnect(presentationId, url) {
sendAsyncMessage("start-reconnect", url);
},
sendIceCandidate(candidate) {
mockControlChannelOfReceiver.notifyIceCandidate(candidate);
},
notifyIceCandidate(candidate) {
if (!this._listener) {
return;
}
this._listener
.QueryInterface(Ci.nsIPresentationControlChannelListener)
.onIceCandidate(candidate);
},
};
// control channel of receiver
const mockControlChannelOfReceiver = {
QueryInterface: ChromeUtils.generateQI(["nsIPresentationControlChannel"]),
set listener(listener) {
// PresentationPresentingInfo::SetControlChannel
if (listener) {
debug("set listener for mockControlChannelOfReceiver without null");
} else {
debug("set listener for mockControlChannelOfReceiver with null");
}
this._listener = listener;
if (this._pendingOpened) {
this._pendingOpened = false;
this.notifyConnected();
}
},
get listener() {
return this._listener;
},
notifyConnected() {
// do nothing
if (!this._listener) {
this._pendingOpened = true;
return;
}
this._listener
.QueryInterface(Ci.nsIPresentationControlChannelListener)
.notifyConnected();
},
onOffer(offer) {
this._listener
.QueryInterface(Ci.nsIPresentationControlChannelListener)
.onOffer(offer);
},
sendAnswer(answer) {
Services.tm.dispatchToMainThread(() => {
mockControlChannelOfSender.onAnswer(answer);
});
},
disconnect(reason) {
if (!this._listener) {
return;
}
this._listener
.QueryInterface(Ci.nsIPresentationControlChannelListener)
.notifyDisconnected(reason);
sendAsyncMessage("control-channel-receiver-closed", reason);
},
terminate(presentaionId) {},
sendIceCandidate(candidate) {
mockControlChannelOfSender.notifyIceCandidate(candidate);
},
notifyIceCandidate(candidate) {
if (!this._listener) {
return;
}
this._listener
.QueryInterface(Ci.nsIPresentationControlChannelListener)
.onIceCandidate(candidate);
},
};
const mockDevice = {
QueryInterface: ChromeUtils.generateQI(["nsIPresentationDevice"]),
id: "id",
name: "name",
type: "type",
establishControlChannel(url, presentationId) {
if (triggerControlChannelError) {
throw Components.Exception("", Cr.NS_ERROR_FAILURE);
}
sendAsyncMessage("control-channel-established");
return mockControlChannelOfSender;
},
disconnect() {
sendAsyncMessage("device-disconnected");
},
isRequestedUrlSupported(requestedUrl) {
return true;
},
};
const mockDevicePrompt = {
QueryInterface: ChromeUtils.generateQI([
"nsIPresentationDevicePrompt",
"nsIFactory",
]),
createInstance(aOuter, aIID) {
if (aOuter) {
throw Components.Exception("", Cr.NS_ERROR_NO_AGGREGATION);
}
return this.QueryInterface(aIID);
},
set request(request) {
this._request = request;
},
get request() {
return this._request;
},
promptDeviceSelection(request) {
this._request = request;
sendAsyncMessage("device-prompt");
},
simulateSelect() {
this._request.select(mockDevice);
},
simulateCancel() {
this._request.cancel();
},
};
const mockRequestUIGlue = {
QueryInterface: ChromeUtils.generateQI([
"nsIPresentationRequestUIGlue",
"nsIFactory",
]),
set promise(aPromise) {
this._promise = aPromise;
},
get promise() {
return this._promise;
},
createInstance(aOuter, aIID) {
if (aOuter) {
throw Components.Exception("", Cr.NS_ERROR_NO_AGGREGATION);
}
return this.QueryInterface(aIID);
},
sendRequest(aUrl, aSessionId) {
return this.promise;
},
};
function initMockAndListener() {
function registerMockFactory(contractId, mockClassId, mockFactory) {
var originalClassId, originalFactory;
var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
if (!registrar.isCIDRegistered(mockClassId)) {
try {
originalClassId = registrar.contractIDToCID(contractId);
originalFactory = Cm.getClassObject(Cc[contractId], Ci.nsIFactory);
} catch (ex) {
originalClassId = "";
originalFactory = null;
}
if (originalFactory) {
registrar.unregisterFactory(originalClassId, originalFactory);
}
registrar.registerFactory(mockClassId, "", contractId, mockFactory);
}
return {
contractId,
mockClassId,
mockFactory,
originalClassId,
originalFactory,
};
}
// Register mock factories.
originalFactoryData.push(
registerMockFactory(
"@mozilla.org/presentation-device/prompt;1",
uuidGenerator.generateUUID(),
mockDevicePrompt
)
);
originalFactoryData.push(
registerMockFactory(
"@mozilla.org/presentation/requestuiglue;1",
uuidGenerator.generateUUID(),
mockRequestUIGlue
)
);
addMessageListener("trigger-device-add", function() {
debug("Got message: trigger-device-add");
var deviceManager = Cc[
"@mozilla.org/presentation-device/manager;1"
].getService(Ci.nsIPresentationDeviceManager);
deviceManager
.QueryInterface(Ci.nsIPresentationDeviceListener)
.addDevice(mockDevice);
});
addMessageListener("trigger-device-prompt-select", function() {
debug("Got message: trigger-device-prompt-select");
mockDevicePrompt.simulateSelect();
});
addMessageListener("trigger-on-session-request", function(url) {
debug("Got message: trigger-on-session-request");
var deviceManager = Cc[
"@mozilla.org/presentation-device/manager;1"
].getService(Ci.nsIPresentationDeviceManager);
deviceManager
.QueryInterface(Ci.nsIPresentationDeviceListener)
.onSessionRequest(
mockDevice,
url,
sessionId,
mockControlChannelOfReceiver
);
});
addMessageListener("trigger-on-terminate-request", function() {
debug("Got message: trigger-on-terminate-request");
var deviceManager = Cc[
"@mozilla.org/presentation-device/manager;1"
].getService(Ci.nsIPresentationDeviceManager);
deviceManager
.QueryInterface(Ci.nsIPresentationDeviceListener)
.onTerminateRequest(
mockDevice,
sessionId,
mockControlChannelOfReceiver,
false
);
});
addMessageListener("trigger-control-channel-open", function(reason) {
debug("Got message: trigger-control-channel-open");
mockControlChannelOfSender.notifyConnected();
mockControlChannelOfReceiver.notifyConnected();
});
addMessageListener("trigger-control-channel-error", function(reason) {
debug("Got message: trigger-control-channel-open");
triggerControlChannelError = true;
});
addMessageListener("trigger-reconnected-acked", function(url) {
debug("Got message: trigger-reconnected-acked");
mockControlChannelOfSender.notifyReconnected();
var deviceManager = Cc[
"@mozilla.org/presentation-device/manager;1"
].getService(Ci.nsIPresentationDeviceManager);
deviceManager
.QueryInterface(Ci.nsIPresentationDeviceListener)
.onReconnectRequest(
mockDevice,
url,
sessionId,
mockControlChannelOfReceiver
);
});
// Used to call sendAsyncMessage in chrome script from receiver.
addMessageListener("forward-command", function(command_data) {
let command = JSON.parse(command_data);
sendAsyncMessage(command.name, command.data);
});
addMessageListener("teardown", teardown);
Services.obs.addObserver(function setupRequestPromiseHandler(
aSubject,
aTopic,
aData
) {
debug("Got observer: setup-request-promise");
Services.obs.removeObserver(setupRequestPromiseHandler, aTopic);
mockRequestUIGlue.promise = aSubject;
sendAsyncMessage("promise-setup-ready");
},
"setup-request-promise");
}
function teardown() {
function registerOriginalFactory(
contractId,
mockedClassId,
mockedFactory,
originalClassId,
originalFactory
) {
if (originalFactory) {
var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
registrar.unregisterFactory(mockedClassId, mockedFactory);
registrar.registerFactory(
originalClassId,
"",
contractId,
originalFactory
);
}
}
mockRequestUIGlue.promise = null;
mockControlChannelOfSender.listener = null;
mockControlChannelOfReceiver.listener = null;
mockDevicePrompt.request = null;
var deviceManager = Cc[
"@mozilla.org/presentation-device/manager;1"
].getService(Ci.nsIPresentationDeviceManager);
deviceManager
.QueryInterface(Ci.nsIPresentationDeviceListener)
.removeDevice(mockDevice);
// Register original factories.
for (var data of originalFactoryData) {
registerOriginalFactory(
data.contractId,
data.mockClassId,
data.mockFactory,
data.originalClassId,
data.originalFactory
);
}
sendAsyncMessage("teardown-complete");
}
initMockAndListener();