Bug 1145011 - Add test for waitingforkey. r=jya draft
authorBryce Van Dyk <bvandyk@mozilla.com>
Mon, 22 Aug 2016 08:52:45 +1200
changeset 403720 e7089e48d90739470686868541c9e8bfd6789dc0
parent 403719 2c61fc41636e430afa23240ad5d26c886124d87f
child 528978 4e7a552b4a3a84b0d2f3a210b0e3b9eb1b0af5ac
push id26988
push userbvandyk@mozilla.com
push dateSun, 21 Aug 2016 20:57:17 +0000
reviewersjya
bugs1145011
milestone51.0a1
Bug 1145011 - Add test for waitingforkey. r=jya MozReview-Commit-ID: LKlDd4wkRSE
dom/media/test/eme.js
dom/media/test/mochitest.ini
dom/media/test/test_eme_waitingforkey.html
--- a/dom/media/test/eme.js
+++ b/dom/media/test/eme.js
@@ -244,24 +244,26 @@ function LoadTest(test, elem, token, loa
         Log(token, "sourceopen again?");
         return;
       }
 
       firstOpen = false;
       Log(token, "sourceopen");
       return Promise.all(test.tracks.map(function(track) {
         return AppendTrack(test, ms, track, token, loadParams);
-      })).then(function(){
+      })).then(function() {
         if (loadParams && loadParams.noEndOfStream) {
           Log(token, "Tracks loaded");
         } else {
           Log(token, "Tracks loaded, calling MediaSource.endOfStream()");
           ms.endOfStream();
         }
         resolve();
+      }).catch(function() {
+        Log(token, "error while loading tracks");
       });
     })
   });
 }
 
 // Same as LoadTest, but manage a token+"_load" start&finished.
 // Also finish main token if loading fails.
 function LoadTestWithManagedLoadToken(test, elem, manager, token, loadParams)
@@ -294,38 +296,53 @@ function SetupEME(test, token, params)
         v.onerror = null;
         v.src = null;
       });
   };
 
   // Log events dispatched to make debugging easier...
   [ "canplay", "canplaythrough", "ended", "error", "loadeddata",
     "loadedmetadata", "loadstart", "pause", "play", "playing", "progress",
-    "stalled", "suspend", "waiting",
+    "stalled", "suspend", "waiting", "waitingforkey",
   ].forEach(function (e) {
     v.addEventListener(e, function(event) {
       Log(token, "" + e);
     }, false);
   });
 
   // Finish the test when error is encountered.
   v.onerror = bail(token + " got error event");
 
   var onSetKeysFail = (params && params.onSetKeysFail)
     ? params.onSetKeysFail
     : bail(token + " Failed to set MediaKeys on <video> element");
 
   // null: No session management in progress, just go ahead and update the session.
-  // [...]: Session management in progress, add [initDataType, initData] to
+  // [...]: Session management in progress, add {initDataType, initData} to
   //        this queue to get it processed when possible.
   var initDataQueue = [];
+  function pushInitData(ev)
+  {
+    if (initDataQueue === null) {
+      initDataQueue = [];
+    }
+    initDataQueue.push(ev);
+    if (params && params.onInitDataQueued) {
+      params.onInitDataQueued(ev, ev.initDataType, StringToHex(ArrayBufferToString(ev.initData)));
+    }
+  }
+
   function processInitDataQueue()
   {
     if (initDataQueue === null) { return; }
-    if (initDataQueue.length === 0) { initDataQueue = null; return; }
+    // If we're processed all our init data null the queue to indicate encrypted event handled.
+    if (initDataQueue.length === 0) {
+      initDataQueue = null;
+      return;
+    }
     var ev = initDataQueue.shift();
 
     var sessionType = (params && params.sessionType) ? params.sessionType : "temporary";
     Log(token, "createSession(" + sessionType + ") for (" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + ")");
     var session = v.mediaKeys.createSession(sessionType);
     if (params && params.onsessioncreated) {
       params.onsessioncreated(session);
     }
@@ -351,24 +368,29 @@ function SetupEME(test, token, params)
     });
   }
 
   function streamType(type) {
     var x = test.tracks.find(o => o.name == type);
     return x ? x.type : undefined;
   }
 
-  // All 'initDataType's should be the same.
-  // null indicates no 'encrypted' event received yet.
-  var initDataType = null;
+  // If sessions are to be delayed we won't peform any processing until the
+  // callback the assigned here is called by the test.
+  if (params && params.delaySessions) {
+    params.ProcessSessions = processInitDataQueue;
+  }
+
+  // Is this the first piece of init data we're processing?
+  var firstInitData = true;
   v.addEventListener("encrypted", function(ev) {
-    if (initDataType === null) {
+    if (firstInitData) {
       Log(token, "got first encrypted(" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + "), setup session");
-      initDataType = ev.initDataType;
-      initDataQueue.push(ev);
+      firstInitData = false;
+      pushInitData(ev);
 
       function chain(promise, onReject) {
         return promise.then(function(value) {
           return Promise.resolve(value);
         }).catch(function(reason) {
           onReject(reason);
           return Promise.reject();
         })
@@ -395,30 +417,33 @@ function SetupEME(test, token, params)
         Log(token, "created MediaKeys object ok");
         mediaKeys.sessions = [];
         var p = v.setMediaKeys(mediaKeys);
         return chain(p, onSetKeysFail);
       })
 
       .then(function() {
         Log(token, "set MediaKeys on <video> element ok");
-        processInitDataQueue();
+        if (params && params.onMediaKeysSet) {
+          params.onMediaKeysSet();
+        }
+        if (!(params && params.delaySessions)) {
+          processInitDataQueue();
+        }
       })
     } else {
-      if (ev.initDataType !== initDataType) {
-        return bail(token + ": encrypted(" + ev.initDataType + ", " +
-                    StringToHex(ArrayBufferToString(ev.initData)) + ")")
-                   ("expected " + initDataType);
-      }
-      if (initDataQueue !== null) {
+      if (params && params.delaySessions) {
+        Log(token, "got encrypted(" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + ") event, queue it in because we're delaying sessions");
+        pushInitData(ev);
+      } else if (initDataQueue !== null) {
         Log(token, "got encrypted(" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + ") event, queue it for later session update");
-        initDataQueue.push(ev);
+        pushInitData(ev);
       } else {
         Log(token, "got encrypted(" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + ") event, update session now");
-        initDataQueue = [ev];
+        pushInitData(ev);
         processInitDataQueue();
       }
     }
   });
   return v;
 }
 
 function SetupEMEPref(callback) {
--- a/dom/media/test/mochitest.ini
+++ b/dom/media/test/mochitest.ini
@@ -664,16 +664,18 @@ skip-if = toolkit == 'android' # bug 114
 tags=msg capturestream
 skip-if = toolkit == 'android' || toolkit == 'gonk' # android: bug 1149374; gonk: bug 1193351
 [test_eme_stream_capture_blocked_case2.html]
 tags=msg capturestream
 skip-if = toolkit == 'android' || toolkit == 'gonk' # android: bug 1149374; gonk: bug 1193351
 [test_eme_stream_capture_blocked_case3.html]
 tags=msg capturestream
 skip-if = toolkit == 'android' || toolkit == 'gonk' # android: bug 1149374; gonk: bug 1193351
+[test_eme_waitingforkey.html]
+skip-if = toolkit == 'android' || toolkit == 'gonk' # android: bug 1149374; gonk: bug 1193351
 [test_empty_resource.html]
 [test_error_in_video_document.html]
 [test_error_on_404.html]
 [test_fastSeek.html]
 [test_fastSeek-forwards.html]
 [test_gmp_playback.html]
 skip-if = (os != 'win' || os_version == '5.1') # Only gmp-clearkey on Windows Vista and later decodes
 [test_imagecapture.html]
new file mode 100644
--- /dev/null
+++ b/dom/media/test/test_eme_waitingforkey.html
@@ -0,0 +1,111 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test Encrypted Media Extensions</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+  <script type="text/javascript" src="manifest.js"></script>
+  <script type="text/javascript" src="http://test1.mochi.test:8888/tests/dom/media/test/eme.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var manager = new MediaTestManager;
+
+function startTest(test, token)
+{
+  // Test if the appropriate preconditions are met such that we can start
+  // prcoessing delayed sessions.
+  function TestIfDoneDelaying()
+  {
+    var got = "Got:";
+    if (loaded) { got += " loaded,"; }
+    got += " " + gotEncrypted + "/" + test.sessionCount + " sessions,";
+    got += " " + gotWaitingForKey + " waiting for key events"
+    if (loaded && gotEncrypted == test.sessionCount && gotWaitingForKey > 0) {
+      Log(token, got + " -> Update sessions with keys");
+      params.ProcessSessions();
+    } else {
+      Log(token, got + " -> Wait for more...");
+    }
+  }
+
+  manager.started(token);
+
+  var updatedSessionsCount = 0;
+  var loaded = false;
+
+  var params = {
+    // params will be populated with a ProcessSessions() callback, that can be
+    // called to process delayed sessions.
+    delaySessions: true,
+    // Function to be called once we start processing and updating sessions.
+    // This should only be called once the preconditions in TestIfDoneDealying
+    // are met.
+    onsessionupdated: function(session) {
+      updatedSessionsCount += 1;
+      if (updatedSessionsCount == test.sessionCount) {
+          info(TimeStamp(token) + " Updated all sessions, loading complete -> Play");
+          v.play();
+      } else {
+         info(TimeStamp(token) + " Updated " + updatedSessionsCount + "/" + test.sessionCount + " sessions so far");
+      }
+    },
+  };
+  var v = SetupEME(test, token, params);
+
+  document.body.appendChild(v);
+
+  var gotEncrypted = 0;
+  var gotWaitingForKey = 0;
+
+  v.addEventListener("encrypted", function() {
+    gotEncrypted += 1;
+    TestIfDoneDelaying();
+  });
+
+  v.addEventListener("waitingforkey", function() {
+    gotWaitingForKey += 1;
+    TestIfDoneDelaying()
+  });
+
+  v.addEventListener("loadedmetadata", function() {
+    ok(SpecialPowers.do_lookupGetter(v, "isEncrypted").apply(v),
+       TimeStamp(token) + " isEncrypted should be true");
+    is(v.isEncrypted, undefined, "isEncrypted should not be accessible from content");
+  });
+
+  v.addEventListener("ended", function() {
+    ok(true, TimeStamp(token) + " got ended event");
+    // We expect only one waitingForKey as we delay until all sessions are ready.
+    // I.e. one waitingForKey should be fired, after which, we process all sessions,
+    // so it should not be possible to be blocked by a key after that point.
+    ok(gotWaitingForKey == 1,  "Expected number 1 wait, got: " + gotWaitingForKey);
+
+    v.closeSessions().then(() => manager.finished(token));
+  });
+
+  LoadTest(test, v, token)
+  .then(function() {
+    loaded = true;
+    TestIfDoneDelaying();
+  }).catch(function() {
+    ok(false, token + " failed to load");
+    manager.finished(token);
+  });
+}
+
+function beginTest() {
+  manager.runTests(gEMETests, startTest);
+}
+
+if (!IsMacOSSnowLeopardOrEarlier()) {
+  SimpleTest.waitForExplicitFinish();
+  SetupEMEPref(beginTest);
+} else {
+  todo(false, "Test disabled on this platform.");
+}
+</script>
+</pre>
+</body>
+</html>