import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

View file

@ -0,0 +1,150 @@
/* -*- 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';
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Cu.import('resource://gre/modules/PresentationDeviceInfoManager.jsm');
const { XPCOMUtils } = Cu.import('resource://gre/modules/XPCOMUtils.jsm');
const manager = Cc['@mozilla.org/presentation-device/manager;1']
.getService(Ci.nsIPresentationDeviceManager);
var testProvider = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceProvider]),
forceDiscovery: function() {
sendAsyncMessage('force-discovery');
},
listener: null,
};
var testDevice = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
establishControlChannel: function() {
return null;
},
disconnect: function() {},
isRequestedUrlSupported: function(requestedUrl) {
return true;
},
id: null,
name: null,
type: null,
listener: null,
};
var testDevice1 = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
id: 'dummyid',
name: 'dummyName',
type: 'dummyType',
establishControlChannel: function(url, presentationId) {
return null;
},
disconnect: function() {},
isRequestedUrlSupported: function(requestedUrl) {
return true;
},
};
var testDevice2 = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
id: 'dummyid',
name: 'dummyName',
type: 'dummyType',
establishControlChannel: function(url, presentationId) {
return null;
},
disconnect: function() {},
isRequestedUrlSupported: function(requestedUrl) {
return true;
},
};
var mockedDeviceWithoutSupportedURL = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
id: 'dummyid',
name: 'dummyName',
type: 'dummyType',
establishControlChannel: function(url, presentationId) {
return null;
},
disconnect: function() {},
isRequestedUrlSupported: function(requestedUrl) {
return false;
},
};
var mockedDeviceSupportHttpsURL = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
id: 'dummyid',
name: 'dummyName',
type: 'dummyType',
establishControlChannel: function(url, presentationId) {
return null;
},
disconnect: function() {},
isRequestedUrlSupported: function(requestedUrl) {
if (requestedUrl.indexOf("https://") != -1) {
return true;
}
return false;
},
};
addMessageListener('setup', function() {
manager.addDeviceProvider(testProvider);
sendAsyncMessage('setup-complete');
});
addMessageListener('trigger-device-add', function(device) {
testDevice.id = device.id;
testDevice.name = device.name;
testDevice.type = device.type;
manager.addDevice(testDevice);
});
addMessageListener('trigger-add-unsupport-url-device', function() {
manager.addDevice(mockedDeviceWithoutSupportedURL);
});
addMessageListener('trigger-add-multiple-devices', function() {
manager.addDevice(testDevice1);
manager.addDevice(testDevice2);
});
addMessageListener('trigger-add-https-devices', function() {
manager.addDevice(mockedDeviceSupportHttpsURL);
});
addMessageListener('trigger-device-update', function(device) {
testDevice.id = device.id;
testDevice.name = device.name;
testDevice.type = device.type;
manager.updateDevice(testDevice);
});
addMessageListener('trigger-device-remove', function() {
manager.removeDevice(testDevice);
});
addMessageListener('trigger-remove-unsupported-device', function() {
manager.removeDevice(mockedDeviceWithoutSupportedURL);
});
addMessageListener('trigger-remove-multiple-devices', function() {
manager.removeDevice(testDevice1);
manager.removeDevice(testDevice2);
});
addMessageListener('trigger-remove-https-devices', function() {
manager.removeDevice(mockedDeviceSupportHttpsURL);
});
addMessageListener('teardown', function() {
manager.removeDeviceProvider(testProvider);
});

View file

@ -0,0 +1,470 @@
/* -*- 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';
const { classes: Cc, interfaces: Ci, manager: Cm, utils: Cu, results: Cr } = Components;
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://gre/modules/Timer.jsm');
const uuidGenerator = Cc["@mozilla.org/uuid-generator;1"]
.getService(Ci.nsIUUIDGenerator);
function registerMockedFactory(contractId, mockedClassId, mockedFactory) {
var originalClassId, originalFactory;
var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
if (!registrar.isCIDRegistered(mockedClassId)) {
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(mockedClassId, "", contractId, mockedFactory);
}
return { contractId: contractId,
mockedClassId: mockedClassId,
mockedFactory: mockedFactory,
originalClassId: originalClassId,
originalFactory: originalFactory };
}
function registerOriginalFactory(contractId, mockedClassId, mockedFactory, originalClassId, originalFactory) {
if (originalFactory) {
var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
registrar.unregisterFactory(mockedClassId, mockedFactory);
registrar.registerFactory(originalClassId, "", contractId, originalFactory);
}
}
var sessionId = 'test-session-id-' + uuidGenerator.generateUUID().toString();
const address = Cc["@mozilla.org/supports-cstring;1"]
.createInstance(Ci.nsISupportsCString);
address.data = "127.0.0.1";
const addresses = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
addresses.appendElement(address, false);
const mockedChannelDescription = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationChannelDescription]),
get type() {
if (Services.prefs.getBoolPref("dom.presentation.session_transport.data_channel.enable")) {
return Ci.nsIPresentationChannelDescription.TYPE_DATACHANNEL;
}
return Ci.nsIPresentationChannelDescription.TYPE_TCP;
},
tcpAddress: addresses,
tcpPort: 1234,
};
const mockedServerSocket = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIServerSocket,
Ci.nsIFactory]),
createInstance: function(aOuter, aIID) {
if (aOuter) {
throw Components.results.NS_ERROR_NO_AGGREGATION;
}
return this.QueryInterface(aIID);
},
get port() {
return this._port;
},
set listener(listener) {
this._listener = listener;
},
init: function(port, loopbackOnly, backLog) {
if (port != -1) {
this._port = port;
} else {
this._port = 5678;
}
},
asyncListen: function(listener) {
this._listener = listener;
},
close: function() {
this._listener.onStopListening(this, Cr.NS_BINDING_ABORTED);
},
simulateOnSocketAccepted: function(serverSocket, socketTransport) {
this._listener.onSocketAccepted(serverSocket, socketTransport);
}
};
const mockedSocketTransport = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsISocketTransport]),
};
const mockedControlChannel = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel]),
set listener(listener) {
this._listener = listener;
},
get listener() {
return this._listener;
},
sendOffer: function(offer) {
sendAsyncMessage('offer-sent', this._isValidSDP(offer));
},
sendAnswer: function(answer) {
sendAsyncMessage('answer-sent', this._isValidSDP(answer));
if (answer.type == Ci.nsIPresentationChannelDescription.TYPE_TCP) {
this._listener.QueryInterface(Ci.nsIPresentationSessionTransportCallback).notifyTransportReady();
}
},
_isValidSDP: function(aSDP) {
var isValid = false;
if (aSDP.type == Ci.nsIPresentationChannelDescription.TYPE_TCP) {
try {
var addresses = aSDP.tcpAddress;
if (addresses.length > 0) {
for (var i = 0; i < addresses.length; i++) {
// Ensure CString addresses are used. Otherwise, an error will be thrown.
addresses.queryElementAt(i, Ci.nsISupportsCString);
}
isValid = true;
}
} catch (e) {
isValid = false;
}
} else if (aSDP.type == Ci.nsIPresentationChannelDescription.TYPE_DATACHANNEL) {
isValid = (aSDP.dataChannelSDP == "test-sdp");
}
return isValid;
},
launch: function(presentationId, url) {
sessionId = presentationId;
},
terminate: function(presentationId) {
sendAsyncMessage('sender-terminate', presentationId);
},
reconnect: function(presentationId, url) {
sendAsyncMessage('start-reconnect', url);
},
notifyReconnected: function() {
this._listener
.QueryInterface(Ci.nsIPresentationControlChannelListener)
.notifyReconnected();
},
disconnect: function(reason) {
sendAsyncMessage('control-channel-closed', reason);
this._listener.QueryInterface(Ci.nsIPresentationControlChannelListener).notifyDisconnected(reason);
},
simulateReceiverReady: function() {
this._listener.QueryInterface(Ci.nsIPresentationControlChannelListener).notifyReceiverReady();
},
simulateOnOffer: function() {
sendAsyncMessage('offer-received');
this._listener.QueryInterface(Ci.nsIPresentationControlChannelListener).onOffer(mockedChannelDescription);
},
simulateOnAnswer: function() {
sendAsyncMessage('answer-received');
this._listener.QueryInterface(Ci.nsIPresentationControlChannelListener).onAnswer(mockedChannelDescription);
},
simulateNotifyConnected: function() {
sendAsyncMessage('control-channel-opened');
this._listener.QueryInterface(Ci.nsIPresentationControlChannelListener).notifyConnected();
},
};
const mockedDevice = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
id: 'id',
name: 'name',
type: 'type',
establishControlChannel: function(url, presentationId) {
sendAsyncMessage('control-channel-established');
return mockedControlChannel;
},
disconnect: function() {},
isRequestedUrlSupported: function(requestedUrl) {
return true;
},
};
const mockedDevicePrompt = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevicePrompt,
Ci.nsIFactory]),
createInstance: function(aOuter, aIID) {
if (aOuter) {
throw Components.results.NS_ERROR_NO_AGGREGATION;
}
return this.QueryInterface(aIID);
},
set request(request) {
this._request = request;
},
get request() {
return this._request;
},
promptDeviceSelection: function(request) {
this._request = request;
sendAsyncMessage('device-prompt');
},
simulateSelect: function() {
this._request.select(mockedDevice);
},
simulateCancel: function(result) {
this._request.cancel(result);
}
};
const mockedSessionTransport = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationSessionTransport,
Ci.nsIPresentationSessionTransportBuilder,
Ci.nsIPresentationTCPSessionTransportBuilder,
Ci.nsIPresentationDataChannelSessionTransportBuilder,
Ci.nsIPresentationControlChannelListener,
Ci.nsIFactory]),
createInstance: function(aOuter, aIID) {
if (aOuter) {
throw Components.results.NS_ERROR_NO_AGGREGATION;
}
return this.QueryInterface(aIID);
},
set callback(callback) {
this._callback = callback;
},
get callback() {
return this._callback;
},
get selfAddress() {
return this._selfAddress;
},
buildTCPSenderTransport: function(transport, listener) {
this._listener = listener;
this._role = Ci.nsIPresentationService.ROLE_CONTROLLER;
this._listener.onSessionTransport(this);
this._listener = null;
sendAsyncMessage('data-transport-initialized');
setTimeout(()=>{
this.simulateTransportReady();
}, 0);
},
buildTCPReceiverTransport: function(description, listener) {
this._listener = listener;
this._role = Ci.nsIPresentationService.ROLE_RECEIVER;
var addresses = description.QueryInterface(Ci.nsIPresentationChannelDescription).tcpAddress;
this._selfAddress = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsINetAddr]),
address: (addresses.length > 0) ?
addresses.queryElementAt(0, Ci.nsISupportsCString).data : "",
port: description.QueryInterface(Ci.nsIPresentationChannelDescription).tcpPort,
};
setTimeout(()=>{
this._listener.onSessionTransport(this);
this._listener = null;
}, 0);
},
// in-process case
buildDataChannelTransport: function(role, window, listener) {
this._listener = listener;
this._role = role;
var hasNavigator = window ? (typeof window.navigator != "undefined") : false;
sendAsyncMessage('check-navigator', hasNavigator);
setTimeout(()=>{
this._listener.onSessionTransport(this);
this._listener = null;
this.simulateTransportReady();
}, 0);
},
enableDataNotification: function() {
sendAsyncMessage('data-transport-notification-enabled');
},
send: function(data) {
sendAsyncMessage('message-sent', data);
},
close: function(reason) {
sendAsyncMessage('data-transport-closed', reason);
this._callback.QueryInterface(Ci.nsIPresentationSessionTransportCallback).notifyTransportClosed(reason);
},
simulateTransportReady: function() {
this._callback.QueryInterface(Ci.nsIPresentationSessionTransportCallback).notifyTransportReady();
},
simulateIncomingMessage: function(message) {
this._callback.QueryInterface(Ci.nsIPresentationSessionTransportCallback).notifyData(message, false);
},
onOffer: function(aOffer) {
},
onAnswer: function(aAnswer) {
}
};
const mockedNetworkInfo = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkInfo]),
getAddresses: function(ips, prefixLengths) {
ips.value = ["127.0.0.1"];
prefixLengths.value = [0];
return 1;
},
};
const mockedNetworkManager = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkManager,
Ci.nsIFactory]),
createInstance: function(aOuter, aIID) {
if (aOuter) {
throw Components.results.NS_ERROR_NO_AGGREGATION;
}
return this.QueryInterface(aIID);
},
get activeNetworkInfo() {
return mockedNetworkInfo;
},
};
var requestPromise = null;
const mockedRequestUIGlue = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationRequestUIGlue,
Ci.nsIFactory]),
createInstance: function(aOuter, aIID) {
if (aOuter) {
throw Components.results.NS_ERROR_NO_AGGREGATION;
}
return this.QueryInterface(aIID);
},
sendRequest: function(aUrl, aSessionId) {
sendAsyncMessage('receiver-launching', aSessionId);
return requestPromise;
},
};
// Register mocked factories.
const originalFactoryData = [];
originalFactoryData.push(registerMockedFactory("@mozilla.org/presentation-device/prompt;1",
uuidGenerator.generateUUID(),
mockedDevicePrompt));
originalFactoryData.push(registerMockedFactory("@mozilla.org/network/server-socket;1",
uuidGenerator.generateUUID(),
mockedServerSocket));
originalFactoryData.push(registerMockedFactory("@mozilla.org/presentation/presentationtcpsessiontransport;1",
uuidGenerator.generateUUID(),
mockedSessionTransport));
originalFactoryData.push(registerMockedFactory("@mozilla.org/presentation/datachanneltransportbuilder;1",
uuidGenerator.generateUUID(),
mockedSessionTransport));
originalFactoryData.push(registerMockedFactory("@mozilla.org/network/manager;1",
uuidGenerator.generateUUID(),
mockedNetworkManager));
originalFactoryData.push(registerMockedFactory("@mozilla.org/presentation/requestuiglue;1",
uuidGenerator.generateUUID(),
mockedRequestUIGlue));
function tearDown() {
requestPromise = null;
mockedServerSocket.listener = null;
mockedControlChannel.listener = null;
mockedDevice.listener = null;
mockedDevicePrompt.request = null;
mockedSessionTransport.callback = null;
var deviceManager = Cc['@mozilla.org/presentation-device/manager;1']
.getService(Ci.nsIPresentationDeviceManager);
deviceManager.QueryInterface(Ci.nsIPresentationDeviceListener).removeDevice(mockedDevice);
// Register original factories.
for (var data of originalFactoryData) {
registerOriginalFactory(data.contractId, data.mockedClassId,
data.mockedFactory, data.originalClassId,
data.originalFactory);
}
sendAsyncMessage('teardown-complete');
}
addMessageListener('trigger-device-add', function() {
var deviceManager = Cc['@mozilla.org/presentation-device/manager;1']
.getService(Ci.nsIPresentationDeviceManager);
deviceManager.QueryInterface(Ci.nsIPresentationDeviceListener).addDevice(mockedDevice);
});
addMessageListener('trigger-device-prompt-select', function() {
mockedDevicePrompt.simulateSelect();
});
addMessageListener('trigger-device-prompt-cancel', function(result) {
mockedDevicePrompt.simulateCancel(result);
});
addMessageListener('trigger-incoming-session-request', function(url) {
var deviceManager = Cc['@mozilla.org/presentation-device/manager;1']
.getService(Ci.nsIPresentationDeviceManager);
deviceManager.QueryInterface(Ci.nsIPresentationDeviceListener)
.onSessionRequest(mockedDevice, url, sessionId, mockedControlChannel);
});
addMessageListener('trigger-incoming-terminate-request', function() {
var deviceManager = Cc['@mozilla.org/presentation-device/manager;1']
.getService(Ci.nsIPresentationDeviceManager);
deviceManager.QueryInterface(Ci.nsIPresentationDeviceListener)
.onTerminateRequest(mockedDevice, sessionId, mockedControlChannel, true);
});
addMessageListener('trigger-reconnected-acked', function(url) {
mockedControlChannel.notifyReconnected();
});
addMessageListener('trigger-incoming-offer', function() {
mockedControlChannel.simulateOnOffer();
});
addMessageListener('trigger-incoming-answer', function() {
mockedControlChannel.simulateOnAnswer();
});
addMessageListener('trigger-incoming-transport', function() {
mockedServerSocket.simulateOnSocketAccepted(mockedServerSocket, mockedSocketTransport);
});
addMessageListener('trigger-control-channel-open', function(reason) {
mockedControlChannel.simulateNotifyConnected();
});
addMessageListener('trigger-control-channel-close', function(reason) {
mockedControlChannel.disconnect(reason);
});
addMessageListener('trigger-data-transport-close', function(reason) {
mockedSessionTransport.close(reason);
});
addMessageListener('trigger-incoming-message', function(message) {
mockedSessionTransport.simulateIncomingMessage(message);
});
addMessageListener('teardown', function() {
tearDown();
});
var controlChannelListener;
addMessageListener('save-control-channel-listener', function() {
controlChannelListener = mockedControlChannel.listener;
});
addMessageListener('restore-control-channel-listener', function(message) {
mockedControlChannel.listener = controlChannelListener;
controlChannelListener = null;
});
var obs = Cc["@mozilla.org/observer-service;1"]
.getService(Ci.nsIObserverService);
obs.addObserver(function observer(aSubject, aTopic, aData) {
obs.removeObserver(observer, aTopic);
requestPromise = aSubject;
}, 'setup-request-promise', false);

View file

@ -0,0 +1,366 @@
/* 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';
const { classes: Cc, interfaces: Ci, manager: Cm, utils: Cu, results: Cr } = Components;
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.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: XPCOMUtils.generateQI([Ci.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: function() {
// send offer after notifyConnected immediately
this._listener
.QueryInterface(Ci.nsIPresentationControlChannelListener)
.notifyConnected();
},
notifyReconnected: function() {
// send offer after notifyOpened immediately
this._listener
.QueryInterface(Ci.nsIPresentationControlChannelListener)
.notifyReconnected();
},
sendOffer: function(offer) {
Services.tm.mainThread.dispatch(() => {
mockControlChannelOfReceiver.onOffer(offer);
}, Ci.nsIThread.DISPATCH_NORMAL);
},
onAnswer: function(answer) {
this._listener
.QueryInterface(Ci.nsIPresentationControlChannelListener)
.onAnswer(answer);
},
launch: function(presentationId, url) {
sessionId = presentationId;
sendAsyncMessage('sender-launch', url);
},
disconnect: function(reason) {
if (!this._listener) {
return;
}
this._listener
.QueryInterface(Ci.nsIPresentationControlChannelListener)
.notifyDisconnected(reason);
mockControlChannelOfReceiver.disconnect();
},
terminate: function(presentationId) {
sendAsyncMessage('sender-terminate');
},
reconnect: function(presentationId, url) {
sendAsyncMessage('start-reconnect', url);
},
sendIceCandidate: function(candidate) {
mockControlChannelOfReceiver.notifyIceCandidate(candidate);
},
notifyIceCandidate: function(candidate) {
if (!this._listener) {
return;
}
this._listener
.QueryInterface(Ci.nsIPresentationControlChannelListener)
.onIceCandidate(candidate);
},
};
// control channel of receiver
const mockControlChannelOfReceiver = {
QueryInterface: XPCOMUtils.generateQI([Ci.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: function() {
// do nothing
if (!this._listener) {
this._pendingOpened = true;
return;
}
this._listener
.QueryInterface(Ci.nsIPresentationControlChannelListener)
.notifyConnected();
},
onOffer: function(offer) {
this._listener
.QueryInterface(Ci.nsIPresentationControlChannelListener)
.onOffer(offer);
},
sendAnswer: function(answer) {
Services.tm.mainThread.dispatch(() => {
mockControlChannelOfSender.onAnswer(answer);
}, Ci.nsIThread.DISPATCH_NORMAL);
},
disconnect: function(reason) {
if (!this._listener) {
return;
}
this._listener
.QueryInterface(Ci.nsIPresentationControlChannelListener)
.notifyDisconnected(reason);
sendAsyncMessage('control-channel-receiver-closed', reason);
},
terminate: function(presentaionId) {
},
sendIceCandidate: function(candidate) {
mockControlChannelOfReceiver.notifyIceCandidate(candidate);
},
notifyIceCandidate: function(candidate) {
if (!this._listener) {
return;
}
this._listener
.QueryInterface(Ci.nsIPresentationControlChannelListener)
.onIceCandidate(candidate);
},
};
const mockDevice = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
id: 'id',
name: 'name',
type: 'type',
establishControlChannel: function(url, presentationId) {
if (triggerControlChannelError) {
throw Cr.NS_ERROR_FAILURE;
}
sendAsyncMessage('control-channel-established');
return mockControlChannelOfSender;
},
disconnect: function() {
sendAsyncMessage('device-disconnected');
},
isRequestedUrlSupported: function(requestedUrl) {
return true;
},
};
const mockDevicePrompt = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevicePrompt,
Ci.nsIFactory]),
createInstance: function(aOuter, aIID) {
if (aOuter) {
throw Components.results.NS_ERROR_NO_AGGREGATION;
}
return this.QueryInterface(aIID);
},
set request(request) {
this._request = request;
},
get request() {
return this._request;
},
promptDeviceSelection: function(request) {
this._request = request;
sendAsyncMessage('device-prompt');
},
simulateSelect: function() {
this._request.select(mockDevice);
},
simulateCancel: function() {
this._request.cancel();
}
};
const mockRequestUIGlue = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationRequestUIGlue,
Ci.nsIFactory]),
set promise(aPromise) {
this._promise = aPromise
},
get promise() {
return this._promise;
},
createInstance: function(aOuter, aIID) {
if (aOuter) {
throw Components.results.NS_ERROR_NO_AGGREGATION;
}
return this.QueryInterface(aIID);
},
sendRequest: function(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: contractId,
mockClassId: mockClassId,
mockFactory: mockFactory,
originalClassId: originalClassId,
originalFactory: originalFactory };
}
// Register mock factories.
const uuidGenerator = Cc["@mozilla.org/uuid-generator;1"]
.getService(Ci.nsIUUIDGenerator);
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);
var obs = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
obs.addObserver(function setupRequestPromiseHandler(aSubject, aTopic, aData) {
debug('Got observer: setup-request-promise');
obs.removeObserver(setupRequestPromiseHandler, aTopic);
mockRequestUIGlue.promise = aSubject;
sendAsyncMessage('promise-setup-ready');
}, 'setup-request-promise', false);
}
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();

View file

@ -0,0 +1,258 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function loadPrivilegedScriptTest() {
/**
* The script is loaded as
* (a) a privileged script in content process for dc_sender.html
* (b) a frame script in the remote iframe process for dc_receiver_oop.html
* |type port == "undefined"| indicates the script is load by
* |loadPrivilegedScript| which is the first case.
*/
function sendMessage(type, data) {
if (typeof port == "undefined") {
sendAsyncMessage(type, {'data': data});
} else {
port.postMessage({'type': type,
'data': data
});
}
}
if (typeof port != "undefined") {
/**
* When the script is loaded by |loadPrivilegedScript|, these APIs
* are exposed to this script.
*/
port.onmessage = (e) => {
var type = e.data['type'];
if (!handlers.hasOwnProperty(type)) {
return;
}
var args = [e];
handlers[type].forEach(handler => handler.apply(null, args));
};
var handlers = {};
addMessageListener = function(message, handler) {
if (handlers.hasOwnProperty(message)) {
handlers[message].push(handler);
} else {
handlers[message] = [handler];
}
};
removeMessageListener = function(message, handler) {
if (!handler || !handlers.hasOwnProperty(message)) {
return;
}
var index = handlers[message].indexOf(handler);
if (index != -1) {
handlers[message].splice(index, 1);
}
};
}
const { classes: Cc, interfaces: Ci, manager: Cm, utils: Cu, results: Cr } = Components;
const mockedChannelDescription = {
QueryInterface : function (iid) {
const interfaces = [Ci.nsIPresentationChannelDescription];
if (!interfaces.some(v => iid.equals(v))) {
throw Cr.NS_ERROR_NO_INTERFACE;
}
return this;
},
get type() {
if (Services.prefs.getBoolPref("dom.presentation.session_transport.data_channel.enable")) {
return Ci.nsIPresentationChannelDescription.TYPE_DATACHANNEL;
}
return Ci.nsIPresentationChannelDescription.TYPE_TCP;
},
get dataChannelSDP() {
return "test-sdp";
}
};
function setTimeout(callback, delay) {
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
timer.initWithCallback({ notify: callback },
delay,
Ci.nsITimer.TYPE_ONE_SHOT);
return timer;
}
const mockedSessionTransport = {
QueryInterface : function (iid) {
const interfaces = [Ci.nsIPresentationSessionTransport,
Ci.nsIPresentationDataChannelSessionTransportBuilder,
Ci.nsIFactory];
if (!interfaces.some(v => iid.equals(v))) {
throw Cr.NS_ERROR_NO_INTERFACE;
}
return this;
},
createInstance: function(aOuter, aIID) {
if (aOuter) {
throw Components.results.NS_ERROR_NO_AGGREGATION;
}
return this.QueryInterface(aIID);
},
set callback(callback) {
this._callback = callback;
},
get callback() {
return this._callback;
},
/* OOP case */
buildDataChannelTransport: function(role, window, listener) {
dump("PresentationSessionFrameScript: build data channel transport\n");
this._listener = listener;
this._role = role;
var hasNavigator = window ? (typeof window.navigator != "undefined") : false;
sendMessage('check-navigator', hasNavigator);
if (this._role == Ci.nsIPresentationService.ROLE_CONTROLLER) {
this._listener.sendOffer(mockedChannelDescription);
}
},
enableDataNotification: function() {
sendMessage('data-transport-notification-enabled');
},
send: function(data) {
sendMessage('message-sent', data);
},
close: function(reason) {
sendMessage('data-transport-closed', reason);
this._callback.QueryInterface(Ci.nsIPresentationSessionTransportCallback).notifyTransportClosed(reason);
this._callback = null;
},
simulateTransportReady: function() {
this._callback.QueryInterface(Ci.nsIPresentationSessionTransportCallback).notifyTransportReady();
},
simulateIncomingMessage: function(message) {
this._callback.QueryInterface(Ci.nsIPresentationSessionTransportCallback).notifyData(message, false);
},
onOffer: function(aOffer) {
this._listener.sendAnswer(mockedChannelDescription);
this._onSessionTransport();
},
onAnswer: function(aAnswer) {
this._onSessionTransport();
},
_onSessionTransport: function() {
setTimeout(()=>{
this._listener.onSessionTransport(this);
this.simulateTransportReady();
this._listener = null;
}, 0);
}
};
function tearDown() {
mockedSessionTransport.callback = null;
/* Register original factories. */
for (var data of originalFactoryData) {
registerOriginalFactory(data.contractId, data.mockedClassId,
data.mockedFactory, data.originalClassId,
data.originalFactory);
}
sendMessage("teardown-complete");
}
function registerMockedFactory(contractId, mockedClassId, mockedFactory) {
var originalClassId, originalFactory;
var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
if (!registrar.isCIDRegistered(mockedClassId)) {
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(mockedClassId, "", contractId, mockedFactory);
}
return { contractId: contractId,
mockedClassId: mockedClassId,
mockedFactory: mockedFactory,
originalClassId: originalClassId,
originalFactory: originalFactory };
}
function registerOriginalFactory(contractId, mockedClassId, mockedFactory, originalClassId, originalFactory) {
if (originalFactory) {
var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
registrar.unregisterFactory(mockedClassId, mockedFactory);
registrar.registerFactory(originalClassId, "", contractId, originalFactory);
}
}
/* Register mocked factories. */
const originalFactoryData = [];
const uuidGenerator = Cc["@mozilla.org/uuid-generator;1"]
.getService(Ci.nsIUUIDGenerator);
originalFactoryData.push(registerMockedFactory("@mozilla.org/presentation/datachanneltransportbuilder;1",
uuidGenerator.generateUUID(),
mockedSessionTransport));
addMessageListener('trigger-incoming-message', function(event) {
mockedSessionTransport.simulateIncomingMessage(event.data.data);
});
addMessageListener('teardown', ()=>tearDown());
}
// Exposed to the caller of |loadPrivilegedScript|
var contentScript = {
handlers: {},
addMessageListener: function(message, handler) {
if (this.handlers.hasOwnProperty(message)) {
this.handlers[message].push(handler);
} else {
this.handlers[message] = [handler];
}
},
removeMessageListener: function(message, handler) {
if (!handler || !this.handlers.hasOwnProperty(message)) {
return;
}
var index = this.handlers[message].indexOf(handler);
if (index != -1) {
this.handlers[message].splice(index, 1);
}
},
sendAsyncMessage: function(message, data) {
port.postMessage({'type': message,
'data': data
});
}
}
if (!SpecialPowers.isMainProcess()) {
var port;
try {
port = SpecialPowers.loadPrivilegedScript(loadPrivilegedScriptTest.toSource());
} catch (e) {
ok(false, "loadPrivilegedScript shoulde not throw" + e);
}
port.onmessage = (e) => {
var type = e.data['type'];
if (!contentScript.handlers.hasOwnProperty(type)) {
return;
}
var args = [e.data['data']];
contentScript.handlers[type].forEach(handler => handler.apply(null, args));
};
}

View file

@ -0,0 +1,14 @@
[DEFAULT]
support-files =
PresentationDeviceInfoChromeScript.js
PresentationSessionChromeScript.js
[test_presentation_datachannel_sessiontransport.html]
skip-if = os == 'android'
[test_presentation_device_info.html]
[test_presentation_sender_startWithDevice.html]
skip-if = toolkit == 'android' # Bug 1129785
[test_presentation_tcp_sender.html]
skip-if = toolkit == 'android' # Bug 1129785
[test_presentation_tcp_sender_default_request.html]
skip-if = toolkit == 'android' # Bug 1129785

View file

@ -0,0 +1,220 @@
<!DOCTYPE HTML>
<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: -->
<html>
<head>
<meta charset="utf-8">
<title>Test for B2G PresentationReceiver at receiver side</title>
</head>
<body>
<div id="content"></div>
<script type="application/javascript;version=1.7">
"use strict";
function is(a, b, msg) {
if (a === b) {
alert('OK ' + msg);
} else {
alert('KO ' + msg + ' | reason: ' + a + ' != ' + b);
}
}
function ok(a, msg) {
alert((a ? 'OK ' : 'KO ') + msg);
}
function info(msg) {
alert('INFO ' + msg);
}
function command(name, data) {
alert('COMMAND ' + JSON.stringify({name: name, data: data}));
}
function finish() {
alert('DONE');
}
var connection;
const DATA_ARRAY = [0, 255, 254, 0, 1, 2, 3, 0, 255, 255, 254, 0];
const DATA_ARRAY_BUFFER = new ArrayBuffer(DATA_ARRAY.length);
const TYPED_DATA_ARRAY = new Uint8Array(DATA_ARRAY_BUFFER);
TYPED_DATA_ARRAY.set(DATA_ARRAY);
function is_same_buffer(recv_data, expect_data) {
let recv_dataview = new Uint8Array(recv_data);
let expected_dataview = new Uint8Array(expect_data);
if (recv_dataview.length !== expected_dataview.length) {
return false;
}
for (let i = 0; i < recv_dataview.length; i++) {
if (recv_dataview[i] != expected_dataview[i]) {
info('discover byte differenct at ' + i);
return false;
}
}
return true;
}
function testConnectionAvailable() {
return new Promise(function(aResolve, aReject) {
info('Receiver: --- testConnectionAvailable ---');
ok(navigator.presentation, "Receiver: navigator.presentation should be available.");
ok(navigator.presentation.receiver, "Receiver: navigator.presentation.receiver should be available.");
is(navigator.presentation.defaultRequest, null, "Receiver: navigator.presentation.defaultRequest should be null.");
navigator.presentation.receiver.connectionList
.then((aList) => {
is(aList.connections.length, 1, "Should get one conncetion.");
connection = aList.connections[0];
ok(connection.id, "Connection ID should be set: " + connection.id);
is(connection.state, "connected", "Connection state at receiver side should be connected.");
aResolve();
})
.catch((aError) => {
ok(false, "Receiver: Error occurred when getting the connection: " + aError);
finish();
aReject();
});
});
}
function testConnectionReady() {
return new Promise(function(aResolve, aReject) {
info('Receiver: --- testConnectionReady ---');
connection.onconnect = function() {
connection.onconnect = null;
ok(false, "Should not get |onconnect| event.")
aReject();
};
if (connection.state === "connected") {
connection.onconnect = null;
is(connection.state, "connected", "Receiver: Connection state should become connected.");
aResolve();
}
});
}
function testIncomingMessage() {
return new Promise(function(aResolve, aReject) {
info('Receiver: --- testIncomingMessage ---');
connection.addEventListener('message', function messageHandler(evt) {
connection.removeEventListener('message', messageHandler);
let msg = evt.data;
is(msg, 'msg-sender-to-receiver', 'Receiver: Receiver should receive message from sender.');
command('forward-command', JSON.stringify({ name: 'message-from-sender-received' }));
aResolve();
});
command('forward-command', JSON.stringify({ name: 'trigger-message-from-sender' }));
});
}
function testSendMessage() {
return new Promise(function(aResolve, aReject) {
window.addEventListener('hashchange', function hashchangeHandler(evt) {
var message = JSON.parse(decodeURIComponent(window.location.hash.substring(1)));
if (message.type === 'trigger-message-from-receiver') {
info('Receiver: --- testSendMessage ---');
connection.send('msg-receiver-to-sender');
}
if (message.type === 'message-from-receiver-received') {
window.removeEventListener('hashchange', hashchangeHandler);
aResolve();
}
});
});
}
function testIncomingBlobMessage() {
return new Promise(function(aResolve, aReject) {
info('Receiver: --- testIncomingBlobMessage ---');
connection.send('testIncomingBlobMessage');
connection.addEventListener('message', function messageHandler(evt) {
connection.removeEventListener('message', messageHandler);
let recvData= String.fromCharCode.apply(null, new Uint8Array(evt.data));
is(recvData, "Hello World", 'expected same string data');
aResolve();
});
});
}
function testConnectionClosed() {
return new Promise(function(aResolve, aReject) {
info('Receiver: --- testConnectionClosed ---');
connection.onclose = function() {
connection.onclose = null;
is(connection.state, "closed", "Receiver: Connection should be closed.");
command('forward-command', JSON.stringify({ name: 'receiver-closed' }));
aResolve();
};
command('forward-command', JSON.stringify({ name: 'ready-to-close' }));
});
}
function testReconnectConnection() {
return new Promise(function(aResolve, aReject) {
info('Receiver: --- testReconnectConnection ---');
window.addEventListener('hashchange', function hashchangeHandler(evt) {
var message = JSON.parse(decodeURIComponent(window.location.hash.substring(1)));
if (message.type === 'prepare-for-reconnect') {
command('forward-command', JSON.stringify({ name: 'ready-to-reconnect' }));
}
});
connection.onconnect = function() {
connection.onconnect = null;
ok(true, "The connection is reconnected.")
aResolve();
};
});
}
function testIncomingArrayBuffer() {
return new Promise(function(aResolve, aReject) {
info('Receiver: --- testIncomingArrayBuffer ---');
connection.binaryType = "blob";
connection.send('testIncomingArrayBuffer');
connection.addEventListener('message', function messageHandler(evt) {
connection.removeEventListener('message', messageHandler);
var fileReader = new FileReader();
fileReader.onload = function() {
ok(is_same_buffer(DATA_ARRAY_BUFFER, this.result), "expected same buffer data");
aResolve();
};
fileReader.readAsArrayBuffer(evt.data);
});
});
}
function testIncomingArrayBufferView() {
return new Promise(function(aResolve, aReject) {
info('Receiver: --- testIncomingArrayBufferView ---');
connection.binaryType = "arraybuffer";
connection.send('testIncomingArrayBufferView');
connection.addEventListener('message', function messageHandler(evt) {
connection.removeEventListener('message', messageHandler);
ok(is_same_buffer(evt.data, TYPED_DATA_ARRAY), "expected same buffer data");
aResolve();
});
});
}
function runTests() {
testConnectionAvailable()
.then(testConnectionReady)
.then(testIncomingMessage)
.then(testSendMessage)
.then(testIncomingBlobMessage)
.then(testConnectionClosed)
.then(testReconnectConnection)
.then(testIncomingArrayBuffer)
.then(testIncomingArrayBufferView)
.then(testConnectionClosed);
}
runTests();
</script>
</body>
</html>

View file

@ -0,0 +1,95 @@
<!DOCTYPE HTML>
<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: -->
<html>
<head>
<meta charset="utf-8">
<title>Test for B2G PresentationReceiver at receiver side</title>
</head>
<body>
<div id="content"></div>
<script type="application/javascript;version=1.7">
"use strict";
function is(a, b, msg) {
if (a === b) {
alert('OK ' + msg);
} else {
alert('KO ' + msg + ' | reason: ' + a + ' != ' + b);
}
}
function ok(a, msg) {
alert((a ? 'OK ' : 'KO ') + msg);
}
function info(msg) {
alert('INFO ' + msg);
}
function command(name, data) {
alert('COMMAND ' + JSON.stringify({name: name, data: data}));
}
function finish() {
alert('DONE');
}
var connection;
function testConnectionAvailable() {
return new Promise(function(aResolve, aReject) {
info('Receiver: --- testConnectionAvailable ---');
ok(navigator.presentation, "Receiver: navigator.presentation should be available.");
ok(navigator.presentation.receiver, "Receiver: navigator.presentation.receiver should be available.");
navigator.presentation.receiver.connectionList
.then((aList) => {
is(aList.connections.length, 1, "Should get one conncetion.");
connection = aList.connections[0];
ok(connection.id, "Connection ID should be set: " + connection.id);
is(connection.state, "connected", "Connection state at receiver side should be connected.");
aResolve();
})
.catch((aError) => {
ok(false, "Receiver: Error occurred when getting the connection: " + aError);
finish();
aReject();
});
});
}
function testConnectionReady() {
return new Promise(function(aResolve, aReject) {
info('Receiver: --- testConnectionReady ---');
connection.onconnect = function() {
connection.onconnect = null;
ok(false, "Should not get |onconnect| event.")
aReject();
};
if (connection.state === "connected") {
connection.onconnect = null;
is(connection.state, "connected", "Receiver: Connection state should become connected.");
aResolve();
}
});
}
function testConnectionWentaway() {
return new Promise(function(aResolve, aReject) {
info('Receiver: --- testConnectionWentaway ---\n');
command('forward-command', JSON.stringify({ name: 'ready-to-remove-receiverFrame' }));
});
}
function runTests() {
testConnectionAvailable()
.then(testConnectionReady)
.then(testConnectionWentaway);
}
runTests();
</script>
</body>
</html>

View file

@ -0,0 +1,159 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test allow-presentation sandboxing flag</title>
<script type="application/javascript;version=1.8">
"use strict";
function is(a, b, msg) {
window.parent.postMessage((a === b ? "OK " : "KO ") + msg, "*");
}
function ok(a, msg) {
window.parent.postMessage((a ? "OK " : "KO ") + msg, "*");
}
function info(msg) {
window.parent.postMessage("INFO " + msg, "*");
}
function command(msg) {
window.parent.postMessage("COMMAND " + JSON.stringify(msg), "*");
}
function finish() {
window.parent.postMessage("DONE", "*");
}
function testGetAvailability() {
return new Promise(function(aResolve, aReject) {
ok(navigator.presentation, "navigator.presentation should be available.");
var request = new PresentationRequest("http://example.com");
request.getAvailability().then(
function(aAvailability) {
ok(false, "Unexpected success, should get a security error.");
aReject();
},
function(aError) {
is(aError.name, "SecurityError", "Should get a security error.");
aResolve();
}
);
});
}
function testStartRequest() {
return new Promise(function(aResolve, aReject) {
var request = new PresentationRequest("http://example.com");
request.start().then(
function(aAvailability) {
ok(false, "Unexpected success, should get a security error.");
aReject();
},
function(aError) {
is(aError.name, "SecurityError", "Should get a security error.");
aResolve();
}
);
});
}
function testReconnectRequest() {
return new Promise(function(aResolve, aReject) {
var request = new PresentationRequest("http://example.com");
request.reconnect("dummyId").then(
function(aConnection) {
ok(false, "Unexpected success, should get a security error.");
aReject();
},
function(aError) {
is(aError.name, "SecurityError", "Should get a security error.");
aResolve();
}
);
});
}
function testGetAvailabilityForAboutBlank() {
return new Promise(function(aResolve, aReject) {
var request = new PresentationRequest("about:blank");
request.getAvailability().then(
function(aAvailability) {
ok(true, "Success due to a priori authenticated URL.");
aResolve();
},
function(aError) {
ok(false, "Error occurred when getting availability: " + aError);
aReject();
}
);
});
}
function testGetAvailabilityForAboutSrcdoc() {
return new Promise(function(aResolve, aReject) {
var request = new PresentationRequest("about:srcdoc");
request.getAvailability().then(
function(aAvailability) {
ok(true, "Success due to a priori authenticated URL.");
aResolve();
},
function(aError) {
ok(false, "Error occurred when getting availability: " + aError);
aReject();
}
);
});
}
function testGetAvailabilityForDataURL() {
return new Promise(function(aResolve, aReject) {
var request = new PresentationRequest("data:text/html,1");
request.getAvailability().then(
function(aAvailability) {
ok(true, "Success due to a priori authenticated URL.");
aResolve();
},
function(aError) {
ok(false, "Error occurred when getting availability: " + aError);
aReject();
}
);
});
}
function runTest() {
testGetAvailability()
.then(testStartRequest)
.then(testReconnectRequest)
.then(testGetAvailabilityForAboutBlank)
.then(testGetAvailabilityForAboutSrcdoc)
.then(testGetAvailabilityForDataURL)
.then(finish);
}
window.addEventListener("message", function onMessage(evt) {
window.removeEventListener("message", onMessage);
if (evt.data === "start") {
runTest();
}
}, false);
window.setTimeout(function() {
command("ready-to-start");
}, 3000);
</script>
</head>
<body>
</body>
</html>

View file

@ -0,0 +1,41 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test for B2G PresentationReceiver on a non-receiver page at receiver side</title>
</head>
<body>
<div id="content"></div>
<script type="application/javascript;version=1.7">
"use strict";
function is(a, b, msg) {
alert((a === b ? 'OK ' : 'KO ') + msg);
}
function ok(a, msg) {
alert((a ? 'OK ' : 'KO ') + msg);
}
function info(msg) {
alert('INFO ' + msg);
}
function finish() {
alert('DONE');
}
function testConnectionAvailable() {
return new Promise(function(aResolve, aReject) {
is(navigator.presentation.receiver, null, "navigator.presentation.receiver shouldn't be available in non-receiving pages.");
aResolve();
});
}
testConnectionAvailable().
then(finish);
</script>
</body>
</html>

View file

@ -0,0 +1,26 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test for B2G PresentationReceiver on a non-receiver inner iframe of the receiver page at receiver side</title>
</head>
<body onload="testConnectionAvailable()">
<div id="content"></div>
<script type="application/javascript;version=1.7">
"use strict";
function ok(a, msg) {
alert((a ? 'OK ' : 'KO ') + msg);
}
function testConnectionAvailable() {
return new Promise(function(aResolve, aReject) {
is(navigator.presentation.receiver, null, "navigator.presentation.receiver shouldn't be available in inner iframes with different origins from receiving pages.");
aResolve();
});
}
</script>
</body>
</html>

View file

@ -0,0 +1,140 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test for B2G PresentationReceiver at receiver side</title>
</head>
<body>
<div id="content"></div>
<script type="application/javascript;version=1.7">
"use strict";
function is(a, b, msg) {
alert((a === b ? 'OK ' : 'KO ') + msg);
}
function ok(a, msg) {
alert((a ? 'OK ' : 'KO ') + msg);
}
function info(msg) {
alert('INFO ' + msg);
}
function command(msg) {
alert('COMMAND ' + JSON.stringify(msg));
}
function finish() {
alert('DONE');
}
var connection;
function testConnectionAvailable() {
return new Promise(function(aResolve, aReject) {
ok(navigator.presentation, "navigator.presentation should be available in receiving pages.");
ok(navigator.presentation.receiver, "navigator.presentation.receiver should be available in receiving pages.");
navigator.presentation.receiver.connectionList.then(
function(aList) {
is(aList.connections.length, 1, "Should get one conncetion.");
connection = aList.connections[0];
ok(connection.id, "Connection ID should be set: " + connection.id);
is(connection.state, "connected", "Connection state at receiver side should be connected.");
aResolve();
},
function(aError) {
ok(false, "Error occurred when getting the connection list: " + aError);
finish();
aReject();
}
);
command({ name: 'trigger-incoming-offer' });
});
}
function testDefaultRequestIsUndefined() {
return new Promise(function(aResolve, aReject) {
is(navigator.presentation.defaultRequest, undefined, "navigator.presentation.defaultRequest should not be available in receiving UA");
aResolve();
});
}
function testConnectionAvailableSameOriginInnerIframe() {
return new Promise(function(aResolve, aReject) {
var iframe = document.createElement('iframe');
iframe.setAttribute('src', './file_presentation_receiver_inner_iframe.html');
document.body.appendChild(iframe);
aResolve();
});
}
function testConnectionUnavailableDiffOriginInnerIframe() {
return new Promise(function(aResolve, aReject) {
var iframe = document.createElement('iframe');
iframe.setAttribute('src', 'http://example.com/tests/dom/presentation/tests/mochitest/file_presentation_non_receiver_inner_iframe.html');
document.body.appendChild(iframe);
aResolve();
});
}
function testConnectionListSameObject() {
return new Promise(function(aResolve, aReject) {
is(navigator.presentation.receiver.connectionList, navigator.presentation.receiver.connectionList, "The promise should be the same object.");
var promise = navigator.presentation.receiver.connectionList.then(
function(aList) {
is(connection, aList.connections[0], "The connection from list and the one from |connectionavailable| event should be the same.");
aResolve();
},
function(aError) {
ok(false, "Error occurred when getting the connection list: " + aError);
finish();
aReject();
}
);
});
}
function testIncomingMessage() {
return new Promise(function(aResolve, aReject) {
const incomingMessage = "test incoming message";
connection.addEventListener('message', function messageHandler(aEvent) {
connection.removeEventListener('message', messageHandler);
is(aEvent.data, incomingMessage, "An incoming message should be received.");
aResolve();
});
command({ name: 'trigger-incoming-message',
data: incomingMessage });
});
}
function testCloseConnection() {
return new Promise(function(aResolve, aReject) {
connection.onclose = function() {
connection.onclose = null;
is(connection.state, "closed", "Connection should be closed.");
aResolve();
};
connection.close();
});
}
testConnectionAvailable().
then(testDefaultRequestIsUndefined).
then(testConnectionAvailableSameOriginInnerIframe).
then(testConnectionUnavailableDiffOriginInnerIframe).
then(testConnectionListSameObject).
then(testIncomingMessage).
then(testCloseConnection).
then(finish);
</script>
</body>
</html>

View file

@ -0,0 +1,60 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test for sandboxed auxiliary navigation flag in receiver page</title>
</head>
<body>
<div id="content"></div>
<script type="application/javascript;version=1.7">
"use strict";
function is(a, b, msg) {
alert((a === b ? 'OK ' : 'KO ') + msg);
}
function ok(a, msg) {
alert((a ? 'OK ' : 'KO ') + msg);
}
function info(msg) {
alert('INFO ' + msg);
}
function command(msg) {
alert('COMMAND ' + JSON.stringify(msg));
}
function finish() {
alert('DONE');
}
function testConnectionAvailable() {
return new Promise(function(aResolve, aReject) {
ok(navigator.presentation, "navigator.presentation should be available in OOP receiving pages.");
ok(navigator.presentation.receiver, "navigator.presentation.receiver should be available in receiving pages.");
aResolve();
});
}
function testOpenWindow() {
return new Promise(function(aResolve, aReject) {
try {
window.open("http://example.com");
ok(false, "receiver page should not be able to open a new window.");
} catch(e) {
ok(true, "receiver page should not be able to open a new window.");
aResolve();
}
});
}
testConnectionAvailable().
then(testOpenWindow).
then(finish);
</script>
</body>
</html>

View file

@ -0,0 +1,79 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test for connection establishing errors of B2G Presentation API at receiver side</title>
</head>
<body>
<div id="content"></div>
<script type="application/javascript;version=1.7">
"use strict";
function is(a, b, msg) {
if (a === b) {
alert('OK ' + msg);
} else {
alert('KO ' + msg + ' | reason: ' + a + ' != ' + b);
}
}
function ok(a, msg) {
alert((a ? 'OK ' : 'KO ') + msg);
}
function info(msg) {
alert('INFO ' + msg);
}
function command(name, data) {
alert('COMMAND ' + JSON.stringify({name: name, data: data}));
}
function finish() {
alert('DONE');
}
function testConnectionAvailable() {
return new Promise(function(aResolve, aReject) {
ok(navigator.presentation, "navigator.presentation should be available.");
ok(navigator.presentation.receiver, "navigator.presentation.receiver should be available.");
aResolve();
});
}
function testUnexpectedControlChannelClose() {
// Trigger the control channel to be closed with error code.
command({ name: 'trigger-control-channel-close', data: 0x80004004 /* NS_ERROR_ABORT */ });
return new Promise(function(aResolve, aReject) {
return Promise.race([
navigator.presentation.receiver.connectionList.then(
(aList) => {
ok(false, "Should not get a connection list.")
aReject();
},
(aError) => {
ok(false, "Error occurred when getting the connection list: " + aError);
aReject();
}
),
new Promise(
() => {
setTimeout(() => {
ok(true, "Not getting a conenction list.");
aResolve();
}, 3000);
}
),
]);
});
}
testConnectionAvailable().
then(testUnexpectedControlChannelClose).
then(finish);
</script>
</body>
</html>

View file

@ -0,0 +1,26 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test for B2G PresentationReceiver in an inner iframe of the receiver page at receiver side</title>
</head>
<body onload="testConnectionAvailable()">
<div id="content"></div>
<script type="application/javascript;version=1.7">
"use strict";
function ok(a, msg) {
alert((a ? 'OK ' : 'KO ') + msg);
}
function testConnectionAvailable() {
return new Promise(function(aResolve, aReject) {
ok(navigator.presentation.receiver, "navigator.presentation.receiver should be available in same-origin inner iframes of receiving pages.");
aResolve();
});
}
</script>
</body>
</html>

View file

@ -0,0 +1,102 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test allow-presentation sandboxing flag</title>
<script type="application/javascript;version=1.8">
"use strict";
function is(a, b, msg) {
window.parent.postMessage((a === b ? "OK " : "KO ") + msg, "*");
}
function ok(a, msg) {
window.parent.postMessage((a ? "OK " : "KO ") + msg, "*");
}
function info(msg) {
window.parent.postMessage("INFO " + msg, "*");
}
function command(msg) {
window.parent.postMessage("COMMAND " + JSON.stringify(msg), "*");
}
function finish() {
window.parent.postMessage("DONE", "*");
}
var request;
var connection;
function testStartRequest() {
return new Promise(function(aResolve, aReject) {
ok(navigator.presentation, "navigator.presentation should be available.");
request = new PresentationRequest("http://example1.com");
request.start().then(
function(aConnection) {
connection = aConnection;
ok(connection, "Connection should be available.");
ok(connection.id, "Connection ID should be set.");
is(connection.state, "connecting", "The initial state should be connecting.");
connection.onclose = function() {
connection.onclose = null;
command({ name: "notify-connection-closed", id: connection.id });
};
connection.onconnect = function() {
connection.onconnect = null;
is(connection.state, "connected", "Connection should be connected.");
aResolve();
};
},
function(aError) {
ok(false, "Error occurred when establishing a connection: " + aError);
teardown();
aReject();
}
);
});
}
function testCloseConnection() {
return new Promise(function(aResolve, aReject) {
if (connection.state === "closed") {
aResolve();
return;
}
connection.onclose = function() {
connection.onclose = null;
is(connection.state, "closed", "The connection should be closed.");
aResolve();
};
connection.close();
});
}
window.addEventListener("message", function onMessage(evt) {
if (evt.data === "startConnection") {
testStartRequest().then(
function () {
command({ name: "connection-connected", id: connection.id });
}
);
}
else if (evt.data === "closeConnection") {
testCloseConnection().then(
function () {
command({ name: "connection-closed", id: connection.id });
}
);
}
}, false);
</script>
</head>
<body>
</body>
</html>

View file

@ -0,0 +1,114 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test allow-presentation sandboxing flag</title>
<script type="application/javascript;version=1.8">
"use strict";
function is(a, b, msg) {
window.parent.postMessage((a === b ? "OK " : "KO ") + msg, "*");
}
function ok(a, msg) {
window.parent.postMessage((a ? "OK " : "KO ") + msg, "*");
}
function info(msg) {
window.parent.postMessage("INFO " + msg, "*");
}
function command(msg) {
window.parent.postMessage("COMMAND " + JSON.stringify(msg), "*");
}
function finish() {
window.parent.postMessage("DONE", "*");
}
function testGetAvailability() {
return new Promise(function(aResolve, aReject) {
ok(navigator.presentation, "navigator.presentation should be available.");
var request = new PresentationRequest("http://example.com");
request.getAvailability().then(
function(aAvailability) {
ok(false, "Unexpected success, should get a security error.");
aReject();
},
function(aError) {
is(aError.name, "SecurityError", "Should get a security error.");
aResolve();
}
);
});
}
function testStartRequest() {
return new Promise(function(aResolve, aReject) {
var request = new PresentationRequest("http://example.com");
request.start().then(
function(aAvailability) {
ok(false, "Unexpected success, should get a security error.");
aReject();
},
function(aError) {
is(aError.name, "SecurityError", "Should get a security error.");
aResolve();
}
);
});
}
function testDefaultRequest() {
return new Promise(function(aResolve, aReject) {
navigator.presentation.defaultRequest = new PresentationRequest("http://example.com");
is(navigator.presentation.defaultRequest, null, "DefaultRequest shoud be null.");
aResolve();
});
}
function testReconnectRequest() {
return new Promise(function(aResolve, aReject) {
var request = new PresentationRequest("http://example.com");
request.reconnect("dummyId").then(
function(aConnection) {
ok(false, "Unexpected success, should get a security error.");
aReject();
},
function(aError) {
is(aError.name, "SecurityError", "Should get a security error.");
aResolve();
}
);
});
}
function runTest() {
testGetAvailability()
.then(testStartRequest)
.then(testDefaultRequest)
.then(testReconnectRequest)
.then(finish);
}
window.addEventListener("message", function onMessage(evt) {
window.removeEventListener("message", onMessage);
if (evt.data === "start") {
runTest();
}
}, false);
window.setTimeout(function() {
command("ready-to-start");
}, 3000);
</script>
</head>
<body>
</body>
</html>

View file

@ -0,0 +1,104 @@
<!DOCTYPE HTML>
<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: -->
<html>
<head>
<meta charset='utf-8'>
<title>Test for B2G PresentationReceiver at receiver side</title>
</head>
<body>
<div id='content'></div>
<script type='application/javascript;version=1.7'>
'use strict';
function is(a, b, msg) {
if (a === b) {
alert('OK ' + msg);
} else {
alert('KO ' + msg + ' | reason: ' + a + ' != ' + b);
}
}
function ok(a, msg) {
alert((a ? 'OK ' : 'KO ') + msg);
}
function info(msg) {
alert('INFO ' + msg);
}
function command(name, data) {
alert('COMMAND ' + JSON.stringify({name: name, data: data}));
}
function finish() {
alert('DONE');
}
var connection;
function testConnectionAvailable() {
return new Promise(function(aResolve, aReject) {
info('Receiver: --- testConnectionAvailable ---');
ok(navigator.presentation, 'Receiver: navigator.presentation should be available.');
ok(navigator.presentation.receiver, 'Receiver: navigator.presentation.receiver should be available.');
navigator.presentation.receiver.connectionList
.then((aList) => {
is(aList.connections.length, 1, 'Should get one conncetion.');
connection = aList.connections[0];
ok(connection.id, 'Connection ID should be set: ' + connection.id);
is(connection.state, 'connected', 'Connection state at receiver side should be connected.');
aResolve();
})
.catch((aError) => {
ok(false, 'Receiver: Error occurred when getting the connection: ' + aError);
finish();
aReject();
});
});
}
function testConnectionReady() {
return new Promise(function(aResolve, aReject) {
info('Receiver: --- testConnectionReady ---');
connection.onconnect = function() {
connection.onconnect = null;
ok(false, 'Should not get |onconnect| event.')
aReject();
};
if (connection.state === 'connected') {
connection.onconnect = null;
is(connection.state, 'connected', 'Receiver: Connection state should become connected.');
aResolve();
}
});
}
function testConnectionTerminate() {
return new Promise(function(aResolve, aReject) {
info('Receiver: --- testConnectionTerminate ---');
connection.onterminate = function() {
connection.onterminate = null;
// Using window.alert at this stage will cause window.close() fail.
// Only trigger it if verdict fail.
if (connection.state !== 'terminated') {
is(connection.state, 'terminated', 'Receiver: Connection should be terminated.');
}
aResolve();
};
command('forward-command', JSON.stringify({ name: 'ready-to-terminate' }));
});
}
function runTests() {
testConnectionAvailable()
.then(testConnectionReady)
.then(testConnectionTerminate)
}
runTests();
</script>
</body>
</html>

View file

@ -0,0 +1,114 @@
<!DOCTYPE HTML>
<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: -->
<html>
<head>
<meta charset='utf-8'>
<title>Test for B2G PresentationReceiver at receiver side</title>
</head>
<body>
<div id='content'></div>
<script type='application/javascript;version=1.7'>
'use strict';
function is(a, b, msg) {
if (a === b) {
alert('OK ' + msg);
} else {
alert('KO ' + msg + ' | reason: ' + a + ' != ' + b);
}
}
function ok(a, msg) {
alert((a ? 'OK ' : 'KO ') + msg);
}
function info(msg) {
alert('INFO ' + msg);
}
function command(name, data) {
alert('COMMAND ' + JSON.stringify({name: name, data: data}));
}
function finish() {
alert('DONE');
}
var connection;
function testConnectionAvailable() {
return new Promise(function(aResolve, aReject) {
info('Receiver: --- testConnectionAvailable ---');
ok(navigator.presentation, 'Receiver: navigator.presentation should be available.');
ok(navigator.presentation.receiver, 'Receiver: navigator.presentation.receiver should be available.');
navigator.presentation.receiver.connectionList
.then((aList) => {
is(aList.connections.length, 1, 'Should get one connection.');
connection = aList.connections[0];
ok(connection.id, 'Connection ID should be set: ' + connection.id);
is(connection.state, 'connected', 'Connection state at receiver side should be connected.');
aResolve();
})
.catch((aError) => {
ok(false, 'Receiver: Error occurred when getting the connection: ' + aError);
finish();
aReject();
});
});
}
function testConnectionReady() {
return new Promise(function(aResolve, aReject) {
info('Receiver: --- testConnectionReady ---');
connection.onconnect = function() {
connection.onconnect = null;
ok(false, 'Should not get |onconnect| event.')
aReject();
};
if (connection.state === 'connected') {
connection.onconnect = null;
is(connection.state, 'connected', 'Receiver: Connection state should become connected.');
aResolve();
}
});
}
function testConnectionTerminate() {
return new Promise(function(aResolve, aReject) {
info('Receiver: --- testConnectionTerminate ---');
connection.onterminate = function() {
connection.onterminate = null;
// Using window.alert at this stage will cause window.close() fail.
// Only trigger it if verdict fail.
if (connection.state !== 'terminated') {
is(connection.state, 'terminated', 'Receiver: Connection should be terminated.');
}
aResolve();
};
window.addEventListener('hashchange', function hashchangeHandler(evt) {
var message = JSON.parse(decodeURIComponent(window.location.hash.substring(1)));
if (message.type === 'ready-to-terminate') {
info('Receiver: --- ready-to-terminate ---');
connection.terminate();
}
});
command('forward-command', JSON.stringify({ name: 'prepare-for-terminate' }));
});
}
function runTests() {
testConnectionAvailable()
.then(testConnectionReady)
.then(testConnectionTerminate)
}
runTests();
</script>
</body>
</html>

View file

@ -0,0 +1 @@
Content-Type: application/unknown

View file

@ -0,0 +1,77 @@
[DEFAULT]
support-files =
PresentationDeviceInfoChromeScript.js
PresentationSessionChromeScript.js
PresentationSessionFrameScript.js
PresentationSessionChromeScript1UA.js
file_presentation_1ua_receiver.html
test_presentation_1ua_sender_and_receiver.js
file_presentation_non_receiver_inner_iframe.html
file_presentation_non_receiver.html
file_presentation_receiver.html
file_presentation_receiver_establish_connection_error.html
file_presentation_receiver_inner_iframe.html
file_presentation_1ua_wentaway.html
test_presentation_1ua_connection_wentaway.js
file_presentation_receiver_auxiliary_navigation.html
test_presentation_receiver_auxiliary_navigation.js
file_presentation_sandboxed_presentation.html
file_presentation_terminate.html
test_presentation_terminate.js
file_presentation_terminate_establish_connection_error.html
test_presentation_terminate_establish_connection_error.js
file_presentation_reconnect.html
file_presentation_unknown_content_type.test
file_presentation_unknown_content_type.test^headers^
test_presentation_tcp_receiver_establish_connection_unknown_content_type.js
file_presentation_mixed_security_contexts.html
[test_presentation_dc_sender.html]
[test_presentation_dc_receiver.html]
skip-if = (e10s || toolkit == 'android') # Bug 1129785
[test_presentation_dc_receiver_oop.html]
skip-if = (e10s || toolkit == 'android') # Bug 1129785
[test_presentation_1ua_sender_and_receiver_inproc.html]
skip-if = (e10s || toolkit == 'android') # Bug 1129785
[test_presentation_1ua_sender_and_receiver_oop.html]
skip-if = (e10s || toolkit == 'android') # Bug 1129785
[test_presentation_1ua_connection_wentaway_inproc.html]
skip-if = (e10s || toolkit == 'android') # Bug 1129785
[test_presentation_1ua_connection_wentaway_oop.html]
skip-if = (e10s || toolkit == 'android') # Bug 1129785
[test_presentation_device_info_permission.html]
[test_presentation_tcp_sender_disconnect.html]
skip-if = toolkit == 'android' # Bug 1129785
[test_presentation_tcp_sender_establish_connection_error.html]
skip-if = toolkit == 'android' # Bug 1129785
[test_presentation_tcp_receiver_establish_connection_error.html]
skip-if = (e10s || toolkit == 'android' || os == 'mac' || os == 'win') # Bug 1129785, Bug 1204709
[test_presentation_tcp_receiver_establish_connection_timeout.html]
skip-if = (e10s || toolkit == 'android') # Bug 1129785
[test_presentation_tcp_receiver_establish_connection_unknown_content_type_inproc.html]
skip-if = (e10s || toolkit == 'android')
[test_presentation_tcp_receiver_establish_connection_unknown_content_type_oop.html]
skip-if = (e10s || toolkit == 'android')
[test_presentation_tcp_receiver.html]
skip-if = (e10s || toolkit == 'android') # Bug 1129785
[test_presentation_tcp_receiver_oop.html]
skip-if = (e10s || toolkit == 'android') # Bug 1129785
[test_presentation_receiver_auxiliary_navigation_inproc.html]
skip-if = e10s
[test_presentation_receiver_auxiliary_navigation_oop.html]
skip-if = e10s
[test_presentation_terminate_inproc.html]
skip-if = (e10s || toolkit == 'android')
[test_presentation_terminate_oop.html]
skip-if = (e10s || toolkit == 'android')
[test_presentation_terminate_establish_connection_error_inproc.html]
skip-if = (e10s || toolkit == 'android')
[test_presentation_terminate_establish_connection_error_oop.html]
skip-if = (e10s || toolkit == 'android')
[test_presentation_sender_on_terminate_request.html]
skip-if = toolkit == 'android'
[test_presentation_sandboxed_presentation.html]
skip-if = true # bug 1315867
[test_presentation_reconnect.html]
[test_presentation_mixed_security_contexts.html]
[test_presentation_availability.html]

View file

@ -0,0 +1,175 @@
'use strict';
SimpleTest.waitForExplicitFinish();
SimpleTest.requestFlakyTimeout('Test for guarantee not firing async event');
function debug(str) {
// info(str);
}
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript1UA.js'));
var receiverUrl = SimpleTest.getTestFileURL('file_presentation_1ua_wentaway.html');
var request;
var connection;
var receiverIframe;
function setup() {
gScript.addMessageListener('device-prompt', function devicePromptHandler() {
debug('Got message: device-prompt');
gScript.removeMessageListener('device-prompt', devicePromptHandler);
gScript.sendAsyncMessage('trigger-device-prompt-select');
});
gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
gScript.removeMessageListener('control-channel-established',
controlChannelEstablishedHandler);
gScript.sendAsyncMessage("trigger-control-channel-open");
});
gScript.addMessageListener('sender-launch', function senderLaunchHandler(url) {
debug('Got message: sender-launch');
gScript.removeMessageListener('sender-launch', senderLaunchHandler);
is(url, receiverUrl, 'Receiver: should receive the same url');
receiverIframe = document.createElement('iframe');
receiverIframe.setAttribute("mozbrowser", "true");
receiverIframe.setAttribute("mozpresentation", receiverUrl);
var oop = location.pathname.indexOf('_inproc') == -1;
receiverIframe.setAttribute("remote", oop);
receiverIframe.setAttribute('src', receiverUrl);
receiverIframe.addEventListener("mozbrowserloadend", function mozbrowserloadendHander() {
receiverIframe.removeEventListener("mozbrowserloadend", mozbrowserloadendHander);
info("Receiver loaded.");
});
// This event is triggered when the iframe calls "alert".
receiverIframe.addEventListener("mozbrowsershowmodalprompt", function receiverListener(evt) {
var message = evt.detail.message;
if (/^OK /.exec(message)) {
ok(true, message.replace(/^OK /, ""));
} else if (/^KO /.exec(message)) {
ok(false, message.replace(/^KO /, ""));
} else if (/^INFO /.exec(message)) {
info(message.replace(/^INFO /, ""));
} else if (/^COMMAND /.exec(message)) {
var command = JSON.parse(message.replace(/^COMMAND /, ""));
gScript.sendAsyncMessage(command.name, command.data);
} else if (/^DONE$/.exec(message)) {
receiverIframe.removeEventListener("mozbrowsershowmodalprompt",
receiverListener);
teardown();
}
}, false);
var promise = new Promise(function(aResolve, aReject) {
document.body.appendChild(receiverIframe);
aResolve(receiverIframe);
});
var obs = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
.getService(SpecialPowers.Ci.nsIObserverService);
obs.notifyObservers(promise, 'setup-request-promise', null);
});
gScript.addMessageListener('promise-setup-ready', function promiseSetupReadyHandler() {
debug('Got message: promise-setup-ready');
gScript.removeMessageListener('promise-setup-ready',
promiseSetupReadyHandler);
gScript.sendAsyncMessage('trigger-on-session-request', receiverUrl);
});
return Promise.resolve();
}
function testCreateRequest() {
return new Promise(function(aResolve, aReject) {
info('Sender: --- testCreateRequest ---');
request = new PresentationRequest(receiverUrl);
request.getAvailability().then((aAvailability) => {
is(aAvailability.value, false, "Sender: should have no available device after setup");
aAvailability.onchange = function() {
aAvailability.onchange = null;
ok(aAvailability.value, "Sender: Device should be available.");
aResolve();
}
gScript.sendAsyncMessage('trigger-device-add');
}).catch((aError) => {
ok(false, "Sender: Error occurred when getting availability: " + aError);
teardown();
aReject();
});
});
}
function testStartConnection() {
return new Promise(function(aResolve, aReject) {
request.start().then((aConnection) => {
connection = aConnection;
ok(connection, "Sender: Connection should be available.");
ok(connection.id, "Sender: Connection ID should be set.");
is(connection.state, "connecting", "Sender: The initial state should be connecting.");
connection.onconnect = function() {
connection.onconnect = null;
is(connection.state, "connected", "Connection should be connected.");
aResolve();
};
}).catch((aError) => {
ok(false, "Sender: Error occurred when establishing a connection: " + aError);
teardown();
aReject();
});
});
}
function testConnectionWentaway() {
return new Promise(function(aResolve, aReject) {
info('Sender: --- testConnectionWentaway ---');
connection.onclose = function() {
connection.onclose = null;
is(connection.state, "closed", "Sender: Connection should be closed.");
receiverIframe.addEventListener('mozbrowserclose', function closeHandler() {
ok(false, 'wentaway should not trigger receiver close');
aResolve();
});
setTimeout(aResolve, 3000);
};
gScript.addMessageListener('ready-to-remove-receiverFrame', function onReadyToRemove() {
gScript.removeMessageListener('ready-to-remove-receiverFrame', onReadyToRemove);
receiverIframe.src = "http://example.com";
});
});
}
function teardown() {
gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
debug('Got message: teardown-complete');
gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
gScript.destroy();
SimpleTest.finish();
});
gScript.sendAsyncMessage('teardown');
}
function runTests() {
setup().then(testCreateRequest)
.then(testStartConnection)
.then(testConnectionWentaway)
.then(teardown);
}
SpecialPowers.pushPermissions([
{type: 'presentation-device-manage', allow: false, context: document},
{type: "browser", allow: true, context: document},
], () => {
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
["dom.presentation.controller.enabled", true],
["dom.presentation.receiver.enabled", true],
["dom.presentation.test.enabled", true],
["dom.mozBrowserFramesEnabled", true],
["dom.ipc.tabs.disabled", false],
["network.disable.ipc.security", true],
["dom.presentation.test.stage", 0]]},
runTests);
});

View file

@ -0,0 +1,18 @@
<!DOCTYPE HTML>
<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: -->
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for B2G Presentation API when sender and receiver at the same side</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1258600">
Test for PresentationConnectionCloseEvent with wentaway reason</a>
<script type="application/javascript;version=1.8" src="test_presentation_1ua_connection_wentaway.js">
</script>
</body>
</html>

View file

@ -0,0 +1,18 @@
<!DOCTYPE HTML>
<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: -->
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for B2G Presentation API when sender and receiver at the same side</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1258600">
Test for PresentationConnectionCloseEvent with wentaway reason</a>
<script type="application/javascript;version=1.8" src="test_presentation_1ua_connection_wentaway.js">
</script>
</body>
</html>

View file

@ -0,0 +1,370 @@
/* 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';
function debug(str) {
// info(str);
}
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript1UA.js'));
var receiverUrl = SimpleTest.getTestFileURL('file_presentation_1ua_receiver.html');
var request;
var connection;
var receiverIframe;
var presentationId;
const DATA_ARRAY = [0, 255, 254, 0, 1, 2, 3, 0, 255, 255, 254, 0];
const DATA_ARRAY_BUFFER = new ArrayBuffer(DATA_ARRAY.length);
const TYPED_DATA_ARRAY = new Uint8Array(DATA_ARRAY_BUFFER);
TYPED_DATA_ARRAY.set(DATA_ARRAY);
function postMessageToIframe(aType) {
receiverIframe.src = receiverUrl + "#" +
encodeURIComponent(JSON.stringify({ type: aType }));
}
function setup() {
gScript.addMessageListener('device-prompt', function devicePromptHandler() {
debug('Got message: device-prompt');
gScript.removeMessageListener('device-prompt', devicePromptHandler);
gScript.sendAsyncMessage('trigger-device-prompt-select');
});
gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
gScript.removeMessageListener('control-channel-established',
controlChannelEstablishedHandler);
gScript.sendAsyncMessage("trigger-control-channel-open");
});
gScript.addMessageListener('sender-launch', function senderLaunchHandler(url) {
debug('Got message: sender-launch');
gScript.removeMessageListener('sender-launch', senderLaunchHandler);
is(url, receiverUrl, 'Receiver: should receive the same url');
receiverIframe = document.createElement('iframe');
receiverIframe.setAttribute('src', receiverUrl);
receiverIframe.setAttribute("mozbrowser", "true");
receiverIframe.setAttribute("mozpresentation", receiverUrl);
var oop = location.pathname.indexOf('_inproc') == -1;
receiverIframe.setAttribute("remote", oop);
// This event is triggered when the iframe calls "alert".
receiverIframe.addEventListener("mozbrowsershowmodalprompt", function receiverListener(evt) {
var message = evt.detail.message;
debug('Got iframe message: ' + message);
if (/^OK /.exec(message)) {
ok(true, message.replace(/^OK /, ""));
} else if (/^KO /.exec(message)) {
ok(false, message.replace(/^KO /, ""));
} else if (/^INFO /.exec(message)) {
info(message.replace(/^INFO /, ""));
} else if (/^COMMAND /.exec(message)) {
var command = JSON.parse(message.replace(/^COMMAND /, ""));
gScript.sendAsyncMessage(command.name, command.data);
} else if (/^DONE$/.exec(message)) {
receiverIframe.removeEventListener("mozbrowsershowmodalprompt",
receiverListener);
}
}, false);
var promise = new Promise(function(aResolve, aReject) {
document.body.appendChild(receiverIframe);
aResolve(receiverIframe);
});
var obs = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
.getService(SpecialPowers.Ci.nsIObserverService);
obs.notifyObservers(promise, 'setup-request-promise', null);
});
gScript.addMessageListener('promise-setup-ready', function promiseSetupReadyHandler() {
debug('Got message: promise-setup-ready');
gScript.removeMessageListener('promise-setup-ready', promiseSetupReadyHandler);
gScript.sendAsyncMessage('trigger-on-session-request', receiverUrl);
});
return Promise.resolve();
}
function testCreateRequest() {
return new Promise(function(aResolve, aReject) {
info('Sender: --- testCreateRequest ---');
request = new PresentationRequest("file_presentation_1ua_receiver.html");
request.getAvailability().then((aAvailability) => {
is(aAvailability.value, false, "Sender: should have no available device after setup");
aAvailability.onchange = function() {
aAvailability.onchange = null;
ok(aAvailability.value, "Sender: Device should be available.");
aResolve();
}
gScript.sendAsyncMessage('trigger-device-add');
}).catch((aError) => {
ok(false, "Sender: Error occurred when getting availability: " + aError);
teardown();
aReject();
});
});
}
function testStartConnection() {
return new Promise(function(aResolve, aReject) {
request.start().then((aConnection) => {
connection = aConnection;
ok(connection, "Sender: Connection should be available.");
ok(connection.id, "Sender: Connection ID should be set.");
is(connection.state, "connecting", "The initial state should be connecting.");
is(connection.url, receiverUrl, "request URL should be expanded to absolute URL");
connection.onconnect = function() {
connection.onconnect = null;
is(connection.state, "connected", "Connection should be connected.");
presentationId = connection.id;
aResolve();
};
}).catch((aError) => {
ok(false, "Sender: Error occurred when establishing a connection: " + aError);
teardown();
aReject();
});
let request2 = new PresentationRequest("/");
request2.start().then(() => {
ok(false, "Sender: session start should fail while there is an unsettled promise.");
}).catch((aError) => {
is(aError.name, "OperationError", "Expect to get OperationError.");
});
});
}
function testSendMessage() {
return new Promise(function(aResolve, aReject) {
info('Sender: --- testSendMessage ---');
gScript.addMessageListener('trigger-message-from-sender', function triggerMessageFromSenderHandler() {
debug('Got message: trigger-message-from-sender');
gScript.removeMessageListener('trigger-message-from-sender', triggerMessageFromSenderHandler);
info('Send message to receiver');
connection.send('msg-sender-to-receiver');
});
gScript.addMessageListener('message-from-sender-received', function messageFromSenderReceivedHandler() {
debug('Got message: message-from-sender-received');
gScript.removeMessageListener('message-from-sender-received', messageFromSenderReceivedHandler);
aResolve();
});
});
}
function testIncomingMessage() {
return new Promise(function(aResolve, aReject) {
info('Sender: --- testIncomingMessage ---');
connection.addEventListener('message', function messageHandler(evt) {
connection.removeEventListener('message', messageHandler);
let msg = evt.data;
is(msg, "msg-receiver-to-sender", "Sender: Sender should receive message from Receiver");
postMessageToIframe('message-from-receiver-received');
aResolve();
});
postMessageToIframe('trigger-message-from-receiver');
});
}
function testSendBlobMessage() {
return new Promise(function(aResolve, aReject) {
info('Sender: --- testSendBlobMessage ---');
connection.addEventListener('message', function messageHandler(evt) {
connection.removeEventListener('message', messageHandler);
let msg = evt.data;
is(msg, "testIncomingBlobMessage", "Sender: Sender should receive message from Receiver");
let blob = new Blob(["Hello World"], {type : 'text/plain'});
connection.send(blob);
aResolve();
});
});
}
function testSendArrayBuffer() {
return new Promise(function(aResolve, aReject) {
info('Sender: --- testSendArrayBuffer ---');
connection.addEventListener('message', function messageHandler(evt) {
connection.removeEventListener('message', messageHandler);
let msg = evt.data;
is(msg, "testIncomingArrayBuffer", "Sender: Sender should receive message from Receiver");
connection.send(DATA_ARRAY_BUFFER);
aResolve();
});
});
}
function testSendArrayBufferView() {
return new Promise(function(aResolve, aReject) {
info('Sender: --- testSendArrayBufferView ---');
connection.addEventListener('message', function messageHandler(evt) {
connection.removeEventListener('message', messageHandler);
let msg = evt.data;
is(msg, "testIncomingArrayBufferView", "Sender: Sender should receive message from Receiver");
connection.send(TYPED_DATA_ARRAY);
aResolve();
});
});
}
function testCloseConnection() {
info('Sender: --- testCloseConnection ---');
// Test terminate immediate after close.
function controlChannelEstablishedHandler()
{
gScript.removeMessageListener('control-channel-established',
controlChannelEstablishedHandler);
ok(false, "terminate after close should do nothing");
}
gScript.addMessageListener('ready-to-close', function onReadyToClose() {
gScript.removeMessageListener('ready-to-close', onReadyToClose);
connection.close();
gScript.addMessageListener('control-channel-established', controlChannelEstablishedHandler);
connection.terminate();
});
return Promise.all([
new Promise(function(aResolve, aReject) {
connection.onclose = function() {
connection.onclose = null;
is(connection.state, 'closed', 'Sender: Connection should be closed.');
gScript.removeMessageListener('control-channel-established',
controlChannelEstablishedHandler);
aResolve();
};
}),
new Promise(function(aResolve, aReject) {
let timeout = setTimeout(function() {
gScript.removeMessageListener('device-disconnected',
deviceDisconnectedHandler);
ok(true, "terminate after close should not trigger device.disconnect");
aResolve();
}, 3000);
function deviceDisconnectedHandler() {
gScript.removeMessageListener('device-disconnected',
deviceDisconnectedHandler);
ok(false, "terminate after close should not trigger device.disconnect");
clearTimeout(timeout);
aResolve();
}
gScript.addMessageListener('device-disconnected', deviceDisconnectedHandler);
}),
new Promise(function(aResolve, aReject) {
gScript.addMessageListener('receiver-closed', function onReceiverClosed() {
gScript.removeMessageListener('receiver-closed', onReceiverClosed);
gScript.removeMessageListener('control-channel-established',
controlChannelEstablishedHandler);
aResolve();
});
}),
]);
}
function testTerminateAfterClose() {
info('Sender: --- testTerminateAfterClose ---');
return Promise.race([
new Promise(function(aResolve, aReject) {
connection.onterminate = function() {
connection.onterminate = null;
ok(false, 'terminate after close should do nothing');
aResolve();
};
connection.terminate();
}),
new Promise(function(aResolve, aReject) {
setTimeout(function() {
is(connection.state, 'closed', 'Sender: Connection should be closed.');
aResolve();
}, 3000);
}),
]);
}
function testReconnect() {
return new Promise(function(aResolve, aReject) {
info('Sender: --- testReconnect ---');
gScript.addMessageListener('control-channel-established', function controlChannelEstablished() {
gScript.removeMessageListener('control-channel-established', controlChannelEstablished);
gScript.sendAsyncMessage("trigger-control-channel-open");
});
gScript.addMessageListener('start-reconnect', function startReconnectHandler(url) {
debug('Got message: start-reconnect');
gScript.removeMessageListener('start-reconnect', startReconnectHandler);
is(url, receiverUrl, "URLs should be the same.")
gScript.sendAsyncMessage('trigger-reconnected-acked', url);
});
gScript.addMessageListener('ready-to-reconnect', function onReadyToReconnect() {
gScript.removeMessageListener('ready-to-reconnect', onReadyToReconnect);
request.reconnect(presentationId).then((aConnection) => {
connection = aConnection;
ok(connection, "Sender: Connection should be available.");
is(connection.id, presentationId, "The presentationId should be the same.");
is(connection.state, "connecting", "The initial state should be connecting.");
connection.onconnect = function() {
connection.onconnect = null;
is(connection.state, "connected", "Connection should be connected.");
aResolve();
};
}).catch((aError) => {
ok(false, "Sender: Error occurred when establishing a connection: " + aError);
teardown();
aReject();
});
});
postMessageToIframe('prepare-for-reconnect');
});
}
function teardown() {
gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
debug('Got message: teardown-complete');
gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
gScript.destroy();
SimpleTest.finish();
});
gScript.sendAsyncMessage('teardown');
}
function runTests() {
setup().then(testCreateRequest)
.then(testStartConnection)
.then(testSendMessage)
.then(testIncomingMessage)
.then(testSendBlobMessage)
.then(testCloseConnection)
.then(testReconnect)
.then(testSendArrayBuffer)
.then(testSendArrayBufferView)
.then(testCloseConnection)
.then(testTerminateAfterClose)
.then(teardown);
}
SimpleTest.waitForExplicitFinish();
SimpleTest.requestFlakyTimeout('Test for guarantee not firing async event');
SpecialPowers.pushPermissions([
{type: 'presentation-device-manage', allow: false, context: document},
{type: "browser", allow: true, context: document},
], () => {
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
/* Mocked TCP session transport builder in the test */
["dom.presentation.session_transport.data_channel.enable", true],
["dom.presentation.controller.enabled", true],
["dom.presentation.receiver.enabled", true],
["dom.presentation.test.enabled", true],
["dom.presentation.test.stage", 0],
["dom.mozBrowserFramesEnabled", true],
["network.disable.ipc.security", true],
["media.navigator.permission.disabled", true]]},
runTests);
});

View file

@ -0,0 +1,18 @@
<!DOCTYPE HTML>
<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: -->
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for B2G Presentation API when sender and receiver at the same side</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1234492">
Test for B2G Presentation API when sender and receiver at the same side</a>
<script type="application/javascript;version=1.8" src="test_presentation_1ua_sender_and_receiver.js">
</script>
</body>
</html>

View file

@ -0,0 +1,18 @@
<!DOCTYPE HTML>
<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: -->
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for B2G Presentation API when sender and receiver at the same side (OOP ver.)</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1234492">
Test for B2G Presentation API when sender and receiver at the same side (OOP ver.)</a>
<script type="application/javascript;version=1.8" src="test_presentation_1ua_sender_and_receiver.js">
</script>
</body>
</html>

View file

@ -0,0 +1,236 @@
<!DOCTYPE HTML>
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for PresentationAvailability</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1228508">Test PresentationAvailability</a>
<script type="application/javascript;version=1.8">
"use strict";
var testDevice = {
id: 'id',
name: 'name',
type: 'type',
};
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationDeviceInfoChromeScript.js'));
var request;
var availability;
function testSetup() {
return new Promise(function(aResolve, aReject) {
gScript.addMessageListener('setup-complete', function() {
aResolve();
});
gScript.sendAsyncMessage('setup');
});
}
function testInitialUnavailable() {
request = new PresentationRequest("https://example.com");
return request.getAvailability().then(function(aAvailability) {
is(aAvailability.value, false, "Should have no available device after setup");
aAvailability.onchange = function() {
aAvailability.onchange = null;
ok(aAvailability.value, "Device should be available.");
}
availability = aAvailability;
gScript.sendAsyncMessage('trigger-device-add', testDevice);
}).catch(function(aError) {
ok(false, "Error occurred when getting availability: " + aError);
teardown();
});
}
function testInitialAvailable() {
let anotherRequest = new PresentationRequest("https://example.net");
return anotherRequest.getAvailability().then(function(aAvailability) {
is(aAvailability.value, true, "Should have available device initially");
isnot(aAvailability, availability, "Should get different availability object for different request URL");
}).catch(function(aError) {
ok(false, "Error occurred when getting availability: " + aError);
teardown();
});
}
function testSameObject() {
let sameUrlRequest = new PresentationRequest("https://example.com");
return sameUrlRequest.getAvailability().then(function(aAvailability) {
is(aAvailability, availability, "Should get same availability object for same request URL");
}).catch(function(aError) {
ok(false, "Error occurred when getting availability: " + aError);
teardown();
});
}
function testOnChangeEvent() {
return new Promise(function(aResolve, aReject) {
availability.onchange = function() {
availability.onchange = null;
is(availability.value, false, "Should have no available device after device removed");
aResolve();
}
gScript.sendAsyncMessage('trigger-device-remove');
});
}
function testConsecutiveGetAvailability() {
let request = new PresentationRequest("https://example.org");
let firstAvailabilityResolved = false;
return Promise.all([
request.getAvailability().then(function() {
firstAvailabilityResolved = true;
}),
request.getAvailability().then(function() {
ok(firstAvailabilityResolved, "getAvailability() should be resolved in sequence");
})
]).catch(function(aError) {
ok(false, "Error occurred when getting availability: " + aError);
teardown();
});
}
function testUnsupportedDeviceAvailability() {
return Promise.race([
new Promise(function(aResolve, aReject) {
let request = new PresentationRequest("https://test.com");
request.getAvailability().then(function(aAvailability) {
availability = aAvailability;
aAvailability.onchange = function() {
availability.onchange = null;
ok(false, "Should not get onchange event.");
teardown();
}
});
gScript.sendAsyncMessage('trigger-add-unsupport-url-device');
}),
new Promise(function(aResolve, aReject) {
setTimeout(function() {
ok(true, "Should not get onchange event.");
availability.onchange = null;
gScript.sendAsyncMessage('trigger-remove-unsupported-device');
aResolve();
}, 3000);
}),
]);
}
function testMultipleAvailabilityURLs() {
let request1 = new PresentationRequest(["https://example.com",
"https://example1.com"]);
let request2 = new PresentationRequest(["https://example1.com",
"https://example2.com"]);
return Promise.all([
request1.getAvailability().then(function(aAvailability) {
return new Promise(function(aResolve) {
aAvailability.onchange = function() {
aAvailability.onchange = null;
ok(true, "Should get onchange event.");
aResolve();
};
});
}),
request2.getAvailability().then(function(aAvailability) {
return new Promise(function(aResolve) {
aAvailability.onchange = function() {
aAvailability.onchange = null;
ok(true, "Should get onchange event.");
aResolve();
};
});
}),
new Promise(function(aResolve) {
gScript.sendAsyncMessage('trigger-add-multiple-devices');
aResolve();
}),
]).then(new Promise(function(aResolve) {
gScript.sendAsyncMessage('trigger-remove-multiple-devices');
aResolve();
}));
}
function testPartialSupportedDeviceAvailability() {
let request1 = new PresentationRequest(["https://supportedUrl.com"]);
let request2 = new PresentationRequest(["http://notSupportedUrl.com"]);
return Promise.all([
request1.getAvailability().then(function(aAvailability) {
return new Promise(function(aResolve) {
aAvailability.onchange = function() {
aAvailability.onchange = null;
ok(true, "Should get onchange event.");
aResolve();
};
});
}),
Promise.race([
request2.getAvailability().then(function(aAvailability) {
return new Promise(function(aResolve) {
aAvailability.onchange = function() {
aAvailability.onchange = null;
ok(false, "Should get onchange event.");
aResolve();
};
});
}),
new Promise(function(aResolve) {
setTimeout(function() {
ok(true, "Should not get onchange event.");
availability.onchange = null;
aResolve();
}, 3000);
}),
]),
new Promise(function(aResolve) {
gScript.sendAsyncMessage('trigger-add-https-devices');
aResolve();
}),
]).then(new Promise(function(aResolve) {
gScript.sendAsyncMessage('trigger-remove-https-devices');
aResolve();
}));
}
function teardown() {
request = null;
availability = null;
gScript.sendAsyncMessage('teardown');
gScript.destroy();
SimpleTest.finish();
}
function runTests() {
ok(navigator.presentation, "navigator.presentation should be available.");
testSetup().then(testInitialUnavailable)
.then(testInitialAvailable)
.then(testSameObject)
.then(testOnChangeEvent)
.then(testConsecutiveGetAvailability)
.then(testMultipleAvailabilityURLs)
.then(testUnsupportedDeviceAvailability)
.then(testPartialSupportedDeviceAvailability)
.then(teardown);
}
SimpleTest.waitForExplicitFinish();
SimpleTest.requestFlakyTimeout('Test for guarantee not firing async event');
SpecialPowers.pushPermissions([
{type: "presentation-device-manage", allow: false, context: document},
], function() {
SpecialPowers.pushPrefEnv({ "set": [["dom.presentation.enabled", true],
["dom.presentation.controller.enabled", true],
["dom.presentation.session_transport.data_channel.enable", false]]},
runTests);
});
</script>
</body>
</html>

View file

@ -0,0 +1,245 @@
<!DOCTYPE HTML>
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for data channel as session transport in Presentation API</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1148307">Test for data channel as session transport in Presentation API</a>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
"use strict";
SimpleTest.waitForExplicitFinish();
const loadingTimeoutPref = "presentation.receiver.loading.timeout";
var clientBuilder;
var serverBuilder;
var clientTransport;
var serverTransport;
const clientMessage = "Client Message";
const serverMessage = "Server Message";
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
const { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const { Services } = Cu.import("resource://gre/modules/Services.jsm");
var isClientReady = false;
var isServerReady = false;
var isClientClosed = false;
var isServerClosed = false;
var gResolve;
var gReject;
const clientCallback = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationSessionTransportCallback]),
notifyTransportReady: function () {
info("Client transport ready.");
isClientReady = true;
if (isClientReady && isServerReady) {
gResolve();
}
},
notifyTransportClosed: function (aReason) {
info("Client transport is closed.");
isClientClosed = true;
if (isClientClosed && isServerClosed) {
gResolve();
}
},
notifyData: function(aData) {
is(aData, serverMessage, "Client transport receives data.");
gResolve();
},
};
const serverCallback = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationSessionTransportCallback]),
notifyTransportReady: function () {
info("Server transport ready.");
isServerReady = true;
if (isClientReady && isServerReady) {
gResolve();
}
},
notifyTransportClosed: function (aReason) {
info("Server transport is closed.");
isServerClosed = true;
if (isClientClosed && isServerClosed) {
gResolve();
}
},
notifyData: function(aData) {
is(aData, clientMessage, "Server transport receives data.");
gResolve()
},
};
const clientListener = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationSessionTransportBuilderListener]),
onSessionTransport: function(aTransport) {
info("Client Transport is built.");
clientTransport = aTransport;
clientTransport.callback = clientCallback;
},
onError: function(aError) {
ok(false, "client's builder reports error " + aError);
},
sendOffer: function(aOffer) {
setTimeout(()=>this._remoteBuilder.onOffer(aOffer), 0);
},
sendAnswer: function(aAnswer) {
setTimeout(()=>this._remoteBuilder.onAnswer(aAnswer), 0);
},
sendIceCandidate: function(aCandidate) {
setTimeout(()=>this._remoteBuilder.onIceCandidate(aCandidate), 0);
},
disconnect: function(aReason) {
setTimeout(()=>this._localBuilder.notifyDisconnected(aReason), 0);
setTimeout(()=>this._remoteBuilder.notifyDisconnected(aReason), 0);
},
set remoteBuilder(aRemoteBuilder) {
this._remoteBuilder = aRemoteBuilder;
},
set localBuilder(aLocalBuilder) {
this._localBuilder = aLocalBuilder;
},
}
const serverListener = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationSessionTransportBuilderListener]),
onSessionTransport: function(aTransport) {
info("Server Transport is built.");
serverTransport = aTransport;
serverTransport.callback = serverCallback;
serverTransport.enableDataNotification();
},
onError: function(aError) {
ok(false, "server's builder reports error " + aError);
},
sendOffer: function(aOffer) {
setTimeout(()=>this._remoteBuilder.onOffer(aOffer), 0);
},
sendAnswer: function(aAnswer) {
setTimeout(()=>this._remoteBuilder.onAnswer(aAnswer), 0);
},
sendIceCandidate: function(aCandidate) {
setTimeout(()=>this._remoteBuilder.onIceCandidate(aCandidate), 0);
},
disconnect: function(aReason) {
setTimeout(()=>this._localBuilder.notifyDisconnected(aReason), 0);
setTimeout(()=>this._remoteBuilder.notifyDisconnected(aReason), 0);
},
set remoteBuilder(aRemoteBuilder) {
this._remoteBuilder = aRemoteBuilder;
},
set localBuilder(aLocalBuilder) {
this._localBuilder = aLocalBuilder;
},
}
function testBuilder() {
return new Promise(function(aResolve, aReject) {
gResolve = aResolve;
gReject = aReject;
clientBuilder = Cc["@mozilla.org/presentation/datachanneltransportbuilder;1"]
.createInstance(Ci.nsIPresentationDataChannelSessionTransportBuilder);
serverBuilder = Cc["@mozilla.org/presentation/datachanneltransportbuilder;1"]
.createInstance(Ci.nsIPresentationDataChannelSessionTransportBuilder);
clientListener.localBuilder = clientBuilder;
clientListener.remoteBuilder = serverBuilder;
serverListener.localBuilder = serverBuilder;
serverListener.remoteBuilder = clientBuilder;
clientBuilder
.buildDataChannelTransport(Ci.nsIPresentationService.ROLE_CONTROLLER,
window,
clientListener);
serverBuilder
.buildDataChannelTransport(Ci.nsIPresentationService.ROLE_RECEIVER,
window,
serverListener);
});
}
function testClientSendMessage() {
return new Promise(function(aResolve, aReject) {
info("client sends message");
gResolve = aResolve;
gReject = aReject;
clientTransport.send(clientMessage);
});
}
function testServerSendMessage() {
return new Promise(function(aResolve, aReject) {
info("server sends message");
gResolve = aResolve;
gReject = aReject;
serverTransport.send(serverMessage);
setTimeout(()=>clientTransport.enableDataNotification(), 0);
});
}
function testCloseSessionTransport() {
return new Promise(function(aResolve, aReject) {
info("close session transport");
gResolve = aResolve;
gReject = aReject;
serverTransport.close(Cr.NS_OK);
});
}
function finish() {
info("test finished, teardown");
Services.prefs.clearUserPref(loadingTimeoutPref);
SimpleTest.finish();
}
function error(aError) {
ok(false, "report Error " + aError.name + ":" + aError.message);
gReject();
}
function runTests() {
Services.prefs.setIntPref(loadingTimeoutPref, 30000);
testBuilder()
.then(testClientSendMessage)
.then(testServerSendMessage)
.then(testCloseSessionTransport)
.then(finish)
.catch(error);
}
window.addEventListener("load", function() {
runTests();
});
</script>
</pre>
</body>
</html>

View file

@ -0,0 +1,141 @@
<!DOCTYPE HTML>
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for B2G PresentationConnection API at receiver side</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1148307">Test for B2G PresentationConnection API at receiver side</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
<script type="application/javascript">
'use strict';
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
var receiverUrl = SimpleTest.getTestFileURL('file_presentation_receiver.html');
var obs = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
.getService(SpecialPowers.Ci.nsIObserverService);
function setup() {
return new Promise(function(aResolve, aReject) {
gScript.sendAsyncMessage('trigger-device-add');
var iframe = document.createElement('iframe');
iframe.setAttribute('src', receiverUrl);
iframe.setAttribute("mozbrowser", "true");
iframe.setAttribute("mozpresentation", receiverUrl);
// This event is triggered when the iframe calls "alert".
iframe.addEventListener("mozbrowsershowmodalprompt", function receiverListener(evt) {
var message = evt.detail.message;
if (/^OK /.exec(message)) {
ok(true, message.replace(/^OK /, ""));
} else if (/^KO /.exec(message)) {
ok(false, message.replace(/^KO /, ""));
} else if (/^INFO /.exec(message)) {
info(message.replace(/^INFO /, ""));
} else if (/^COMMAND /.exec(message)) {
var command = JSON.parse(message.replace(/^COMMAND /, ""));
gScript.sendAsyncMessage(command.name, command.data);
} else if (/^DONE$/.exec(message)) {
iframe.removeEventListener("mozbrowsershowmodalprompt",
receiverListener);
teardown();
}
}, false);
var promise = new Promise(function(aResolve, aReject) {
document.body.appendChild(iframe);
aResolve(iframe);
});
obs.notifyObservers(promise, 'setup-request-promise', null);
gScript.addMessageListener('offer-received', function offerReceivedHandler() {
gScript.removeMessageListener('offer-received', offerReceivedHandler);
info("An offer is received.");
});
gScript.addMessageListener('answer-sent', function answerSentHandler(aIsValid) {
gScript.removeMessageListener('answer-sent', answerSentHandler);
ok(aIsValid, "A valid answer is sent.");
});
gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
is(aReason, SpecialPowers.Cr.NS_OK, "The control channel is closed normally.");
});
gScript.addMessageListener('check-navigator', function checknavigatorHandler(aSuccess) {
gScript.removeMessageListener('check-navigator', checknavigatorHandler);
ok(aSuccess, "buildDataChannel get correct window object");
});
gScript.addMessageListener('data-transport-notification-enabled', function dataTransportNotificationEnabledHandler() {
gScript.removeMessageListener('data-transport-notification-enabled', dataTransportNotificationEnabledHandler);
info("Data notification is enabled for data transport channel.");
});
gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
is(aReason, SpecialPowers.Cr.NS_OK, "The data transport should be closed normally.");
});
aResolve();
});
}
function testIncomingSessionRequest() {
return new Promise(function(aResolve, aReject) {
gScript.addMessageListener('receiver-launching', function launchReceiverHandler(aSessionId) {
gScript.removeMessageListener('receiver-launching', launchReceiverHandler);
info("Trying to launch receiver page.");
ok(navigator.presentation, "navigator.presentation should be available in in-process pages.");
is(navigator.presentation.receiver, null, "Non-receiving in-process pages shouldn't get a presentation receiver instance.");
aResolve();
});
gScript.sendAsyncMessage('trigger-incoming-session-request', receiverUrl);
});
}
function teardown() {
gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
gScript.destroy();
SimpleTest.finish();
});
gScript.sendAsyncMessage('teardown');
}
function runTests() {
setup().
then(testIncomingSessionRequest);
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPermissions([
{type: 'presentation-device-manage', allow: false, context: document},
{type: "browser", allow: true, context: document},
], function() {
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
["dom.presentation.controller.enabled", false],
["dom.presentation.receiver.enabled", true],
["dom.presentation.session_transport.data_channel.enable", true],
["dom.mozBrowserFramesEnabled", true],
["network.disable.ipc.security", true]]},
runTests);
});
</script>
</body>
</html>

View file

@ -0,0 +1,213 @@
<!DOCTYPE HTML>
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for B2G PresentationConnection API at receiver side (OOP)</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="PresentationSessionFrameScript.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1148307">Test B2G PresentationConnection API at receiver side (OOP)</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
<script type="application/javascript">
'use strict';
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
var receiverUrl = SimpleTest.getTestFileURL('file_presentation_receiver.html');
var nonReceiverUrl = SimpleTest.getTestFileURL('file_presentation_non_receiver.html');
var isReceiverFinished = false;
var isNonReceiverFinished = false;
var obs = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
.getService(SpecialPowers.Ci.nsIObserverService);
var receiverIframe;
function setup() {
return new Promise(function(aResolve, aReject) {
gScript.sendAsyncMessage('trigger-device-add');
// Create a receiver OOP iframe.
receiverIframe = document.createElement('iframe');
receiverIframe.setAttribute('remote', 'true');
receiverIframe.setAttribute('mozbrowser', 'true');
receiverIframe.setAttribute('mozpresentation', receiverUrl);
receiverIframe.setAttribute('src', receiverUrl);
// This event is triggered when the iframe calls "alert".
receiverIframe.addEventListener('mozbrowsershowmodalprompt', function receiverListener(aEvent) {
var message = aEvent.detail.message;
if (/^OK /.exec(message)) {
ok(true, "Message from iframe: " + message);
} else if (/^KO /.exec(message)) {
ok(false, "Message from iframe: " + message);
} else if (/^INFO /.exec(message)) {
info("Message from iframe: " + message);
} else if (/^COMMAND /.exec(message)) {
var command = JSON.parse(message.replace(/^COMMAND /, ''));
if (command.name == "trigger-incoming-message") {
var mm = SpecialPowers.getBrowserFrameMessageManager(receiverIframe);
mm.sendAsyncMessage('trigger-incoming-message', {"data": command.data});
} else {
gScript.sendAsyncMessage(command.name, command.data);
}
} else if (/^DONE$/.exec(message)) {
ok(true, "Messaging from iframe complete.");
receiverIframe.removeEventListener('mozbrowsershowmodalprompt', receiverListener);
isReceiverFinished = true;
if (isNonReceiverFinished) {
teardown();
}
}
}, false);
var promise = new Promise(function(aResolve, aReject) {
document.body.appendChild(receiverIframe);
receiverIframe.addEventListener("mozbrowserloadstart", function onLoadEnd() {
receiverIframe.removeEventListener("mozbrowserloadstart", onLoadEnd);
var mm = SpecialPowers.getBrowserFrameMessageManager(receiverIframe);
mm.loadFrameScript("data:,(" + loadPrivilegedScriptTest.toString() + ")();", false);
});
aResolve(receiverIframe);
});
obs.notifyObservers(promise, 'setup-request-promise', null);
// Create a non-receiver OOP iframe.
var nonReceiverIframe = document.createElement('iframe');
nonReceiverIframe.setAttribute('remote', 'true');
nonReceiverIframe.setAttribute('mozbrowser', 'true');
nonReceiverIframe.setAttribute('src', nonReceiverUrl);
// This event is triggered when the iframe calls "alert".
nonReceiverIframe.addEventListener('mozbrowsershowmodalprompt', function nonReceiverListener(aEvent) {
var message = aEvent.detail.message;
if (/^OK /.exec(message)) {
ok(true, "Message from iframe: " + message);
} else if (/^KO /.exec(message)) {
ok(false, "Message from iframe: " + message);
} else if (/^INFO /.exec(message)) {
info("Message from iframe: " + message);
} else if (/^COMMAND /.exec(message)) {
var command = JSON.parse(message.replace(/^COMMAND /, ''));
gScript.sendAsyncMessage(command.name, command.data);
} else if (/^DONE$/.exec(message)) {
ok(true, "Messaging from iframe complete.");
nonReceiverIframe.removeEventListener('mozbrowsershowmodalprompt', nonReceiverListener);
isNonReceiverFinished = true;
if (isReceiverFinished) {
teardown();
}
}
}, false);
document.body.appendChild(nonReceiverIframe);
gScript.addMessageListener('offer-received', function offerReceivedHandler() {
gScript.removeMessageListener('offer-received', offerReceivedHandler);
info("An offer is received.");
});
gScript.addMessageListener('answer-sent', function answerSentHandler(aIsValid) {
gScript.removeMessageListener('answer-sent', answerSentHandler);
ok(aIsValid, "A valid answer is sent.");
});
gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
is(aReason, SpecialPowers.Cr.NS_OK, "The control channel is closed normally.");
});
var mm = SpecialPowers.getBrowserFrameMessageManager(receiverIframe);
mm.addMessageListener('check-navigator', function checknavigatorHandler(aSuccess) {
mm.removeMessageListener('check-navigator', checknavigatorHandler);
ok(aSuccess.data.data, "buildDataChannel get correct window object");
});
mm.addMessageListener('data-transport-notification-enabled', function dataTransportNotificationEnabledHandler() {
mm.removeMessageListener('data-transport-notification-enabled', dataTransportNotificationEnabledHandler);
info("Data notification is enabled for data transport channel.");
});
mm.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
mm.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
is(aReason.data.data, SpecialPowers.Cr.NS_OK, "The data transport should be closed normally.");
});
aResolve();
});
}
function testIncomingSessionRequest() {
return new Promise(function(aResolve, aReject) {
gScript.addMessageListener('receiver-launching', function launchReceiverHandler(aSessionId) {
gScript.removeMessageListener('receiver-launching', launchReceiverHandler);
info("Trying to launch receiver page.");
aResolve();
});
gScript.sendAsyncMessage('trigger-incoming-session-request', receiverUrl);
});
}
var mmTeardownComplete = false;
var gScriptTeardownComplete = false;
function teardown() {
var mm = SpecialPowers.getBrowserFrameMessageManager(receiverIframe);
mm.addMessageListener('teardown-complete', function teardownCompleteHandler() {
mm.removeMessageListener('teardown-complete', teardownCompleteHandler);
mmTeardownComplete = true;
if (gScriptTeardownComplete) {
SimpleTest.finish();
}
});
mm.sendAsyncMessage('teardown');
gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
gScript.destroy();
gScriptTeardownComplete = true;
if (mmTeardownComplete) {
SimpleTest.finish();
}
});
gScript.sendAsyncMessage('teardown');
}
function runTests() {
setup().
then(testIncomingSessionRequest);
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPermissions([
{type: 'presentation-device-manage', allow: false, context: document},
{type: 'browser', allow: true, context: document},
], function() {
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
["dom.presentation.controller.enabled", false],
["dom.presentation.receiver.enabled", true],
["dom.presentation.session_transport.data_channel.enable", true],
["dom.mozBrowserFramesEnabled", true],
["network.disable.ipc.security", true],
["dom.ipc.browser_frames.oop_by_default", true],
["presentation.receiver.loading.timeout", 5000000]]},
runTests);
});
</script>
</body>
</html>

View file

@ -0,0 +1,291 @@
<!DOCTYPE HTML>
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for B2G Presentation API at sender side</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="PresentationSessionFrameScript.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1148307">Test for B2G Presentation API at sender side</a>
<script type="application/javascript;version=1.8">
'use strict';
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
var frameScript = SpecialPowers.isMainProcess() ? gScript : contentScript;
var request;
var connection;
function testSetup() {
return new Promise(function(aResolve, aReject) {
request = new PresentationRequest("http://example.com/");
request.getAvailability().then(
function(aAvailability) {
is(aAvailability.value, false, "Sender: should have no available device after setup");
aAvailability.onchange = function() {
aAvailability.onchange = null;
ok(aAvailability.value, "Device should be available.");
aResolve();
}
gScript.sendAsyncMessage('trigger-device-add');
},
function(aError) {
ok(false, "Error occurred when getting availability: " + aError);
teardown();
aReject();
}
);
});
}
function testStartConnection() {
return new Promise(function(aResolve, aReject) {
gScript.addMessageListener('device-prompt', function devicePromptHandler() {
gScript.removeMessageListener('device-prompt', devicePromptHandler);
info("Device prompt is triggered.");
gScript.sendAsyncMessage('trigger-device-prompt-select');
});
gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
info("A control channel is established.");
gScript.sendAsyncMessage('trigger-control-channel-open');
});
gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler(aReason) {
gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
info("The control channel is opened.");
});
gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
info("The control channel is closed. " + aReason);
});
frameScript.addMessageListener('check-navigator', function checknavigatorHandler(aSuccess) {
frameScript.removeMessageListener('check-navigator', checknavigatorHandler);
ok(aSuccess, "buildDataChannel get correct window object");
});
gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
gScript.removeMessageListener('offer-sent', offerSentHandler);
ok(aIsValid, "A valid offer is sent out.");
gScript.sendAsyncMessage('trigger-incoming-answer');
});
gScript.addMessageListener('answer-received', function answerReceivedHandler() {
gScript.removeMessageListener('answer-received', answerReceivedHandler);
info("An answer is received.");
});
frameScript.addMessageListener('data-transport-initialized', function dataTransportInitializedHandler() {
frameScript.removeMessageListener('data-transport-initialized', dataTransportInitializedHandler);
info("Data transport channel is initialized.");
});
frameScript.addMessageListener('data-transport-notification-enabled', function dataTransportNotificationEnabledHandler() {
frameScript.removeMessageListener('data-transport-notification-enabled', dataTransportNotificationEnabledHandler);
info("Data notification is enabled for data transport channel.");
});
var connectionFromEvent;
request.onconnectionavailable = function(aEvent) {
request.onconnectionavailable = null;
connectionFromEvent = aEvent.connection;
ok(connectionFromEvent, "|connectionavailable| event is fired with a connection.");
if (connection) {
is(connection, connectionFromEvent, "The connection from promise and the one from |connectionavailable| event should be the same.");
}
};
request.start().then(
function(aConnection) {
connection = aConnection;
ok(connection, "Connection should be available.");
ok(connection.id, "Connection ID should be set.");
is(connection.state, "connecting", "The initial state should be connecting.");
if (connectionFromEvent) {
is(connection, connectionFromEvent, "The connection from promise and the one from |connectionavailable| event should be the same.");
}
connection.onconnect = function() {
connection.onconnect = null;
is(connection.state, "connected", "Connection should be connected.");
aResolve();
};
},
function(aError) {
ok(false, "Error occurred when establishing a connection: " + aError);
teardown();
aReject();
}
);
});
}
function testSend() {
return new Promise(function(aResolve, aReject) {
const outgoingMessage = "test outgoing message";
frameScript.addMessageListener('message-sent', function messageSentHandler(aMessage) {
frameScript.removeMessageListener('message-sent', messageSentHandler);
is(aMessage, outgoingMessage, "The message is sent out.");
aResolve();
});
connection.send(outgoingMessage);
});
}
function testIncomingMessage() {
return new Promise(function(aResolve, aReject) {
const incomingMessage = "test incoming message";
connection.addEventListener('message', function messageHandler(aEvent) {
connection.removeEventListener('message', messageHandler);
is(aEvent.data, incomingMessage, "An incoming message should be received.");
aResolve();
});
frameScript.sendAsyncMessage('trigger-incoming-message', incomingMessage);
});
}
function testCloseConnection() {
return new Promise(function(aResolve, aReject) {
frameScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
frameScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
info("The data transport is closed. " + aReason);
});
connection.onclose = function() {
connection.onclose = null;
is(connection.state, "closed", "Connection should be closed.");
aResolve();
};
connection.close();
});
}
function testReconnect() {
return new Promise(function(aResolve, aReject) {
info('--- testReconnect ---');
gScript.addMessageListener('control-channel-established', function controlChannelEstablished() {
gScript.removeMessageListener('control-channel-established', controlChannelEstablished);
gScript.sendAsyncMessage("trigger-control-channel-open");
});
gScript.addMessageListener('start-reconnect', function startReconnectHandler(url) {
gScript.removeMessageListener('start-reconnect', startReconnectHandler);
is(url, "http://example.com/", "URLs should be the same.")
gScript.sendAsyncMessage('trigger-reconnected-acked', url);
});
gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
gScript.removeMessageListener('offer-sent', offerSentHandler);
ok(aIsValid, "A valid offer is sent out.");
gScript.sendAsyncMessage('trigger-incoming-answer');
});
gScript.addMessageListener('answer-received', function answerReceivedHandler() {
gScript.removeMessageListener('answer-received', answerReceivedHandler);
info("An answer is received.");
});
frameScript.addMessageListener('check-navigator', function checknavigatorHandler(aSuccess) {
frameScript.removeMessageListener('check-navigator', checknavigatorHandler);
ok(aSuccess, "buildDataChannel get correct window object");
});
request.reconnect(connection.id).then(
function(aConnection) {
ok(aConnection, "Connection should be available.");
ok(aConnection.id, "Connection ID should be set.");
is(aConnection.state, "connecting", "The initial state should be connecting.");
is(aConnection, connection, "The reconnected connection should be the same.");
aConnection.onconnect = function() {
aConnection.onconnect = null;
is(aConnection.state, "connected", "Connection should be connected.");
aResolve();
};
},
function(aError) {
ok(false, "Error occurred when establishing a connection: " + aError);
teardown();
aReject();
}
);
});
}
function teardown() {
gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
gScript.destroy();
info('teardown-complete');
SimpleTest.finish();
});
gScript.sendAsyncMessage('teardown');
}
function testConstructRequestError() {
return Promise.all([
// XXX: Bug 1305204 - uncomment when bug 1275746 is fixed again.
// new Promise(function(aResolve, aReject) {
// try {
// request = new PresentationRequest("\\\\\\");
// }
// catch(e) {
// is(e.name, "SyntaxError", "Expect to get SyntaxError.");
// aResolve();
// }
// }),
new Promise(function(aResolve, aReject) {
try {
request = new PresentationRequest([]);
}
catch(e) {
is(e.name, "NotSupportedError", "Expect to get NotSupportedError.");
aResolve();
}
}),
]);
}
function runTests() {
ok(window.PresentationRequest, "PresentationRequest should be available.");
testSetup().
then(testStartConnection).
then(testSend).
then(testIncomingMessage).
then(testCloseConnection).
then(testReconnect).
then(testCloseConnection).
then(testConstructRequestError).
then(teardown);
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPermissions([
{type: 'presentation-device-manage', allow: false, context: document},
], function() {
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
["dom.presentation.controller.enabled", true],
["dom.presentation.session_transport.data_channel.enable", true]]},
runTests);
});
</script>
</body>
</html>

View file

@ -0,0 +1,144 @@
<!DOCTYPE HTML>
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for B2G Presentation Device Info API</title>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1080474">Test for B2G Presentation Device Info API</a>
<script type="application/javascript;version=1.8">
'use strict';
SimpleTest.waitForExplicitFinish();
var testDevice = {
id: 'id',
name: 'name',
type: 'type',
};
var gUrl = SimpleTest.getTestFileURL('PresentationDeviceInfoChromeScript.js');
var gScript = SpecialPowers.loadChromeScript(gUrl);
function testSetup() {
return new Promise(function(resolve, reject) {
gScript.addMessageListener('setup-complete', function() {
resolve();
});
gScript.sendAsyncMessage('setup');
});
}
function testForceDiscovery() {
info('test force discovery');
return new Promise(function(resolve, reject) {
gScript.addMessageListener('force-discovery', function() {
ok(true, 'nsIPresentationDeviceProvider.forceDiscovery is invoked');
resolve();
});
navigator.mozPresentationDeviceInfo.forceDiscovery();
});
}
function testDeviceAdd() {
info('test device add');
return new Promise(function(resolve, reject) {
navigator.mozPresentationDeviceInfo.addEventListener('devicechange', function deviceChangeHandler(e) {
navigator.mozPresentationDeviceInfo.removeEventListener('devicechange', deviceChangeHandler);
let detail = e.detail;
is(detail.type, 'add', 'expected update type');
is(detail.deviceInfo.id, testDevice.id, 'expected device id');
is(detail.deviceInfo.name, testDevice.name, 'expected device name');
is(detail.deviceInfo.type, testDevice.type, 'expected device type');
navigator.mozPresentationDeviceInfo.getAll()
.then(function(devices) {
is(devices.length, 1, 'expected 1 available device');
is(devices[0].id, testDevice.id, 'expected device id');
is(devices[0].name, testDevice.name, 'expected device name');
is(devices[0].type, testDevice.type, 'expected device type');
resolve();
});
});
gScript.sendAsyncMessage('trigger-device-add', testDevice);
});
}
function testDeviceUpdate() {
info('test device update');
return new Promise(function(resolve, reject) {
testDevice.name = 'name-update';
navigator.mozPresentationDeviceInfo.addEventListener('devicechange', function deviceChangeHandler(e) {
navigator.mozPresentationDeviceInfo.removeEventListener('devicechange', deviceChangeHandler);
let detail = e.detail;
is(detail.type, 'update', 'expected update type');
is(detail.deviceInfo.id, testDevice.id, 'expected device id');
is(detail.deviceInfo.name, testDevice.name, 'expected device name');
is(detail.deviceInfo.type, testDevice.type, 'expected device type');
navigator.mozPresentationDeviceInfo.getAll()
.then(function(devices) {
is(devices.length, 1, 'expected 1 available device');
is(devices[0].id, testDevice.id, 'expected device id');
is(devices[0].name, testDevice.name, 'expected device name');
is(devices[0].type, testDevice.type, 'expected device type');
resolve();
});
});
gScript.sendAsyncMessage('trigger-device-update', testDevice);
});
}
function testDeviceRemove() {
info('test device remove');
return new Promise(function(resolve, reject) {
navigator.mozPresentationDeviceInfo.addEventListener('devicechange', function deviceChangeHandler(e) {
navigator.mozPresentationDeviceInfo.removeEventListener('devicechange', deviceChangeHandler);
let detail = e.detail;
is(detail.type, 'remove', 'expected update type');
is(detail.deviceInfo.id, testDevice.id, 'expected device id');
is(detail.deviceInfo.name, testDevice.name, 'expected device name');
is(detail.deviceInfo.type, testDevice.type, 'expected device type');
navigator.mozPresentationDeviceInfo.getAll()
.then(function(devices) {
is(devices.length, 0, 'expected 0 available device');
resolve();
});
});
gScript.sendAsyncMessage('trigger-device-remove');
});
}
function runTests() {
testSetup()
.then(testForceDiscovery)
.then(testDeviceAdd)
.then(testDeviceUpdate)
.then(testDeviceRemove)
.then(function() {
info('test finished, teardown');
gScript.sendAsyncMessage('teardown', '');
gScript.destroy();
SimpleTest.finish();
});
}
window.addEventListener('load', function() {
SpecialPowers.pushPrefEnv({
'set': [
['dom.presentation.enabled', true],
]
}, runTests);
});
</script>
</pre>
</body>
</html>

View file

@ -0,0 +1,35 @@
<!DOCTYPE HTML>
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for B2G Presentation Device Info API Permission</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1080474">Test for B2G Presentation Device Info API Permission</a>
<script type="application/javascript;version=1.8">
'use strict';
SimpleTest.waitForExplicitFinish();
function runTests() {
is(navigator.mozPresentationDeviceInfo, undefined, 'navigator.mozPresentationDeviceInfo is undefined');
SimpleTest.finish();
}
window.addEventListener('load', function() {
SpecialPowers.pushPrefEnv({
'set': [
['dom.presentation.enabled', true],
]
}, runTests);
});
</script>
</pre>
</body>
</html>

View file

@ -0,0 +1,81 @@
<!DOCTYPE HTML>
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test default request for B2G Presentation API at sender side</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1268758">Test allow-presentation sandboxing flag</a>
<iframe id="iframe" src="https://example.com/tests/dom/presentation/tests/mochitest/file_presentation_mixed_security_contexts.html"></iframe>
<script type="application/javascript;version=1.8">
"use strict";
var iframe = document.getElementById("iframe");
var readyToStart = false;
var testSetuped = false;
function setup() {
SpecialPowers.addPermission("presentation",
true, { url: "https://example.com/tests/dom/presentation/tests/mochitest/file_presentation_mixed_security_contexts.html",
originAttributes: {
appId: SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID,
inIsolatedMozBrowser: false }});
return new Promise(function(aResolve, aReject) {
addEventListener("message", function listener(event) {
var message = event.data;
if (/^OK /.exec(message)) {
ok(true, message.replace(/^OK /, ""));
} else if (/^KO /.exec(message)) {
ok(false, message.replace(/^KO /, ""));
} else if (/^INFO /.exec(message)) {
info(message.replace(/^INFO /, ""));
} else if (/^COMMAND /.exec(message)) {
var command = JSON.parse(message.replace(/^COMMAND /, ""));
if (command === "ready-to-start") {
readyToStart = true;
startTest();
}
} else if (/^DONE$/.exec(message)) {
window.removeEventListener('message', listener);
SimpleTest.finish();
}
}, false);
testSetuped = true;
aResolve();
});
}
iframe.onload = startTest();
function startTest() {
if (!(testSetuped && readyToStart)) {
return;
}
iframe.contentWindow.postMessage("start", "*");
}
function runTests() {
ok(navigator.presentation, "navigator.presentation should be available.");
setup().then(startTest);
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPermissions([
{type: "presentation-device-manage", allow: false, context: document},
], function() {
SpecialPowers.pushPrefEnv({ "set": [["dom.presentation.enabled", true],
["dom.presentation.controller.enabled", true],
["dom.presentation.session_transport.data_channel.enable", false]]},
runTests);
});
</script>
</body>
</html>

View file

@ -0,0 +1,77 @@
"use strict";
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL("PresentationSessionChromeScript.js"));
var receiverUrl = SimpleTest.getTestFileURL("file_presentation_receiver_auxiliary_navigation.html");
var obs = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
.getService(SpecialPowers.Ci.nsIObserverService);
function setup() {
return new Promise(function(aResolve, aReject) {
gScript.sendAsyncMessage("trigger-device-add");
var iframe = document.createElement("iframe");
iframe.setAttribute("mozbrowser", "true");
iframe.setAttribute("mozpresentation", receiverUrl);
var oop = location.pathname.indexOf('_inproc') == -1;
iframe.setAttribute("remote", oop);
iframe.setAttribute("src", receiverUrl);
// This event is triggered when the iframe calls "postMessage".
iframe.addEventListener("mozbrowsershowmodalprompt", function listener(aEvent) {
var message = aEvent.detail.message;
if (/^OK /.exec(message)) {
ok(true, "Message from iframe: " + message);
} else if (/^KO /.exec(message)) {
ok(false, "Message from iframe: " + message);
} else if (/^INFO /.exec(message)) {
info("Message from iframe: " + message);
} else if (/^COMMAND /.exec(message)) {
var command = JSON.parse(message.replace(/^COMMAND /, ""));
gScript.sendAsyncMessage(command.name, command.data);
} else if (/^DONE$/.exec(message)) {
ok(true, "Messaging from iframe complete.");
iframe.removeEventListener("mozbrowsershowmodalprompt", listener);
teardown();
}
}, false);
var promise = new Promise(function(aResolve, aReject) {
document.body.appendChild(iframe);
aResolve(iframe);
});
obs.notifyObservers(promise, "setup-request-promise", null);
aResolve();
});
}
function teardown() {
gScript.addMessageListener("teardown-complete", function teardownCompleteHandler() {
gScript.removeMessageListener("teardown-complete", teardownCompleteHandler);
gScript.destroy();
SimpleTest.finish();
});
gScript.sendAsyncMessage("teardown");
}
function runTests() {
setup().then();
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPermissions([
{type: "presentation-device-manage", allow: false, context: document},
{type: "browser", allow: true, context: document},
], function() {
SpecialPowers.pushPrefEnv({ "set": [["dom.presentation.enabled", true],
["dom.presentation.controller.enabled", true],
["dom.presentation.receiver.enabled", true],
["dom.mozBrowserFramesEnabled", true],
["network.disable.ipc.security", true],
["dom.presentation.session_transport.data_channel.enable", false]]},
runTests);
});

View file

@ -0,0 +1,18 @@
<!DOCTYPE HTML>
<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: -->
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for B2G Presentation API when sender and receiver at the same side</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1268810">
Test for receiver page with sandboxed auxiliary navigation browsing context flag.</a>
<script type="application/javascript;version=1.8" src="test_presentation_receiver_auxiliary_navigation.js">
</script>
</body>
</html>

View file

@ -0,0 +1,18 @@
<!DOCTYPE HTML>
<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: -->
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for B2G Presentation API when sender and receiver at the same side</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1268810">
Test for receiver page with sandboxed auxiliary navigation browsing context flag.</a>
<script type="application/javascript;version=1.8" src="test_presentation_receiver_auxiliary_navigation.js">
</script>
</body>
</html>

View file

@ -0,0 +1,379 @@
<!DOCTYPE HTML>
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for B2G Presentation API at sender side</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="PresentationSessionFrameScript.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1197690">Test for Presentation API at sender side</a>
<iframe id="iframe" src="file_presentation_reconnect.html"></iframe>
<script type="application/javascript;version=1.8">
'use strict';
var iframe = document.getElementById("iframe");
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
var frameScript = SpecialPowers.isMainProcess() ? gScript : contentScript;
var request;
var connection;
var commandHandler = {};
function testSetup() {
return new Promise(function(aResolve, aReject) {
addEventListener("message", function listener(event) {
var message = event.data;
if (/^OK /.exec(message)) {
ok(true, message.replace(/^OK /, ""));
} else if (/^KO /.exec(message)) {
ok(false, message.replace(/^KO /, ""));
} else if (/^INFO /.exec(message)) {
info(message.replace(/^INFO /, ""));
} else if (/^COMMAND /.exec(message)) {
var command = JSON.parse(message.replace(/^COMMAND /, ""));
if (command.name in commandHandler) {
commandHandler[command.name](command);
}
} else if (/^DONE$/.exec(message)) {
window.removeEventListener('message', listener);
SimpleTest.finish();
}
}, false);
request = new PresentationRequest("http://example.com/");
request.getAvailability().then(
function(aAvailability) {
is(aAvailability.value, false, "Sender: should have no available device after setup");
aAvailability.onchange = function() {
aAvailability.onchange = null;
ok(aAvailability.value, "Device should be available.");
aResolve();
}
gScript.sendAsyncMessage('trigger-device-add');
},
function(aError) {
ok(false, "Error occurred when getting availability: " + aError);
teardown();
aReject();
}
);
});
}
function testStartConnection() {
return new Promise(function(aResolve, aReject) {
gScript.addMessageListener('device-prompt', function devicePromptHandler() {
info("Device prompt is triggered.");
gScript.sendAsyncMessage('trigger-device-prompt-select');
});
gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
info("A control channel is established.");
gScript.sendAsyncMessage('trigger-control-channel-open');
});
gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler(aReason) {
info("The control channel is opened.");
});
gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
info("The control channel is closed. " + aReason);
});
frameScript.addMessageListener('check-navigator', function checknavigatorHandler(aSuccess) {
ok(aSuccess, "buildDataChannel get correct window object");
});
gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
ok(aIsValid, "A valid offer is sent out.");
gScript.sendAsyncMessage('trigger-incoming-answer');
});
gScript.addMessageListener('answer-received', function answerReceivedHandler() {
info("An answer is received.");
});
frameScript.addMessageListener('data-transport-initialized', function dataTransportInitializedHandler() {
info("Data transport channel is initialized.");
});
frameScript.addMessageListener('data-transport-notification-enabled', function dataTransportNotificationEnabledHandler() {
info("Data notification is enabled for data transport channel.");
});
var connectionFromEvent;
request.onconnectionavailable = function(aEvent) {
request.onconnectionavailable = null;
connectionFromEvent = aEvent.connection;
ok(connectionFromEvent, "|connectionavailable| event is fired with a connection.");
if (connection) {
is(connection, connectionFromEvent, "The connection from promise and the one from |connectionavailable| event should be the same.");
}
};
request.start().then(
function(aConnection) {
connection = aConnection;
ok(connection, "Connection should be available.");
ok(connection.id, "Connection ID should be set.");
is(connection.state, "connecting", "The initial state should be connecting.");
if (connectionFromEvent) {
is(connection, connectionFromEvent, "The connection from promise and the one from |connectionavailable| event should be the same.");
}
connection.onconnect = function() {
connection.onconnect = null;
is(connection.state, "connected", "Connection should be connected.");
aResolve();
};
},
function(aError) {
ok(false, "Error occurred when establishing a connection: " + aError);
teardown();
aReject();
}
);
});
}
function testCloseConnection() {
return new Promise(function(aResolve, aReject) {
frameScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
frameScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
info("The data transport is closed. " + aReason);
});
connection.onclose = function() {
connection.onclose = null;
is(connection.state, "closed", "Connection should be closed.");
aResolve();
};
connection.close();
});
}
function testReconnectAConnectedConnection() {
return new Promise(function(aResolve, aReject) {
info('--- testReconnectAConnectedConnection ---');
ok(connection.state, "connected", "Make sure the state is connected.");
request.reconnect(connection.id).then(
function(aConnection) {
ok(aConnection, "Connection should be available.");
is(aConnection.id, connection.id, "Connection ID should be the same.");
is(aConnection.state, "connected", "The state should be connected.");
is(aConnection, connection, "The connection should be the same.");
aResolve();
},
function(aError) {
ok(false, "Error occurred when establishing a connection: " + aError);
teardown();
aReject();
}
);
});
}
function testReconnectInvalidID() {
return new Promise(function(aResolve, aReject) {
info('--- testReconnectInvalidID ---');
request.reconnect("dummyID").then(
function(aConnection) {
ok(false, "Unexpected success.");
teardown();
aReject();
},
function(aError) {
is(aError.name, "NotFoundError", "Should get NotFoundError.");
aResolve();
}
);
});
}
function testReconnectInvalidURL() {
return new Promise(function(aResolve, aReject) {
info('--- testReconnectInvalidURL ---');
var request1 = new PresentationRequest("http://invalidURL");
request1.reconnect(connection.id).then(
function(aConnection) {
ok(false, "Unexpected success.");
teardown();
aReject();
},
function(aError) {
is(aError.name, "NotFoundError", "Should get NotFoundError.");
aResolve();
}
);
});
}
function testReconnectIframeConnectedConnection() {
info('--- testReconnectIframeConnectedConnection ---');
gScript.sendAsyncMessage('save-control-channel-listener');
return Promise.all([
new Promise(function(aResolve, aReject) {
commandHandler["connection-connected"] = function(command) {
gScript.addMessageListener('start-reconnect', function startReconnectHandler(url) {
gScript.removeMessageListener('start-reconnect', startReconnectHandler);
gScript.sendAsyncMessage('trigger-reconnected-acked', url);
});
var request1 = new PresentationRequest("http://example1.com");
request1.reconnect(command.id).then(
function(aConnection) {
is(aConnection.state, "connecting", "The state should be connecting.");
aConnection.onclose = function() {
delete commandHandler["connection-connected"];
gScript.sendAsyncMessage('restore-control-channel-listener');
aResolve();
};
aConnection.close();
},
function(aError) {
ok(false, "Error occurred when establishing a connection: " + aError);
teardown();
aReject();
}
);
};
iframe.contentWindow.postMessage("startConnection", "*");
}),
new Promise(function(aResolve, aReject) {
commandHandler["notify-connection-closed"] = function(command) {
delete commandHandler["notify-connection-closed"];
aResolve();
};
}),
]);
}
function testReconnectIframeClosedConnection() {
return new Promise(function(aResolve, aReject) {
info('--- testReconnectIframeClosedConnection ---');
gScript.sendAsyncMessage('save-control-channel-listener');
commandHandler["connection-closed"] = function(command) {
gScript.addMessageListener('start-reconnect', function startReconnectHandler(url) {
gScript.removeMessageListener('start-reconnect', startReconnectHandler);
gScript.sendAsyncMessage('trigger-reconnected-acked', url);
});
var request1 = new PresentationRequest("http://example1.com");
request1.reconnect(command.id).then(
function(aConnection) {
aConnection.onconnect = function() {
aConnection.onconnect = null;
is(aConnection.state, "connected", "The connection should be connected.");
aConnection.onclose = function() {
aConnection.onclose = null;
ok(true, "The connection is closed.");
delete commandHandler["connection-closed"];
aResolve();
};
aConnection.close();
gScript.sendAsyncMessage('restore-control-channel-listener');
};
},
function(aError) {
ok(false, "Error occurred when establishing a connection: " + aError);
teardown();
aReject();
}
);
};
iframe.contentWindow.postMessage("closeConnection", "*");
});
}
function testReconnect() {
return new Promise(function(aResolve, aReject) {
info('--- testReconnect ---');
gScript.addMessageListener('start-reconnect', function startReconnectHandler(url) {
gScript.removeMessageListener('start-reconnect', startReconnectHandler);
is(url, "http://example.com/", "URLs should be the same.");
gScript.sendAsyncMessage('trigger-reconnected-acked', url);
});
request.reconnect(connection.id).then(
function(aConnection) {
ok(aConnection, "Connection should be available.");
ok(aConnection.id, "Connection ID should be set.");
is(aConnection.state, "connecting", "The initial state should be connecting.");
is(aConnection, connection, "The reconnected connection should be the same.");
aConnection.onconnect = function() {
aConnection.onconnect = null;
is(aConnection.state, "connected", "Connection should be connected.");
const incomingMessage = "test incoming message";
aConnection.addEventListener('message', function messageHandler(aEvent) {
aConnection.removeEventListener('message', messageHandler);
is(aEvent.data, incomingMessage, "An incoming message should be received.");
aResolve();
});
frameScript.sendAsyncMessage('trigger-incoming-message', incomingMessage);
};
},
function(aError) {
ok(false, "Error occurred when establishing a connection: " + aError);
teardown();
aReject();
}
);
});
}
function teardown() {
gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
gScript.destroy();
info('teardown-complete');
SimpleTest.finish();
});
gScript.sendAsyncMessage('teardown');
}
function runTests() {
ok(window.PresentationRequest, "PresentationRequest should be available.");
testSetup().
then(testStartConnection).
then(testReconnectInvalidID).
then(testReconnectInvalidURL).
then(testReconnectAConnectedConnection).
then(testReconnectIframeConnectedConnection).
then(testReconnectIframeClosedConnection).
then(testCloseConnection).
then(testReconnect).
then(testCloseConnection).
then(teardown);
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPermissions([
{type: 'presentation-device-manage', allow: false, context: document},
], function() {
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
["dom.presentation.controller.enabled", true],
["dom.presentation.receiver.enabled", true],
["dom.presentation.session_transport.data_channel.enable", true]]},
runTests);
});
</script>
</body>
</html>

View file

@ -0,0 +1,75 @@
<!DOCTYPE HTML>
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test default request for B2G Presentation API at sender side</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1268758">Test allow-presentation sandboxing flag</a>
<iframe sandbox="allow-popups allow-scripts allow-same-origin" id="iframe" src="file_presentation_sandboxed_presentation.html"></iframe>
<script type="application/javascript;version=1.8">
"use strict";
var iframe = document.getElementById("iframe");
var readyToStart = false;
var testSetuped = false;
function setup() {
return new Promise(function(aResolve, aReject) {
addEventListener("message", function listener(event) {
var message = event.data;
if (/^OK /.exec(message)) {
ok(true, message.replace(/^OK /, ""));
} else if (/^KO /.exec(message)) {
ok(false, message.replace(/^KO /, ""));
} else if (/^INFO /.exec(message)) {
info(message.replace(/^INFO /, ""));
} else if (/^COMMAND /.exec(message)) {
var command = JSON.parse(message.replace(/^COMMAND /, ""));
if (command === "ready-to-start") {
readyToStart = true;
startTest();
}
} else if (/^DONE$/.exec(message)) {
window.removeEventListener('message', listener);
SimpleTest.finish();
}
}, false);
testSetuped = true;
aResolve();
});
}
iframe.onload = startTest();
function startTest() {
if (!(testSetuped && readyToStart)) {
return;
}
iframe.contentWindow.postMessage("start", "*");
}
function runTests() {
ok(navigator.presentation, "navigator.presentation should be available.");
setup().then(startTest);
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPermissions([
{type: "presentation-device-manage", allow: false, context: document},
], function() {
SpecialPowers.pushPrefEnv({ "set": [["dom.presentation.enabled", true],
["dom.presentation.controller.enabled", true],
["dom.presentation.receiver.enabled", false],
["dom.presentation.session_transport.data_channel.enable", false]]},
runTests);
});
</script>
</body>
</html>

View file

@ -0,0 +1,187 @@
<!DOCTYPE HTML>
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test onTerminateRequest at sender side</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1276378">Test onTerminateRequest at sender side</a>
<script type="application/javascript;version=1.8">
'use strict';
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
var request;
var connection;
function testSetup() {
return new Promise(function(aResolve, aReject) {
request = new PresentationRequest("http://example.com");
request.getAvailability().then(
function(aAvailability) {
is(aAvailability.value, false, "Sender: should have no available device after setup");
aAvailability.onchange = function() {
aAvailability.onchange = null;
ok(aAvailability.value, "Device should be available.");
aResolve();
}
gScript.sendAsyncMessage('trigger-device-add');
},
function(aError) {
ok(false, "Error occurred when getting availability: " + aError);
teardown();
aReject();
}
);
});
}
function testStartConnection() {
return new Promise(function(aResolve, aReject) {
gScript.addMessageListener('device-prompt', function devicePromptHandler() {
gScript.removeMessageListener('device-prompt', devicePromptHandler);
info("Device prompt is triggered.");
gScript.sendAsyncMessage('trigger-device-prompt-select');
});
gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
info("A control channel is established.");
gScript.sendAsyncMessage('trigger-control-channel-open');
});
gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler(aReason) {
gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
info("The control channel is opened.");
});
gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
info("The control channel is closed. " + aReason);
});
gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
gScript.removeMessageListener('offer-sent', offerSentHandler);
ok(aIsValid, "A valid offer is sent out.");
gScript.sendAsyncMessage('trigger-incoming-transport');
});
gScript.addMessageListener('answer-received', function answerReceivedHandler() {
gScript.removeMessageListener('answer-received', answerReceivedHandler);
info("An answer is received.");
});
gScript.addMessageListener('data-transport-initialized', function dataTransportInitializedHandler() {
gScript.removeMessageListener('data-transport-initialized', dataTransportInitializedHandler);
info("Data transport channel is initialized.");
gScript.sendAsyncMessage('trigger-incoming-answer');
});
gScript.addMessageListener('data-transport-notification-enabled', function dataTransportNotificationEnabledHandler() {
gScript.removeMessageListener('data-transport-notification-enabled', dataTransportNotificationEnabledHandler);
info("Data notification is enabled for data transport channel.");
});
var connectionFromEvent;
request.onconnectionavailable = function(aEvent) {
request.onconnectionavailable = null;
connectionFromEvent = aEvent.connection;
ok(connectionFromEvent, "|connectionavailable| event is fired with a connection.");
if (connection) {
is(connection, connectionFromEvent, "The connection from promise and the one from |connectionavailable| event should be the same.");
}
};
request.start().then(
function(aConnection) {
connection = aConnection;
ok(connection, "Connection should be available.");
ok(connection.id, "Connection ID should be set.");
is(connection.state, "connecting", "The initial state should be connecting.");
if (connectionFromEvent) {
is(connection, connectionFromEvent, "The connection from promise and the one from |connectionavailable| event should be the same.");
}
connection.onconnect = function() {
connection.onconnect = null;
is(connection.state, "connected", "Connection should be connected.");
aResolve();
};
},
function(aError) {
ok(false, "Error occurred when establishing a connection: " + aError);
teardown();
aReject();
}
);
});
}
function testOnTerminateRequest() {
return new Promise(function(aResolve, aReject) {
gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler(aReason) {
gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
info("The control channel is opened.");
});
gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
info("The control channel is closed. " + aReason);
});
gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
info("The data transport is closed. " + aReason);
});
connection.onterminate = function() {
connection.onterminate = null;
is(connection.state, "terminated", "Connection should be closed.");
aResolve();
};
gScript.sendAsyncMessage('trigger-incoming-terminate-request');
gScript.sendAsyncMessage('trigger-control-channel-open');
});
}
function teardown() {
gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
gScript.destroy();
SimpleTest.finish();
});
gScript.sendAsyncMessage('teardown');
}
function runTests() {
ok(window.PresentationRequest, "PresentationRequest should be available.");
testSetup().
then(testStartConnection).
then(testOnTerminateRequest).
then(teardown);
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPermissions([
{type: 'presentation-device-manage', allow: false, context: document},
], function() {
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
["dom.presentation.controller.enabled", true],
["dom.presentation.receiver.enabled", false],
["dom.presentation.session_transport.data_channel.enable", false]]},
runTests);
});
</script>
</body>
</html>

View file

@ -0,0 +1,173 @@
<!DOCTYPE HTML>
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test startWithDevice for B2G Presentation API at sender side</title>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1239242">Test startWithDevice for B2G Presentation API at sender side</a>
<script type="application/javascript;version=1.8">
'use strict';
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
var request;
var connection;
function testSetup() {
return new Promise(function(aResolve, aReject) {
request = new PresentationRequest("https://example.com");
request.getAvailability().then(
function(aAvailability) {
is(aAvailability.value, false, "Sender: should have no available device after setup");
aAvailability.onchange = function() {
aAvailability.onchange = null;
ok(aAvailability.value, "Device should be available.");
aResolve();
}
gScript.sendAsyncMessage('trigger-device-add');
},
function(aError) {
ok(false, "Error occurred when getting availability: " + aError);
teardown();
aReject();
}
);
});
}
function testStartConnectionWithDevice() {
return new Promise(function(aResolve, aReject) {
gScript.addMessageListener('device-prompt', function devicePromptHandler() {
gScript.removeMessageListener('device-prompt', devicePromptHandler);
ok(false, "Device prompt should not be triggered.");
teardown();
aReject();
});
gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
info("A control channel is established.");
gScript.sendAsyncMessage('trigger-control-channel-open');
});
gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler(aReason) {
gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
info("The control channel is opened.");
});
gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
info("The control channel is closed. " + aReason);
});
gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
gScript.removeMessageListener('offer-sent', offerSentHandler);
ok(aIsValid, "A valid offer is sent out.");
gScript.sendAsyncMessage('trigger-incoming-transport');
});
gScript.addMessageListener('answer-received', function answerReceivedHandler() {
gScript.removeMessageListener('answer-received', answerReceivedHandler);
info("An answer is received.");
});
gScript.addMessageListener('data-transport-initialized', function dataTransportInitializedHandler() {
gScript.removeMessageListener('data-transport-initialized', dataTransportInitializedHandler);
info("Data transport channel is initialized.");
gScript.sendAsyncMessage('trigger-incoming-answer');
});
gScript.addMessageListener('data-transport-notification-enabled', function dataTransportNotificationEnabledHandler() {
gScript.removeMessageListener('data-transport-notification-enabled', dataTransportNotificationEnabledHandler);
info("Data notification is enabled for data transport channel.");
});
var connectionFromEvent;
request.onconnectionavailable = function(aEvent) {
request.onconnectionavailable = null;
connectionFromEvent = aEvent.connection;
ok(connectionFromEvent, "|connectionavailable| event is fired with a connection.");
if (connection) {
is(connection, connectionFromEvent, "The connection from promise and the one from |connectionavailable| event should be the same.");
}
};
request.startWithDevice('id').then(
function(aConnection) {
connection = aConnection;
ok(connection, "Connection should be available.");
ok(connection.id, "Connection ID should be set.");
is(connection.state, "connecting", "The initial state should be connecting.");
if (connectionFromEvent) {
is(connection, connectionFromEvent, "The connection from promise and the one from |connectionavailable| event should be the same.");
}
connection.onconnect = function() {
connection.onconnect = null;
is(connection.state, "connected", "Connection should be connected.");
aResolve();
};
},
function(aError) {
ok(false, "Error occurred when establishing a connection: " + aError);
teardown();
aReject();
}
);
});
}
function testStartConnectionWithDeviceNotFoundError() {
return new Promise(function(aResolve, aReject) {
request.startWithDevice('').then(
function(aConnection) {
ok(false, "Should not establish connection to an unknown device");
teardown();
aReject();
},
function(aError) {
is(aError.name, 'NotFoundError', "Expect NotFoundError occurred when establishing a connection");
aResolve();
}
);
});
}
function teardown() {
gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
gScript.destroy();
SimpleTest.finish();
});
gScript.sendAsyncMessage('teardown');
}
function runTests() {
ok(window.PresentationRequest, "PresentationRequest should be available.");
testSetup().
then(testStartConnectionWithDevice).
then(testStartConnectionWithDeviceNotFoundError).
then(teardown);
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
["dom.presentation.session_transport.data_channel.enable", false],
["dom.presentation.controller.enabled", true],
["dom.presentation.test.enabled", true],
["dom.presentation.test.stage", 0]]},
runTests);
</script>
</body>
</html>

View file

@ -0,0 +1,137 @@
<!DOCTYPE HTML>
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for B2G PresentationConnection API at receiver side</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1069230">Test for B2G PresentationConnection API at receiver side</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
<script type="application/javascript">
'use strict';
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
var receiverUrl = SimpleTest.getTestFileURL('file_presentation_receiver.html');
var obs = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
.getService(SpecialPowers.Ci.nsIObserverService);
function setup() {
return new Promise(function(aResolve, aReject) {
gScript.sendAsyncMessage('trigger-device-add');
var iframe = document.createElement('iframe');
iframe.setAttribute('mozbrowser', 'true');
iframe.setAttribute('mozpresentation', receiverUrl);
iframe.setAttribute('src', receiverUrl);
// This event is triggered when the iframe calls "postMessage".
iframe.addEventListener('mozbrowsershowmodalprompt', function listener(aEvent) {
var message = aEvent.detail.message;
if (/^OK /.exec(message)) {
ok(true, "Message from iframe: " + message);
} else if (/^KO /.exec(message)) {
ok(false, "Message from iframe: " + message);
} else if (/^INFO /.exec(message)) {
info("Message from iframe: " + message);
} else if (/^COMMAND /.exec(message)) {
var command = JSON.parse(message.replace(/^COMMAND /, ''));
gScript.sendAsyncMessage(command.name, command.data);
} else if (/^DONE$/.exec(message)) {
ok(true, "Messaging from iframe complete.");
iframe.removeEventListener('mozbrowsershowmodalprompt', listener);
teardown();
}
}, false);
var promise = new Promise(function(aResolve, aReject) {
document.body.appendChild(iframe);
aResolve(iframe);
});
obs.notifyObservers(promise, 'setup-request-promise', null);
gScript.addMessageListener('offer-received', function offerReceivedHandler() {
gScript.removeMessageListener('offer-received', offerReceivedHandler);
info("An offer is received.");
});
gScript.addMessageListener('answer-sent', function answerSentHandler(aIsValid) {
gScript.removeMessageListener('answer-sent', answerSentHandler);
ok(aIsValid, "A valid answer is sent.");
});
gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
is(aReason, SpecialPowers.Cr.NS_OK, "The control channel is closed normally.");
});
gScript.addMessageListener('data-transport-notification-enabled', function dataTransportNotificationEnabledHandler() {
gScript.removeMessageListener('data-transport-notification-enabled', dataTransportNotificationEnabledHandler);
info("Data notification is enabled for data transport channel.");
});
gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
is(aReason, SpecialPowers.Cr.NS_OK, "The data transport should be closed normally.");
});
aResolve();
});
}
function testIncomingSessionRequest() {
return new Promise(function(aResolve, aReject) {
gScript.addMessageListener('receiver-launching', function launchReceiverHandler(aSessionId) {
gScript.removeMessageListener('receiver-launching', launchReceiverHandler);
info("Trying to launch receiver page.");
ok(navigator.presentation, "navigator.presentation should be available in in-process pages.");
is(navigator.presentation.receiver, null, "Non-receiving in-process pages shouldn't get a presentation receiver instance.");
aResolve();
});
gScript.sendAsyncMessage('trigger-incoming-session-request', receiverUrl);
});
}
function teardown() {
gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
gScript.destroy();
SimpleTest.finish();
});
gScript.sendAsyncMessage('teardown');
}
function runTests() {
setup().
then(testIncomingSessionRequest);
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPermissions([
{type: 'presentation-device-manage', allow: false, context: document},
{type: 'browser', allow: true, context: document},
], function() {
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
["dom.presentation.controller.enabled", false],
["dom.presentation.receiver.enabled", true],
["dom.mozBrowserFramesEnabled", true],
["network.disable.ipc.security", true],
["dom.presentation.session_transport.data_channel.enable", false]]},
runTests);
});
</script>
</body>
</html>

View file

@ -0,0 +1,110 @@
<!DOCTYPE HTML>
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for connection establishing errors of B2G Presentation API at receiver side</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1069230">Test for connection establishing errors of B2G Presentation API at receiver side</a>
<script type="application/javascript;version=1.8">
'use strict';
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
var receiverUrl = SimpleTest.getTestFileURL('file_presentation_receiver_establish_connection_error.html');
var obs = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
.getService(SpecialPowers.Ci.nsIObserverService);
function setup() {
return new Promise(function(aResolve, aReject) {
gScript.sendAsyncMessage('trigger-device-add');
var iframe = document.createElement('iframe');
iframe.setAttribute('src', receiverUrl);
iframe.setAttribute("mozbrowser", "true");
iframe.setAttribute("mozpresentation", receiverUrl);
// This event is triggered when the iframe calls "alert".
iframe.addEventListener("mozbrowsershowmodalprompt", function receiverListener(evt) {
var message = evt.detail.message;
if (/^OK /.exec(message)) {
ok(true, message.replace(/^OK /, ""));
} else if (/^KO /.exec(message)) {
ok(false, message.replace(/^KO /, ""));
} else if (/^INFO /.exec(message)) {
info(message.replace(/^INFO /, ""));
} else if (/^COMMAND /.exec(message)) {
var command = JSON.parse(message.replace(/^COMMAND /, ""));
gScript.sendAsyncMessage(command.name, command.data);
} else if (/^DONE$/.exec(message)) {
iframe.removeEventListener("mozbrowsershowmodalprompt",
receiverListener);
teardown();
}
}, false);
var promise = new Promise(function(aResolve, aReject) {
document.body.appendChild(iframe);
aResolve(iframe);
});
obs.notifyObservers(promise, 'setup-request-promise', null);
gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
is(aReason, 0x80004004 /* NS_ERROR_ABORT */, "The control channel is closed abnormally.");
});
aResolve();
});
}
function testIncomingSessionRequest() {
return new Promise(function(aResolve, aReject) {
gScript.addMessageListener('receiver-launching', function launchReceiverHandler(aSessionId) {
gScript.removeMessageListener('receiver-launching', launchReceiverHandler);
info("Trying to launch receiver page.");
aResolve();
});
gScript.sendAsyncMessage('trigger-incoming-session-request', receiverUrl);
});
}
function teardown() {
gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
gScript.destroy();
SimpleTest.finish();
});
gScript.sendAsyncMessage('teardown');
}
function runTests() {
setup().
then(testIncomingSessionRequest);
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPermissions([
{type: 'presentation-device-manage', allow: false, context: document},
{type: "browser", allow: true, context: document},
], function() {
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
["dom.presentation.receiver.enabled", true],
["dom.presentation.session_transport.data_channel.enable", false],
["dom.mozBrowserFramesEnabled", true],
["network.disable.ipc.security", true]]},
runTests);
});
</script>
</body>
</html>

View file

@ -0,0 +1,81 @@
<!DOCTYPE HTML>
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for connection establishing timeout of B2G Presentation API at receiver side</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1069230">Test for connection establishing timeout of B2G Presentation API at receiver side</a>
<script type="application/javascript;version=1.8">
'use strict';
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
var obs = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
.getService(SpecialPowers.Ci.nsIObserverService);
function setup() {
return new Promise(function(aResolve, aReject) {
gScript.sendAsyncMessage('trigger-device-add');
var promise = new Promise(function(aResolve, aReject) {
// In order to trigger timeout, do not resolve the promise.
});
obs.notifyObservers(promise, 'setup-request-promise', null);
aResolve();
});
}
function testIncomingSessionRequestReceiverLaunchTimeout() {
return new Promise(function(aResolve, aReject) {
gScript.addMessageListener('receiver-launching', function launchReceiverHandler(aSessionId) {
gScript.removeMessageListener('receiver-launching', launchReceiverHandler);
info("Trying to launch receiver page.");
});
gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
is(aReason, 0x80530017 /* NS_ERROR_DOM_TIMEOUT_ERR */, "The control channel is closed due to timeout.");
aResolve();
});
gScript.sendAsyncMessage('trigger-incoming-session-request', 'http://example.com');
});
}
function teardown() {
gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
gScript.destroy();
SimpleTest.finish();
});
gScript.sendAsyncMessage('teardown');
}
function runTests() {
setup().
then(testIncomingSessionRequestReceiverLaunchTimeout).
then(teardown);
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPermissions([
{type: 'presentation-device-manage', allow: false, context: document},
], function() {
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
["dom.presentation.receiver.enabled", true],
["dom.presentation.session_transport.data_channel.enable", false],
["presentation.receiver.loading.timeout", 10]]},
runTests);
});
</script>
</body>
</html>

View file

@ -0,0 +1,88 @@
'use strict';
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
var receiverUrl = SimpleTest.getTestFileURL('file_presentation_unknown_content_type.test');
var obs = SpecialPowers.Cc['@mozilla.org/observer-service;1']
.getService(SpecialPowers.Ci.nsIObserverService);
var receiverIframe;
function setup() {
return new Promise(function(aResolve, aReject) {
gScript.sendAsyncMessage('trigger-device-add');
receiverIframe = document.createElement('iframe');
receiverIframe.setAttribute('mozbrowser', 'true');
receiverIframe.setAttribute('mozpresentation', receiverUrl);
receiverIframe.setAttribute('src', receiverUrl);
var oop = location.pathname.indexOf('_inproc') == -1;
receiverIframe.setAttribute("remote", oop);
var promise = new Promise(function(aResolve, aReject) {
document.body.appendChild(receiverIframe);
aResolve(receiverIframe);
});
obs.notifyObservers(promise, 'setup-request-promise', null);
aResolve();
});
}
function testIncomingSessionRequestReceiverLaunchUnknownContentType() {
let promise = Promise.all([
new Promise(function(aResolve, aReject) {
gScript.addMessageListener('receiver-launching', function launchReceiverHandler(aSessionId) {
gScript.removeMessageListener('receiver-launching', launchReceiverHandler);
info('Trying to launch receiver page.');
receiverIframe.addEventListener('mozbrowserclose', function() {
ok(true, 'observe receiver window closed');
aResolve();
});
});
}),
new Promise(function(aResolve, aReject) {
gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
is(aReason, 0x80530020 /* NS_ERROR_DOM_OPERATION_ERR */, 'The control channel is closed due to load failure.');
aResolve();
});
})
]);
gScript.sendAsyncMessage('trigger-incoming-session-request', receiverUrl);
return promise;
}
function teardown() {
gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
gScript.destroy();
SimpleTest.finish();
});
gScript.sendAsyncMessage('teardown');
}
function runTests() {
setup().
then(testIncomingSessionRequestReceiverLaunchUnknownContentType).
then(teardown);
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPermissions([
{type: 'presentation-device-manage', allow: false, context: document},
{type: 'browser', allow: true, context: document},
], function() {
SpecialPowers.pushPrefEnv({ 'set': [['dom.presentation.enabled', true],
["dom.presentation.controller.enabled", true],
["dom.presentation.receiver.enabled", true],
['dom.presentation.session_transport.data_channel.enable', false],
['dom.mozBrowserFramesEnabled', true],
["network.disable.ipc.security", true],
['dom.ipc.tabs.disabled', false]]},
runTests);
});

View file

@ -0,0 +1,16 @@
<!DOCTYPE HTML>
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for unknown content type of B2G Presentation API at receiver side</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1287717">Test for unknown content type of B2G Presentation API at receiver side</a>
<script type="application/javascript;version=1.8" src="test_presentation_tcp_receiver_establish_connection_unknown_content_type.js">
</script>
</body>
</html>

View file

@ -0,0 +1,16 @@
<!DOCTYPE HTML>
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for unknown content type of B2G Presentation API at receiver side (OOP)</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1287717">Test for unknown content type of B2G Presentation API at receiver side (OOP)</a>
<script type="application/javascript;version=1.8" src="test_presentation_tcp_receiver_establish_connection_unknown_content_type.js">
</script>
</body>
</html>

View file

@ -0,0 +1,178 @@
<!DOCTYPE HTML>
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for B2G PresentationConnection API at receiver side (OOP)</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1069230">Test B2G PresentationConnection API at receiver side (OOP)</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
<script type="application/javascript">
'use strict';
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
var receiverUrl = SimpleTest.getTestFileURL('file_presentation_receiver.html');
var nonReceiverUrl = SimpleTest.getTestFileURL('file_presentation_non_receiver.html');
var isReceiverFinished = false;
var isNonReceiverFinished = false;
var obs = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
.getService(SpecialPowers.Ci.nsIObserverService);
function setup() {
return new Promise(function(aResolve, aReject) {
gScript.sendAsyncMessage('trigger-device-add');
// Create a receiver OOP iframe.
var receiverIframe = document.createElement('iframe');
receiverIframe.setAttribute('remote', 'true');
receiverIframe.setAttribute('mozbrowser', 'true');
receiverIframe.setAttribute('mozpresentation', receiverUrl);
receiverIframe.setAttribute('src', receiverUrl);
// This event is triggered when the iframe calls "alert".
receiverIframe.addEventListener('mozbrowsershowmodalprompt', function receiverListener(aEvent) {
var message = aEvent.detail.message;
if (/^OK /.exec(message)) {
ok(true, "Message from iframe: " + message);
} else if (/^KO /.exec(message)) {
ok(false, "Message from iframe: " + message);
} else if (/^INFO /.exec(message)) {
info("Message from iframe: " + message);
} else if (/^COMMAND /.exec(message)) {
var command = JSON.parse(message.replace(/^COMMAND /, ''));
gScript.sendAsyncMessage(command.name, command.data);
} else if (/^DONE$/.exec(message)) {
ok(true, "Messaging from iframe complete.");
receiverIframe.removeEventListener('mozbrowsershowmodalprompt', receiverListener);
isReceiverFinished = true;
if (isNonReceiverFinished) {
teardown();
}
}
}, false);
var promise = new Promise(function(aResolve, aReject) {
document.body.appendChild(receiverIframe);
aResolve(receiverIframe);
});
obs.notifyObservers(promise, 'setup-request-promise', null);
// Create a non-receiver OOP iframe.
var nonReceiverIframe = document.createElement('iframe');
nonReceiverIframe.setAttribute('remote', 'true');
nonReceiverIframe.setAttribute('mozbrowser', 'true');
nonReceiverIframe.setAttribute('src', nonReceiverUrl);
// This event is triggered when the iframe calls "alert".
nonReceiverIframe.addEventListener('mozbrowsershowmodalprompt', function nonReceiverListener(aEvent) {
var message = aEvent.detail.message;
if (/^OK /.exec(message)) {
ok(true, "Message from iframe: " + message);
} else if (/^KO /.exec(message)) {
ok(false, "Message from iframe: " + message);
} else if (/^INFO /.exec(message)) {
info("Message from iframe: " + message);
} else if (/^COMMAND /.exec(message)) {
var command = JSON.parse(message.replace(/^COMMAND /, ''));
gScript.sendAsyncMessage(command.name, command.data);
} else if (/^DONE$/.exec(message)) {
ok(true, "Messaging from iframe complete.");
nonReceiverIframe.removeEventListener('mozbrowsershowmodalprompt', nonReceiverListener);
isNonReceiverFinished = true;
if (isReceiverFinished) {
teardown();
}
}
}, false);
document.body.appendChild(nonReceiverIframe);
gScript.addMessageListener('offer-received', function offerReceivedHandler() {
gScript.removeMessageListener('offer-received', offerReceivedHandler);
info("An offer is received.");
});
gScript.addMessageListener('answer-sent', function answerSentHandler(aIsValid) {
gScript.removeMessageListener('answer-sent', answerSentHandler);
ok(aIsValid, "A valid answer is sent.");
});
gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
is(aReason, SpecialPowers.Cr.NS_OK, "The control channel is closed normally.");
});
gScript.addMessageListener('data-transport-notification-enabled', function dataTransportNotificationEnabledHandler() {
gScript.removeMessageListener('data-transport-notification-enabled', dataTransportNotificationEnabledHandler);
info("Data notification is enabled for data transport channel.");
});
gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
is(aReason, SpecialPowers.Cr.NS_OK, "The data transport should be closed normally.");
});
aResolve();
});
}
function testIncomingSessionRequest() {
return new Promise(function(aResolve, aReject) {
gScript.addMessageListener('receiver-launching', function launchReceiverHandler(aSessionId) {
gScript.removeMessageListener('receiver-launching', launchReceiverHandler);
info("Trying to launch receiver page.");
aResolve();
});
gScript.sendAsyncMessage('trigger-incoming-session-request', receiverUrl);
});
}
function teardown() {
gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
gScript.destroy();
SimpleTest.finish();
});
gScript.sendAsyncMessage('teardown');
}
function runTests() {
setup().
then(testIncomingSessionRequest);
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPermissions([
{type: 'presentation-device-manage', allow: false, context: document},
{type: 'browser', allow: true, context: document},
], function() {
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
["dom.presentation.controller.enabled", false],
["dom.presentation.receiver.enabled", true],
["dom.presentation.session_transport.data_channel.enable", false],
["dom.mozBrowserFramesEnabled", true],
["network.disable.ipc.security", true],
["dom.ipc.browser_frames.oop_by_default", true]]},
runTests);
});
</script>
</body>
</html>

View file

@ -0,0 +1,260 @@
<!DOCTYPE HTML>
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for B2G Presentation API at sender side</title>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1069230">Test for B2G Presentation API at sender side</a>
<script type="application/javascript;version=1.8">
'use strict';
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
var request;
var connection;
function testSetup() {
return new Promise(function(aResolve, aReject) {
request = new PresentationRequest("https://example.com");
request.getAvailability().then(
function(aAvailability) {
is(aAvailability.value, false, "Sender: should have no available device after setup");
aAvailability.onchange = function() {
aAvailability.onchange = null;
ok(aAvailability.value, "Device should be available.");
aResolve();
}
gScript.sendAsyncMessage('trigger-device-add');
},
function(aError) {
ok(false, "Error occurred when getting availability: " + aError);
teardown();
aReject();
}
);
});
}
function testStartConnection() {
return new Promise(function(aResolve, aReject) {
gScript.addMessageListener('device-prompt', function devicePromptHandler() {
gScript.removeMessageListener('device-prompt', devicePromptHandler);
info("Device prompt is triggered.");
gScript.sendAsyncMessage('trigger-device-prompt-select');
});
gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
info("A control channel is established.");
gScript.sendAsyncMessage('trigger-control-channel-open');
});
gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler(aReason) {
gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
info("The control channel is opened.");
});
gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
info("The control channel is closed. " + aReason);
});
gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
gScript.removeMessageListener('offer-sent', offerSentHandler);
ok(aIsValid, "A valid offer is sent out.");
gScript.sendAsyncMessage('trigger-incoming-transport');
});
gScript.addMessageListener('answer-received', function answerReceivedHandler() {
gScript.removeMessageListener('answer-received', answerReceivedHandler);
info("An answer is received.");
});
gScript.addMessageListener('data-transport-initialized', function dataTransportInitializedHandler() {
gScript.removeMessageListener('data-transport-initialized', dataTransportInitializedHandler);
info("Data transport channel is initialized.");
gScript.sendAsyncMessage('trigger-incoming-answer');
});
gScript.addMessageListener('data-transport-notification-enabled', function dataTransportNotificationEnabledHandler() {
gScript.removeMessageListener('data-transport-notification-enabled', dataTransportNotificationEnabledHandler);
info("Data notification is enabled for data transport channel.");
});
var connectionFromEvent;
request.onconnectionavailable = function(aEvent) {
request.onconnectionavailable = null;
connectionFromEvent = aEvent.connection;
ok(connectionFromEvent, "|connectionavailable| event is fired with a connection.");
if (connection) {
is(connection, connectionFromEvent, "The connection from promise and the one from |connectionavailable| event should be the same.");
}
};
request.start().then(
function(aConnection) {
connection = aConnection;
ok(connection, "Connection should be available.");
ok(connection.id, "Connection ID should be set.");
is(connection.state, "connecting", "The initial state should be connecting.");
if (connectionFromEvent) {
is(connection, connectionFromEvent, "The connection from promise and the one from |connectionavailable| event should be the same.");
}
connection.onconnect = function() {
connection.onconnect = null;
is(connection.state, "connected", "Connection should be connected.");
aResolve();
};
},
function(aError) {
ok(false, "Error occurred when establishing a connection: " + aError);
teardown();
aReject();
}
);
});
}
function testSend() {
return new Promise(function(aResolve, aReject) {
const outgoingMessage = "test outgoing message";
gScript.addMessageListener('message-sent', function messageSentHandler(aMessage) {
gScript.removeMessageListener('message-sent', messageSentHandler);
is(aMessage, outgoingMessage, "The message is sent out.");
aResolve();
});
connection.send(outgoingMessage);
});
}
function testIncomingMessage() {
return new Promise(function(aResolve, aReject) {
const incomingMessage = "test incoming message";
connection.addEventListener('message', function messageHandler(aEvent) {
connection.removeEventListener('message', messageHandler);
is(aEvent.data, incomingMessage, "An incoming message should be received.");
aResolve();
});
gScript.sendAsyncMessage('trigger-incoming-message', incomingMessage);
});
}
function testCloseConnection() {
return new Promise(function(aResolve, aReject) {
gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
info("The data transport is closed. " + aReason);
});
connection.onclose = function() {
connection.onclose = null;
is(connection.state, "closed", "Connection should be closed.");
aResolve();
};
connection.close();
});
}
function testReconnect() {
return new Promise(function(aResolve, aReject) {
info('--- testReconnect ---');
gScript.addMessageListener('control-channel-established', function controlChannelEstablished() {
gScript.removeMessageListener('control-channel-established', controlChannelEstablished);
gScript.sendAsyncMessage("trigger-control-channel-open");
});
gScript.addMessageListener('start-reconnect', function startReconnectHandler(url) {
gScript.removeMessageListener('start-reconnect', startReconnectHandler);
is(url, "https://example.com/", "URLs should be the same.")
gScript.sendAsyncMessage('trigger-reconnected-acked', url);
});
gScript.addMessageListener('offer-sent', function offerSentHandler() {
gScript.removeMessageListener('offer-sent', offerSentHandler);
gScript.sendAsyncMessage('trigger-incoming-transport');
});
gScript.addMessageListener('answer-received', function answerReceivedHandler() {
gScript.removeMessageListener('answer-received', answerReceivedHandler);
info("An answer is received.");
});
gScript.addMessageListener('data-transport-initialized', function dataTransportInitializedHandler() {
gScript.removeMessageListener('data-transport-initialized', dataTransportInitializedHandler);
info("Data transport channel is initialized.");
gScript.sendAsyncMessage('trigger-incoming-answer');
});
gScript.addMessageListener('data-transport-notification-enabled', function dataTransportNotificationEnabledHandler() {
gScript.removeMessageListener('data-transport-notification-enabled', dataTransportNotificationEnabledHandler);
info("Data notification is enabled for data transport channel.");
});
request.reconnect(connection.id).then(
function(aConnection) {
ok(aConnection, "Connection should be available.");
ok(aConnection.id, "Connection ID should be set.");
is(aConnection.state, "connecting", "The initial state should be connecting.");
is(aConnection, connection, "The reconnected connection should be the same.");
aConnection.onconnect = function() {
aConnection.onconnect = null;
is(aConnection.state, "connected", "Connection should be connected.");
aResolve();
};
},
function(aError) {
ok(false, "Error occurred when establishing a connection: " + aError);
teardown();
aReject();
}
);
});
}
function teardown() {
gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
gScript.destroy();
SimpleTest.finish();
});
gScript.sendAsyncMessage('teardown');
}
function runTests() {
ok(window.PresentationRequest, "PresentationRequest should be available.");
testSetup().
then(testStartConnection).
then(testSend).
then(testIncomingMessage).
then(testCloseConnection).
then(testReconnect).
then(testCloseConnection).
then(teardown);
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
["dom.presentation.controller.enabled", true],
["dom.presentation.session_transport.data_channel.enable", false]]},
runTests);
</script>
</body>
</html>

View file

@ -0,0 +1,151 @@
<!DOCTYPE HTML>
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test default request for B2G Presentation API at sender side</title>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1069230">Test default request for B2G Presentation API at sender side</a>
<script type="application/javascript;version=1.8">
'use strict';
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
var connection;
function testSetup() {
return new Promise(function(aResolve, aReject) {
navigator.presentation.defaultRequest = new PresentationRequest("https://example.com");
navigator.presentation.defaultRequest.getAvailability().then(
function(aAvailability) {
is(aAvailability.value, false, "Sender: should have no available device after setup");
aAvailability.onchange = function() {
aAvailability.onchange = null;
ok(aAvailability.value, "Device should be available.");
aResolve();
}
gScript.sendAsyncMessage('trigger-device-add');
},
function(aError) {
ok(false, "Error occurred when getting availability: " + aError);
teardown();
aReject();
}
);
});
}
function testStartConnection() {
return new Promise(function(aResolve, aReject) {
gScript.addMessageListener('device-prompt', function devicePromptHandler() {
gScript.removeMessageListener('device-prompt', devicePromptHandler);
info("Device prompt is triggered.");
gScript.sendAsyncMessage('trigger-device-prompt-select');
});
gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
info("A control channel is established.");
gScript.sendAsyncMessage('trigger-control-channel-open');
});
gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler(aReason) {
gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
info("The control channel is opened.");
});
gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
info("The control channel is closed. " + aReason);
});
gScript.addMessageListener('offer-sent', function offerSentHandler() {
gScript.removeMessageListener('offer-sent', offerSentHandler);
info("An offer is sent out.");
gScript.sendAsyncMessage('trigger-incoming-transport');
});
gScript.addMessageListener('answer-received', function answerReceivedHandler() {
gScript.removeMessageListener('answer-received', answerReceivedHandler);
info("An answer is received.");
});
gScript.addMessageListener('data-transport-initialized', function dataTransportInitializedHandler() {
gScript.removeMessageListener('data-transport-initialized', dataTransportInitializedHandler);
info("Data transport channel is initialized.");
gScript.sendAsyncMessage('trigger-incoming-answer');
});
is(navigator.presentation.receiver, undefined, "Sender shouldn't get a presentation receiver instance.");
navigator.presentation.defaultRequest.onconnectionavailable = function(aEvent) {
navigator.presentation.defaultRequest.onconnectionavailable = null;
connection = aEvent.connection;
ok(connection, "|connectionavailable| event is fired with a connection.");
ok(connection.id, "Connection ID should be set.");
is(connection.state, "connecting", "The initial state should be connecting.");
connection.onconnect = function() {
connection.onconnect = null;
is(connection.state, "connected", "Connection should be connected.");
aResolve();
};
};
// Simulate the UA triggers |start()| of the default request.
navigator.presentation.defaultRequest.start();
});
}
function testCloseConnection() {
return new Promise(function(aResolve, aReject) {
gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
info("The data transport is closed. " + aReason);
});
connection.onclose = function() {
connection.onclose = null;
is(connection.state, "closed", "Connection should be closed.");
aResolve();
};
connection.close();
});
}
function teardown() {
gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
gScript.destroy();
SimpleTest.finish();
});
gScript.sendAsyncMessage('teardown');
}
function runTests() {
ok(window.PresentationRequest, "PresentationRequest should be available.");
ok(navigator.presentation, "navigator.presentation should be available.");
testSetup().
then(testStartConnection).
then(testCloseConnection).
then(teardown);
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
["dom.presentation.controller.enabled", true],
["dom.presentation.receiver.enabled", false],
["dom.presentation.session_transport.data_channel.enable", false]]},
runTests);
</script>
</body>
</html>

View file

@ -0,0 +1,160 @@
<!DOCTYPE HTML>
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for disconnection of B2G Presentation API at sender side</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1069230">Test for disconnection of B2G Presentation API at sender side</a>
<script type="application/javascript;version=1.8">
'use strict';
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
var request;
var connection;
function testSetup() {
return new Promise(function(aResolve, aReject) {
request = new PresentationRequest("http://example.com");
request.getAvailability().then(
function(aAvailability) {
is(aAvailability.value, false, "Sender: should have no available device after setup");
aAvailability.onchange = function() {
aAvailability.onchange = null;
ok(aAvailability.value, "Device should be available.");
aResolve();
}
gScript.sendAsyncMessage('trigger-device-add');
},
function(aError) {
ok(false, "Error occurred when getting availability: " + aError);
teardown();
aReject();
}
);
});
}
function testStartConnection() {
return new Promise(function(aResolve, aReject) {
gScript.addMessageListener('device-prompt', function devicePromptHandler() {
gScript.removeMessageListener('device-prompt', devicePromptHandler);
info("Device prompt is triggered.");
gScript.sendAsyncMessage('trigger-device-prompt-select');
});
gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
info("A control channel is established.");
gScript.sendAsyncMessage('trigger-control-channel-open');
});
gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler(aReason) {
gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
info("The control channel is opened.");
});
gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
info("The control channel is closed. " + aReason);
});
gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
gScript.removeMessageListener('offer-sent', offerSentHandler);
ok(aIsValid, "A valid offer is sent out.");
gScript.sendAsyncMessage('trigger-incoming-answer');
});
gScript.addMessageListener('answer-received', function answerReceivedHandler() {
gScript.removeMessageListener('answer-received', answerReceivedHandler);
info("An answer is received.");
gScript.sendAsyncMessage('trigger-incoming-transport');
});
gScript.addMessageListener('data-transport-initialized', function dataTransportInitializedHandler() {
gScript.removeMessageListener('data-transport-initialized', dataTransportInitializedHandler);
info("Data transport channel is initialized.");
});
gScript.addMessageListener('data-transport-notification-enabled', function dataTransportNotificationEnabledHandler() {
gScript.removeMessageListener('data-transport-notification-enabled', dataTransportNotificationEnabledHandler);
info("Data notification is enabled for data transport channel.");
});
request.start().then(
function(aConnection) {
connection = aConnection;
ok(connection, "Connection should be available.");
ok(connection.id, "Connection ID should be set.");
is(connection.state, "connecting", "The initial state should be connecting.");
connection.onconnect = function() {
connection.onconnect = null;
is(connection.state, "connected", "Connection should be connected.");
aResolve();
};
},
function(aError) {
ok(false, "Error occurred when establishing a connection: " + aError);
teardown();
aReject();
}
);
});
}
function testDisconnection() {
return new Promise(function(aResolve, aReject) {
gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
info("The data transport is closed. " + aReason);
});
connection.onclose = function() {
connection.onclose = null;
is(connection.state, "closed", "Connection should be closed.");
aResolve();
};
gScript.sendAsyncMessage('trigger-data-transport-close', SpecialPowers.Cr.NS_ERROR_FAILURE);
});
}
function teardown() {
gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
gScript.destroy();
SimpleTest.finish();
});
gScript.sendAsyncMessage('teardown');
}
function runTests() {
ok(window.PresentationRequest, "PresentationRequest should be available.");
testSetup().
then(testStartConnection).
then(testDisconnection).
then(teardown);
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPermissions([
{type: 'presentation-device-manage', allow: false, context: document},
], function() {
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
["dom.presentation.controller.enabled", true],
["dom.presentation.session_transport.data_channel.enable", false]]},
runTests);
});
</script>
</body>
</html>

View file

@ -0,0 +1,514 @@
<!DOCTYPE HTML>
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for connection establishing errors of B2G Presentation API at sender side</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1069230">Test for connection establishing errors of B2G Presentation API at sender side</a>
<script type="application/javascript;version=1.8">
'use strict';
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
var request;
function setup() {
return new Promise(function(aResolve, aReject) {
request = new PresentationRequest("http://example.com");
request.getAvailability().then(
function(aAvailability) {
is(aAvailability.value, false, "Sender: should have no available device after setup");
aAvailability.onchange = function() {
aAvailability.onchange = null;
ok(aAvailability.value, "Device should be available.");
aResolve();
}
gScript.sendAsyncMessage('trigger-device-add');
},
function(aError) {
ok(false, "Error occurred when getting availability: " + aError);
teardown();
aReject();
}
);
});
}
function testStartConnectionCancelPrompt() {
info('--- testStartConnectionCancelPrompt ---');
return Promise.all([
new Promise((resolve) => {
gScript.addMessageListener('device-prompt', function devicePromptHandler() {
gScript.removeMessageListener('device-prompt', devicePromptHandler);
info("Device prompt is triggered.");
gScript.sendAsyncMessage('trigger-device-prompt-cancel', SpecialPowers.Cr.NS_ERROR_DOM_NOT_ALLOWED_ERR);
resolve();
});
}),
request.start().then(
function(aConnection) {
ok(false, "|start| shouldn't succeed in this case.");
},
function(aError) {
is(aError.name, "NotAllowedError", "NotAllowedError is expected when the prompt is canceled.");
}
),
]);
}
function testStartConnectionNoDevice() {
info('--- testStartConnectionNoDevice ---');
return Promise.all([
new Promise((resolve) => {
gScript.addMessageListener('device-prompt', function devicePromptHandler() {
gScript.removeMessageListener('device-prompt', devicePromptHandler);
info("Device prompt is triggered.");
gScript.sendAsyncMessage('trigger-device-prompt-cancel', SpecialPowers.Cr.NS_ERROR_DOM_NOT_FOUND_ERR);
resolve();
});
}),
request.start().then(
function(aConnection) {
ok(false, "|start| shouldn't succeed in this case.");
},
function(aError) {
is(aError.name, "NotFoundError", "NotFoundError is expected when no available device.");
}
),
]);
}
function testStartConnectionUnexpectedControlChannelCloseBeforeDataTransportInit() {
info('--- testStartConnectionUnexpectedControlChannelCloseBeforeDataTransportInit ---');
return Promise.all([
new Promise((resolve) => {
gScript.addMessageListener('device-prompt', function devicePromptHandler() {
gScript.removeMessageListener('device-prompt', devicePromptHandler);
info("Device prompt is triggered.");
gScript.sendAsyncMessage('trigger-device-prompt-select');
resolve();
});
}),
new Promise((resolve) => {
gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
info("A control channel is established.");
gScript.sendAsyncMessage('trigger-control-channel-open');
resolve();
});
}),
new Promise((resolve) => {
gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler() {
gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
info("The control channel is opened.");
resolve();
});
}),
new Promise((resolve) => {
gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
info("The control channel is closed. " + aReason);
is(aReason, SpecialPowers.Cr.NS_ERROR_FAILURE, "The control channel is closed with NS_ERROR_FAILURE");
resolve();
});
}),
new Promise((resolve) => {
gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
gScript.removeMessageListener('offer-sent', offerSentHandler);
ok(aIsValid, "A valid offer is sent out.");
gScript.sendAsyncMessage('trigger-control-channel-close', SpecialPowers.Cr.NS_ERROR_FAILURE);
resolve();
});
}),
request.start().then(
function(aConnection) {
is(aConnection.state, "connecting", "The initial state should be connecting.");
return new Promise((resolve) => {
aConnection.onclose = function() {
aConnection.onclose = null;
is(aConnection.state, "closed", "Connection should be closed.");
resolve();
};
});
},
function(aError) {
ok(false, "Error occurred when establishing a connection: " + aError);
teardown();
}
),
]);
}
function testStartConnectionUnexpectedControlChannelCloseNoReasonBeforeDataTransportInit() {
info('--- testStartConnectionUnexpectedControlChannelCloseNoReasonBeforeDataTransportInit ---');
return Promise.all([
new Promise((resolve) => {
gScript.addMessageListener('device-prompt', function devicePromptHandler() {
gScript.removeMessageListener('device-prompt', devicePromptHandler);
info("Device prompt is triggered.");
gScript.sendAsyncMessage('trigger-device-prompt-select');
resolve();
});
}),
new Promise((resolve) => {
gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
info("A control channel is established.");
gScript.sendAsyncMessage('trigger-control-channel-open');
resolve();
});
}),
new Promise((resolve) => {
gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler() {
gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
info("The control channel is opened.");
resolve();
});
}),
new Promise((resolve) => {
gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
info("The control channel is closed. " + aReason);
is(aReason, SpecialPowers.Cr.NS_OK, "The control channel is closed with NS_OK");
resolve();
});
}),
new Promise((resolve) => {
gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
gScript.removeMessageListener('offer-sent', offerSentHandler);
ok(aIsValid, "A valid offer is sent out.");
gScript.sendAsyncMessage('trigger-control-channel-close', SpecialPowers.Cr.NS_OK);
resolve();
});
}),
request.start().then(
function(aConnection) {
is(aConnection.state, "connecting", "The initial state should be connecting.");
return new Promise((resolve) => {
aConnection.onclose = function() {
aConnection.onclose = null;
is(aConnection.state, "closed", "Connection should be closed.");
resolve();
};
});
},
function(aError) {
ok(false, "Error occurred when establishing a connection: " + aError);
teardown();
}
),
]);
}
function testStartConnectionUnexpectedControlChannelCloseBeforeDataTransportReady() {
info('--- testStartConnectionUnexpectedControlChannelCloseBeforeDataTransportReady ---');
return Promise.all([
new Promise((resolve) => {
gScript.addMessageListener('device-prompt', function devicePromptHandler() {
gScript.removeMessageListener('device-prompt', devicePromptHandler);
info("Device prompt is triggered.");
gScript.sendAsyncMessage('trigger-device-prompt-select');
resolve();
});
}),
new Promise((resolve) => {
gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
info("A control channel is established.");
gScript.sendAsyncMessage('trigger-control-channel-open');
resolve();
});
}),
new Promise((resolve) => {
gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler() {
gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
info("The control channel is opened.");
resolve();
});
}),
new Promise((resolve) => {
gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
is(aReason, SpecialPowers.Cr.NS_ERROR_ABORT, "The control channel is closed with NS_ERROR_ABORT");
resolve();
});
}),
new Promise((resolve) => {
gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
gScript.removeMessageListener('offer-sent', offerSentHandler);
ok(aIsValid, "A valid offer is sent out.");
gScript.sendAsyncMessage('trigger-incoming-transport');
resolve();
});
}),
new Promise((resolve) => {
gScript.addMessageListener('data-transport-initialized', function dataTransportInitializedHandler() {
gScript.removeMessageListener('data-transport-initialized', dataTransportInitializedHandler);
info("Data transport channel is initialized.");
gScript.sendAsyncMessage('trigger-control-channel-close', SpecialPowers.Cr.NS_ERROR_ABORT);
resolve();
});
}),
new Promise((resolve) => {
gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
info("The data transport is closed. " + aReason);
resolve();
});
}),
request.start().then(
function(aConnection) {
is(aConnection.state, "connecting", "The initial state should be connecting.");
return new Promise((resolve) => {
aConnection.onclose = function() {
aConnection.onclose = null;
is(aConnection.state, "closed", "Connection should be closed.");
resolve();
};
});
},
function(aError) {
ok(false, "Error occurred when establishing a connection: " + aError);
teardown();
}
),
]);
}
function testStartConnectionUnexpectedControlChannelCloseNoReasonBeforeDataTransportReady() {
info('--- testStartConnectionUnexpectedControlChannelCloseNoReasonBeforeDataTransportReady -- ');
return Promise.all([
new Promise((resolve) => {
gScript.addMessageListener('device-prompt', function devicePromptHandler() {
gScript.removeMessageListener('device-prompt', devicePromptHandler);
info("Device prompt is triggered.");
gScript.sendAsyncMessage('trigger-device-prompt-select');
resolve();
});
}),
new Promise((resolve) => {
gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
info("A control channel is established.");
gScript.sendAsyncMessage('trigger-control-channel-open');
resolve();
});
}),
new Promise((resolve) => {
gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler() {
gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
info("The control channel is opened.");
resolve();
});
}),
new Promise((resolve) => {
gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
info("The control channel is closed. " + aReason);
is(aReason, SpecialPowers.Cr.NS_OK, "The control channel is closed with NS_OK");
resolve();
});
}),
new Promise((resolve) => {
gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
gScript.removeMessageListener('offer-sent', offerSentHandler);
ok(aIsValid, "A valid offer is sent out.");
gScript.sendAsyncMessage('trigger-incoming-transport');
resolve();
});
}),
new Promise((resolve) => {
gScript.addMessageListener('data-transport-initialized', function dataTransportInitializedHandler() {
gScript.removeMessageListener('data-transport-initialized', dataTransportInitializedHandler);
info("Data transport channel is initialized.");
gScript.sendAsyncMessage('trigger-control-channel-close', SpecialPowers.Cr.NS_OK);
resolve();
});
}),
new Promise((resolve) => {
gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
info("The data transport is closed. " + aReason);
resolve();
});
}),
request.start().then(
function(aConnection) {
is(aConnection.state, "connecting", "The initial state should be connecting.");
return new Promise((resolve) => {
aConnection.onclose = function() {
aConnection.onclose = null;
is(aConnection.state, "closed", "Connection should be closed.");
resolve();
};
});
},
function(aError) {
ok(false, "Error occurred when establishing a connection: " + aError);
teardown();
}
),
]);
}
function testStartConnectionUnexpectedDataTransportClose() {
info('--- testStartConnectionUnexpectedDataTransportClose ---');
return Promise.all([
new Promise((resolve) => {
gScript.addMessageListener('device-prompt', function devicePromptHandler() {
gScript.removeMessageListener('device-prompt', devicePromptHandler);
info("Device prompt is triggered.");
gScript.sendAsyncMessage('trigger-device-prompt-select');
resolve();
});
}),
new Promise((resolve) => {
gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
info("A control channel is established.");
gScript.sendAsyncMessage('trigger-control-channel-open');
resolve();
});
}),
new Promise((resolve) => {
gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler() {
gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
info("The control channel is opened.");
resolve();
});
}),
new Promise((resolve) => {
gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
info("The control channel is closed. " + aReason);
resolve();
});
}),
new Promise((resolve) => {
gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
gScript.removeMessageListener('offer-sent', offerSentHandler);
ok(aIsValid, "A valid offer is sent out.");
info("recv offer-sent.");
gScript.sendAsyncMessage('trigger-incoming-transport');
resolve();
});
}),
new Promise((resolve) => {
gScript.addMessageListener('data-transport-initialized', function dataTransportInitializedHandler() {
gScript.removeMessageListener('data-transport-initialized', dataTransportInitializedHandler);
info("Data transport channel is initialized.");
gScript.sendAsyncMessage('trigger-data-transport-close', SpecialPowers.Cr.NS_ERROR_UNEXPECTED);
resolve();
});
}),
new Promise((resolve) => {
gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
info("The data transport is closed. " + aReason);
resolve();
});
}),
request.start().then(
function(aConnection) {
is(aConnection.state, "connecting", "The initial state should be connecting.");
return new Promise((resolve) => {
aConnection.onclose = function() {
aConnection.onclose = null;
is(aConnection.state, "closed", "Connection should be closed.");
resolve();
};
});
},
function(aError) {
ok(false, "Error occurred when establishing a connection: " + aError);
teardown();
}
),
]);
}
function teardown() {
gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
gScript.destroy();
SimpleTest.finish();
});
gScript.sendAsyncMessage('teardown');
}
function runTests() {
ok(window.PresentationRequest, "PresentationRequest should be available.");
setup().
then(testStartConnectionCancelPrompt).
then(testStartConnectionNoDevice).
then(testStartConnectionUnexpectedControlChannelCloseBeforeDataTransportInit).
then(testStartConnectionUnexpectedControlChannelCloseNoReasonBeforeDataTransportInit).
then(testStartConnectionUnexpectedControlChannelCloseBeforeDataTransportReady).
then(testStartConnectionUnexpectedControlChannelCloseNoReasonBeforeDataTransportReady).
then(testStartConnectionUnexpectedDataTransportClose).
then(teardown);
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPermissions([
{type: 'presentation-device-manage', allow: false, context: document},
], function() {
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
["dom.presentation.controller.enabled", true],
["dom.presentation.session_transport.data_channel.enable", false]]},
runTests);
});
</script>
</body>
</html>

View file

@ -0,0 +1,243 @@
'use strict';
SimpleTest.waitForExplicitFinish();
SimpleTest.requestFlakyTimeout('Test for guarantee not firing async event');
function debug(str) {
// info(str);
}
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript1UA.js'));
var receiverUrl = SimpleTest.getTestFileURL('file_presentation_terminate.html');
var request;
var connection;
var receiverIframe;
function setup() {
gScript.addMessageListener('device-prompt', function devicePromptHandler() {
debug('Got message: device-prompt');
gScript.removeMessageListener('device-prompt', devicePromptHandler);
gScript.sendAsyncMessage('trigger-device-prompt-select');
});
gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
gScript.removeMessageListener('control-channel-established',
controlChannelEstablishedHandler);
gScript.sendAsyncMessage('trigger-control-channel-open');
});
gScript.addMessageListener('sender-launch', function senderLaunchHandler(url) {
debug('Got message: sender-launch');
gScript.removeMessageListener('sender-launch', senderLaunchHandler);
is(url, receiverUrl, 'Receiver: should receive the same url');
receiverIframe = document.createElement('iframe');
receiverIframe.setAttribute('mozbrowser', 'true');
receiverIframe.setAttribute('mozpresentation', receiverUrl);
var oop = location.pathname.indexOf('_inproc') == -1;
receiverIframe.setAttribute('remote', oop);
receiverIframe.setAttribute('src', receiverUrl);
receiverIframe.addEventListener('mozbrowserloadend', function mozbrowserloadendHander() {
receiverIframe.removeEventListener('mozbrowserloadend', mozbrowserloadendHander);
info('Receiver loaded.');
});
// This event is triggered when the iframe calls 'alert'.
receiverIframe.addEventListener('mozbrowsershowmodalprompt', function receiverListener(evt) {
var message = evt.detail.message;
if (/^OK /.exec(message)) {
ok(true, message.replace(/^OK /, ''));
} else if (/^KO /.exec(message)) {
ok(false, message.replace(/^KO /, ''));
} else if (/^INFO /.exec(message)) {
info(message.replace(/^INFO /, ''));
} else if (/^COMMAND /.exec(message)) {
var command = JSON.parse(message.replace(/^COMMAND /, ''));
gScript.sendAsyncMessage(command.name, command.data);
} else if (/^DONE$/.exec(message)) {
ok(true, 'Messaging from iframe complete.');
receiverIframe.removeEventListener('mozbrowsershowmodalprompt',
receiverListener);
}
}, false);
var promise = new Promise(function(aResolve, aReject) {
document.body.appendChild(receiverIframe);
aResolve(receiverIframe);
});
var obs = SpecialPowers.Cc['@mozilla.org/observer-service;1']
.getService(SpecialPowers.Ci.nsIObserverService);
obs.notifyObservers(promise, 'setup-request-promise', null);
});
gScript.addMessageListener('promise-setup-ready', function promiseSetupReadyHandler() {
debug('Got message: promise-setup-ready');
gScript.removeMessageListener('promise-setup-ready',
promiseSetupReadyHandler);
gScript.sendAsyncMessage('trigger-on-session-request', receiverUrl);
});
return Promise.resolve();
}
function testCreateRequest() {
return new Promise(function(aResolve, aReject) {
info('Sender: --- testCreateRequest ---');
request = new PresentationRequest(receiverUrl);
request.getAvailability().then((aAvailability) => {
is(aAvailability.value, false, "Sender: should have no available device after setup");
aAvailability.onchange = function() {
aAvailability.onchange = null;
ok(aAvailability.value, 'Sender: Device should be available.');
aResolve();
}
gScript.sendAsyncMessage('trigger-device-add');
}).catch((aError) => {
ok(false, 'Sender: Error occurred when getting availability: ' + aError);
teardown();
aReject();
});
});
}
function testStartConnection() {
return new Promise(function(aResolve, aReject) {
request.start().then((aConnection) => {
connection = aConnection;
ok(connection, 'Sender: Connection should be available.');
ok(connection.id, 'Sender: Connection ID should be set.');
is(connection.state, 'connecting', 'Sender: The initial state should be connecting.');
connection.onconnect = function() {
connection.onconnect = null;
is(connection.state, 'connected', 'Connection should be connected.');
aResolve();
};
info('Sender: test terminate at connecting state');
connection.onterminate = function() {
connection.onterminate = null;
ok(false, 'Should not be able to terminate at connecting state');
aReject();
}
connection.terminate();
}).catch((aError) => {
ok(false, 'Sender: Error occurred when establishing a connection: ' + aError);
teardown();
aReject();
});
});
}
function testConnectionTerminate() {
return new Promise(function(aResolve, aReject) {
info('Sender: --- testConnectionTerminate---');
connection.onterminate = function() {
connection.onterminate = null;
is(connection.state, 'terminated', 'Sender: Connection should be terminated.');
};
gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
gScript.removeMessageListener('control-channel-established',
controlChannelEstablishedHandler);
gScript.sendAsyncMessage('trigger-control-channel-open');
});
gScript.addMessageListener('sender-terminate', function senderTerminateHandler() {
gScript.removeMessageListener('sender-terminate',
senderTerminateHandler);
Promise.all([
new Promise((resolve) => {
gScript.addMessageListener('device-disconnected', function deviceDisconnectedHandler() {
gScript.removeMessageListener('device-disconnected', deviceDisconnectedHandler);
ok(true, 'observe device disconnect');
resolve();
});
}),
new Promise((resolve) => {
receiverIframe.addEventListener('mozbrowserclose', function() {
ok(true, 'observe receiver page closing');
resolve();
});
}),
]).then(aResolve);
gScript.sendAsyncMessage('trigger-on-terminate-request');
});
gScript.addMessageListener('ready-to-terminate', function onReadyToTerminate() {
gScript.removeMessageListener('ready-to-terminate', onReadyToTerminate);
connection.terminate();
// test unexpected close right after terminate
connection.onclose = function() {
ok(false, 'close after terminate should do nothing');
};
connection.close();
});
});
}
function testSendAfterTerminate() {
return new Promise(function(aResolve, aReject) {
try {
connection.send('something');
ok(false, 'PresentationConnection.send should be failed');
} catch (e) {
is(e.name, 'InvalidStateError', 'Must throw InvalidStateError');
}
aResolve();
});
}
function testCloseAfterTerminate() {
return Promise.race([
new Promise(function(aResolve, aReject) {
connection.onclose = function() {
connection.onclose = null;
ok(false, 'close at terminated state should do nothing');
aResolve();
};
connection.close();
}),
new Promise(function(aResolve, aReject) {
setTimeout(function() {
is(connection.state, 'terminated', 'Sender: Connection should be terminated.');
aResolve();
}, 3000);
}),
]);
}
function teardown() {
gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
debug('Got message: teardown-complete');
gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
gScript.destroy();
SimpleTest.finish();
});
gScript.sendAsyncMessage('teardown');
}
function runTests() {
setup().then(testCreateRequest)
.then(testStartConnection)
.then(testConnectionTerminate)
.then(testSendAfterTerminate)
.then(testCloseAfterTerminate)
.then(teardown);
}
SpecialPowers.pushPermissions([
{type: 'presentation-device-manage', allow: false, context: document},
{type: 'browser', allow: true, context: document},
], () => {
SpecialPowers.pushPrefEnv({ 'set': [['dom.presentation.enabled', true],
["dom.presentation.controller.enabled", true],
["dom.presentation.receiver.enabled", true],
['dom.presentation.test.enabled', true],
['dom.mozBrowserFramesEnabled', true],
["network.disable.ipc.security", true],
['dom.ipc.tabs.disabled', false],
['dom.presentation.test.stage', 0]]},
runTests);
});

View file

@ -0,0 +1,197 @@
'use strict';
SimpleTest.waitForExplicitFinish();
SimpleTest.requestFlakyTimeout('Test for guarantee not firing async event');
function debug(str) {
// info(str);
}
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript1UA.js'));
var receiverUrl = SimpleTest.getTestFileURL('file_presentation_terminate_establish_connection_error.html');
var request;
var connection;
var receiverIframe;
function postMessageToIframe(aType) {
receiverIframe.src = receiverUrl + "#" +
encodeURIComponent(JSON.stringify({ type: aType }));
}
function setup() {
gScript.addMessageListener('device-prompt', function devicePromptHandler() {
debug('Got message: device-prompt');
gScript.removeMessageListener('device-prompt', devicePromptHandler);
gScript.sendAsyncMessage('trigger-device-prompt-select');
});
gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
gScript.removeMessageListener('control-channel-established',
controlChannelEstablishedHandler);
gScript.sendAsyncMessage('trigger-control-channel-open');
});
gScript.addMessageListener('sender-launch', function senderLaunchHandler(url) {
debug('Got message: sender-launch');
gScript.removeMessageListener('sender-launch', senderLaunchHandler);
is(url, receiverUrl, 'Receiver: should receive the same url');
receiverIframe = document.createElement('iframe');
receiverIframe.setAttribute('mozbrowser', 'true');
receiverIframe.setAttribute('mozpresentation', receiverUrl);
var oop = location.pathname.indexOf('_inproc') == -1;
receiverIframe.setAttribute('remote', oop);
receiverIframe.setAttribute('src', receiverUrl);
receiverIframe.addEventListener('mozbrowserloadend', function mozbrowserloadendHander() {
receiverIframe.removeEventListener('mozbrowserloadend', mozbrowserloadendHander);
info('Receiver loaded.');
});
// This event is triggered when the iframe calls 'alert'.
receiverIframe.addEventListener('mozbrowsershowmodalprompt', function receiverListener(evt) {
var message = evt.detail.message;
if (/^OK /.exec(message)) {
ok(true, message.replace(/^OK /, ''));
} else if (/^KO /.exec(message)) {
ok(false, message.replace(/^KO /, ''));
} else if (/^INFO /.exec(message)) {
info(message.replace(/^INFO /, ''));
} else if (/^COMMAND /.exec(message)) {
var command = JSON.parse(message.replace(/^COMMAND /, ''));
gScript.sendAsyncMessage(command.name, command.data);
} else if (/^DONE$/.exec(message)) {
ok(true, 'Messaging from iframe complete.');
receiverIframe.removeEventListener('mozbrowsershowmodalprompt',
receiverListener);
}
}, false);
var promise = new Promise(function(aResolve, aReject) {
document.body.appendChild(receiverIframe);
aResolve(receiverIframe);
});
var obs = SpecialPowers.Cc['@mozilla.org/observer-service;1']
.getService(SpecialPowers.Ci.nsIObserverService);
obs.notifyObservers(promise, 'setup-request-promise', null);
});
gScript.addMessageListener('promise-setup-ready', function promiseSetupReadyHandler() {
debug('Got message: promise-setup-ready');
gScript.removeMessageListener('promise-setup-ready',
promiseSetupReadyHandler);
gScript.sendAsyncMessage('trigger-on-session-request', receiverUrl);
});
return Promise.resolve();
}
function testCreateRequest() {
return new Promise(function(aResolve, aReject) {
info('Sender: --- testCreateRequest ---');
request = new PresentationRequest(receiverUrl);
request.getAvailability().then((aAvailability) => {
is(aAvailability.value, false, "Sender: should have no available device after setup");
aAvailability.onchange = function() {
aAvailability.onchange = null;
ok(aAvailability.value, 'Sender: Device should be available.');
aResolve();
}
gScript.sendAsyncMessage('trigger-device-add');
}).catch((aError) => {
ok(false, 'Sender: Error occurred when getting availability: ' + aError);
teardown();
aReject();
});
});
}
function testStartConnection() {
return new Promise(function(aResolve, aReject) {
request.start().then((aConnection) => {
connection = aConnection;
ok(connection, 'Sender: Connection should be available.');
ok(connection.id, 'Sender: Connection ID should be set.');
is(connection.state, 'connecting', 'Sender: The initial state should be connecting.');
connection.onconnect = function() {
connection.onconnect = null;
is(connection.state, 'connected', 'Connection should be connected.');
aResolve();
};
}).catch((aError) => {
ok(false, 'Sender: Error occurred when establishing a connection: ' + aError);
teardown();
aReject();
});
});
}
function testConnectionTerminate() {
info('Sender: --- testConnectionTerminate---');
let promise = Promise.all([
new Promise(function(aResolve, aReject) {
connection.onclose = function() {
connection.onclose = null;
is(connection.state, 'closed', 'Sender: Connection should be closed.');
aResolve();
};
}),
new Promise(function(aResolve, aReject) {
function deviceDisconnectedHandler() {
gScript.removeMessageListener('device-disconnected', deviceDisconnectedHandler);
ok(true, 'should not receive device disconnect');
aResolve();
}
gScript.addMessageListener('device-disconnected', deviceDisconnectedHandler);
}),
new Promise(function(aResolve, aReject) {
receiverIframe.addEventListener('mozbrowserclose', function() {
ok(true, 'observe receiver page closing');
aResolve();
});
})
]);
gScript.addMessageListener('prepare-for-terminate', function prepareForTerminateHandler() {
debug('Got message: prepare-for-terminate');
gScript.removeMessageListener('prepare-for-terminate', prepareForTerminateHandler);
gScript.sendAsyncMessage('trigger-control-channel-error');
postMessageToIframe('ready-to-terminate');
});
return promise;
}
function teardown() {
gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
debug('Got message: teardown-complete');
gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
gScript.destroy();
SimpleTest.finish();
});
gScript.sendAsyncMessage('teardown');
}
function runTests() {
setup().then(testCreateRequest)
.then(testStartConnection)
.then(testConnectionTerminate)
.then(teardown);
}
SpecialPowers.pushPermissions([
{type: 'presentation-device-manage', allow: false, context: document},
{type: 'browser', allow: true, context: document},
], () => {
SpecialPowers.pushPrefEnv({ 'set': [['dom.presentation.enabled', true],
["dom.presentation.controller.enabled", true],
["dom.presentation.receiver.enabled", true],
['dom.presentation.test.enabled', true],
['dom.mozBrowserFramesEnabled', true],
["network.disable.ipc.security", true],
['dom.ipc.tabs.disabled', false],
['dom.presentation.test.stage', 0]]},
runTests);
});

View file

@ -0,0 +1,18 @@
<!DOCTYPE HTML>
<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: -->
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset='utf-8'>
<title>Test for control channel establish error during PresentationConnection.terminate()</title>
<link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/>
<script type='application/javascript' src='/tests/SimpleTest/SimpleTest.js'></script>
</head>
<body>
<a target='_blank' href='https://bugzilla.mozilla.org/show_bug.cgi?id=1289292'>
Test for constrol channel establish error during PresentationConnection.terminate()</a>
<script type='application/javascript;version=1.8' src='test_presentation_terminate_establish_connection_error.js'>
</script>
</body>
</html>

View file

@ -0,0 +1,18 @@
<!DOCTYPE HTML>
<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: -->
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset='utf-8'>
<title>Test for control channel establish error during PresentationConnection.terminate()</title>
<link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/>
<script type='application/javascript' src='/tests/SimpleTest/SimpleTest.js'></script>
</head>
<body>
<a target='_blank' href='https://bugzilla.mozilla.org/show_bug.cgi?id=1289292'>
Test for constrol channel establish error during PresentationConnection.terminate()</a>
<script type='application/javascript;version=1.8' src='test_presentation_terminate_establish_connection_error.js'>
</script>
</body>
</html>

View file

@ -0,0 +1,18 @@
<!DOCTYPE HTML>
<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: -->
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset='utf-8'>
<title>Test for PresentationConnection.terminate()</title>
<link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/>
<script type='application/javascript' src='/tests/SimpleTest/SimpleTest.js'></script>
</head>
<body>
<a target='_blank' href='https://bugzilla.mozilla.org/show_bug.cgi?id=1276378'>
Test for PresentationConnection.terminate()</a>
<script type='application/javascript;version=1.8' src='test_presentation_terminate.js'>
</script>
</body>
</html>

View file

@ -0,0 +1,18 @@
<!DOCTYPE HTML>
<!-- vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: -->
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset='utf-8'>
<title>Test for PresentationConnection.terminate()</title>
<link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css'/>
<script type='application/javascript' src='/tests/SimpleTest/SimpleTest.js'></script>
</head>
<body>
<a target='_blank' href='https://bugzilla.mozilla.org/show_bug.cgi?id=1276378'>
Test for PresentationConnection.terminate()</a>
<script type='application/javascript;version=1.8' src='test_presentation_terminate.js'>
</script>
</body>
</html>