Bug 861716 - add a mochitest for gUM request queue in MediaManager. r=florian,jib

MozReview-Commit-ID: 750T4pzvf95

--HG--
extra : rebase_source : b683ce86ce43ca33fdb303d55e6da21eea1725d1
This commit is contained in:
Munro Mengjue Chiang 2017-05-17 10:59:12 +08:00
parent ac029ed760
commit cea6dddaf6
6 changed files with 255 additions and 14 deletions

View File

@ -18,4 +18,6 @@ skip-if = e10s && (asan || debug) # bug 1347625
[browser_devices_get_user_media_unprompted_access_in_frame.js]
[browser_devices_get_user_media_unprompted_access_tear_off_tab.js]
skip-if = (os == "win" && bits == 64) # win8: bug 1334752
[browser_devices_get_user_media_unprompted_access_queue_request.js]
[browser_webrtc_hooks.js]
[browser_devices_get_user_media_queue_request.js]

View File

@ -0,0 +1,158 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
const permissionError = "error: NotAllowedError: The request is not allowed " +
"by the user agent or the platform in the current context.";
const badDeviceError =
"error: NotReadableError: Failed to allocate videosource";
var gTests = [
{
desc: "test queueing deny audio behind allow video",
run: async function testQueuingDenyAudioBehindAllowVideo() {
let promise = promisePopupNotificationShown("webRTC-shareDevices");
await promiseRequestDevice(false, true);
await promiseRequestDevice(true, false);
await promise;
promise = promisePopupNotificationShown("webRTC-shareDevices");
checkDeviceSelectors(false, true);
await expectObserverCalled("getUserMedia:request");
let indicator = promiseIndicatorWindow();
await promiseMessage("ok", () => {
PopupNotifications.panel.firstChild.button.click();
});
await expectObserverCalled("getUserMedia:response:allow");
await expectObserverCalled("recording-device-events");
Assert.deepEqual((await getMediaCaptureState()), {video: true},
"expected camera to be shared");
await indicator;
await checkSharingUI({audio: false, video: true});
await promise;
await expectObserverCalled("getUserMedia:request");
checkDeviceSelectors(true, false);
await promiseMessage(permissionError, () => {
activateSecondaryAction(kActionDeny);
});
await expectObserverCalled("getUserMedia:response:deny");
SitePermissions.remove(null, "microphone", gBrowser.selectedBrowser);
// close all streams
await closeStream();
}
},
{
desc: "test queueing allow video behind deny audio",
run: async function testQueuingAllowVideoBehindDenyAudio() {
let promise = promisePopupNotificationShown("webRTC-shareDevices");
await promiseRequestDevice(true, false);
await promiseRequestDevice(false, true);
await promise;
promise = promisePopupNotificationShown("webRTC-shareDevices");
await expectObserverCalled("getUserMedia:request");
checkDeviceSelectors(true, false);
await promiseMessage(permissionError, () => {
activateSecondaryAction(kActionDeny);
});
await expectObserverCalled("getUserMedia:response:deny");
await promise;
checkDeviceSelectors(false, true);
await expectObserverCalled("getUserMedia:request");
let indicator = promiseIndicatorWindow();
await promiseMessage("ok", () => {
PopupNotifications.panel.firstChild.button.click();
});
await expectObserverCalled("getUserMedia:response:allow");
await expectObserverCalled("recording-device-events");
Assert.deepEqual((await getMediaCaptureState()), {video: true},
"expected camera to be shared");
await indicator;
await checkSharingUI({audio: false, video: true});
SitePermissions.remove(null, "microphone", gBrowser.selectedBrowser);
// close all streams
await closeStream();
}
},
{
desc: "test queueing allow audio behind allow video with error",
run: async function testQueuingAllowAudioBehindAllowVideoWithError() {
let promise = promisePopupNotificationShown("webRTC-shareDevices");
await promiseRequestDevice(false, true, null, null, gBrowser.selectedBrowser, true);
await promiseRequestDevice(true, false);
await promise;
promise = promisePopupNotificationShown("webRTC-shareDevices");
checkDeviceSelectors(false, true);
await expectObserverCalled("getUserMedia:request");
await promiseMessage(badDeviceError, () => {
PopupNotifications.panel.firstChild.button.click();
});
await expectObserverCalled("getUserMedia:response:allow");
await promise;
checkDeviceSelectors(true, false);
await expectObserverCalled("getUserMedia:request");
let indicator = promiseIndicatorWindow();
await promiseMessage("ok", () => {
PopupNotifications.panel.firstChild.button.click();
});
await expectObserverCalled("getUserMedia:response:allow");
await expectObserverCalled("recording-device-events");
Assert.deepEqual((await getMediaCaptureState()), {audio: true},
"expected microphone to be shared");
await indicator;
await checkSharingUI({audio: true, video: false});
// close all streams
await closeStream();
}
},
{
desc: "test queueing audio+video behind deny audio",
run: async function testQueuingAllowVideoBehindDenyAudio() {
let promise = promisePopupNotificationShown("webRTC-shareDevices");
await promiseRequestDevice(true, false);
await promiseRequestDevice(true, true);
await promise;
await expectObserverCalled("getUserMedia:request");
checkDeviceSelectors(true, false);
promise = promiseSpecificMessageReceived(permissionError, 2);
activateSecondaryAction(kActionDeny);
await promise;
await expectObserverCalled("getUserMedia:request");
await expectObserverCalled("getUserMedia:response:deny", 2);
await expectObserverCalled("recording-window-ended");
SitePermissions.remove(null, "microphone", gBrowser.selectedBrowser);
}
}
];
add_task(async function test() {
await runTests(gTests);
});

View File

@ -0,0 +1,37 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
var gTests = [
{
desc: "test queueing allow video behind allow video",
run: async function testQueuingAllowVideoBehindAllowVideo() {
let promise = promisePopupNotificationShown("webRTC-shareDevices");
await promiseRequestDevice(false, true);
await promiseRequestDevice(false, true);
await promise;
checkDeviceSelectors(false, true);
await expectObserverCalled("getUserMedia:request");
let promiseOK = promiseSpecificMessageReceived("ok", 2);
PopupNotifications.panel.firstChild.button.click();
await promiseOK;
await promiseNoPopupNotification("webRTC-shareDevices");
await expectObserverCalled("getUserMedia:request");
await expectObserverCalled("getUserMedia:response:allow", 2);
Assert.deepEqual((await getMediaCaptureState()), {video: true},
"expected camera to be shared");
await expectObserverCalled("recording-device-events", 2);
// close all streams
await closeStream();
}
}
];
add_task(async function test() {
SimpleTest.requestCompleteLog();
await runTests(gTests);
});

View File

@ -24,7 +24,7 @@ function message(m) {
var gStreams = [];
function requestDevice(aAudio, aVideo, aShare) {
function requestDevice(aAudio, aVideo, aShare, aBadDevice = false) {
var opts = {video: aVideo, audio: aAudio};
if (aShare) {
opts.video = {
@ -35,6 +35,20 @@ function requestDevice(aAudio, aVideo, aShare) {
opts.fake = true;
}
if (aVideo && aBadDevice) {
opts.video = {
deviceId: "bad device"
}
opts.fake = true;
}
if (aAudio && aBadDevice) {
opts.audio = {
deviceId: "bad device"
}
opts.fake = true;
}
window.navigator.mediaDevices.getUserMedia(opts)
.then(stream => {
gStreams.push(stream);

View File

@ -51,11 +51,12 @@ kObservedTopics.forEach(topic => {
Services.obs.addObserver(observer, topic);
});
addMessageListener("Test:ExpectObserverCalled", ({data}) => {
addMessageListener("Test:ExpectObserverCalled", ({ data: { topic, count } }) => {
sendAsyncMessage("Test:ExpectObserverCalled:Reply",
{count: gObservedTopics[data]});
if (data in gObservedTopics)
--gObservedTopics[data];
{count: gObservedTopics[topic]});
if (topic in gObservedTopics) {
gObservedTopics[topic] -= count;
}
});
addMessageListener("Test:ExpectNoObserverCalled", data => {
@ -120,8 +121,18 @@ addMessageListener("Test:WaitForObserverCall", ({data}) => {
}, topic);
});
function messageListener({data}) {
sendAsyncMessage("Test:MessageReceived", data);
}
addMessageListener("Test:WaitForMessage", () => {
content.addEventListener("message", ({data}) => {
sendAsyncMessage("Test:MessageReceived", data);
}, {once: true});
content.addEventListener("message", messageListener, {once: true});
});
addMessageListener("Test:WaitForMultipleMessages", () => {
content.addEventListener("message", messageListener);
});
addMessageListener("Test:StopWaitForMultipleMessages", () => {
content.removeEventListener("message", messageListener);
});

View File

@ -202,16 +202,16 @@ function promiseObserverCalled(aTopic) {
});
}
function expectObserverCalled(aTopic) {
function expectObserverCalled(aTopic, aCount = 1) {
return new Promise(resolve => {
let mm = _mm();
mm.addMessageListener("Test:ExpectObserverCalled:Reply",
function listener({data}) {
is(data.count, 1, "expected notification " + aTopic);
is(data.count, aCount, "expected notification " + aTopic);
mm.removeMessageListener("Test:ExpectObserverCalled:Reply", listener);
resolve();
});
mm.sendAsyncMessage("Test:ExpectObserverCalled", aTopic);
mm.sendAsyncMessage("Test:ExpectObserverCalled", {topic: aTopic, count: aCount});
});
}
@ -256,6 +256,24 @@ function promiseMessageReceived() {
});
}
function promiseSpecificMessageReceived(aMessage, aCount = 1) {
return new Promise(resolve => {
let mm = _mm();
let counter = 0;
mm.addMessageListener("Test:MessageReceived", function listener({data}) {
if (data == aMessage) {
counter++;
if (counter == aCount) {
mm.sendAsyncMessage("Test:StopWaitForMultipleMessages");
mm.removeMessageListener("Test:MessageReceived", listener);
resolve(data);
}
}
});
mm.sendAsyncMessage("Test:WaitForMultipleMessages");
});
}
function promiseMessage(aMessage, aAction) {
let promise = new Promise((resolve, reject) => {
promiseMessageReceived(aAction).then(data => {
@ -370,15 +388,16 @@ async function stopSharing(aType = "camera", aShouldKeepSharing = false) {
}
function promiseRequestDevice(aRequestAudio, aRequestVideo, aFrameId, aType,
aBrowser = gBrowser.selectedBrowser) {
aBrowser = gBrowser.selectedBrowser,
aBadDevice = false) {
info("requesting devices");
return ContentTask.spawn(aBrowser,
{aRequestAudio, aRequestVideo, aFrameId, aType},
{aRequestAudio, aRequestVideo, aFrameId, aType, aBadDevice},
async function(args) {
let global = content.wrappedJSObject;
if (args.aFrameId)
global = global.document.getElementById(args.aFrameId).contentWindow;
global.requestDevice(args.aRequestAudio, args.aRequestVideo, args.aType);
global.requestDevice(args.aRequestAudio, args.aRequestVideo, args.aType, args.aBadDevice);
});
}