Bug 1284177 - P2: Video decode suspend mochitests. r?jwwang
Test:
- That video decode suspends when enabled and delay is reached.
- That video decode doesn't suspend when disabled.
- That video decode doesn't suspend when video finishes before suspend delay.
These tests need to run from content process to observe the suspend
notifications via nsIObserverService, but access to gBrowser is in
chrome process in e10s. Thus, the reason for loading
background_video_chrome.js into chrome process and invoking functions
via async messages.
MozReview-Commit-ID: 2eE97FEUMPu
new file mode 100644
--- /dev/null
+++ b/dom/media/test/background_video.js
@@ -0,0 +1,109 @@
+/* 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, info, is, ok */
+
+"use strict";
+
+function startTest(test) {
+ info(test.desc);
+ SimpleTest.waitForExplicitFinish();
+ SpecialPowers.pushPrefEnv({ 'set': test.prefs }, () => {
+ manager.runTests(test.tests, test.runTest);
+ });
+}
+
+/**
+ * @param {string} url video src.
+ * @returns {HTMLMediaElement} The created video element.
+ */
+function appendVideoToDoc(url, token) {
+ let v = document.createElement('video');
+ v.token = token;
+ document.body.appendChild(v);
+ v.src = url;
+ return v;
+}
+
+/**
+ * @param {HTMLMediaElement} video Video element under test.
+ * @returns {Promise} Promise that is resolved when video 'playing' event fires and rejected on error.
+ */
+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.success();
+ }
+
+ 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 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 {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();
+ }
+ });
+ });
+}
\ No newline at end of file
--- a/dom/media/test/mochitest.ini
+++ b/dom/media/test/mochitest.ini
@@ -35,16 +35,17 @@ support-files =
VID_0001.ogg^headers^
allowed.sjs
audio-gaps.ogg
audio-gaps.ogg^headers^
audio-overhang.ogg
audio-overhang.ogg^headers^
audio.wav
audio.wav^headers^
+ background_video.js
badtags.ogg
badtags.ogg^headers^
basic.vtt
bad-signature.vtt
beta-phrasebook.ogg
beta-phrasebook.ogg^headers^
big.wav
big.wav^headers^
@@ -878,8 +879,15 @@ tags = webvtt
tags = webvtt
# The tests below contain backend-specific tests. Write backend independent
# tests rather than adding to this list.
[test_can_play_type_webm.html]
[test_can_play_type_wave.html]
[test_fragment_noplay.html]
[test_fragment_play.html]
+
+[test_background_video_suspend.html]
+tags = suspend
+[test_background_video_no_suspend_short_vid.html]
+tags = suspend
+[test_background_video_no_suspend_disabled.html]
+tags = suspend
new file mode 100644
--- /dev/null
+++ b/dom/media/test/test_background_video_no_suspend_disabled.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Test Background Video Doesn't Suspend When Feature Disabled</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="manifest.js"></script>
+<script src="background_video.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+<p id="display">
+<div id="content" style="display:none"></div>
+<pre id="test">
+<script>
+"use strict";
+
+var manager = new MediaTestManager;
+
+startTest({
+ desc: "Test Background Video Doesn't Suspend When Feature Disabled.",
+ prefs: [
+ [ 'media.test.setVisible', true ],
+ [ 'media.suspend-bkgnd-video.enabled', false ],
+ [ 'media.suspend-bkgnd-video.delay-ms', 0 ]
+ ],
+ tests: [ { name: "gizmo.mp4" } ],
+ runTest: (test, token) => {
+ let v = appendVideoToDoc(test.name, token);
+ manager.started(token);
+
+ /* This test checks that suspend doesn't occur when the feature is disabled */
+ waitUntilPlaying(v)
+ .then(() => checkVideoDoesntSuspend(v))
+ .then(() => {
+ ok(true, 'Video ended before decode was suspended');
+ manager.finished(token); })
+ .catch((e) => {
+ ok(false, 'Test Failed: ' + e.toString());
+ manager.finished(token); });
+ }
+});
+</script>
+</pre>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/media/test/test_background_video_no_suspend_short_vid.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Test Background Video Doesn't Suspend When Timeout Is Longer Than Video</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="manifest.js"></script>
+<script src="background_video.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+<p id="display">
+<div id="content" style="display:none"></div>
+<pre id="test">
+<script>
+"use strict";
+
+var manager = new MediaTestManager;
+
+startTest({
+ desc: "Test Background Video Doesn't Suspend When Timeout Is Longer Than Video.",
+ prefs: [
+ [ 'media.test.setVisible', true ],
+ [ 'media.suspend-bkgnd-video.enabled', true ],
+ // Gizmo.mp4 is about 5.6s
+ [ 'media.suspend-bkgnd-video.delay-ms', 10000 ]
+ ],
+ tests: [ { name: "gizmo.mp4" } ],
+ runTest: (test, token) => {
+ let v = appendVideoToDoc(test.name, token);
+ manager.started(token);
+
+ /* This test checks that suspend doesn't occur when the delay is longer
+ than the duration of the video that's playing */
+ waitUntilPlaying(v)
+ .then(() => checkVideoDoesntSuspend(v))
+ .then(() => {
+ ok(true, 'Video ended before decode was suspended');
+ manager.finished(token); })
+ .catch((e) => {
+ ok(false, 'Test Failed: ' + e.toString());
+ manager.finished(token); });
+ }
+});
+</script>
+</pre>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/media/test/test_background_video_suspend.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Test Background Video Suspends</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="manifest.js"></script>
+<script src="background_video.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+<p id="display">
+<div id="content" style="display: none"></div>
+<pre id="test">
+<script type="text/javascript">
+"use strict";
+
+var manager = new MediaTestManager;
+
+function testDelay(start, min, max) {
+ let end = performance.now();
+ let delay = end - start;
+ ok(delay > min && delay < max, "Video suspend with a delay of " + delay + " ms");
+}
+
+startTest({
+ desc: 'Test Background Video Suspends',
+ prefs: [
+ [ "media.test.setVisible", true ],
+ [ "media.suspend-bkgnd-video.enabled", true ],
+ // User a short delay to ensure video decode suspend happens before end
+ // of video.
+ [ "media.suspend-bkgnd-video.delay-ms", 1000 ]
+ ],
+ tests: [ { name: "gizmo.mp4" } ],
+ runTest: (test, token) => {
+ let v = appendVideoToDoc(test.name, token);
+ manager.started(token);
+
+ let start;
+ waitUntilPlaying(v)
+ .then(() => { start = performance.now(); })
+ .then(() => testVideoSuspendsWhenHidden(v))
+ .then(() => testDelay(start, 1000, 10000))
+ .then(() => waitTil(v, v.duration / 2))
+ .then(() => testVideoResumesWhenShown(v))
+ .then(() => waitUntilEnded(v))
+ .then(() => { manager.finished(token); });
+ }
+});
+</script>
+</pre>
\ No newline at end of file