summaryrefslogtreecommitdiffstats
path: root/dom/media/test/browser/wmfme
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
commit6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch)
treea68f146d7fa01f0134297619fbe7e33db084e0aa /dom/media/test/browser/wmfme
parentInitial commit. (diff)
downloadthunderbird-upstream.tar.xz
thunderbird-upstream.zip
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/media/test/browser/wmfme')
-rw-r--r--dom/media/test/browser/wmfme/browser.ini11
-rw-r--r--dom/media/test/browser/wmfme/browser_wmfme_crash.js52
-rw-r--r--dom/media/test/browser/wmfme/browser_wmfme_max_crashes.js69
-rw-r--r--dom/media/test/browser/wmfme/file_video.html9
-rw-r--r--dom/media/test/browser/wmfme/head.js200
5 files changed, 341 insertions, 0 deletions
diff --git a/dom/media/test/browser/wmfme/browser.ini b/dom/media/test/browser/wmfme/browser.ini
new file mode 100644
index 0000000000..9913bdb19e
--- /dev/null
+++ b/dom/media/test/browser/wmfme/browser.ini
@@ -0,0 +1,11 @@
+[DEFAULT]
+subsuite = media-bc
+tags = media-engine-compatible
+run-if = wmfme
+support-files =
+ head.js
+ file_video.html
+ ../../gizmo.mp4
+
+[browser_wmfme_crash.js]
+[browser_wmfme_max_crashes.js]
diff --git a/dom/media/test/browser/wmfme/browser_wmfme_crash.js b/dom/media/test/browser/wmfme/browser_wmfme_crash.js
new file mode 100644
index 0000000000..8ebe582595
--- /dev/null
+++ b/dom/media/test/browser/wmfme/browser_wmfme_crash.js
@@ -0,0 +1,52 @@
+"use strict";
+
+/**
+ * This test aims to ensure that the media engine playback will recover from a
+ * crash and keep playing without any problem.
+ */
+add_task(async function setupTestingPref() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["media.wmf.media-engine.enabled", true],
+ ["media.wmf.media-engine.channel-decoder.enabled", true],
+ ],
+ });
+});
+
+const VIDEO_PAGE = GetTestWebBasedURL("file_video.html");
+
+add_task(async function testPlaybackRecoveryFromCrash() {
+ info(`Create a tab and load test page`);
+ let tab = await BrowserTestUtils.openNewForegroundTab(
+ window.gBrowser,
+ "about:blank"
+ );
+ BrowserTestUtils.loadURIString(tab.linkedBrowser, VIDEO_PAGE);
+ await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+
+ await playVideo(tab);
+
+ info("Ensure video is running via the media engine framework");
+ await assertRunningProcessAndDecoderName(tab, {
+ expectedProcess: "Utility MF Media Engine CDM",
+ expectedDecoder: "media engine video stream",
+ });
+
+ const pidBeforeCrash = await getMFCDMProcessId();
+ await crashUtilityProcess(pidBeforeCrash);
+
+ info("The CDM process should be recreated which makes media keep playing");
+ await assertRunningProcessAndDecoderName(tab, {
+ expectedProcess: "Utility MF Media Engine CDM",
+ expectedDecoder: "media engine video stream",
+ });
+
+ const pidAfterCrash = await getMFCDMProcessId();
+ isnot(
+ pidBeforeCrash,
+ pidAfterCrash,
+ `new process ${pidAfterCrash} is not previous crashed one ${pidBeforeCrash}`
+ );
+
+ BrowserTestUtils.removeTab(tab);
+});
diff --git a/dom/media/test/browser/wmfme/browser_wmfme_max_crashes.js b/dom/media/test/browser/wmfme/browser_wmfme_max_crashes.js
new file mode 100644
index 0000000000..4472814171
--- /dev/null
+++ b/dom/media/test/browser/wmfme/browser_wmfme_max_crashes.js
@@ -0,0 +1,69 @@
+"use strict";
+
+/**
+ * This test aims to ensure that the MFCDM process won't be recovered once the
+ * amount of crashes has exceeded the amount of value which we tolerate.
+ */
+add_task(async function setupTestingPref() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["media.wmf.media-engine.enabled", true],
+ ["media.wmf.media-engine.channel-decoder.enabled", true],
+ ],
+ });
+});
+
+const VIDEO_PAGE = GetTestWebBasedURL("file_video.html");
+
+add_task(async function testPlaybackRecoveryFromCrash() {
+ const maxCrashes = Services.prefs.getIntPref(
+ "media.wmf.media-engine.max-crashes"
+ );
+ info(`The amount of tolerable crashes=${maxCrashes}`);
+
+ info(`Create a tab and load test page`);
+ let tab = await BrowserTestUtils.openNewForegroundTab(
+ window.gBrowser,
+ "about:blank"
+ );
+ BrowserTestUtils.loadURIString(tab.linkedBrowser, VIDEO_PAGE);
+ await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+
+ await playVideo(tab);
+
+ info("Ensure video is running via the media engine framework");
+ await assertRunningProcessAndDecoderName(tab, {
+ expectedProcess: "Utility MF Media Engine CDM",
+ expectedDecoder: "media engine video stream",
+ });
+
+ let pidBeforeCrash, pidAfterCrash;
+ for (let idx = 0; idx < maxCrashes; idx++) {
+ pidBeforeCrash = await getMFCDMProcessId();
+ await crashUtilityProcess(pidBeforeCrash);
+
+ info("The CDM process should be recreated which makes media keep playing");
+ await assertRunningProcessAndDecoderName(tab, {
+ expectedProcess: "Utility MF Media Engine CDM",
+ expectedDecoder: "media engine video stream",
+ });
+
+ pidAfterCrash = await getMFCDMProcessId();
+ isnot(
+ pidBeforeCrash,
+ pidAfterCrash,
+ `new process ${pidAfterCrash} is not previous crashed one ${pidBeforeCrash}`
+ );
+ }
+
+ info("This crash should result in not spawning MFCDM process again");
+ pidBeforeCrash = await getMFCDMProcessId();
+ await crashUtilityProcess(pidBeforeCrash);
+
+ await assertNotEqualRunningProcessAndDecoderName(tab, {
+ givenProcess: "Utility MF Media Engine CDM",
+ givenDecoder: "media engine video stream",
+ });
+
+ BrowserTestUtils.removeTab(tab);
+});
diff --git a/dom/media/test/browser/wmfme/file_video.html b/dom/media/test/browser/wmfme/file_video.html
new file mode 100644
index 0000000000..3c70268fbb
--- /dev/null
+++ b/dom/media/test/browser/wmfme/file_video.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>video</title>
+</head>
+<body>
+<video id="v" src="gizmo.mp4" controls loop></video>
+</body>
+</html>
diff --git a/dom/media/test/browser/wmfme/head.js b/dom/media/test/browser/wmfme/head.js
new file mode 100644
index 0000000000..2524287870
--- /dev/null
+++ b/dom/media/test/browser/wmfme/head.js
@@ -0,0 +1,200 @@
+"use strict";
+
+/**
+ * Return a web-based URL for a given file based on the testing directory.
+ * @param {String} fileName
+ * file that caller wants its web-based url
+ * @param {Boolean} cors [optional]
+ * if set, then return a url with different origin
+ */
+function GetTestWebBasedURL(fileName) {
+ const origin = "https://example.com";
+ return (
+ getRootDirectory(gTestPath).replace("chrome://mochitests/content", origin) +
+ fileName
+ );
+}
+
+/**
+ * Return current process Id for the Media Foundation CDM process.
+ */
+async function getMFCDMProcessId() {
+ const process = (await ChromeUtils.requestProcInfo()).children.find(
+ p =>
+ p.type === "utility" &&
+ p.utilityActors.find(a => a.actorName === "mfMediaEngineCDM")
+ );
+ return process.pid;
+}
+
+/**
+ * Make the utility process with given process id crash.
+ * @param {int} pid
+ * the process id for the process which is going to crash
+ */
+async function crashUtilityProcess(utilityPid) {
+ info(`Crashing process ${utilityPid}`);
+ SimpleTest.expectChildProcessCrash();
+
+ const crashMan = Services.crashmanager;
+ const utilityProcessGone = TestUtils.topicObserved(
+ "ipc:utility-shutdown",
+ (subject, data) => {
+ info(`ipc:utility-shutdown: data=${data} subject=${subject}`);
+ return parseInt(data, 10) === utilityPid;
+ }
+ );
+
+ info("Prune any previous crashes");
+ const future = new Date(Date.now() + 1000 * 60 * 60 * 24);
+ await crashMan.pruneOldCrashes(future);
+
+ info("Crash Utility Process");
+ const ProcessTools = Cc["@mozilla.org/processtools-service;1"].getService(
+ Ci.nsIProcessToolsService
+ );
+
+ info(`Crash Utility Process ${utilityPid}`);
+ ProcessTools.crash(utilityPid);
+
+ info(`Waiting for utility process ${utilityPid} to go away.`);
+ let [subject, data] = await utilityProcessGone;
+ ok(
+ parseInt(data, 10) === utilityPid,
+ `Should match the crashed PID ${utilityPid} with ${data}`
+ );
+ ok(
+ subject instanceof Ci.nsIPropertyBag2,
+ "Subject needs to be a nsIPropertyBag2 to clean up properly"
+ );
+
+ const dumpID = subject.getPropertyAsAString("dumpID");
+ ok(dumpID, "There should be a dumpID");
+
+ await crashMan.ensureCrashIsPresent(dumpID);
+ await crashMan.getCrashes().then(crashes => {
+ is(crashes.length, 1, "There should be only one record");
+ const crash = crashes[0];
+ ok(
+ crash.isOfType(
+ crashMan.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_UTILITY],
+ crashMan.CRASH_TYPE_CRASH
+ ),
+ "Record should be a utility process crash"
+ );
+ ok(crash.id === dumpID, "Record should have an ID");
+ });
+
+ let minidumpDirectory = Services.dirsvc.get("ProfD", Ci.nsIFile);
+ minidumpDirectory.append("minidumps");
+
+ let dumpfile = minidumpDirectory.clone();
+ dumpfile.append(dumpID + ".dmp");
+ if (dumpfile.exists()) {
+ info(`Removal of ${dumpfile.path}`);
+ dumpfile.remove(false);
+ }
+
+ let extrafile = minidumpDirectory.clone();
+ extrafile.append(dumpID + ".extra");
+ info(`Removal of ${extrafile.path}`);
+ if (extrafile.exists()) {
+ extrafile.remove(false);
+ }
+}
+
+/**
+ * Make video in the tab play.
+ * @param {object} tab
+ * the tab contains at least one video element
+ */
+async function playVideo(tab) {
+ return SpecialPowers.spawn(tab.linkedBrowser, [], async _ => {
+ const video = content.document.querySelector("video");
+ ok(
+ await video.play().then(
+ () => true,
+ () => false
+ ),
+ "video started playing"
+ );
+ });
+}
+
+/**
+ * Check whether the video playback is performed in the right process and right decoder.
+ * @param {object} tab
+ * the tab which has a playing video
+ * @param {string} expectedProcess
+ * the expected process name
+ * @param {string} expectedDecoder
+ * the expected decoder name
+ */
+async function assertRunningProcessAndDecoderName(
+ tab,
+ { expectedProcess, expectedDecoder } = {}
+) {
+ return SpecialPowers.spawn(
+ tab.linkedBrowser,
+ [expectedProcess, expectedDecoder],
+ // eslint-disable-next-line no-shadow
+ async (expectedProcess, expectedDecoder) => {
+ const video = content.document.querySelector("video");
+ ok(!video.paused, "checking a playing video");
+
+ const debugInfo = await SpecialPowers.wrap(video).mozRequestDebugInfo();
+ const videoDecoderName = debugInfo.decoder.reader.videoDecoderName;
+
+ const isExpectedDecoder =
+ videoDecoderName.indexOf(`${expectedDecoder}`) == 0;
+ ok(
+ isExpectedDecoder,
+ `Playback running by decoder '${videoDecoderName}', expected '${expectedDecoder}'`
+ );
+
+ const isExpectedProcess =
+ videoDecoderName.indexOf(`(${expectedProcess} remote)`) > 0;
+ ok(
+ isExpectedProcess,
+ `Playback running in process '${videoDecoderName}', expected '${expectedProcess}'`
+ );
+ }
+ );
+}
+
+/**
+ * Check whether the video playback is not performed in the given process and given decoder.
+ * @param {object} tab
+ * the tab which has a playing video
+ * @param {string} givenProcess
+ * the process name on which the video playback should not be running
+ * @param {string} givenDecoder
+ * the decoder name with which the video playback should not be running
+ */
+async function assertNotEqualRunningProcessAndDecoderName(
+ tab,
+ { givenProcess, givenDecoder } = {}
+) {
+ return SpecialPowers.spawn(
+ tab.linkedBrowser,
+ [givenProcess, givenDecoder],
+ // eslint-disable-next-line no-shadow
+ async (givenProcess, givenDecoder) => {
+ const video = content.document.querySelector("video");
+ ok(!video.paused, "checking a playing video");
+
+ const debugInfo = await SpecialPowers.wrap(video).mozRequestDebugInfo();
+ const videoDecoderName = debugInfo.decoder.reader.videoDecoderName;
+ const pattern = /(.+?)\s+\((\S+)\s+remote\)/;
+ const match = videoDecoderName.match(pattern);
+ if (match) {
+ const decoder = match[1];
+ const process = match[2];
+ isnot(decoder, givenDecoder, `Decoder name is not equal`);
+ isnot(process, givenProcess, `Process name is not equal`);
+ } else {
+ ok(false, "failed to match decoder/process name?");
+ }
+ }
+ );
+}