Bug 1284177 - P2: Video decode suspend mochitests. r?jwwang draft
authorDan Glastonbury <dglastonbury@mozilla.com>
Mon, 04 Jul 2016 12:35:25 +1000
changeset 399489 de4deb24974f188be76d35afcc970ff42bb1e320
parent 399487 8ba6067aadb735f80aca04a1149d2b31b2f0f07e
child 399505 a567269e88fbf3a24a1764a84123cca18b84ebf4
child 399556 37d24bee206d98b39b1a6a0b93328e6923cb20c5
child 399557 3fb20ad96b879717ea6b2ba8d7ad91030ccffc26
push id25853
push userbmo:dglastonbury@mozilla.com
push dateThu, 11 Aug 2016 07:40:30 +0000
reviewersjwwang
bugs1284177
milestone51.0a1
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
dom/media/test/background_video.js
dom/media/test/mochitest.ini
dom/media/test/test_background_video_no_suspend_disabled.html
dom/media/test/test_background_video_no_suspend_short_vid.html
dom/media/test/test_background_video_suspend.html
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