summaryrefslogtreecommitdiffstats
path: root/ipc/glue/test/browser/head-telemetry.js
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/glue/test/browser/head-telemetry.js')
-rw-r--r--ipc/glue/test/browser/head-telemetry.js205
1 files changed, 205 insertions, 0 deletions
diff --git a/ipc/glue/test/browser/head-telemetry.js b/ipc/glue/test/browser/head-telemetry.js
new file mode 100644
index 0000000000..64a6aee1c4
--- /dev/null
+++ b/ipc/glue/test/browser/head-telemetry.js
@@ -0,0 +1,205 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/* import-globals-from head.js */
+
+const Telemetry = Services.telemetry;
+
+const { TelemetryController } = ChromeUtils.importESModule(
+ "resource://gre/modules/TelemetryController.sys.mjs"
+);
+
+/* eslint-disable mozilla/no-redeclare-with-import-autofix */
+const { ContentTaskUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/ContentTaskUtils.sys.mjs"
+);
+
+const MEDIA_AUDIO_PROCESS = "media.audio_process_per_codec_name";
+
+const utilityPerCodecs = {
+ Linux: [
+ {
+ process: "utility+audioDecoder_Generic",
+ codecs: ["vorbis", "mp3", "aac", "flac"],
+ },
+ ],
+ WINNT: [
+ {
+ process: "utility+audioDecoder_Generic",
+ codecs: ["vorbis", "mp3", "flac"],
+ },
+ {
+ process: "utility+audioDecoder_WMF",
+ codecs: ["aac"],
+ },
+ ],
+ Darwin: [
+ {
+ process: "utility+audioDecoder_Generic",
+ codecs: ["vorbis", "mp3", "flac"],
+ },
+ {
+ process: "utility+audioDecoder_AppleMedia",
+ codecs: ["aac"],
+ },
+ ],
+};
+
+const kInterval = 300; /* ms */
+const kRetries = 5;
+
+/**
+ * This function waits until utility scalars are reported into the
+ * scalar snapshot.
+ */
+async function waitForKeyedScalars(process) {
+ await ContentTaskUtils.waitForCondition(
+ () => {
+ const scalars = Telemetry.getSnapshotForKeyedScalars("main", false);
+ return Object.keys(scalars).includes("content");
+ },
+ `Waiting for ${process} scalars to have been set`,
+ kInterval,
+ kRetries
+ );
+}
+
+async function waitForValue(process, codecNames, extra = "") {
+ await ContentTaskUtils.waitForCondition(
+ () => {
+ const telemetry = Telemetry.getSnapshotForKeyedScalars(
+ "main",
+ false
+ ).content;
+ if (telemetry && MEDIA_AUDIO_PROCESS in telemetry) {
+ const keyProcMimeTypes = Object.keys(telemetry[MEDIA_AUDIO_PROCESS]);
+ const found = codecNames.every(item =>
+ keyProcMimeTypes.includes(`${process},${item}${extra}`)
+ );
+ return found;
+ }
+ return false;
+ },
+ `Waiting for ${MEDIA_AUDIO_PROCESS}`,
+ kInterval,
+ kRetries
+ );
+}
+
+async function runTest({ expectUtility = false, expectRDD = false }) {
+ info(
+ `Running tests with decoding from Utility or RDD: expectUtility=${expectUtility} expectRDD=${expectRDD}`
+ );
+
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["media.utility-process.enabled", expectUtility],
+ ["media.rdd-process.enabled", expectRDD],
+ ["toolkit.telemetry.ipcBatchTimeout", 0],
+ ],
+ });
+
+ const platform = Services.appinfo.OS;
+
+ for (let { src, expectations } of audioTestData()) {
+ if (!(platform in expectations)) {
+ info(`Skipping ${src} for ${platform}`);
+ continue;
+ }
+
+ const expectation = expectations[platform];
+
+ info(`Add media tab: ${src}`);
+ let tab = await addMediaTab(src);
+
+ info("Play tab");
+ await play(
+ tab,
+ expectUtility ? expectation.process : "RDD",
+ expectation.decoder,
+ !expectUtility && !expectRDD
+ );
+
+ info("Stop tab");
+ await stop(tab);
+
+ info("Remove tab");
+ await BrowserTestUtils.removeTab(tab);
+ }
+}
+
+function getTelemetry() {
+ const telemetry = Telemetry.getSnapshotForKeyedScalars("main", false).content;
+ return telemetry;
+}
+
+async function verifyTelemetryForProcess(process, codecNames, extraKey = "") {
+ // Once scalars are set by the utility process, they don't immediately get
+ // sent to the parent process. Wait for the Telemetry IPC Timer to trigger
+ // and batch send the data back to the parent process.
+ await waitForKeyedScalars(process);
+ await waitForValue(process, codecNames, extraKey);
+
+ const telemetry = getTelemetry();
+
+ // The amount here depends on how many times RemoteAudioDecoderParent::RemoteAudioDecoderParent
+ // gets called, which might be more than actual audio files being playback, e.g., we would get one for metadata loading, then one for playback etc.
+ // But we dont care really we just want to ensure 0 on RDD, Content and others
+ // in the wild.[${codecName}]
+ codecNames.forEach(codecName => {
+ Assert.equal(
+ telemetry[MEDIA_AUDIO_PROCESS][`${process},${codecName}${extraKey}`],
+ 1,
+ `${MEDIA_AUDIO_PROCESS} must have the correct value (${process}, ${codecName}).`
+ );
+ });
+}
+
+async function verifyNoTelemetryForProcess(process, codecNames, extraKey = "") {
+ try {
+ await waitForKeyedScalars(process);
+ await waitForValue(process, codecNames, extraKey);
+ } catch (ex) {
+ if (ex.indexOf("timed out after") > 0) {
+ Assert.ok(
+ true,
+ `Expected timeout ${process}[${MEDIA_AUDIO_PROCESS}] for ${codecNames}`
+ );
+ } else {
+ Assert.ok(
+ false,
+ `Unexpected exception on ${process}[${MEDIA_AUDIO_PROCESS}] for ${codecNames}: ${ex}`
+ );
+ }
+ }
+
+ const telemetry = getTelemetry();
+
+ // There could be races with telemetry for power usage coming up
+ codecNames.forEach(codecName => {
+ if (telemetry) {
+ if (telemetry && MEDIA_AUDIO_PROCESS in telemetry) {
+ Assert.ok(
+ !(
+ `${process},${codecName}${extraKey}` in
+ telemetry[MEDIA_AUDIO_PROCESS]
+ ),
+ `Some telemetry but no ${process}[${MEDIA_AUDIO_PROCESS}][${codecName}]`
+ );
+ } else {
+ Assert.ok(
+ !(MEDIA_AUDIO_PROCESS in telemetry),
+ `No telemetry for ${process}[${MEDIA_AUDIO_PROCESS}][${codecName}]`
+ );
+ }
+ } else {
+ Assert.equal(
+ undefined,
+ telemetry,
+ `No telemetry for ${process}[${MEDIA_AUDIO_PROCESS}][${codecName}]`
+ );
+ }
+ });
+}