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 );