tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

browser_encrypted_play_time_telemetry.js (6743B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 // This test verifies that telemetry gathered around encrypted media playtime
      6 // is gathered as expected.
      7 
      8 "use strict";
      9 
     10 /* import-globals-from ../eme_standalone.js */
     11 
     12 // Clears any existing telemetry data that has been accumulated. Returns a
     13 // promise the will be resolved once the telemetry store is clear.
     14 async function clearTelemetry() {
     15  // There's an arbitrary interval of 2 seconds in which the content
     16  // processes sync their event data with the parent process, we wait
     17  // this out to ensure that we clear everything that is left over from
     18  // previous tests and don't receive random events in the middle of our tests.
     19  // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
     20  await new Promise(resolve => setTimeout(resolve, 2000));
     21 
     22  Services.telemetry.clearEvents();
     23  return TestUtils.waitForCondition(() => {
     24    let events = Services.telemetry.snapshotEvents(
     25      Ci.nsITelemetry.DATASET_ALL_CHANNELS,
     26      true
     27    ).content;
     28    return !events || !events.length;
     29  });
     30 }
     31 
     32 // Plays the media in `tab` until the 'ended' event is fire. Returns a promise
     33 // that resolves once that state has been reached.
     34 async function playMediaThrough(tab) {
     35  return SpecialPowers.spawn(tab.linkedBrowser, [], async () => {
     36    let video = content.document.getElementById("media");
     37    await Promise.all([new Promise(r => (video.onended = r)), video.play()]);
     38  });
     39 }
     40 
     41 // Plays the media in `tab` until the 'timeupdate' event is fire. Returns a
     42 // promise that resolves once that state has been reached.
     43 async function playMediaToTimeUpdate(tab) {
     44  return SpecialPowers.spawn(tab.linkedBrowser, [], async () => {
     45    let video = content.document.getElementById("media");
     46    await Promise.all([
     47      new Promise(r => (video.ontimeupdate = r)),
     48      video.play(),
     49    ]);
     50  });
     51 }
     52 
     53 // Aborts existing loads and replaces the media on the media element with an
     54 // unencrypted file.
     55 async function replaceMediaWithUnencrypted(tab) {
     56  return SpecialPowers.spawn(tab.linkedBrowser, [], async () => {
     57    let video = content.document.getElementById("media");
     58    video.src = "gizmo.mp4";
     59    video.load();
     60  });
     61 }
     62 
     63 // Clears/nulls the media keys on the media in `tab`.
     64 async function clearMediaKeys(tab) {
     65  return SpecialPowers.spawn(tab.linkedBrowser, [], async () => {
     66    let video = content.document.getElementById("media");
     67    await video.setMediaKeys(null);
     68  });
     69 }
     70 
     71 // Wait for telemetry information to be received from the content process
     72 // then get the relevant histograms for the tests and return the sums of
     73 // those histograms. If a histogram does not exist this will return a 0
     74 // sum. Returns a promise the resolves to an object with sums for
     75 // - VIDEO_PLAY_TIME_MS
     76 // - VIDEO_ENCRYPTED_PLAY_TIME_MS
     77 // - VIDEO_CLEARKEY_PLAY_TIME_MS
     78 // This function clears the histograms as it gets them.
     79 async function getTelemetrySums() {
     80  // The telemetry was gathered in the content process, so we have to wait
     81  // until is arrived in the parent to check it. At time of writing there's
     82  // not a more elegant way of doing this than polling.
     83  return TestUtils.waitForCondition(() => {
     84    let histograms = Services.telemetry.getSnapshotForHistograms(
     85      "main",
     86      true
     87    ).content;
     88    // All the histogram data should come at the same time, so we just check
     89    // for playtime here as we always expect it in these tests, but we'll
     90    // grab other values if present.
     91    if (histograms.VIDEO_PLAY_TIME_MS) {
     92      // We only expect to have one value for each histogram, so returning the
     93      // sums is a short hand for returning that one value.
     94      return {
     95        VIDEO_PLAY_TIME_MS: histograms.VIDEO_PLAY_TIME_MS.sum,
     96        VIDEO_ENCRYPTED_PLAY_TIME_MS: histograms.VIDEO_ENCRYPTED_PLAY_TIME_MS
     97          ? histograms.VIDEO_ENCRYPTED_PLAY_TIME_MS.sum
     98          : 0,
     99        VIDEO_CLEARKEY_PLAY_TIME_MS: histograms.VIDEO_CLEARKEY_PLAY_TIME_MS
    100          ? histograms.VIDEO_CLEARKEY_PLAY_TIME_MS.sum
    101          : 0,
    102      };
    103    }
    104    return null;
    105  }, "recorded telemetry from playing media");
    106 }
    107 
    108 // Clear telemetry before other tests. Internally the tests clear the telemetry
    109 // when they check it, so we shouldn't need to do this between tests.
    110 add_task(clearTelemetry);
    111 
    112 add_task(async function testEncryptedMediaPlayback() {
    113  let testTab = await openTab();
    114 
    115  await loadEmeVideo(testTab);
    116  await playMediaThrough(testTab);
    117 
    118  BrowserTestUtils.removeTab(testTab);
    119 
    120  let telemetrySums = await getTelemetrySums();
    121 
    122  ok(telemetrySums, "Should get play time telemetry");
    123  is(
    124    telemetrySums.VIDEO_PLAY_TIME_MS,
    125    telemetrySums.VIDEO_ENCRYPTED_PLAY_TIME_MS,
    126    "Play time should be the same as encrypted play time"
    127  );
    128  is(
    129    telemetrySums.VIDEO_PLAY_TIME_MS,
    130    telemetrySums.VIDEO_CLEARKEY_PLAY_TIME_MS,
    131    "Play time should be the same as clearkey play time"
    132  );
    133  Assert.greater(
    134    telemetrySums.VIDEO_PLAY_TIME_MS,
    135    0,
    136    "Should have a play time greater than zero"
    137  );
    138 });
    139 
    140 add_task(async function testChangingFromEncryptedToUnencrypted() {
    141  let testTab = await openTab();
    142 
    143  await loadEmeVideo(testTab);
    144  await replaceMediaWithUnencrypted(testTab);
    145  await playMediaToTimeUpdate(testTab);
    146 
    147  BrowserTestUtils.removeTab(testTab);
    148 
    149  let telemetrySums = await getTelemetrySums();
    150 
    151  ok(telemetrySums, "Should get play time telemetry");
    152  is(
    153    telemetrySums.VIDEO_ENCRYPTED_PLAY_TIME_MS,
    154    0,
    155    "Encrypted play time should be 0"
    156  );
    157  is(
    158    telemetrySums.VIDEO_PLAY_TIME_MS,
    159    telemetrySums.VIDEO_CLEARKEY_PLAY_TIME_MS,
    160    "Play time should be the same as clearkey play time because the media element still has a media keys attached"
    161  );
    162  Assert.greater(
    163    telemetrySums.VIDEO_PLAY_TIME_MS,
    164    0,
    165    "Should have a play time greater than zero"
    166  );
    167 });
    168 
    169 add_task(
    170  async function testChangingFromEncryptedToUnencryptedAndClearingMediaKeys() {
    171    let testTab = await openTab();
    172 
    173    await loadEmeVideo(testTab);
    174    await replaceMediaWithUnencrypted(testTab);
    175    await clearMediaKeys(testTab);
    176    await playMediaToTimeUpdate(testTab);
    177 
    178    BrowserTestUtils.removeTab(testTab);
    179 
    180    let telemetrySums = await getTelemetrySums();
    181 
    182    ok(telemetrySums, "Should get play time telemetry");
    183    is(
    184      telemetrySums.VIDEO_ENCRYPTED_PLAY_TIME_MS,
    185      0,
    186      "Encrypted play time should be 0"
    187    );
    188    is(
    189      telemetrySums.VIDEO_CLEARKEY_PLAY_TIME_MS,
    190      0,
    191      "Clearkey play time should be 0"
    192    );
    193    Assert.greater(
    194      telemetrySums.VIDEO_PLAY_TIME_MS,
    195      0,
    196      "Should have a play time greater than zero"
    197    );
    198  }
    199 );