Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / LayoutTests / media / encrypted-media / encrypted-media-v2-syntax.html
1 <!DOCTYPE html>
2 <html>
3     <head>
4         <title>Test EME syntax</title>
5         <script src="encrypted-media-utils.js"></script>
6         <script src="../../resources/testharness.js"></script>
7         <script src="../../resources/testharnessreport.js"></script>
8     </head>
9     <body>
10         <div id="log"></div>
11         <script>
12             // Since promises catch any exception and convert it into a
13             // rejected Promise, there is no current way to have the W3C
14             // test framework report a failed test. For now, simply force
15             // a timeout to indicate failure.
16             // FIXME: Once W3C test framework handles Promises, fix this.
17
18             // This function checks that calling |testCase.func| returns a
19             // rejected Promise with the error.name equal to
20             // |testCase.exception|.
21             function test_exception(testCase /*...*/)
22             {
23                 var func = testCase.func;
24                 var exception = testCase.exception;
25                 var args = Array.prototype.slice.call(arguments, 1);
26
27                 // Currently blink throws for TypeErrors rather than returning
28                 // a rejected promise (http://crbug.com/359386).
29                 // FIXME: Remove try/catch once they become failed promises.
30                 try {
31                     return func.apply(null, args).then(
32                         function(result)
33                         {
34                             assert_unreached(format_value(func));
35                         },
36                         function(error)
37                         {
38                             assert_equals(error.name, exception, format_value(func));
39                             assert_not_equals(error.message, "", format_value(func));
40                         }
41                     );
42                 } catch (e) {
43                     // Only allow 'TypeError' exceptions to be thrown.
44                     // Everything else should be a failed promise.
45                     assert_equals('TypeError', exception, format_value(func));
46                     assert_equals(e.name, exception, format_value(func));
47                 }
48             }
49
50             var kRequestMediaKeySystemAccessExceptionsTestCases = [
51                 // Too few parameters.
52                 {
53                     exception: 'TypeError',
54                     func: function() { return navigator.requestMediaKeySystemAccess(); }
55                 },
56                 // Invalid parameters.
57                 {
58                     exception: 'InvalidAccessError',
59                     func: function() { return navigator.requestMediaKeySystemAccess(''); }
60                 },
61                 // Invalid key systems. Note that JavaScript converts all these
62                 // values into strings by calling toString(), so they fail due
63                 // to the key system not being supported, not due to the type.
64                 {
65                     exception: 'NotSupportedError',
66                     func: function() { return navigator.requestMediaKeySystemAccess(null); }
67                 },
68                 {
69                     exception: 'NotSupportedError',
70                     func: function() { return navigator.requestMediaKeySystemAccess(undefined); }
71                 },
72                 {
73                     exception: 'NotSupportedError',
74                     func: function() { return navigator.requestMediaKeySystemAccess(1); }
75                 },
76                 {
77                     exception: 'NotSupportedError',
78                     func: function() { return navigator.requestMediaKeySystemAccess(new Uint8Array(0)); }
79                 },
80                 {
81                     exception: 'NotSupportedError',
82                     func: function() { return navigator.requestMediaKeySystemAccess('unsupported'); }
83                 },
84                 // Non-ASCII names.
85                 {
86                     exception: 'NotSupportedError',
87                     func: function() { return navigator.requestMediaKeySystemAccess('org.w3\u263A.clearkey'); }
88                 }
89             ];
90
91             async_test(function(test)
92             {
93                 var createPromises = kRequestMediaKeySystemAccessExceptionsTestCases.map(function(testCase) {
94                     return test_exception(testCase);
95                 });
96
97                 Promise.all(createPromises).then(function(result) {
98                     test.done();
99                 }).catch(function(error) {
100                     forceTestFailureFromPromise(test, error, 'requestMediaKeySystemAccess() tests failed');
101                 });
102             }, 'Test Navigator.requestMediaKeySystemAccess() exceptions.');
103
104             async_test(function(test)
105             {
106                 assert_equals(typeof navigator.requestMediaKeySystemAccess, 'function');
107                 navigator.requestMediaKeySystemAccess('org.w3.clearkey').then(function(access) {
108                     assert_not_equals(access, null);
109                     assert_equals(typeof access, 'object');
110                     assert_equals(access.keySystem, 'org.w3.clearkey');
111                     assert_equals(typeof access.createMediaKeys, 'function');
112                     test.done();
113                 }).catch(function(error) {
114                     forceTestFailureFromPromise(test, error, 'requestMediaKeySystemAccess() tests failed');
115                 });
116             }, 'Test Navigator.requestMediaKeySystemAccess().');
117
118             async_test(function(test)
119             {
120                 var access;
121
122                 navigator.requestMediaKeySystemAccess('org.w3.clearkey').then(function(result) {
123                     access = result;
124                     assert_equals(access.keySystem, 'org.w3.clearkey');
125                     return access.createMediaKeys();
126                 }).then(function(mediaKeys) {
127                     assert_not_equals(mediaKeys, null);
128                     assert_equals(typeof mediaKeys, 'object');
129                     assert_equals(typeof mediaKeys.createSession, 'function');
130                     assert_equals(typeof mediaKeys.setServerCertificate, 'function');
131
132                     // Test creation of a second MediaKeys.
133                     // The extra parameter is ignored.
134                     return access.createMediaKeys('extra');
135                 }).then(function(mediaKeys) {
136                     assert_not_equals(mediaKeys, null);
137                     assert_equals(typeof mediaKeys, 'object');
138                     assert_equals(typeof mediaKeys.createSession, 'function');
139                     assert_equals(typeof mediaKeys.setServerCertificate, 'function');
140                     test.done();
141                 }).catch(function(error) {
142                     forceTestFailureFromPromise(test, error, 'create() tests failed');
143                 });
144             }, 'Test MediaKeys create().');
145
146             var kCreateSessionExceptionsTestCases = [
147                 // Tests in this set use a shortened parameter name due to
148                 // format_value() only returning the first 60 characters as the
149                 // result. With a longer name the first 60 characters is not
150                 // enough to determine which test failed.
151
152                 // Invalid parameters.
153                 {
154                     exception: 'TypeError',
155                     func: function(mk) { return mk.createSession(); }
156                 },
157                 {
158                     exception: 'TypeError',
159                     func: function(mk) { return mk.createSession(''); }
160                 },
161                 {
162                     exception: 'TypeError',
163                     func: function(mk) { return mk.createSession(null); }
164                 },
165                 {
166                     exception: 'TypeError',
167                     func: function(mk) { return mk.createSession(undefined); }
168                 },
169                 {
170                     exception: 'TypeError',
171                     func: function(mk) { return mk.createSession(1); }
172                 },
173                 {
174                     exception: 'TypeError',
175                     func: function(mk) { return mk.createSession(new Uint8Array(0)); }
176                 },
177                 {
178                     exception: 'TypeError',
179                     func: function(mk) { return mk.createSession('TEMPORARY'); }
180                 }
181             ];
182
183             async_test(function(test)
184             {
185                 navigator.requestMediaKeySystemAccess('org.w3.clearkey').then(function(access) {
186                     return access.createMediaKeys();
187                 }).then(function(mediaKeys) {
188                     var sessionPromises = kCreateSessionExceptionsTestCases.map(function(testCase) {
189                         return test_exception(testCase, mediaKeys);
190                     });
191
192                     assert_not_equals(sessionPromises.length, 0);
193                     return Promise.all(sessionPromises);
194                 }).then(function(result) {
195                     test.done();
196                 }).catch(function(error) {
197                     forceTestFailureFromPromise(test, error, 'createSession() tests failed');
198                 });
199             }, 'Test MediaKeys createSession() exceptions.');
200
201             var kGenerateRequestExceptionsTestCases = [
202                 // Tests in this set use a shortened parameter name due to
203                 // format_value() only returning the first 60 characters as the
204                 // result. With a longer name the first 60 characters is not
205                 // enough to determine which test failed. Even with the
206                 // shortened name, the error message for the last couple of
207                 // tests is the same.
208                 // Too few parameters.
209                 {
210                     exception: 'TypeError',
211                     func: function(mk1) { return mk1.createSession().generateRequest(); }
212                 },
213                 {
214                     exception: 'TypeError',
215                     func: function(mk2) { return mk2.createSession().generateRequest(''); }
216                 },
217                 {
218                     exception: 'TypeError',
219                     func: function(mk3) { return mk3.createSession().generateRequest(null); }
220                 },
221                 {
222                     exception: 'TypeError',
223                     func: function(mk4) { return mk4.createSession().generateRequest(undefined); }
224                 },
225                 {
226                     exception: 'TypeError',
227                     func: function(mk5) { return mk5.createSession().generateRequest(1); }
228                 },
229                 {
230                     exception: 'TypeError',
231                     func: function(mk6) { return mk6.createSession().generateRequest(new Uint8Array(0)); }
232                 },
233                 {
234                     exception: 'TypeError',
235                     func: function(mk7, _, initData) { return mk7.createSession().generateRequest(initData); }
236                 },
237                 // Invalid parameters.
238                 {
239                     exception: 'InvalidAccessError',
240                     func: function(mk8, _, initData) { return mk8.createSession().generateRequest('', initData); }
241                 },
242                 // Not supported initDataTypes.
243                 {
244                     exception: 'NotSupportedError',
245                     func: function(mk9, _, initData) { return mk9.createSession().generateRequest(null, initData); }
246                 },
247                 {
248                     exception: 'NotSupportedError',
249                     func: function(mk10, _, initData) { return mk10.createSession().generateRequest(undefined, initData); }
250                 },
251                 {
252                     exception: 'NotSupportedError',
253                     func: function(mk11, _, initData) { return mk11.createSession().generateRequest(1, initData); }
254                 },
255                 {
256                     exception: 'NotSupportedError',
257                     func: function(mk12, _, initData) { return mk12.createSession().generateRequest(new Uint8Array(0), initData); }
258                 },
259                 {
260                     exception: 'NotSupportedError',
261                     func: function(mk13, _, initData) { return mk13.createSession().generateRequest('unsupported', initData); }
262                 },
263                 {
264                     exception: 'NotSupportedError',
265                     func: function(mk14, _, initData) { return mk14.createSession().generateRequest('video/foo', initData); }
266                 },
267                 {
268                     exception: 'NotSupportedError',
269                     func: function(mk15, _, initData) { return mk15.createSession().generateRequest('text/webm', initData); }
270                 }
271                 // FIXME: Enable when switching to initDataType from MIME type.
272                 // http://crbug.com/385874.
273                 // {
274                 //     exception: 'NotSupportedError',
275                 //     func: function(mk16, _, initData) { return mk16.createSession('video/webm', initData); }
276                 // }
277             ];
278
279             var kTypeSpecificGenerateRequestExceptionsTestCases = [
280                 // Tests in this set use a shortened parameter name due to
281                 // format_value() only returning the first 60 characters as the
282                 // result. With a longer name the first 60 characters is not
283                 // enough to determine which test failed. Even with the
284                 // shortened name, the error message for the last couple of
285                 // tests is the same.
286
287                 // Too few parameters.
288                 {
289                     exception: 'TypeError',
290                     func: function(mk1, type) { return mk1.createSession().generateRequest(type); }
291                 },
292                 // Invalid parameters.
293                 {
294                     exception: 'TypeError',
295                     func: function(mk2, type) { return mk2.createSession().generateRequest(type, ''); }
296                 },
297                 {
298                     exception: 'TypeError',
299                     func: function(mk3, type) { return mk3.createSession().generateRequest(type, null); }
300                 },
301                 {
302                     exception: 'TypeError',
303                     func: function(mk4, type) { return mk4.createSession().generateRequest(type, undefined); }
304                 },
305                 {
306                     exception: 'TypeError',
307                     func: function(mk5, type) { return mk5.createSession().generateRequest(type, 1); }
308                 },
309                 {
310                     exception: 'InvalidAccessError',
311                     func: function(mk6, type) { return mk6.createSession().generateRequest(type, new Uint8Array(0)); }
312                 }
313             ];
314
315             async_test(function(test)
316             {
317                 navigator.requestMediaKeySystemAccess('org.w3.clearkey').then(function(access) {
318                     return access.createMediaKeys();
319                 }).then(function(mediaKeys) {
320                     // FIXME: Remove "video/" from the calls to isTypeSupported() once it is updated.
321                     // http://crbug.com/405731.
322                     var initData = stringToUint8Array('init data');
323                     var sessionPromises = kGenerateRequestExceptionsTestCases.map(function(testCase) {
324                         return test_exception(testCase, mediaKeys, '', initData);
325                     });
326
327                     // Test that WebM sessions generate the expected error, if
328                     // supported.
329                     if (MediaKeys.isTypeSupported('org.w3.clearkey', 'video/webm')) {
330                         var WebmSessionPromises = kTypeSpecificGenerateRequestExceptionsTestCases.map(function(testCase) {
331                             return test_exception(testCase, mediaKeys, 'webm', getInitData('webm'));
332                         });
333                         sessionPromises = sessionPromises.concat(WebmSessionPromises);
334                     }
335
336                     // Repeat for MP4, if supported.
337                     if (MediaKeys.isTypeSupported('org.w3.clearkey', 'video/mp4')) {
338                         var mp4SessionPromises = kTypeSpecificGenerateRequestExceptionsTestCases.map(function(testCase) {
339                             return test_exception(testCase, mediaKeys, 'cenc', getInitData('cenc'));
340                         });
341                         sessionPromises = sessionPromises.concat(mp4SessionPromises);
342                     }
343
344                     assert_not_equals(sessionPromises.length, 0);
345                     return Promise.all(sessionPromises);
346                 }).then(function(result) {
347                     test.done();
348                 }).catch(function(error) {
349                     forceTestFailureFromPromise(test, error, 'generateRequest() tests failed');
350                 });
351             }, 'Test MediaKeys generateRequest() exceptions.');
352
353             var kLoadExceptionsTestCases = [
354                 // Too few parameters.
355                 {
356                     exception: 'TypeError',
357                     func: function(mk1) { return mk1.createSession('temporary').load(); }
358                 },
359                 {
360                     exception: 'TypeError',
361                     func: function(mk2) { return mk2.createSession('persistent').load(); }
362                 },
363                 // Invalid parameters.
364                 // 'temporary' sessions are never allowed, so always return
365                 // 'InvalidAccessError'. For 'persistent' sessions, JS calls
366                 // .toString() on the parameter if it is not already a string
367                 // before passing it to code. So tests like mk6 or mk8 pass in
368                 // "null" or "undefined" as the sessionId.
369                 {
370                     exception: 'InvalidAccessError',
371                     func: function(mk3) { return mk3.createSession('temporary').load(''); }
372                 },
373                 {
374                     exception: 'InvalidAccessError',
375                     func: function(mk4) { return mk4.createSession('persistent').load(''); }
376                 },
377                 {
378                     exception: 'InvalidAccessError',
379                     func: function(mk5) { return mk5.createSession('temporary').load(null); }
380                 },
381                 {
382                     exception: 'NotSupportedError',
383                     func: function(mk6) { return mk6.createSession('persistent').load(null); }
384                 },
385                 {
386                     exception: 'InvalidAccessError',
387                     func: function(mk7) { return mk7.createSession('temporary').load(undefined); }
388                 },
389                 {
390                     exception: 'NotSupportedError',
391                     func: function(mk8) { return mk8.createSession('persistent').load(undefined); }
392                 },
393                 {
394                     exception: 'InvalidAccessError',
395                     func: function(mk9) { return mk9.createSession('temporary').load(1); }
396                 },
397                 {
398                     exception: 'NotSupportedError',
399                     func: function(mk10) { return mk10.createSession('persistent').load(1); }
400                 },
401                 {
402                     exception: 'InvalidAccessError',
403                     func: function(mk11) { return mk11.createSession('temporary').load(new Uint8Array(0)); }
404                 },
405                 {
406                     exception: 'InvalidAccessError',
407                     func: function(mk12) { return mk12.createSession('persistent').load(new Uint8Array(0)); }
408                 },
409                 // Invalid session id.
410                 {
411                     exception: 'InvalidAccessError',
412                     func: function(mk13) { return mk13.createSession('temporary').load('!@#$%^&*()'); }
413                 },
414                 {
415                     exception: 'InvalidAccessError',
416                     func: function(mk14) { return mk14.createSession('persistent').load('!@#$%^&*()'); }
417                 },
418                 // Valid session id (but not supported by ClearKey).
419                 {
420                     exception: 'InvalidAccessError',
421                     func: function(mk15) { return mk15.createSession('temporary').load('1234'); }
422                 },
423                 {
424                     exception: 'NotSupportedError',
425                     func: function(mk16) { return mk16.createSession('persistent').load('1234'); }
426                 }
427             ];
428
429             async_test(function(test)
430             {
431                 navigator.requestMediaKeySystemAccess('org.w3.clearkey').then(function(access) {
432                     return access.createMediaKeys();
433                 }).then(function(mediaKeys) {
434                     // FIXME: Remove "video/" from the calls to isTypeSupported() once it is updated.
435                     // http://crbug.com/405731.
436                     var initData = stringToUint8Array('init data');
437                     var sessionPromises = kLoadExceptionsTestCases.map(function(testCase) {
438                         return test_exception(testCase, mediaKeys);
439                     });
440
441                     assert_not_equals(sessionPromises.length, 0);
442                     return Promise.all(sessionPromises);
443                 }).then(function(result) {
444                     test.done();
445                 }).catch(function(error) {
446                     forceTestFailureFromPromise(test, error, 'load() tests failed');
447                 });
448             }, 'Test MediaKeys load() exceptions.');
449
450             // All calls to |func| in this group are supposed to succeed.
451             // However, the spec notes that some things are optional for
452             // Clear Key. In particular, support for persistent sessions
453             // is optional. Since some implementations won't support some
454             // features, a NotSupportedError is treated as a success
455             // if |isNotSupportedAllowed| is true.
456             var kCreateSessionTestCases = [
457                 // Use the default sessionType.
458                 {
459                     func: function(mk) { return mk.createSession(); },
460                     isNotSupportedAllowed: false
461                 },
462                 // Try variations of sessionType.
463                 {
464                     func: function(mk) { return mk.createSession('temporary'); },
465                     isNotSupportedAllowed: false
466                 },
467                 {
468                     func: function(mk) { return mk.createSession(undefined); },
469                     isNotSupportedAllowed: false
470                 },
471                 {
472                     // Since this is optional, some Clear Key implementations
473                     // will succeed, others will return a "NotSupportedError".
474                     // Both are allowed results.
475                     func: function(mk) { return mk.createSession('persistent'); },
476                     isNotSupportedAllowed: true
477                 },
478                 // Try additional parameter, which should be ignored.
479                 {
480                     func: function(mk) { return mk.createSession('temporary', 'extra'); },
481                     isNotSupportedAllowed: false
482                 }
483             ];
484
485             // This function checks that calling |testCase.func| creates a
486             // MediaKeySession object with some default values. It also
487             // allows for an NotSupportedError to be generated and treated as a
488             // success, if allowed. See comment above kCreateSessionTestCases.
489             function test_createSession(testCase, mediaKeys)
490             {
491                 var mediaKeySession;
492                 try {
493                     mediaKeySession = testCase.func.call(null, mediaKeys);
494                 } catch (e) {
495                     assert_true(testCase.isNotSupportedAllowed);
496                     return;
497                 }
498
499                 // FIXME: Update this set of tests when done
500                 // implementing the latest spec.
501                 assert_equals(typeof mediaKeySession, 'object');
502                 assert_equals(typeof mediaKeySession.addEventListener, 'function');
503                 assert_equals(typeof mediaKeySession.generateRequest, 'function');
504                 assert_equals(typeof mediaKeySession.update, 'function');
505                 assert_equals(typeof mediaKeySession.close, 'function');
506                 assert_equals(typeof mediaKeySession.remove, 'function');
507                 assert_equals(mediaKeySession.error, null);
508                 assert_equals(mediaKeySession.sessionId, '');
509                 assert_equals(typeof mediaKeySession.sessionId, 'string');
510                 assert_equals(typeof mediaKeySession.onopen, 'undefined');
511                 assert_equals(typeof mediaKeySession.onmessage, 'undefined');
512                 assert_equals(typeof mediaKeySession.onclose, 'undefined');
513                 assert_equals(typeof mediaKeySession.onerror, 'undefined');
514             }
515
516             async_test(function(test)
517             {
518                 navigator.requestMediaKeySystemAccess('org.w3.clearkey').then(function(access) {
519                     return access.createMediaKeys();
520                 }).then(function(mediaKeys) {
521                     kCreateSessionTestCases.map(function(testCase) {
522                         test_createSession(testCase, mediaKeys);
523                     });
524                     test.done();
525                 }).catch(function(error) {
526                     forceTestFailureFromPromise(test, error, 'createSession() tests failed');
527                 });
528             }, 'Test MediaKeys createSession().');
529
530             // This function checks that calling generateRequest() works for
531             // various sessions. |testCase.func| creates a MediaKeySession
532             // object, and then generateRequest() is called on that object. It
533             // allows for an NotSupportedError to be generated and treated as a
534             // success, if allowed. See comment above kCreateSessionTestCases.
535             function test_generateRequest(testCase, mediaKeys, type, initData)
536             {
537                 var mediaKeySession;
538                 try {
539                     mediaKeySession = testCase.func.call(null, mediaKeys);
540                 } catch (e) {
541                     assert_true(testCase.isNotSupportedAllowed);
542                     return new Promise(new Promise(function() {}));
543                 }
544                 return mediaKeySession.generateRequest(type, initData);
545             }
546
547             async_test(function(test)
548             {
549                 navigator.requestMediaKeySystemAccess('org.w3.clearkey').then(function(access) {
550                     return access.createMediaKeys();
551                 }).then(function(mediaKeys) {
552                     var sessionPromises = [];
553
554                     // Test that WebM sessions generate the expected error, if
555                     // supported.
556                     if (MediaKeys.isTypeSupported('org.w3.clearkey', 'video/webm')) {
557                         var WebmSessionPromises = kCreateSessionTestCases.map(function(testCase) {
558                             return test_generateRequest(testCase, mediaKeys, 'webm', getInitData('webm'));
559                         });
560                         sessionPromises = sessionPromises.concat(WebmSessionPromises);
561                     }
562
563                     // Repeat for MP4, if supported.
564                     if (MediaKeys.isTypeSupported('org.w3.clearkey', 'video/mp4')) {
565                         var mp4SessionPromises = kCreateSessionTestCases.map(function(testCase) {
566                             return test_generateRequest(testCase, mediaKeys, 'cenc', getInitData('cenc'));
567                         });
568                         sessionPromises = sessionPromises.concat(mp4SessionPromises);
569                     }
570
571                     assert_not_equals(sessionPromises.length, 0);
572                     return Promise.all(sessionPromises);
573                 }).then(function(result) {
574                     test.done();
575                 }).catch(function(error) {
576                     forceTestFailureFromPromise(test, error, 'generateRequest() tests failed');
577                 });
578             }, 'Test MediaKeys generateRequest().');
579
580             var kUpdateSessionExceptionsTestCases = [
581                 // Tests in this set use a shortened parameter name due to
582                 // format_value() only returning the first 60 characters as the
583                 // result. With a longer name (mediaKeySession) the first 60
584                 // characters is not enough to determine which test failed.
585
586                 // Too few parameters.
587                 {
588                     exception: 'TypeError',
589                     func: function(s) { return s.update(); }
590                 },
591                 // Invalid parameters.
592                 {
593                     exception: 'TypeError',
594                     func: function(s) { return s.update(''); }
595                 },
596                 {
597                     exception: 'TypeError',
598                     func: function(s) { return s.update(null); }
599                 },
600                 {
601                     exception: 'TypeError',
602                     func: function(s) { return s.update(undefined); }
603                 },
604                 {
605                     exception: 'TypeError',
606                     func: function(s) { return s.update(1); }
607                 },
608                 {
609                     exception: 'InvalidAccessError',
610                     func: function(s) { return s.update(new Uint8Array(0)); }
611                 }
612             ];
613
614             async_test(function(test)
615             {
616                 navigator.requestMediaKeySystemAccess('org.w3.clearkey').then(function(access) {
617                     return access.createMediaKeys();
618                 }).then(function(mediaKeys) {
619                     var promises = [];
620
621                     if (MediaKeys.isTypeSupported('org.w3.clearkey', 'video/webm')) {
622                         var WebmSessionPromises = kUpdateSessionExceptionsTestCases.map(function(testCase) {
623                             var mediaKeySession = mediaKeys.createSession();
624                             return mediaKeySession.generateRequest('webm', getInitData('webm')).then(function(result) {
625                                 return test_exception(testCase, mediaKeySession);
626                             });
627                         });
628                         promises = promises.concat(WebmSessionPromises);
629                     }
630
631                     if (MediaKeys.isTypeSupported('org.w3.clearkey', 'video/mp4')) {
632                         var mp4SessionPromises = kUpdateSessionExceptionsTestCases.map(function(testCase) {
633                           var mediaKeySession = mediaKeys.createSession();
634                           return mediaKeySession.generateRequest('cenc', getInitData('cenc')).then(function(result) {
635                               return test_exception(testCase, mediaKeySession);
636                           });
637                       });
638                       promises = promises.concat(mp4SessionPromises);
639                     }
640
641                     assert_not_equals(promises.length, 0);
642                     return Promise.all(promises);
643                 }).then(function(result) {
644                     test.done();
645                 }).catch(function(error) {
646                     forceTestFailureFromPromise(test, error, 'update() tests failed');
647                 });
648             }, 'Test MediaKeySession update() exceptions.');
649
650             function create_update_test(mediaKeys, type, initData)
651             {
652                 var mediaKeySession = mediaKeys.createSession();
653                 var promise = mediaKeySession.generateRequest(type, initData).then(function(result) {
654                     var validLicense = stringToUint8Array(createJWKSet(createJWK(stringToUint8Array('123'), stringToUint8Array('1234567890abcdef'))));
655                     return mediaKeySession.update(validLicense);
656                 }).then(function(result) {
657                     // Call update() with a different license and an extra
658                     // parameter. The extra parameter is ignored.
659                     var validLicense = stringToUint8Array(createJWKSet(createJWK(stringToUint8Array('4567890'), stringToUint8Array('01234567890abcde'))));
660                     return mediaKeySession.update(validLicense, 'extra');
661                 });
662                 return promise;
663             }
664
665             async_test(function(test)
666             {
667                 navigator.requestMediaKeySystemAccess('org.w3.clearkey').then(function(access) {
668                     return access.createMediaKeys();
669                 }).then(function(mediaKeys) {
670                   var promises = [];
671
672                   if (MediaKeys.isTypeSupported('org.w3.clearkey', 'video/webm')) {
673                       promises.push(create_update_test(mediaKeys, 'webm', getInitData('webm')));
674                   }
675
676                   if (MediaKeys.isTypeSupported('org.w3.clearkey', 'video/mp4')) {
677                       promises.push(create_update_test(mediaKeys, 'cenc', getInitData('cenc')));
678                   }
679
680                   assert_not_equals(promises.length, 0);
681                   return Promise.all(promises);
682                 }).then(function(result) {
683                     test.done();
684                 }).catch(function(error) {
685                     forceTestFailureFromPromise(test, error, 'update() tests failed');
686                 });
687             }, 'Test MediaKeySession update().');
688
689             function create_close_exception_test(mediaKeys, type, initData)
690             {
691                 var mediaKeySession = mediaKeys.createSession();
692                 return mediaKeySession.close().then(function(result) {
693                     assert_unreached('close() should not succeed if session uninitialized');
694                 }).catch(function(error) {
695                     assert_equals(error.name, 'InvalidStateError');
696                     // Return something so the promise resolves.
697                     return Promise.resolve();
698                 });
699             }
700
701             async_test(function(test)
702             {
703                 navigator.requestMediaKeySystemAccess('org.w3.clearkey').then(function(access) {
704                     return access.createMediaKeys();
705                 }).then(function(mediaKeys) {
706                     var promises = [];
707
708                     if (MediaKeys.isTypeSupported('org.w3.clearkey', 'video/webm')) {
709                         promises.push(create_close_exception_test(mediaKeys, 'webm', getInitData('webm')));
710                     }
711
712                     if (MediaKeys.isTypeSupported('org.w3.clearkey', 'video/mp4')) {
713                         promises.push(create_close_exception_test(mediaKeys, 'cenc', getInitData('cenc')));
714                     }
715
716                     assert_not_equals(promises.length, 0);
717                     return Promise.all(promises);
718                 }).then(function(result) {
719                     test.done();
720                 }).catch(function(error) {
721                     forceTestFailureFromPromise(test, error, 'close() exception tests failed');
722                 });
723             }, 'Test MediaKeySession close() exceptions.');
724
725
726             function create_close_test(mediaKeys, type, initData)
727             {
728                 var mediaKeySession = mediaKeys.createSession();
729                 var promise = mediaKeySession.generateRequest(type, initData).then(function(result) {
730                     return mediaKeySession.close();
731                 }).then(function(result) {
732                     // Call close() again with an extra parameter. The extra
733                     // parameter is ignored.
734                     return mediaKeySession.close('extra');
735                 });
736                 return promise;
737             }
738
739             async_test(function(test)
740             {
741                 navigator.requestMediaKeySystemAccess('org.w3.clearkey').then(function(access) {
742                     return access.createMediaKeys();
743                 }).then(function(mediaKeys) {
744                     var promises = [];
745
746                     if (MediaKeys.isTypeSupported('org.w3.clearkey', 'video/webm')) {
747                         promises.push(create_close_test(mediaKeys, 'webm', getInitData('webm')));
748                     }
749
750                     if (MediaKeys.isTypeSupported('org.w3.clearkey', 'video/mp4')) {
751                         promises.push(create_close_test(mediaKeys, 'cenc', getInitData('cenc')));
752                     }
753
754                     assert_not_equals(promises.length, 0);
755                     return Promise.all(promises);
756                 }).then(function(result) {
757                     test.done();
758                 }).catch(function(error) {
759                     forceTestFailureFromPromise(test, error, 'close() tests failed');
760                 });
761             }, 'Test MediaKeySession close().');
762
763             function create_remove_exception_test(mediaKeys, type, initData)
764             {
765                 // remove() on an uninitialized session should fail.
766                 var mediaKeySession = mediaKeys.createSession('temporary');
767                 return mediaKeySession.remove().then(function(result) {
768                     assert_unreached('remove() should not succeed if session uninitialized');
769                 }).catch(function(error) {
770                     assert_equals(error.name, 'InvalidStateError');
771
772                     // remove() on a temporary session should fail.
773                     return mediaKeySession.generateRequest(type, initData);
774                 }).then(function(result) {
775                     return mediaKeySession.remove();
776                 }).then(function(result) {
777                     assert_unreached('remove() should not succeed for temporary sessions');
778                 }).catch(function(error) {
779                     assert_equals(error.name, 'InvalidAccessError');
780
781                     // remove() on a closed persistent session should also fail.
782                     mediaKeySession = mediaKeys.createSession('persistent');
783                     return mediaKeySession.generateRequest(type, initData);
784                 }).then(function(result) {
785                     return mediaKeySession.close();
786                 }).then(function(result) {
787                     return mediaKeySession.remove();
788                 }).then(function(result) {
789                     assert_unreached('remove() should not succeed for closed persistent sessions');
790                 }).catch(function(error) {
791                     assert_equals(error.name, 'InvalidStateError');
792
793                     // Return something so the promise resolves.
794                     return Promise.resolve();
795                 });
796             }
797
798             async_test(function(test)
799             {
800                 navigator.requestMediaKeySystemAccess('org.w3.clearkey').then(function(access) {
801                     return access.createMediaKeys();
802                 }).then(function(mediaKeys) {
803                     var promises = [];
804
805                     if (MediaKeys.isTypeSupported('org.w3.clearkey', 'video/webm')) {
806                         promises.push(create_remove_exception_test(mediaKeys, 'webm', getInitData('webm')));
807                     }
808
809                     if (MediaKeys.isTypeSupported('org.w3.clearkey', 'video/mp4')) {
810                         promises.push(create_remove_exception_test(mediaKeys, 'cenc', getInitData('cenc')));
811                     }
812
813                     assert_not_equals(promises.length, 0);
814                     return Promise.all(promises);
815                 }).then(function(result) {
816                     test.done();
817                 }).catch(function(error) {
818                     forceTestFailureFromPromise(test, error, 'remove() exception tests failed');
819                 });
820             }, 'Test MediaKeySession remove() exceptions.');
821
822             function create_remove_test(mediaKeys, type, initData)
823             {
824                 // ClearKey may not support persistent sessions.
825                 var mediaKeySession;
826                 try {
827                     mediaKeySession = mediaKeys.createSession('persistent');
828                 } catch (error) {
829                     // Not supported, so return a resolved promise.
830                     assert_equals(error.name, 'NotSupportedError');
831                     return Promise.resolve();
832                 }
833                 return mediaKeySession.generateRequest(type, initData).then(function(result) {
834                     return mediaKeySession.remove();
835                 });
836             }
837
838             async_test(function(test)
839             {
840                 navigator.requestMediaKeySystemAccess('org.w3.clearkey').then(function(access) {
841                     return access.createMediaKeys();
842                 }).then(function(mediaKeys) {
843                     var promises = [];
844
845                     if (MediaKeys.isTypeSupported('org.w3.clearkey', 'video/webm')) {
846                         promises.push(create_remove_test(mediaKeys, 'webm', getInitData('webm')));
847                     }
848
849                     if (MediaKeys.isTypeSupported('org.w3.clearkey', 'video/mp4')) {
850                         promises.push(create_remove_test(mediaKeys, 'cenc', getInitData('cenc')));
851                     }
852
853                     assert_not_equals(promises.length, 0);
854                     return Promise.all(promises);
855                 }).then(function(result) {
856                     test.done();
857                 }).catch(function(error) {
858                     forceTestFailureFromPromise(test, error, 'remove() tests failed');
859                 });
860             }, 'Test MediaKeySession remove().');
861
862             var kSetServerCertificateExceptionsTestCases = [
863                 // Too few parameters.
864                 {
865                     exception: 'TypeError',
866                     func: function(mk) { return mk.setServerCertificate(); }
867                 },
868                 // Invalid parameters.
869                 {
870                     exception: 'TypeError',
871                     func: function(mk) { return mk.setServerCertificate(''); }
872                 },
873                 {
874                     exception: 'TypeError',
875                     func: function(mk) { return mk.setServerCertificate(null); }
876                 },
877                 {
878                     exception: 'TypeError',
879                     func: function(mk) { return mk.setServerCertificate(undefined); }
880                 },
881                 {
882                     exception: 'TypeError',
883                     func: function(mk) { return mk.setServerCertificate(1); }
884                 },
885                 // Empty array.
886                 {
887                     exception: 'InvalidAccessError',
888                     func: function(mk) { return mk.setServerCertificate(new Uint8Array(0)); }
889                 },
890                 // Valid calls, but not supported by ClearKey.
891                 {
892                     exception: 'NotSupportedError',
893                     func: function(mk) { var cert = new Uint8Array(200); assert_true(ArrayBuffer.isView(cert)); return mk.setServerCertificate(cert); }
894                 },
895                 {
896                     // Pass in ArrayBuffer
897                     exception: 'NotSupportedError',
898                     func: function(mk) { var cert = new Uint8Array(200); assert_false(ArrayBuffer.isView(cert.buffer)); return mk.setServerCertificate(cert.buffer); }
899                 }
900             ];
901
902             async_test(function(test)
903             {
904                 navigator.requestMediaKeySystemAccess('org.w3.clearkey').then(function(access) {
905                     return access.createMediaKeys();
906                 }).then(function(mediaKeys) {
907                     var promises = kSetServerCertificateExceptionsTestCases.map(function(testCase) {
908                         return test_exception(testCase, mediaKeys);
909                     });
910
911                     assert_not_equals(promises.length, 0);
912                     return Promise.all(promises);
913                 }).then(function(result) {
914                     test.done();
915                 }).catch(function(error) {
916                     forceTestFailureFromPromise(test, error, 'setServerCertificate() exception tests failed');
917                 });
918             }, 'Test MediaKeys setServerCertificate() exceptions.');
919
920             // FIXME: Add test for successful setServerCertificate(). Note that
921             // ClearKey does not support it.
922
923             // FIXME: Add syntax checks for MediaKeys.IsTypeSupported().
924             // FIXME: Add syntax checks for MediaKeyError and MediaKeySession events.
925             // FIXME: Add HTMLMediaElement syntax checks, e.g. setMediaKeys, mediakeys, onencrypted.
926         </script>
927     </body>
928 </html>