diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /dom/media/test/browser/wmfme | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
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.toml | 13 | ||||
-rw-r--r-- | dom/media/test/browser/wmfme/browser_wmfme_crash.js | 52 | ||||
-rw-r--r-- | dom/media/test/browser/wmfme/browser_wmfme_max_crashes.js | 69 | ||||
-rw-r--r-- | dom/media/test/browser/wmfme/file_video.html | 9 | ||||
-rw-r--r-- | dom/media/test/browser/wmfme/head.js | 201 |
5 files changed, 344 insertions, 0 deletions
diff --git a/dom/media/test/browser/wmfme/browser.toml b/dom/media/test/browser/wmfme/browser.toml new file mode 100644 index 0000000000..422ea29228 --- /dev/null +++ b/dom/media/test/browser/wmfme/browser.toml @@ -0,0 +1,13 @@ +[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..57064cfe8d --- /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", 1], + ["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.startLoadingURIString(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..8cc8dc08b8 --- /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", 1], + ["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.startLoadingURIString(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..1e6f3b18bb --- /dev/null +++ b/dom/media/test/browser/wmfme/head.js @@ -0,0 +1,201 @@ +"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; + Assert.strictEqual( + 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" + ); + Assert.strictEqual(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?"); + } + } + ); +} |