<!DOCTYPE html>
<html>
<head>
<title>Test EME syntax</title>
<script src="encrypted-media-utils.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<script>
// Since promises catch any exception and convert it into a
// rejected Promise, there is no current way to have the W3C
// test framework report a failed test. For now, simply force
// a timeout to indicate failure.
// FIXME: Once W3C test framework handles Promises, fix this.
// This function checks that calling |testCase.func| returns a
// rejected Promise with the error.name equal to
// |testCase.exception|.
function test_exception(testCase /*...*/)
{
var func = testCase.func;
var exception = testCase.exception;
var args = Array.prototype.slice.call(arguments, 1);
// Currently blink throws for TypeErrors rather than returning
// a rejected promise (http://crbug.com/359386).
// FIXME: Remove try/catch once they become failed promises.
try {
return func.apply(null, args).then(
function(result)
{
assert_unreached(format_value(func));
},
function(error)
{
assert_equals(error.name, exception, format_value(func));
assert_not_equals(error.message, "", format_value(func));
}
);
} catch (e) {
// Only allow 'TypeError' exceptions to be thrown.
// Everything else should be a failed promise.
assert_equals('TypeError', exception, format_value(func));
assert_equals(e.name, exception, format_value(func));
}
}
var kRequestMediaKeySystemAccessExceptionsTestCases = [
// Too few parameters.
{
exception: 'TypeError',
func: function() { return navigator.requestMediaKeySystemAccess(); }
},
{
exception: 'TypeError',
func: function() { return navigator.requestMediaKeySystemAccess('org.w3.clearkey'); }
},
// Invalid key systems. Note that JavaScript converts all these
// values into strings by calling toString(), so they fail due
// to the key system not being supported, not due to the type.
{
exception: 'NotSupportedError',
func: function() { return navigator.requestMediaKeySystemAccess(null, [{}]); }
},
{
exception: 'NotSupportedError',
func: function() { return navigator.requestMediaKeySystemAccess(undefined, [{}]); }
},
{
exception: 'NotSupportedError',
func: function() { return navigator.requestMediaKeySystemAccess(1, [{}]); }
},
{
exception: 'TypeError',
func: function() { return navigator.requestMediaKeySystemAccess(new Uint8Array(0), [{}]); }
},
{
exception: 'TypeError',
func: function() { return navigator.requestMediaKeySystemAccess('', [{}]); }
},
{
exception: 'NotSupportedError',
func: function() { return navigator.requestMediaKeySystemAccess('unsupported', [{}]); }
},
// Non-ASCII names.
{
exception: 'NotSupportedError',
func: function() { return navigator.requestMediaKeySystemAccess('org.w3\u263A.clearkey', [{}]); }
},
// Empty sequence of MediaKeySystemConfiguration.
{
exception: 'TypeError',
func: function() { return navigator.requestMediaKeySystemAccess('org.w3.clearkey', []); }
},
// Invalid sequences of MediaKeySystemConfigurations.
{
exception: 'TypeError',
func: function() { return navigator.requestMediaKeySystemAccess('org.w3.clearkey', {}); }
},
{
exception: 'TypeError',
func: function() { return navigator.requestMediaKeySystemAccess('org.w3.clearkey', "invalid"); }
},
{
exception: 'TypeError',
func: function() { return navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}, 6]); }
},
{
exception: 'TypeError',
func: function() { return navigator.requestMediaKeySystemAccess('org.w3.clearkey', ["invalid", "upsupported"]); }
}
];
async_test(function(test)
{
var createPromises = kRequestMediaKeySystemAccessExceptionsTestCases.map(function(testCase) {
return test_exception(testCase);
});
Promise.all(createPromises).then(function(result) {
test.done();
}).catch(function(error) {
forceTestFailureFromPromise(test, error, 'requestMediaKeySystemAccess() tests failed');
});
}, 'Test Navigator.requestMediaKeySystemAccess() exceptions.');
async_test(function(test)
{
assert_equals(typeof navigator.requestMediaKeySystemAccess, 'function');
navigator.requestMediaKeySystemAccess('org.w3.clearkey', getSimpleConfiguration()).then(function(access) {
assert_not_equals(access, null);
assert_equals(typeof access, 'object');
assert_equals(access.keySystem, 'org.w3.clearkey');
assert_equals(typeof access.getConfiguration, 'function');
assert_equals(typeof access.createMediaKeys, 'function');
test.done();
}).catch(function(error) {
forceTestFailureFromPromise(test, error, 'requestMediaKeySystemAccess() tests failed');
});
}, 'Test Navigator.requestMediaKeySystemAccess().');
async_test(function(test)
{
var access;
navigator.requestMediaKeySystemAccess('org.w3.clearkey', getSimpleConfiguration()).then(function(result) {
access = result;
assert_equals(access.keySystem, 'org.w3.clearkey');
return access.createMediaKeys();
}).then(function(mediaKeys) {
assert_not_equals(mediaKeys, null);
assert_equals(typeof mediaKeys, 'object');
assert_equals(typeof mediaKeys.createSession, 'function');
assert_equals(typeof mediaKeys.setServerCertificate, 'function');
// Test creation of a second MediaKeys.
// The extra parameter is ignored.
return access.createMediaKeys('extra');
}).then(function(mediaKeys) {
assert_not_equals(mediaKeys, null);
assert_equals(typeof mediaKeys, 'object');
assert_equals(typeof mediaKeys.createSession, 'function');
assert_equals(typeof mediaKeys.setServerCertificate, 'function');
test.done();
}).catch(function(error) {
forceTestFailureFromPromise(test, error, 'create() tests failed');
});
}, 'Test MediaKeySystemAccess createMediaKeys().');
var kCreateSessionExceptionsTestCases = [
// Tests in this set use a shortened parameter name due to
// format_value() only returning the first 60 characters as the
// result. With a longer name the first 60 characters is not
// enough to determine which test failed.
// Invalid parameters.
{
exception: 'TypeError',
func: function(mk) { return mk.createSession(); }
},
{
exception: 'TypeError',
func: function(mk) { return mk.createSession(''); }
},
{
exception: 'TypeError',
func: function(mk) { return mk.createSession(null); }
},
{
exception: 'TypeError',
func: function(mk) { return mk.createSession(undefined); }
},
{
exception: 'TypeError',
func: function(mk) { return mk.createSession(1); }
},
{
exception: 'TypeError',
func: function(mk) { return mk.createSession(new Uint8Array(0)); }
},
{
exception: 'TypeError',
func: function(mk) { return mk.createSession('TEMPORARY'); }
}
];
// This function checks that calling createSession() with an
// unsupported session type doesn't create a MediaKeySession object.
// Since requestMediaKeySystemAccess() is called without specifying
// persistent sessions, only temporary sessions will be allowed.
function test_unsupported_sessionType(mediaKeys)
{
var mediaKeySession = 'test';
try {
mediaKeySession = mediaKeys.createSession('persistent-license');
assert_unreached('Session should not be created.');
} catch (error) {
assert_equals(error.name, 'NotSupportedError');
assert_not_equals(error.message, "");
// Since createSession() failed, |mediaKeySession| is not
// touched.
assert_equals(mediaKeySession, 'test');
}
}
async_test(function(test)
{
navigator.requestMediaKeySystemAccess('org.w3.clearkey', getSimpleConfiguration()).then(function(access) {
return access.createMediaKeys();
}).then(function(mediaKeys) {
var sessionPromises = kCreateSessionExceptionsTestCases.map(function(testCase) {
return test_exception(testCase, mediaKeys);
});
sessionPromises = sessionPromises.concat(test_unsupported_sessionType(mediaKeys));
assert_not_equals(sessionPromises.length, 0);
return Promise.all(sessionPromises);
}).then(function(result) {
test.done();
}).catch(function(error) {
forceTestFailureFromPromise(test, error, 'createSession() tests failed');
});
}, 'Test MediaKeys createSession() exceptions.');
var kGenerateRequestExceptionsTestCases = [
// Tests in this set use a shortened parameter name due to
// format_value() only returning the first 60 characters as the
// result. With a longer name the first 60 characters is not
// enough to determine which test failed. Even with the
// shortened name, the error message for the last couple of
// tests is the same.
// Too few parameters.
{
exception: 'TypeError',
func: function(mk1) { return mk1.createSession().generateRequest(); }
},
{
exception: 'TypeError',
func: function(mk2) { return mk2.createSession().generateRequest(''); }
},
{
exception: 'TypeError',
func: function(mk3) { return mk3.createSession().generateRequest(null); }
},
{
exception: 'TypeError',
func: function(mk4) { return mk4.createSession().generateRequest(undefined); }
},
{
exception: 'TypeError',
func: function(mk5) { return mk5.createSession().generateRequest(1); }
},
{
exception: 'TypeError',
func: function(mk6) { return mk6.createSession().generateRequest(new Uint8Array(0)); }
},
{
exception: 'TypeError',
func: function(mk7, _, initData) { return mk7.createSession().generateRequest(initData); }
},
// Invalid parameters.
{
exception: 'TypeError',
func: function(mk8, _, initData) { return mk8.createSession().generateRequest('', initData); }
},
// Not supported initDataTypes.
{
exception: 'NotSupportedError',
func: function(mk9, _, initData) { return mk9.createSession().generateRequest(null, initData); }
},
{
exception: 'NotSupportedError',
func: function(mk10, _, initData) { return mk10.createSession().generateRequest(undefined, initData); }
},
{
exception: 'NotSupportedError',
func: function(mk11, _, initData) { return mk11.createSession().generateRequest(1, initData); }
},
{
exception: 'TypeError',
func: function(mk12, _, initData) { return mk12.createSession().generateRequest(new Uint8Array(0), initData); }
},
{
exception: 'NotSupportedError',
func: function(mk13, _, initData) { return mk13.createSession().generateRequest('unsupported', initData); }
},
{
exception: 'NotSupportedError',
func: function(mk14, _, initData) { return mk14.createSession().generateRequest('video/webm', initData); }
},
{
exception: 'NotSupportedError',
func: function(mk15, _, initData) { return mk15.createSession().generateRequest('video/mp4', initData); }
},
{
exception: 'NotSupportedError',
func: function(mk16, _, initData) { return mk16.createSession().generateRequest('video/cenc', initData); }
},
{
exception: 'NotSupportedError',
func: function(mk17, _, initData) { return mk17.createSession().generateRequest('web\u263A', initData); }
}
];
var kTypeSpecificGenerateRequestExceptionsTestCases = [
// Tests in this set use a shortened parameter name due to
// format_value() only returning the first 60 characters as the
// result. With a longer name the first 60 characters is not
// enough to determine which test failed. Even with the
// shortened name, the error message for the last couple of
// tests is the same.
// Too few parameters.
{
exception: 'TypeError',
func: function(mk1, type) { return mk1.createSession().generateRequest(type); }
},
// Invalid parameters.
{
exception: 'TypeError',
func: function(mk2, type) { return mk2.createSession().generateRequest(type, ''); }
},
{
exception: 'TypeError',
func: function(mk3, type) { return mk3.createSession().generateRequest(type, null); }
},
{
exception: 'TypeError',
func: function(mk4, type) { return mk4.createSession().generateRequest(type, undefined); }
},
{
exception: 'TypeError',
func: function(mk5, type) { return mk5.createSession().generateRequest(type, 1); }
},
{
exception: 'TypeError',
func: function(mk6, type) { return mk6.createSession().generateRequest(type, new Uint8Array(0)); }
}
];
async_test(function(test)
{
var isWebmSupported;
var isCencSupported;
isInitDataTypeSupported('webm').then(function(result) {
isWebmSupported = result;
return isInitDataTypeSupported('cenc');
}).then(function(result) {
isCencSupported = result;
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', getSimpleConfiguration());
}).then(function(access) {
return access.createMediaKeys();
}).then(function(mediaKeys) {
var initData = stringToUint8Array('init data');
var sessionPromises = kGenerateRequestExceptionsTestCases.map(function(testCase) {
return test_exception(testCase, mediaKeys, '', initData);
});
// Test that WebM sessions generate the expected error, if
// supported.
if (isWebmSupported) {
var WebmSessionPromises = kTypeSpecificGenerateRequestExceptionsTestCases.map(function(testCase) {
return test_exception(testCase, mediaKeys, 'webm', getInitData('webm'));
});
sessionPromises = sessionPromises.concat(WebmSessionPromises);
}
// Repeat for MP4, if supported.
if (isCencSupported) {
var mp4SessionPromises = kTypeSpecificGenerateRequestExceptionsTestCases.map(function(testCase) {
return test_exception(testCase, mediaKeys, 'cenc', getInitData('cenc'));
});
sessionPromises = sessionPromises.concat(mp4SessionPromises);
}
assert_not_equals(sessionPromises.length, 0);
return Promise.all(sessionPromises);
}).then(function(result) {
test.done();
}).catch(function(error) {
forceTestFailureFromPromise(test, error, 'generateRequest() tests failed');
});
}, 'Test MediaKeys generateRequest() exceptions.');
var kLoadExceptionsTestCases = [
// Too few parameters.
{
exception: 'TypeError',
func: function(mk1) { return mk1.createSession('temporary').load(); }
},
// 'temporary' sessions are never allowed, so always return
// 'TypeError'.
{
exception: 'TypeError',
func: function(mk3) { return mk3.createSession('temporary').load(''); }
},
{
exception: 'TypeError',
func: function(mk4) { return mk4.createSession('temporary').load(1); }
},
{
exception: 'TypeError',
func: function(mk5) { return mk5.createSession('temporary').load('!@#$%^&*()'); }
},
{
exception: 'TypeError',
func: function(mk6) { return mk6.createSession('temporary').load('1234'); }
}
];
async_test(function(test)
{
navigator.requestMediaKeySystemAccess('org.w3.clearkey', getSimpleConfiguration()).then(function(access) {
return access.createMediaKeys();
}).then(function(mediaKeys) {
var initData = stringToUint8Array('init data');
var sessionPromises = kLoadExceptionsTestCases.map(function(testCase) {
return test_exception(testCase, mediaKeys);
});
assert_not_equals(sessionPromises.length, 0);
return Promise.all(sessionPromises);
}).then(function(result) {
test.done();
}).catch(function(error) {
forceTestFailureFromPromise(test, error, 'load() tests failed');
});
}, 'Test MediaKeys load() exceptions.');
// All calls to |func| in this group are supposed to succeed.
// However, the spec notes that some things are optional for
// Clear Key. In particular, support for persistent sessions
// is optional. Since some implementations won't support some
// features, a NotSupportedError is treated as a success
// if |isNotSupportedAllowed| is true.
var kCreateSessionTestCases = [
// Use the default sessionType.
{
func: function(mk) { return mk.createSession(); },
isNotSupportedAllowed: false
},
// Try variations of sessionType.
{
func: function(mk) { return mk.createSession('temporary'); },
isNotSupportedAllowed: false
},
{
func: function(mk) { return mk.createSession(undefined); },
isNotSupportedAllowed: false
},
{
// Since this is optional, some Clear Key implementations
// will succeed, others will return a "NotSupportedError".
// Both are allowed results.
func: function(mk) { return mk.createSession('persistent-license'); },
isNotSupportedAllowed: true
},
// Try additional parameter, which should be ignored.
{
func: function(mk) { return mk.createSession('temporary', 'extra'); },
isNotSupportedAllowed: false
}
];
// This function checks that calling |testCase.func| creates a
// MediaKeySession object with some default values. It also
// allows for an NotSupportedError to be generated and treated as a
// success, if allowed. See comment above kCreateSessionTestCases.
function test_createSession(testCase, mediaKeys)
{
var mediaKeySession;
try {
mediaKeySession = testCase.func.call(null, mediaKeys);
} catch (e) {
assert_true(testCase.isNotSupportedAllowed);
return;
}
assert_equals(typeof mediaKeySession, 'object');
assert_equals(typeof mediaKeySession.addEventListener, 'function');
assert_equals(typeof mediaKeySession.sessionId, 'string');
assert_equals(typeof mediaKeySession.expiration, 'number');
assert_equals(typeof mediaKeySession.closed, 'object');
assert_equals(typeof mediaKeySession.keyStatuses, 'object');
assert_equals(typeof mediaKeySession.onkeystatuseschange, 'object');
assert_equals(typeof mediaKeySession.onmessage, 'object');
assert_equals(typeof mediaKeySession.generateRequest, 'function');
assert_equals(typeof mediaKeySession.load, 'function');
assert_equals(typeof mediaKeySession.update, 'function');
assert_equals(typeof mediaKeySession.close, 'function');
assert_equals(typeof mediaKeySession.remove, 'function');
assert_equals(mediaKeySession.sessionId, '');
}
async_test(function(test)
{
navigator.requestMediaKeySystemAccess('org.w3.clearkey', getSimpleConfiguration()).then(function(access) {
return access.createMediaKeys();
}).then(function(mediaKeys) {
kCreateSessionTestCases.map(function(testCase) {
test_createSession(testCase, mediaKeys);
});
test.done();
}).catch(function(error) {
forceTestFailureFromPromise(test, error, 'createSession() tests failed');
});
}, 'Test MediaKeys createSession().');
// This function checks that calling generateRequest() works for
// various sessions. |testCase.func| creates a MediaKeySession
// object, and then generateRequest() is called on that object. It
// allows for an NotSupportedError to be generated and treated as a
// success, if allowed. See comment above kCreateSessionTestCases.
function test_generateRequest(testCase, mediaKeys, type, initData)
{
try {
var mediaKeySession = testCase.func.call(null, mediaKeys);
return mediaKeySession.generateRequest(type, initData);
} catch (e) {
assert_true(testCase.isNotSupportedAllowed);
}
}
async_test(function(test)
{
var isWebmSupported;
var isCencSupported;
isInitDataTypeSupported('webm').then(function(result) {
isWebmSupported = result;
return isInitDataTypeSupported('cenc');
}).then(function(result) {
isCencSupported = result;
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', getSimpleConfiguration());
}).then(function(access) {
return access.createMediaKeys();
}).then(function(mediaKeys) {
var sessionPromises = [];
// Test that WebM sessions generate the expected error, if
// supported.
if (isWebmSupported) {
var WebmSessionPromises = kCreateSessionTestCases.map(function(testCase) {
return test_generateRequest(testCase, mediaKeys, 'webm', getInitData('webm'));
});
sessionPromises = sessionPromises.concat(WebmSessionPromises);
}
// Repeat for MP4, if supported.
if (isCencSupported) {
var mp4SessionPromises = kCreateSessionTestCases.map(function(testCase) {
return test_generateRequest(testCase, mediaKeys, 'cenc', getInitData('cenc'));
});
sessionPromises = sessionPromises.concat(mp4SessionPromises);
}
assert_not_equals(sessionPromises.length, 0);
return Promise.all(sessionPromises);
}).then(function(result) {
test.done();
}).catch(function(error) {
forceTestFailureFromPromise(test, error, 'generateRequest() tests failed');
});
}, 'Test MediaKeys generateRequest().');
var kUpdateSessionExceptionsTestCases = [
// Tests in this set use a shortened parameter name due to
// format_value() only returning the first 60 characters as the
// result. With a longer name (mediaKeySession) the first 60
// characters is not enough to determine which test failed.
// Too few parameters.
{
exception: 'TypeError',
func: function(s) { return s.update(); }
},
// Invalid parameters.
{
exception: 'TypeError',
func: function(s) { return s.update(''); }
},
{
exception: 'TypeError',
func: function(s) { return s.update(null); }
},
{
exception: 'TypeError',
func: function(s) { return s.update(undefined); }
},
{
exception: 'TypeError',
func: function(s) { return s.update(1); }
},
{
exception: 'TypeError',
func: function(s) { return s.update(new Uint8Array(0)); }
}
];
async_test(function(test)
{
var isWebmSupported;
var isCencSupported;
isInitDataTypeSupported('webm').then(function(result) {
isWebmSupported = result;
return isInitDataTypeSupported('cenc');
}).then(function(result) {
isCencSupported = result;
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', getSimpleConfiguration());
}).then(function(access) {
return access.createMediaKeys();
}).then(function(mediaKeys) {
var promises = [];
if (isWebmSupported) {
var WebmSessionPromises = kUpdateSessionExceptionsTestCases.map(function(testCase) {
var mediaKeySession = mediaKeys.createSession();
return mediaKeySession.generateRequest('webm', getInitData('webm')).then(function(result) {
return test_exception(testCase, mediaKeySession);
});
});
promises = promises.concat(WebmSessionPromises);
}
if (isCencSupported) {
var mp4SessionPromises = kUpdateSessionExceptionsTestCases.map(function(testCase) {
var mediaKeySession = mediaKeys.createSession();
return mediaKeySession.generateRequest('cenc', getInitData('cenc')).then(function(result) {
return test_exception(testCase, mediaKeySession);
});
});
promises = promises.concat(mp4SessionPromises);
}
assert_not_equals(promises.length, 0);
return Promise.all(promises);
}).then(function(result) {
test.done();
}).catch(function(error) {
forceTestFailureFromPromise(test, error, 'update() tests failed');
});
}, 'Test MediaKeySession update() exceptions.');
function create_update_test(mediaKeys, type, initData)
{
var mediaKeySession = mediaKeys.createSession();
var promise = mediaKeySession.generateRequest(type, initData).then(function(result) {
var validLicense = stringToUint8Array(createJWKSet(createJWK(stringToUint8Array('123'), stringToUint8Array('1234567890abcdef'))));
return mediaKeySession.update(validLicense);
}).then(function(result) {
// Call update() with a different license and an extra
// parameter. The extra parameter is ignored.
var validLicense = stringToUint8Array(createJWKSet(createJWK(stringToUint8Array('4567890'), stringToUint8Array('01234567890abcde'))));
return mediaKeySession.update(validLicense, 'extra');
});
return promise;
}
async_test(function(test)
{
var isWebmSupported;
var isCencSupported;
isInitDataTypeSupported('webm').then(function(result) {
isWebmSupported = result;
return isInitDataTypeSupported('cenc');
}).then(function(result) {
isCencSupported = result;
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', getSimpleConfiguration());
}).then(function(access) {
return access.createMediaKeys();
}).then(function(mediaKeys) {
var promises = [];
if (isWebmSupported) {
promises.push(create_update_test(mediaKeys, 'webm', getInitData('webm')));
}
if (isCencSupported) {
promises.push(create_update_test(mediaKeys, 'cenc', getInitData('cenc')));
}
assert_not_equals(promises.length, 0);
return Promise.all(promises);
}).then(function(result) {
test.done();
}).catch(function(error) {
forceTestFailureFromPromise(test, error, 'update() tests failed');
});
}, 'Test MediaKeySession update().');
function create_close_exception_test(mediaKeys, type, initData)
{
var mediaKeySession = mediaKeys.createSession();
return mediaKeySession.close().then(function(result) {
assert_unreached('close() should not succeed if session uninitialized');
}).catch(function(error) {
assert_equals(error.name, 'InvalidStateError');
// Return something so the promise resolves.
return Promise.resolve();
});
}
async_test(function(test)
{
var isWebmSupported;
var isCencSupported;
isInitDataTypeSupported('webm').then(function(result) {
isWebmSupported = result;
return isInitDataTypeSupported('cenc');
}).then(function(result) {
isCencSupported = result;
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', getSimpleConfiguration());
}).then(function(access) {
return access.createMediaKeys();
}).then(function(mediaKeys) {
var promises = [];
if (isWebmSupported) {
promises.push(create_close_exception_test(mediaKeys, 'webm', getInitData('webm')));
}
if (isCencSupported) {
promises.push(create_close_exception_test(mediaKeys, 'cenc', getInitData('cenc')));
}
assert_not_equals(promises.length, 0);
return Promise.all(promises);
}).then(function(result) {
test.done();
}).catch(function(error) {
forceTestFailureFromPromise(test, error, 'close() exception tests failed');
});
}, 'Test MediaKeySession close() exceptions.');
function create_close_test(mediaKeys, type, initData)
{
var mediaKeySession = mediaKeys.createSession();
var promise = mediaKeySession.generateRequest(type, initData).then(function(result) {
return mediaKeySession.close();
}).then(function(result) {
// Call close() again with an extra parameter. The extra
// parameter is ignored.
return mediaKeySession.close('extra');
});
return promise;
}
async_test(function(test)
{
var isWebmSupported;
var isCencSupported;
isInitDataTypeSupported('webm').then(function(result) {
isWebmSupported = result;
return isInitDataTypeSupported('cenc');
}).then(function(result) {
isCencSupported = result;
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', getSimpleConfiguration());
}).then(function(access) {
return access.createMediaKeys();
}).then(function(mediaKeys) {
var promises = [];
if (isWebmSupported) {
promises.push(create_close_test(mediaKeys, 'webm', getInitData('webm')));
}
if (isCencSupported) {
promises.push(create_close_test(mediaKeys, 'cenc', getInitData('cenc')));
}
assert_not_equals(promises.length, 0);
return Promise.all(promises);
}).then(function(result) {
test.done();
}).catch(function(error) {
forceTestFailureFromPromise(test, error, 'close() tests failed');
});
}, 'Test MediaKeySession close().');
function create_remove_exception_test(mediaKeys, type, initData)
{
// remove() on an uninitialized session should fail.
var mediaKeySession = mediaKeys.createSession('temporary');
return mediaKeySession.remove().then(function(result) {
assert_unreached('remove() should not succeed if session uninitialized');
}, function(error) {
assert_equals(error.name, 'InvalidStateError');
});
}
async_test(function(test)
{
var isWebmSupported;
var isCencSupported;
isInitDataTypeSupported('webm').then(function(result) {
isWebmSupported = result;
return isInitDataTypeSupported('cenc');
}).then(function(result) {
isCencSupported = result;
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', getSimpleConfiguration());
}).then(function(access) {
return access.createMediaKeys();
}).then(function(mediaKeys) {
var promises = [];
if (isWebmSupported) {
promises.push(create_remove_exception_test(mediaKeys, 'webm', getInitData('webm')));
}
if (isCencSupported) {
promises.push(create_remove_exception_test(mediaKeys, 'cenc', getInitData('cenc')));
}
assert_not_equals(promises.length, 0);
return Promise.all(promises);
}).then(function(result) {
test.done();
}).catch(function(error) {
forceTestFailureFromPromise(test, error, 'remove() exception tests failed');
});
}, 'Test MediaKeySession remove() exceptions.');
function create_remove_test(mediaKeys, type, initData)
{
var mediaKeySession = mediaKeys.createSession();
var promise = mediaKeySession.generateRequest(type, initData).then(function(result) {
return mediaKeySession.remove();
}).then(function() {
// remove() doesn't close the session, so must call close().
return mediaKeySession.close();
}).then(function() {
try {
// Clear Key may not support persistent-license sessions.
mediaKeySession = mediaKeys.createSession('persistent-license');
return mediaKeySession.generateRequest(type, initData).then(function(result) {
return mediaKeySession.remove();
}).then(function() {
return mediaKeySession.close();
});
} catch (error) {
// Not supported, so return a resolved promise.
assert_equals(error.name, 'NotSupportedError');
return Promise.resolve();
}
});
}
async_test(function(test)
{
var isWebmSupported;
var isCencSupported;
isInitDataTypeSupported('webm').then(function(result) {
isWebmSupported = result;
return isInitDataTypeSupported('cenc');
}).then(function(result) {
isCencSupported = result;
return navigator.requestMediaKeySystemAccess('org.w3.clearkey', getSimpleConfiguration());
}).then(function(access) {
return access.createMediaKeys();
}).then(function(mediaKeys) {
var promises = [];
if (isWebmSupported) {
promises.push(create_remove_test(mediaKeys, 'webm', getInitData('webm')));
}
if (isCencSupported) {
promises.push(create_remove_test(mediaKeys, 'cenc', getInitData('cenc')));
}
assert_not_equals(promises.length, 0);
return Promise.all(promises);
}).then(function(result) {
test.done();
}).catch(function(error) {
forceTestFailureFromPromise(test, error, 'remove() tests failed');
});
}, 'Test MediaKeySession remove().');
var kSetServerCertificateExceptionsTestCases = [
// Too few parameters.
{
exception: 'TypeError',
func: function(mk) { return mk.setServerCertificate(); }
},
// Invalid parameters.
{
exception: 'TypeError',
func: function(mk) { return mk.setServerCertificate(''); }
},
{
exception: 'TypeError',
func: function(mk) { return mk.setServerCertificate(null); }
},
{
exception: 'TypeError',
func: function(mk) { return mk.setServerCertificate(undefined); }
},
{
exception: 'TypeError',
func: function(mk) { return mk.setServerCertificate(1); }
},
// Empty array.
{
exception: 'TypeError',
func: function(mk) { return mk.setServerCertificate(new Uint8Array(0)); }
}
];
async_test(function(test)
{
navigator.requestMediaKeySystemAccess('org.w3.clearkey', getSimpleConfiguration()).then(function(access) {
return access.createMediaKeys();
}).then(function(mediaKeys) {
var promises = kSetServerCertificateExceptionsTestCases.map(function(testCase) {
return test_exception(testCase, mediaKeys);
});
assert_not_equals(promises.length, 0);
return Promise.all(promises);
}).then(function(result) {
test.done();
}).catch(function(error) {
forceTestFailureFromPromise(test, error, 'setServerCertificate() exception tests failed');
});
}, 'Test MediaKeys setServerCertificate() exceptions.');
// All calls to |func| in this group are expected to resolve.
var kSetServerCertificateTestCases = [
{
// Pass in ArrayBufferView
func: function(mk) {
var cert = new Uint8Array(200);
assert_true(ArrayBuffer.isView(cert));
return mk.setServerCertificate(cert);
},
expected: false,
},
{
// Pass in ArrayBuffer
func: function(mk) {
var buffer = new ArrayBuffer(200);
assert_false(ArrayBuffer.isView(buffer));
return mk.setServerCertificate(buffer);
},
expected: false,
}
];
async_test(function(test)
{
var expected_result;
navigator.requestMediaKeySystemAccess('org.w3.clearkey', getSimpleConfiguration()).then(function(access) {
return access.createMediaKeys();
}).then(function(mediaKeys) {
var promises = kSetServerCertificateTestCases.map(function(testCase) {
return testCase.func.call(null, mediaKeys);
});
expected_result = kSetServerCertificateTestCases.map(function(testCase) {
return testCase.expected;
});
assert_not_equals(promises.length, 0);
return Promise.all(promises);
}).then(function(result) {
assert_array_equals(result, expected_result);
test.done();
}).catch(function(error) {
forceTestFailureFromPromise(test, error, 'setServerCertificate() test failed');
});
}, 'Test MediaKeys setServerCertificate().');
function test_valid_message_type(message_type)
{
var event = new MediaKeyMessageEvent('eventType', { messageType: message_type, message: new ArrayBuffer(0) } );
assert_equals(event.messageType, message_type);
}
test(function(test)
{
// Valid MediaKeyMessageType values.
test_valid_message_type('license-request');
test_valid_message_type('license-renewal');
test_valid_message_type('license-release');
// TODO(jrummell): Add 'individualization-request' if the final
// spec includes it. http://crbug.com/628437.
// Invalid MediaKeyMessageType values should throw a TypeError.
assert_throws_js(TypeError, function() {
new MediaKeyMessageEvent('eventType', { messageType: 'something-else', message: new ArrayBuffer(0) } );
});
// Missing required values should throw a TypeError.
assert_throws_js(TypeError, function() {
new MediaKeyMessageEvent('eventType', { message: new ArrayBuffer(0) } );
});
assert_throws_js(TypeError, function() {
new MediaKeyMessageEvent('eventType', { messageType: 'license-request' } );
});
}, 'Test MediaKeyMessageEvent.');
// FIXME: Add syntax checks for MediaKeys.IsTypeSupported().
// FIXME: Add syntax checks for MediaKeyError and MediaKeySession events.
// FIXME: Add HTMLMediaElement syntax checks, e.g. setMediaKeys, mediakeys, onencrypted.
</script>
</body>
</html>