gecko-dev/dom/media/test/background_video.js
Chris Pearce dd45189315 Bug 1443942 - Rewrite test_mediarecorder_principals. r=bryce
I changed this test earlier in this set of commits to use
midflight-redirect.sjs so that we get more reliable and predictable cross
origin redirects during the download. Unfortunately this test now times out on
Windows.

This test times out on Windows because midflight-redirect.sjs redirects at 1/4
through the resource, whereas this test expects to be able to play through to
1/5 through the resource, and on Windows that seems to be not reached during
playback. This is likely due to decode latency being higher on Windows.

On top of that, the test's first case can sometimes call MediaRecorder.start()
before the redirect has happened, and before the principal has changed, and so
start() doesn't throw a SecurityError as expected, and the test intermittently
fails.

Additionally, the test's code could be clearer if we used async/await.

So rewrite the test to use async/await, and take advantage of
midflight-redirect.sjs's redirect being more predictable than the old
dynamic_redirect.sjs. Basically, we can be careful to wait for either
"loadedmetadata" or "error" on the media element in order to be more confident
the redirect has or hasn't happened yet.

We still can't be 100% sure that the redirect won't have already happened by
the time our "loadedmetadata" handlers run. It's quite possible that the
download has reached 1/4 through the resource by the time the loadedmetadata
handler has run, so we need to handle the "error" and "loadedmetadata" events
racing.

MozReview-Commit-ID: 8plMjkXgjYt

--HG--
extra : rebase_source : 7305598f40c09219494f3e7150799d8875b7c30e
2018-04-05 13:35:14 +12:00

159 lines
4.6 KiB
JavaScript

/* 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/. */
/* jshint esversion: 6, -W097 */
/* globals SimpleTest, SpecialPowers, document, info, is, manager, ok */
"use strict";
function startTest(test) {
info(test.desc);
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({ 'set': test.prefs }, () => {
manager.runTests(test.tests, test.runTest);
});
}
function nextVideoEnded(video) {
return nextEvent(video, 'ended');
}
function nextVideoPlaying(video) {
return nextEvent(video, 'playing');
}
function nextVideoResumes(video) {
return nextEvent(video, 'mozexitvideosuspend');
}
function nextVideoSuspends(video) {
return nextEvent(video, 'mozentervideosuspend');
}
/**
* @param {string} url video src.
* @returns {HTMLMediaElement} The created video element.
*/
function appendVideoToDoc(url, token, width, height) {
// Default size of (160, 120) is used by other media tests.
if (width === undefined) { width = 160; }
if (height === undefined) { height = 3 * width / 4; }
let v = document.createElement('video');
v.token = token;
v.width = width;
v.height = height;
v.src = url;
document.body.appendChild(v);
return v;
}
/**
* @param {HTMLMediaElement} video Video element under test.
* @returns {Promise} Promise that is resolved when video 'playing' event fires.
*/
function waitUntilPlaying(video) {
var p = once(video, 'playing', () => { ok(true, `${video.token} played.`); });
Log(video.token, "Start playing");
video.play();
return p;
}
/**
* @param {HTMLMediaElement} video Video element under test.
* @returns {Promise} Promise which is resolved when video 'ended' event fires.
*/
function waitUntilEnded(video) {
Log(video.token, "Waiting for ended");
if (video.ended) {
ok(true, video.token + " already ended");
return Promise.resolve();
}
return once(video, 'ended', () => { ok(true, `${video.token} ended`); });
}
/**
* @param {HTMLMediaElement} video Video element under test.
* @returns {Promise} Promise that is resolved when video decode starts
* suspend timer.
*/
function testSuspendTimerStartedWhenHidden(video) {
var p = once(video, 'mozstartvideosuspendtimer').then(() => {
ok(true, `${video.token} suspend begins`)
});
Log(video.token, 'Set Hidden');
video.setVisible(false);
return p;
}
/**
* @param {HTMLMediaElement} video Video element under test.
* @returns {Promise} Promise that is resolved when video decode suspends.
*/
function testVideoSuspendsWhenHidden(video) {
let p = once(video, 'mozentervideosuspend').then(() => {
ok(true, `${video.token} suspends`);
});
Log(video.token, "Set hidden");
video.setVisible(false);
return p;
}
/**
* @param {HTMLMediaElement} video Video element under test.
* @returns {Promise} Promise that is resolved when video decode resumes.
*/
function testVideoResumesWhenShown(video) {
var p = once(video, 'mozexitvideosuspend').then(() => {
ok(true, `${video.token} resumes`);
});
Log(video.token, "Set visible");
video.setVisible(true);
return p;
}
/**
* @param {HTMLMediaElement} video Video element under test.
* @returns {Promise} Promise that is resolved when video decode resumes.
*/
function testVideoOnlySeekCompletedWhenShown(video) {
var p = once(video, 'mozvideoonlyseekcompleted').then(() => {
ok(true, `${video.token} resumes`);
});
Log(video.token, "Set visible");
video.setVisible(true);
return p;
}
/**
* @param {HTMLVideoElement} video Video element under test.
* @returns {Promise} Promise that is resolved if video ends and rejects if video suspends.
*/
function checkVideoDoesntSuspend(video) {
let p = Promise.race([
waitUntilEnded(video).then(() => { ok(true, `${video.token} ended before decode was suspended`) }),
once(video, 'mozentervideosuspend', () => { Promise.reject(new Error(`${video.token} suspended`)) })
]);
Log(video.token, "Set hidden.");
video.setVisible(false);
return p;
}
/**
* @param {HTMLMediaElement} video Video element under test.
* @param {number} time video current time to wait til.
* @returns {Promise} Promise that is resolved once currentTime passes time.
*/
function waitTil(video, time) {
Log(video.token, `Waiting for time to reach ${time}s`);
return new Promise(resolve => {
video.addEventListener('timeupdate', function timeUpdateEvent() {
if (video.currentTime > time) {
video.removeEventListener(name, timeUpdateEvent);
resolve();
}
});
});
}