Bug 1809985 - part1 : add a test to ensure that playback can be recovered from crash. r=jolin

Differential Revision: https://phabricator.services.mozilla.com/D166721
This commit is contained in:
alwu 2023-01-17 20:00:49 +00:00
Родитель 9ebf1f03a8
Коммит b6fd1283a6
5 изменённых файлов: 235 добавлений и 0 удалений

Просмотреть файл

@ -98,6 +98,7 @@ BROWSER_CHROME_MANIFESTS += [
"mediacontrol/tests/browser/browser.ini",
"mediasession/test/browser.ini",
"test/browser/browser.ini",
"test/browser/wmfme/browser.ini",
]
if CONFIG["MOZ_WEBRTC"]:

Просмотреть файл

@ -0,0 +1,10 @@
[DEFAULT]
subsuite = media-bc
tags = media-engine-compatible
run-if = wmfme
support-files =
head.js
file_video.html
../../gizmo.mp4
[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.loadURI(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);
});

Просмотреть файл

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<title>video</title>
</head>
<body>
<video id="v" src="gizmo.mp4" controls loop></video>
</body>
</html>

Просмотреть файл

@ -0,0 +1,163 @@
"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}'`
);
}
);
}