From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../scripts/check-encryption-scheme.js | 46 +++ .../encrypted-media/scripts/check-initdata-type.js | 35 ++ .../scripts/check-status-for-hdcp.js | 26 ++ .../scripts/clearkey-update-non-ascii-input.js | 52 +++ .../scripts/events-session-closed-event.js | 52 +++ .../tests/encrypted-media/scripts/events.js | 59 +++ .../tests/encrypted-media/scripts/expiration.js | 43 ++ .../scripts/generate-request-disallowed-input.js | 72 ++++ .../encrypted-media/scripts/invalid-license.js | 38 ++ .../scripts/keystatuses-multiple-sessions.js | 103 +++++ .../tests/encrypted-media/scripts/keystatuses.js | 165 ++++++++ .../scripts/not-callable-after-createsession.js | 50 +++ .../tests/encrypted-media/scripts/onencrypted.js | 48 +++ .../scripts/playback-destroy-persistent-license.js | 95 +++++ .../scripts/playback-persistent-license-events.js | 158 +++++++ .../scripts/playback-persistent-license.js | 77 ++++ .../playback-persistent-usage-record-events.js | 109 +++++ .../scripts/playback-persistent-usage-record.js | 104 +++++ .../playback-retrieve-persistent-license.js | 115 ++++++ .../playback-retrieve-persistent-usage-record.js | 114 ++++++ ...-temporary-encrypted-clear-segmented-sources.js | 109 +++++ .../playback-temporary-encrypted-clear-sources.js | 109 +++++ .../scripts/playback-temporary-events.js | 131 ++++++ .../scripts/playback-temporary-expired.js | 95 +++++ .../playback-temporary-multikey-sequential.js | 122 ++++++ .../scripts/playback-temporary-multisession.js | 76 ++++ .../playback-temporary-playduration-keystatus.js | 78 ++++ .../scripts/playback-temporary-playduration.js | 80 ++++ .../scripts/playback-temporary-setMediaKeys.js | 105 +++++ .../scripts/playback-temporary-two-videos.js | 83 ++++ .../scripts/playback-temporary-waitingforkey.js | 71 ++++ .../encrypted-media/scripts/playback-temporary.js | 82 ++++ .../scripts/requestmediakeysystemaccess.js | 341 ++++++++++++++++ .../scripts/reset-src-after-setmediakeys.js | 61 +++ .../scripts/setmediakeys-again-after-playback.js | 79 ++++ .../setmediakeys-again-after-resetting-src.js | 79 ++++ .../scripts/setmediakeys-at-same-time.js | 59 +++ ...keys-multiple-times-with-different-mediakeys.js | 98 +++++ ...akeys-multiple-times-with-the-same-mediakeys.js | 46 +++ .../setmediakeys-to-multiple-video-elements.js | 54 +++ .../tests/encrypted-media/scripts/setmediakeys.js | 50 +++ .../encrypted-media/scripts/syntax-mediakeys.js | 184 +++++++++ .../scripts/syntax-mediakeysession.js | 452 +++++++++++++++++++++ .../scripts/syntax-mediakeysystemaccess.js | 147 +++++++ .../scripts/temporary-license-type.js | 61 +++ .../tests/encrypted-media/scripts/unique-origin.js | 64 +++ .../scripts/update-disallowed-input.js | 43 ++ .../encrypted-media/scripts/waiting-for-a-key.js | 166 ++++++++ 48 files changed, 4686 insertions(+) create mode 100644 testing/web-platform/tests/encrypted-media/scripts/check-encryption-scheme.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/check-initdata-type.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/check-status-for-hdcp.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/clearkey-update-non-ascii-input.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/events-session-closed-event.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/events.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/expiration.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/generate-request-disallowed-input.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/invalid-license.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/keystatuses-multiple-sessions.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/keystatuses.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/not-callable-after-createsession.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/onencrypted.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/playback-destroy-persistent-license.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/playback-persistent-license-events.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/playback-persistent-license.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/playback-persistent-usage-record-events.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/playback-persistent-usage-record.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/playback-retrieve-persistent-license.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/playback-retrieve-persistent-usage-record.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/playback-temporary-encrypted-clear-segmented-sources.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/playback-temporary-encrypted-clear-sources.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/playback-temporary-events.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/playback-temporary-expired.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/playback-temporary-multikey-sequential.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/playback-temporary-multisession.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/playback-temporary-playduration-keystatus.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/playback-temporary-playduration.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/playback-temporary-setMediaKeys.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/playback-temporary-two-videos.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/playback-temporary-waitingforkey.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/playback-temporary.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/requestmediakeysystemaccess.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/reset-src-after-setmediakeys.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/setmediakeys-again-after-playback.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/setmediakeys-again-after-resetting-src.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/setmediakeys-at-same-time.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/setmediakeys-multiple-times-with-different-mediakeys.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/setmediakeys-multiple-times-with-the-same-mediakeys.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/setmediakeys-to-multiple-video-elements.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/setmediakeys.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/syntax-mediakeys.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/syntax-mediakeysession.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/syntax-mediakeysystemaccess.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/temporary-license-type.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/unique-origin.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/update-disallowed-input.js create mode 100644 testing/web-platform/tests/encrypted-media/scripts/waiting-for-a-key.js (limited to 'testing/web-platform/tests/encrypted-media/scripts') diff --git a/testing/web-platform/tests/encrypted-media/scripts/check-encryption-scheme.js b/testing/web-platform/tests/encrypted-media/scripts/check-encryption-scheme.js new file mode 100644 index 0000000000..ffab4a3491 --- /dev/null +++ b/testing/web-platform/tests/encrypted-media/scripts/check-encryption-scheme.js @@ -0,0 +1,46 @@ +function runTest(config, qualifier) +{ + function checkEncryptionScheme(encryptionScheme) + { + var simpleConfig = getSimpleConfiguration(); + assert_greater_than(simpleConfig[0].audioCapabilities.length, 0); + simpleConfig[0].audioCapabilities.forEach(function(capability) { + capability.encryptionScheme = encryptionScheme; + }); + + return navigator.requestMediaKeySystemAccess(config.keysystem, simpleConfig) + .then( + function(access) { + var actualConfiguration = access.getConfiguration(); + for (let i = 0; i < actualConfiguration.audioCapabilities.length; i++) { + const capability = actualConfiguration.audioCapabilities[i]; + + // If "encryptionScheme" is not supported, fail. + if (!('encryptionScheme' in capability)) { + return Promise.reject('Not implemented'); + } + + // If "encryptionScheme" is supported, it should be returned. + assert_equals(capability.encryptionScheme, encryptionScheme); + } + return Promise.resolve('Supported'); + }, + function error() { + // CDM does not support "encryptionScheme". Test should still pass. + return Promise.resolve('Not supported'); + }); + } + + promise_test( + () => checkEncryptionScheme('cenc'), + testnamePrefix(qualifier, config.keysystem) + ' support for "cenc" encryption scheme.'); + + promise_test( + () => checkEncryptionScheme('cbcs'), + testnamePrefix(qualifier, config.keysystem) + ' support for "cbcs" encryption scheme.'); + + promise_test( + () => checkEncryptionScheme('cbcs-1-9'), + testnamePrefix(qualifier, config.keysystem) + + ' support for "cbcs-1-9" encryption scheme.'); +} diff --git a/testing/web-platform/tests/encrypted-media/scripts/check-initdata-type.js b/testing/web-platform/tests/encrypted-media/scripts/check-initdata-type.js new file mode 100644 index 0000000000..5c7cb6e4b9 --- /dev/null +++ b/testing/web-platform/tests/encrypted-media/scripts/check-initdata-type.js @@ -0,0 +1,35 @@ + function runTest( config, qualifier ) + { + function checkInitDataType(initDataType) + { + return isInitDataTypeSupported(initDataType).then(function(result) { + // If |initDataType| is not supported, simply succeed. + if (!result) + return Promise.resolve('Not supported'); + + return navigator.requestMediaKeySystemAccess( config.keysystem, getSimpleConfigurationForInitDataType(initDataType)) + .then(function(access) { + return access.createMediaKeys(); + }).then(function(mediaKeys) { + var mediaKeySession = mediaKeys.createSession(); + var initData = getInitData(initDataType); + return mediaKeySession.generateRequest(initDataType, initData); + }); + }); + } + + promise_test(function() + { + return checkInitDataType('webm'); + }, testnamePrefix( qualifier, config.keysystem ) + ' support for "webm".'); + + promise_test(function() + { + return checkInitDataType('cenc'); + }, testnamePrefix( qualifier, config.keysystem ) + ' support for "cenc".'); + + promise_test(function() + { + return checkInitDataType('keyids'); + }, testnamePrefix( qualifier, config.keysystem ) + ' support for "keyids".'); +} diff --git a/testing/web-platform/tests/encrypted-media/scripts/check-status-for-hdcp.js b/testing/web-platform/tests/encrypted-media/scripts/check-status-for-hdcp.js new file mode 100644 index 0000000000..ac30819695 --- /dev/null +++ b/testing/web-platform/tests/encrypted-media/scripts/check-status-for-hdcp.js @@ -0,0 +1,26 @@ +function runTest(config, qualifier) +{ + function checkStatusForMinHdcpVersionPolicy(hdcpVersion) + { + return navigator.requestMediaKeySystemAccess(config.keysystem, getSimpleConfiguration()) + .then(function(access) { + return access.createMediaKeys(); + }) + .then(function(mediaKeys) { + // As HDCP policy depends on the hardware running this test, + // don't bother checking the result returned as it may or + // may not be supported. This simply verifies that + // getStatusForPolicy() exists and doesn't blow up. + return mediaKeys.getStatusForPolicy({minHdcpVersion: hdcpVersion}); + }); + } + + promise_test( + () => checkStatusForMinHdcpVersionPolicy(''), + testnamePrefix(qualifier, config.keysystem) + + ' support for empty HDCP version.'); + + promise_test( + () => checkStatusForMinHdcpVersionPolicy('1.0'), + testnamePrefix(qualifier, config.keysystem) + ' support for HDCP 1.0.'); +} diff --git a/testing/web-platform/tests/encrypted-media/scripts/clearkey-update-non-ascii-input.js b/testing/web-platform/tests/encrypted-media/scripts/clearkey-update-non-ascii-input.js new file mode 100644 index 0000000000..7a5c073bfa --- /dev/null +++ b/testing/web-platform/tests/encrypted-media/scripts/clearkey-update-non-ascii-input.js @@ -0,0 +1,52 @@ +// This test is only applicable to clearkey +function runTest(config, qualifier) +{ + var testname = testnamePrefix(qualifier, config.keysystem) + ' test handling of non-ASCII responses for update()'; + + var configuration = getSimpleConfigurationForContent(config.content); + + if (config.initDataType) { + configuration.initDataTypes = [config.initDataType]; + } + + promise_test(function (test) { + var initDataType; + var initData; + var mediaKeySession; + var messageEventFired = false; + + var p = navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function (access) { + initDataType = access.getConfiguration().initDataTypes[0]; + initData = getInitData(config.content, initDataType); + return access.createMediaKeys(); + }).then(function (mediaKeys) { + mediaKeySession = mediaKeys.createSession(); + var eventWatcher = new EventWatcher(test, mediaKeySession, ['message']); + var promise = eventWatcher.wait_for('message'); + mediaKeySession.generateRequest(initDataType, initData); + return promise; + }).then(function (messageEvent) { + // |jwkSet| contains a non-ASCII character \uDC00. + var jwkSet = '{"keys":[{' + + '"kty":"oct",' + + '"k":"MDEyMzQ1Njc4OTAxMjM0NQ",' + + '"kid":"MDEyMzQ1Njc4O\uDC00TAxMjM0NQ"' + + '}]}'; + messageEventFired = true; + return messageEvent.target.update(stringToUint8Array(jwkSet)); + }).catch(function (error) { + // Ensure we reached the update() call we are trying to test. + if (!messageEventFired) { + assert_unreached( + `Failed to reach the update() call. Error: '${error.name}' '${error.message}'`); + } + + // Propagate the error on through. + throw error; + }); + + return promise_rejects_js( + test, TypeError, p, + 'update() should fail because the processed message has non-ASCII character.'); + }, testname); +} diff --git a/testing/web-platform/tests/encrypted-media/scripts/events-session-closed-event.js b/testing/web-platform/tests/encrypted-media/scripts/events-session-closed-event.js new file mode 100644 index 0000000000..44f683eac8 --- /dev/null +++ b/testing/web-platform/tests/encrypted-media/scripts/events-session-closed-event.js @@ -0,0 +1,52 @@ +function runTest(config, qualifier) +{ + var testname = testnamePrefix(qualifier, config.keysystem) + ' test MediaKeySession closed event.'; + + var configuration = { + initDataTypes: [config.initDataType], + audioCapabilities: [{ + contentType: config.audioType + }], + videoCapabilities: [{ + contentType: config.videoType + }], + sessionTypes: ['temporary'] + }; + + promise_test(function (test) { + var initDataType; + var initData; + var mediaKeySession; + + return navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function (access) { + initDataType = access.getConfiguration().initDataTypes[0]; + return access.createMediaKeys(); + }).then(function (mediaKeys) { + mediaKeySession = mediaKeys.createSession(); + if(config.initData) { + initData = config.initData; + } else { + initData = stringToUint8Array(atob(config.content.keys[0].initData)); + } + return mediaKeySession.generateRequest(initDataType, initData); + }).then(function() { + // close() should result in the closed promise being + // fulfilled. + return mediaKeySession.close(); + }).then(function (result) { + assert_equals(result, undefined); + // Wait for the session to be closed. + return mediaKeySession.closed; + }).then(function (result) { + assert_equals(result, undefined); + // Now that the session is closed, verify that the + // closed attribute immediately returns a fulfilled + // promise. + return mediaKeySession.closed; + }).then(function (result) { + assert_equals(result, undefined); + }).catch(function(error) { + assert_unreached('Error: ' + error.name); + }); + }, testname); +} \ No newline at end of file diff --git a/testing/web-platform/tests/encrypted-media/scripts/events.js b/testing/web-platform/tests/encrypted-media/scripts/events.js new file mode 100644 index 0000000000..85c86ae78d --- /dev/null +++ b/testing/web-platform/tests/encrypted-media/scripts/events.js @@ -0,0 +1,59 @@ +function runTest(config,qualifier) { + + var testname = testnamePrefix(qualifier, config.keysystem) + ', basic events'; + + var configuration = getSimpleConfigurationForContent(config.content); + + if (config.initDataType && config.initData) { + configuration.initDataTypes = [config.initDataType]; + } + + async_test(function(test) + { + var initDataType; + var initData; + var mediaKeySession; + + function onFailure(error) { + forceTestFailureFromPromise(test, error); + } + + function processMessage(event) + { + assert_true(event instanceof window.MediaKeyMessageEvent); + assert_equals(event.target, mediaKeySession); + assert_equals(event.type, 'message'); + assert_in_array(event.messageType,['license-request', 'individualization-request']); + + config.messagehandler( event.messageType, event.message ).then(function(response) { + waitForEventAndRunStep('keystatuseschange', mediaKeySession, test.step_func(processKeyStatusesChange), test); + return mediaKeySession.update( response ); + }).catch(onFailure); + } + + function processKeyStatusesChange(event) + { + assert_true(event instanceof Event); + assert_equals(event.target, mediaKeySession); + assert_equals(event.type, 'keystatuseschange'); + test.done(); + } + + navigator.requestMediaKeySystemAccess(config.keysystem,[configuration]).then(function(access) { + initDataType = access.getConfiguration().initDataTypes[0]; + + if (config.initDataType && config.initData) { + initData = config.initData; + } else { + initData = getInitData(config.content, initDataType); + } + + return access.createMediaKeys(); + }).then(test.step_func(function(mediaKeys) { + mediaKeySession = mediaKeys.createSession(); + waitForEventAndRunStep('message', mediaKeySession, test.step_func(processMessage), test); + return mediaKeySession.generateRequest(initDataType, initData); + })).catch(onFailure); + }, testname ); + +} diff --git a/testing/web-platform/tests/encrypted-media/scripts/expiration.js b/testing/web-platform/tests/encrypted-media/scripts/expiration.js new file mode 100644 index 0000000000..96b7fbfeef --- /dev/null +++ b/testing/web-platform/tests/encrypted-media/scripts/expiration.js @@ -0,0 +1,43 @@ +function runTest(config,qualifier) { + + var testname = testnamePrefix(qualifier, config.keysystem) + ', expiration'; + + var configuration = getSimpleConfigurationForContent(config.content); + if (config.initDataType && config.initData) { + configuration.initDataTypes = [config.initDataType]; + } + + async_test(function(test) { + + var _mediaKeys, + _mediaKeySession; + + function onFailure(error) { + forceTestFailureFromPromise(test, error); + } + + function onMessage(event) { + assert_equals(event.target, _mediaKeySession); + assert_true(event instanceof window.MediaKeyMessageEvent); + assert_equals(event.type, 'message'); + + assert_in_array(event.messageType, [ 'license-request', 'individualization-request' ] ); + + config.messagehandler(event.messageType, event.message, {expiration: config.expiration}).then(function(response) { + return event.target.update(response); + }).then(test.step_func(function() { + assert_approx_equals(event.target.expiration, config.expiration, 4000, "expiration attribute should equal provided expiration time"); + test.done(); + })).catch(onFailure); + } + + navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function(access) { + return access.createMediaKeys(); + }).then(function(mediaKeys) { + _mediaKeys = mediaKeys; + _mediaKeySession = _mediaKeys.createSession( 'temporary' ); + waitForEventAndRunStep('message', _mediaKeySession, onMessage, test); + return _mediaKeySession.generateRequest(config.initDataType, config.initData); + }).catch(onFailure); + }, testname); +} diff --git a/testing/web-platform/tests/encrypted-media/scripts/generate-request-disallowed-input.js b/testing/web-platform/tests/encrypted-media/scripts/generate-request-disallowed-input.js new file mode 100644 index 0000000000..9fd42ee85f --- /dev/null +++ b/testing/web-platform/tests/encrypted-media/scripts/generate-request-disallowed-input.js @@ -0,0 +1,72 @@ +function runTest(config,qualifier) { + var tests = [ ], initData, keyId; + function push_test(keysystem, initDataType, initData, testname) { + tests.push({ keysystem: keysystem, initDataType: initDataType, initData: initData, testname: testname }); + } + + initData = new Uint8Array(70000); + push_test(config.keysystem, 'webm', initData, testnamePrefix( qualifier, config.keysystem ) + ', temporary, webm, initData longer than 64Kb characters'); + + initData = new Uint8Array(70000); + push_test(config.keysystem, 'cenc', initData, testnamePrefix( qualifier, config.keysystem ) + ', temporary, cenc, initData longer than 64Kb characters'); + + initData = new Uint8Array(70000); + push_test(config.keysystem, 'keyids', initData, testnamePrefix( qualifier, config.keysystem ) + ', temporary, keyids, initData longer than 64Kb characters'); + + // Invalid 'pssh' box as the size specified is larger than what + // is provided. + initData = new Uint8Array([ + 0x00, 0x00, 0xff, 0xff, // size = huge + 0x70, 0x73, 0x73, 0x68, // 'pssh' + 0x00, // version = 0 + 0x00, 0x00, 0x00, // flags + 0x10, 0x77, 0xEF, 0xEC, 0xC0, 0xB2, 0x4D, 0x02, // Common SystemID + 0xAC, 0xE3, 0x3C, 0x1E, 0x52, 0xE2, 0xFB, 0x4B, + 0x00, 0x00, 0x00, 0x00 // datasize + ]); + push_test(config.keysystem, 'cenc', initData, testnamePrefix( qualifier, config.keysystem ) + ', temporary, cenc, invalid initdata (invalid pssh)'); + + // Invalid data as type = 'psss'. + initData = new Uint8Array([ + 0x00, 0x00, 0x00, 0x00, // size = 0 + 0x70, 0x73, 0x73, 0x73, // 'psss' + 0x00, // version = 0 + 0x00, 0x00, 0x00, // flags + 0x10, 0x77, 0xEF, 0xEC, 0xC0, 0xB2, 0x4D, 0x02, // Common SystemID + 0xAC, 0xE3, 0x3C, 0x1E, 0x52, 0xE2, 0xFB, 0x4B, + 0x00, 0x00, 0x00, 0x00 // datasize + ]); + push_test(config.keysystem, 'cenc', initData, testnamePrefix( qualifier, config.keysystem ) + ', temporary, cenc, invalid initdata (not pssh)'); + + // Valid key ID size must be at least 1 character for keyids. + keyId = new Uint8Array(0); + initData = stringToUint8Array(createKeyIDs(keyId)); + push_test(config.keysystem, 'keyids', initData, testnamePrefix( qualifier, config.keysystem ) + ', temporary, keyids, invalid initdata (too short key ID)'); + + // Valid key ID size must be less than 512 characters for keyids. + keyId = new Uint8Array(600); + initData = stringToUint8Array(createKeyIDs(keyId)); + push_test(config.keysystem, 'keyids', initData, testnamePrefix( qualifier, config.keysystem ) + ', temporary, keyids, invalid initdata (too long key ID)'); + + Promise.all( tests.map(function(testspec) { + return isInitDataTypeSupported(testspec.keysystem,testspec.initDataType); + })).then(function(results) { + tests.filter(function(testspec, i) { return results[i]; } ).forEach(function(testspec) { + promise_test(function(test) { + // Create a "temporary" session for |keysystem| and call generateRequest() + // with the provided initData. generateRequest() should fail with an + // TypeError. Returns a promise that is resolved + // if the error occurred and rejected otherwise. + var p = navigator.requestMediaKeySystemAccess(testspec.keysystem, getSimpleConfigurationForInitDataType(testspec.initDataType)).then(function(access) { + return access.createMediaKeys(); + }).then(function(mediaKeys) { + var mediaKeySession = mediaKeys.createSession("temporary"); + return mediaKeySession.generateRequest(testspec.initDataType, testspec.initData); + }); + + return promise_rejects_js(test, TypeError, p, + "generateRequest() should fail"); + }, testspec.testname); + }); + }); +} diff --git a/testing/web-platform/tests/encrypted-media/scripts/invalid-license.js b/testing/web-platform/tests/encrypted-media/scripts/invalid-license.js new file mode 100644 index 0000000000..89d43769e5 --- /dev/null +++ b/testing/web-platform/tests/encrypted-media/scripts/invalid-license.js @@ -0,0 +1,38 @@ +function runTest(config) +{ + promise_test(function (test) { + var initDataType; + var initData; + var keySystem = config.keysystem; + var invalidLicense = new Uint8Array([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77]); + var messageEventFired = false; + + var p = navigator.requestMediaKeySystemAccess(keySystem, getSimpleConfiguration()).then(function (access) { + initDataType = access.getConfiguration().initDataTypes[0]; + initData = getInitData(initDataType); + return access.createMediaKeys(); + }).then(function (mediaKeys) { + var keySession = mediaKeys.createSession(); + var eventWatcher = new EventWatcher(test, keySession, ['message']); + var promise = eventWatcher.wait_for('message'); + keySession.generateRequest(initDataType, initData); + return promise; + }).then(function (messageEvent) { + messageEventFired = true; + return messageEvent.target.update(invalidLicense); + }).catch(function (error) { + // Ensure we reached the update() call we are trying to test. + if (!messageEventFired) { + assert_unreached( + `Failed to reach the update() call. Error: '${error.name}' '${error.message}'`); + } + + // Propagate the error on through. + throw error; + }); + + return promise_rejects_js( + test, TypeError, p, + 'update() should fail because of an invalid license.'); + }, 'Update with invalid Clear Key license'); +} diff --git a/testing/web-platform/tests/encrypted-media/scripts/keystatuses-multiple-sessions.js b/testing/web-platform/tests/encrypted-media/scripts/keystatuses-multiple-sessions.js new file mode 100644 index 0000000000..e9bf10e886 --- /dev/null +++ b/testing/web-platform/tests/encrypted-media/scripts/keystatuses-multiple-sessions.js @@ -0,0 +1,103 @@ +function runTest(config,qualifier) +{ + var testname = testnamePrefix(qualifier, config.keysystem) + ', temporary, keystatuses, multiple sessions'; + + var configuration = getSimpleConfigurationForContent(config.content); + + if (config.initDataType && config.initData) configuration.initDataTypes = [config.initDataType]; + + async_test(function(test) + { + var mediaKeySession1; + var mediaKeySession2; + + // Even though key ids are uint8, using printable values so that + // they can be verified easily. + var key1 = new Uint8Array(config.content.keys[0].kid), + key2 = new Uint8Array(config.content.keys[1].kid), + variant1 = config.content.keys[0].variantId, + variant2 = config.content.keys[1].variantId; + + function onFailure(error) { + forceTestFailureFromPromise(test,error); + } + + function processMessage1(event) + { + // This should only be called for session1. + assert_equals(event.target, mediaKeySession1); + + // No keys added yet. + verifyKeyStatuses(mediaKeySession1.keyStatuses, {expected: [], unexpected: [key1, key2]}); + + // Add key1 to session1. + config.messagehandler(event.messageType, event.message, {variantId:variant1}).then(function(response) { + return event.target.update(response); + }).catch(onFailure); + + } + + function processKeyStatusesChange1(event) + { + // This should only be called for session1. + assert_equals(event.target, mediaKeySession1); + + // Check that keyStatuses contains the expected key1 only. + verifyKeyStatuses(mediaKeySession1.keyStatuses, {expected: [key1], unexpected: [key2]}); + + // Now trigger a message event on session2. + mediaKeySession2.generateRequest(config.initDataType, config.initData[1]).catch(onFailure); + } + + function processMessage2(event) + { + // This should only be called for session2. + assert_equals(event.target, mediaKeySession2); + + // session2 has no keys added yet. + verifyKeyStatuses(mediaKeySession2.keyStatuses, {expected: [], unexpected: [key1, key2]}); + + // session1 should still have 1 key. + verifyKeyStatuses(mediaKeySession1.keyStatuses, {expected: [key1], unexpected: [key2]}); + + // Add key2 to session2. + config.messagehandler(event.messageType, event.message, {variantId:variant2}).then(function(response) { + return event.target.update(response); + }).catch(onFailure); + } + + function processKeyStatusesChange2(event) + { + // This should only be called for session2. + assert_equals(event.target, mediaKeySession2); + + // Check that keyStatuses contains the expected key2 only. + verifyKeyStatuses(mediaKeySession2.keyStatuses, {expected: [key2], unexpected: [key1]}); + + // session1 should still have 1 key. + verifyKeyStatuses(mediaKeySession1.keyStatuses, {expected: [key1], unexpected: [key2]}); + + test.done(); + } + + navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function(access) { + return access.createMediaKeys(); + }).then(function(mediaKeys) { + mediaKeySession1 = mediaKeys.createSession(); + mediaKeySession2 = mediaKeys.createSession(); + + // There should be no keys defined on either session. + verifyKeyStatuses(mediaKeySession1.keyStatuses, {expected: [], unexpected: [key1, key2]}); + verifyKeyStatuses(mediaKeySession2.keyStatuses, {expected: [], unexpected: [key1, key2]}); + + // Bind all the event handlers now. + waitForEventAndRunStep('message', mediaKeySession1, processMessage1, test); + waitForEventAndRunStep('message', mediaKeySession2, processMessage2, test); + waitForEventAndRunStep('keystatuseschange', mediaKeySession1, processKeyStatusesChange1, test); + waitForEventAndRunStep('keystatuseschange', mediaKeySession2, processKeyStatusesChange2, test); + + // Generate a request on session1. + return mediaKeySession1.generateRequest(config.initDataType, config.initData[0]); + }).catch(onFailure); + }, testname ); +} diff --git a/testing/web-platform/tests/encrypted-media/scripts/keystatuses.js b/testing/web-platform/tests/encrypted-media/scripts/keystatuses.js new file mode 100644 index 0000000000..8d33dd4210 --- /dev/null +++ b/testing/web-platform/tests/encrypted-media/scripts/keystatuses.js @@ -0,0 +1,165 @@ +function runTest(config,qualifier) +{ + var testname = testnamePrefix(qualifier, config.keysystem) + ', temporary, keystatuses'; + + var configuration = getSimpleConfigurationForContent(config.content); + + if (config.initDataType && config.initData) { + configuration.initDataTypes = [config.initDataType]; + } + + async_test(function(test) + { + var mediaKeySession; + var initDataType; + var initData; + var closed = false; + + // Even though key ids are uint8, using printable values so that + // they can be verified easily. + var key1 = new Uint8Array(config.content.keys[0].kid), + key2 = new Uint8Array(config.content.keys[1].kid), + key1String = arrayBufferAsString(key1), + key2String = arrayBufferAsString(key2); + + function onFailure(error) { + forceTestFailureFromPromise(test, error); + } + + function processMessage(event) + { + // No keys added yet. + assert_equals(mediaKeySession.keyStatuses.size, 0); + + waitForEventAndRunStep('keystatuseschange', mediaKeySession, processKeyStatusesChange, test); + + // Add keys to session + config.messagehandler(event.messageType, event.message).then(function(response) { + return event.target.update(response); + }).catch(onFailure); + } + + function checkKeyStatusFor2Keys() + { + // Two keys added, so both should show up in |keyStatuses|. + assert_equals(mediaKeySession.keyStatuses.size, 2); + + // Check |keyStatuses| for 2 entries. + var result = []; + for (let item of mediaKeySession.keyStatuses) { + result.push({ key: arrayBufferAsString(item[0]), value: item[1] }); + } + function lexicographical( a, b ) { return a < b ? -1 : a === b ? 0 : +1; } + function lexicographicalkey( a, b ) { return lexicographical( a.key, b.key ); } + var expected1 = [{ key: key1String, value: 'usable'}, { key: key2String, value: 'usable'}].sort( lexicographicalkey ); + var expected2 = [{ key: key1String, value: 'status-pending'}, { key: key2String, value: 'status-pending'}].sort( lexicographicalkey ); + assert_in_array( JSON.stringify(result), + [ JSON.stringify(expected1),JSON.stringify(expected2) ], + "keystatuses should have the two expected keys with keystatus 'usable' or 'status-pending'"); + + // |keyStatuses| must contain both keys. + result = []; + for (var key of mediaKeySession.keyStatuses.keys()) { + result.push(arrayBufferAsString(key)); + } + assert_array_equals(result, + [key1String, key2String].sort( lexicographical ), + "keyStatuses.keys() should return an iterable over the two expected keys"); + + // Both values in |mediaKeySession| should be 'usable' or 'status-pending'. + result = []; + for (var value of mediaKeySession.keyStatuses.values()) { + result.push(value); + } + + assert_equals( result.length, 2, "keyStatuses.values() should have two elements" ); + assert_equals( result[0], result[1], "the values in keyStatuses.values() should be equal" ); + assert_in_array( result[0], [ 'usable', 'status-pending' ] ); + + // Check |keyStatuses.entries()|. + result = []; + for (var entry of mediaKeySession.keyStatuses.entries()) { + result.push({ key: arrayBufferAsString(entry[0]), value: entry[1] }); + } + assert_in_array(JSON.stringify(result), + [ JSON.stringify(expected1), JSON.stringify(expected2) ], + "keyStatuses.entries() should return an iterable over the two expected keys, with keystatus 'usable' or 'status-pending'"); + + // forEach() should return both entries. + result = []; + mediaKeySession.keyStatuses.forEach(function(status, keyId) { + result.push({ key: arrayBufferAsString(keyId), value: status }); + }); + assert_in_array(JSON.stringify(result), + [ JSON.stringify(expected1), JSON.stringify(expected2) ], + "keyStatuses.forEach() should iterate over the two expected keys, with keystatus 'usable' or 'status-pending'"); + + // has() and get() should return the expected values. + assert_true(mediaKeySession.keyStatuses.has(key1), "keyStatuses should have key1"); + assert_true(mediaKeySession.keyStatuses.has(key2), "keyStatuses should have key2"); + assert_in_array(mediaKeySession.keyStatuses.get(key1), [ 'usable', 'status-pending' ], "key1 should have status 'usable' or 'status-pending'"); + assert_in_array(mediaKeySession.keyStatuses.get(key2), [ 'usable', 'status-pending' ], "key2 should have status 'usable' or 'status-pending'"); + + // Try some invalid keyIds. + var invalid1 = key1.subarray(0, key1.length - 1); + assert_false(mediaKeySession.keyStatuses.has(invalid1), "keystatuses should not have invalid key (1)"); + assert_equals(mediaKeySession.keyStatuses.get(invalid1), undefined, "keystatus value for invalid key should be undefined (1)"); + + var invalid2 = key1.subarray(1); + assert_false(mediaKeySession.keyStatuses.has(invalid2), "keystatuses should not have invalid key (2)"); + assert_equals(mediaKeySession.keyStatuses.get(invalid2), undefined, "keystatus value for invalid key should be undefined (2)"); + + var invalid3 = new Uint8Array(key1); + invalid3[0] += 1; + assert_false(mediaKeySession.keyStatuses.has(invalid3), "keystatuses should not have invalid key (3)"); + assert_equals(mediaKeySession.keyStatuses.get(invalid3), undefined, "keystatus value for invalid key should be undefined (3)"); + + var invalid4 = new Uint8Array(key1); + invalid4[invalid4.length - 1] -= 1; + assert_false(mediaKeySession.keyStatuses.has(invalid4), "keystatuses should not have invalid key (4)"); + assert_equals(mediaKeySession.keyStatuses.get(invalid4), undefined, "keystatus value for invalid key should be undefined (4)"); + + var invalid5 = new Uint8Array(key1.length + 1); + invalid5.set(key1, 1); // First element will be 0. + assert_false(mediaKeySession.keyStatuses.has(invalid5), "keystatuses should not have invalid key (5)"); + assert_equals(mediaKeySession.keyStatuses.get(invalid5), undefined, "keystatus value for invalid key should be undefined (5)"); + + var invalid6 = new Uint8Array(key1.length + 1); + invalid6.set(key1, 0); // Last element will be 0. + assert_false(mediaKeySession.keyStatuses.has(invalid6), "keystatuses should not have invalid key (6)"); + assert_equals(mediaKeySession.keyStatuses.get(invalid6), undefined, "keystatus value for invalid key should be undefined (6)"); + } + + function processKeyStatusesChange(event) + { + if (!closed) + { + // The first keystatuseschange (caused by update()) + // should include both keys. + checkKeyStatusFor2Keys(); + + mediaKeySession.close().catch(onFailure); + closed = true; + } + else + { + // The second keystatuseschange (caused by close()) + // should not have any keys. + assert_equals(mediaKeySession.keyStatuses.size, 0); + test.done(); + } + } + + navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function(access) { + return access.createMediaKeys(); + }).then(test.step_func(function(mediaKeys) { + mediaKeySession = mediaKeys.createSession(); + + // There should be no keys defined yet. + //verifyKeyStatuses(mediaKeySession.keyStatuses, { expected: [], unexpected: [key1, key2] }); + + waitForEventAndRunStep('message', mediaKeySession, processMessage, test); + return mediaKeySession.generateRequest(config.initDataType, config.initData); + })).catch(onFailure); + }, testname ); +} diff --git a/testing/web-platform/tests/encrypted-media/scripts/not-callable-after-createsession.js b/testing/web-platform/tests/encrypted-media/scripts/not-callable-after-createsession.js new file mode 100644 index 0000000000..2642c71e0e --- /dev/null +++ b/testing/web-platform/tests/encrypted-media/scripts/not-callable-after-createsession.js @@ -0,0 +1,50 @@ + function runTest(config,qualifier) { + // After creation, the MediaKeySession object is not + // callable, and we should get a InvalidStateError. + + promise_test(function() + { + return navigator.requestMediaKeySystemAccess(config.keysystem, getSimpleConfiguration()).then(function(access) { + return access.createMediaKeys(); + }).then(function(mediaKeys) { + var mediaKeySession = mediaKeys.createSession(); + + var arbitraryResponse = new Uint8Array([0x00, 0x11]); + return mediaKeySession.update(arbitraryResponse).then(function(result) { + assert_unreached('update() succeeded unexpectedly.'); + }).catch(function(error) { + assert_equals(error.name, 'InvalidStateError'); + }); + }); + }, testnamePrefix( qualifier, config.keysystem ) + ', temporary, update() immediately after createSession()'); + + promise_test(function() + { + return navigator.requestMediaKeySystemAccess(config.keysystem, getSimpleConfiguration()).then(function(access) { + return access.createMediaKeys(); + }).then(function(mediaKeys) { + var mediaKeySession = mediaKeys.createSession(); + + return mediaKeySession.close().then(function(result) { + assert_unreached('close() succeeded unexpectedly.'); + }).catch(function(error) { + assert_equals(error.name, 'InvalidStateError'); + }); + }); + }, testnamePrefix( qualifier, config.keysystem ) + ', temporary, close() immediately after createSession()'); + + promise_test(function() + { + return navigator.requestMediaKeySystemAccess(config.keysystem, getSimpleConfiguration()).then(function(access) { + return access.createMediaKeys(); + }).then(function(mediaKeys) { + var mediaKeySession = mediaKeys.createSession(); + + return mediaKeySession.remove().then(function(result) { + assert_unreached('remove() succeeded unexpectedly.'); + }).catch(function(error) { + assert_equals(error.name, 'InvalidStateError'); + }); + }); + }, testnamePrefix( qualifier, config.keysystem ) + ', temporary, remove() immediately after createSession()'); +} diff --git a/testing/web-platform/tests/encrypted-media/scripts/onencrypted.js b/testing/web-platform/tests/encrypted-media/scripts/onencrypted.js new file mode 100644 index 0000000000..acf0ffacc0 --- /dev/null +++ b/testing/web-platform/tests/encrypted-media/scripts/onencrypted.js @@ -0,0 +1,48 @@ +function runTest(config) { + var expectedInitData = []; + expectedInitData.push(stringToUint8Array(atob(config.keys[0].initData))); + expectedInitData.push(stringToUint8Array(atob(config.keys[1].initData))); + + // Will get 2 identical events, one for audio, one for video. + var expectedEvents = 2; + var currentData; + + async_test(function (test) { + var video = config.video, + mediaSource, + onEncrypted = function (event) { + currentData = new Uint8Array(event.initData); + assert_equals(event.target, config.video); + assert_true(event instanceof window.MediaEncryptedEvent); + assert_equals(event.type, 'encrypted'); + assert_equals(event.initDataType, 'cenc'); + // At this point we do not know if the event is related to audio or video. So check for both expected init data + assert_true(checkInitData(currentData, expectedInitData[0]) || checkInitData(currentData, expectedInitData[1])); + + if (--expectedEvents === 0) { + test.done(); + } + }; + + waitForEventAndRunStep('encrypted', video, onEncrypted, test); + testmediasource(config).then(function (source) { + mediaSource = source; + config.video.src = URL.createObjectURL(mediaSource); + return source.done; + }).then(function(){ + video.play(); + }); + }, 'encrypted fired on encrypted media file.'); +} + +function checkInitData(data, expectedData) { + if (data.length !== expectedData.length) { + return false; + } + for (var i = 0; i < data.length; i++) { + if (data[i] !== expectedData[i]) { + return false; + } + } + return true; +} diff --git a/testing/web-platform/tests/encrypted-media/scripts/playback-destroy-persistent-license.js b/testing/web-platform/tests/encrypted-media/scripts/playback-destroy-persistent-license.js new file mode 100644 index 0000000000..8a6cacedb4 --- /dev/null +++ b/testing/web-platform/tests/encrypted-media/scripts/playback-destroy-persistent-license.js @@ -0,0 +1,95 @@ +function runTest(config,qualifier) { + + var testname = testnamePrefix( qualifier, config.keysystem ) + + ', persistent-license, ' + + /video\/([^;]*)/.exec( config.videoType )[ 1 ] + + ', playback, destroy and acknowledge'; + + var configuration = { initDataTypes: [ config.initDataType ], + audioCapabilities: [ { contentType: config.audioType } ], + videoCapabilities: [ { contentType: config.videoType } ], + sessionTypes: [ 'persistent-license' ] }; + + async_test( function(test) { + + var _video = config.video, + _mediaKeys, + _mediaKeySession, + _mediaSource, + _sessionId, + _startedReleaseSequence = false; + + function onFailure(error) { + forceTestFailureFromPromise(test, error); + } + + function onMessage(event) { + assert_equals(event.target, _mediaKeySession); + assert_true(event instanceof window.MediaKeyMessageEvent); + assert_equals(event.type, 'message'); + + config.messagehandler(event.messageType, event.message).then(function(response) { + return _mediaKeySession.update(response); + }).catch(onFailure); + } + + function onEncrypted(event) { + assert_equals(event.target, _video); + assert_true(event instanceof window.MediaEncryptedEvent); + assert_equals(event.type, 'encrypted'); + + waitForEventAndRunStep('message', _mediaKeySession, onMessage, test); + _mediaKeySession.generateRequest( config.initData ? config.initDataType : event.initDataType, + config.initData || event.initData ).then( test.step_func(function() { + assert_not_equals( _mediaKeySession.sessionId, undefined, "SessionId should be defined" ); + _sessionId = _mediaKeySession.sessionId; + })).catch(onFailure); + } + + function onTimeupdate(event) { + if (_video.currentTime > ( config.duration || 1 ) && !_startedReleaseSequence) { + _video.removeEventListener('timeupdate', onTimeupdate); + _video.pause(); + _video.removeAttribute('src'); + _video.load(); + + _startedReleaseSequence = true; + _mediaKeySession.closed.then(onClosed); + _mediaKeySession.remove().catch(onFailure); + } + } + + function onPlaying(event) { + // Not using waitForEventAndRunStep() to avoid too many + // EVENT(onTimeUpdate) logs. + _video.addEventListener('timeupdate', onTimeupdate, true); + } + + function onClosed() { + // Try and reload and check this fails + var mediaKeySession = _mediaKeys.createSession( 'persistent-license' ); + mediaKeySession.load(_sessionId).then( test.step_func(function(success) { + assert_false( success, "Load of removed session shouold fail" ); + test.done(); + })).catch(onFailure); + } + + navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function(access) { + return access.createMediaKeys(); + }).then(function(mediaKeys) { + _mediaKeys = mediaKeys; + return _video.setMediaKeys(_mediaKeys); + }).then(function() { + _mediaKeySession = _mediaKeys.createSession('persistent-license'); + waitForEventAndRunStep('encrypted', _video, onEncrypted, test); + waitForEventAndRunStep('playing', _video, onPlaying, test); + return testmediasource(config); + }).then(function(source) { + _mediaSource = source; + _video.src = URL.createObjectURL(_mediaSource); + return source.done; + }).then(function(){ + _video.play(); + }).catch(onFailure); + }, testname); +} diff --git a/testing/web-platform/tests/encrypted-media/scripts/playback-persistent-license-events.js b/testing/web-platform/tests/encrypted-media/scripts/playback-persistent-license-events.js new file mode 100644 index 0000000000..2d99f679f4 --- /dev/null +++ b/testing/web-platform/tests/encrypted-media/scripts/playback-persistent-license-events.js @@ -0,0 +1,158 @@ +function runTest(config,qualifier) { + + var testname = testnamePrefix(qualifier, config.keysystem) + + ', persistent-license, ' + + /video\/([^;]*)/.exec(config.videoType)[1] + + ', playback, check events'; + + var configuration = { initDataTypes: [ config.initDataType ], + audioCapabilities: [ { contentType: config.audioType } ], + videoCapabilities: [ { contentType: config.videoType } ], + sessionTypes: [ 'persistent-license' ] }; + + + async_test(function(test) { + var _video = config.video, + _mediaKeys, + _mediaKeySession, + _mediaSource, + _receivedTimeupdateEvent = false, + _startedReleaseSequence = false, + _events = [ ]; + + function recordEventFunc(eventType) { + return function() { _events.push(eventType); }; + } + + function recordEventFuncAndCheckExpirationForNaN(eventType) { + return function() { + _events.push(eventType); + assert_equals(_mediaKeySession.expiration, NaN); + }; + } + + function onFailure(error) { + forceTestFailureFromPromise(test, error); + } + + function onMessage(event) { + assert_equals( event.target, _mediaKeySession ); + assert_true( event instanceof window.MediaKeyMessageEvent ); + assert_equals( event.type, 'message'); + + if (!_startedReleaseSequence) { + assert_in_array(event.messageType, ['license-request', 'individualization-request']); + } else { + assert_equals(event.messageType, 'license-release'); + } + + if (event.messageType !== 'individualization-request') { + _events.push(event.messageType); + } + + config.messagehandler(event.messageType, event.message ).then(function(response) { + _events.push(event.messageType + '-response'); + return _mediaKeySession.update(response); + }).then(test.step_func(function() { + _events.push(event.messageType + '-response-resolved'); + if (event.messageType === 'license-release') { + test.step_timeout(function() { + checkEventSequence(_events, [ + 'generaterequest', + [ // potentially repeating + 'license-request', + 'license-request-response', + 'license-request-response-resolved' + ], + 'keystatuseschange-usablekey', + 'playing', + 'remove-resolved', + 'keystatuseschange-allkeysreleased', + 'license-release', + 'license-release-response', + 'closed-attribute-resolved', + 'license-release-response-resolved', + 'keystatuseschange-empty' + ]); + test.done(); + }, 100); + } + })).catch(onFailure); + } + + function onKeyStatusesChange(event) { + assert_equals(event.target, _mediaKeySession); + assert_true(event instanceof window.Event); + assert_equals(event.type, 'keystatuseschange'); + var hasKeys = false, + usableKey = false; // true if any key usable. + _mediaKeySession.keyStatuses.forEach(function(value, keyid) { + assert_in_array(value, ['usable', 'released']); + hasKeys = true; + usableKey = usableKey || (value === 'usable'); + }); + + if (!hasKeys) { + _events.push('keystatuseschange-empty'); + } else if (usableKey) { + _events.push('keystatuseschange-usablekey'); + } else { + _events.push('keystatuseschange-allkeysreleased'); + } + } + + function onEncrypted(event) { + assert_equals(event.target, _video); + assert_true(event instanceof window.MediaEncryptedEvent); + assert_equals(event.type, 'encrypted'); + + _mediaKeySession.generateRequest( config.initData ? config.initDataType : event.initDataType, + config.initData || event.initData ).then(recordEventFunc('generaterequest') + ).catch(onFailure); + } + + function onTimeupdate(event) { + if ( _video.currentTime > ( config.duration || 1 ) && !_receivedTimeupdateEvent ) { + _receivedTimeupdateEvent = true; + _video.pause(); + _video.removeAttribute('src'); + _video.load(); + + _startedReleaseSequence = true; + _mediaKeySession.remove() + .then(recordEventFuncAndCheckExpirationForNaN('remove-resolved')) + .catch(onFailure); + } + } + + function onPlaying(event) { + _events.push( 'playing' ); + } + + navigator.requestMediaKeySystemAccess(config.keysystem, [ configuration ]).then(function(access) { + return access.createMediaKeys(); + }).then(function(mediaKeys) { + _mediaKeys = mediaKeys; + return _video.setMediaKeys(_mediaKeys); + }).then(function() { + waitForEventAndRunStep('encrypted', _video, onEncrypted, test); + waitForEventAndRunStep('playing', _video, onPlaying, test); + // Not using waitForEventAndRunStep() to avoid too many + // EVENT(onTimeUpdate) logs. + _video.addEventListener('timeupdate', onTimeupdate, true); + _mediaKeySession = _mediaKeys.createSession( 'persistent-license' ); + waitForEventAndRunStep('keystatuseschange', _mediaKeySession, onKeyStatusesChange, test); + waitForEventAndRunStep('message', _mediaKeySession, onMessage, test); + _mediaKeySession.closed + .then(recordEventFuncAndCheckExpirationForNaN('closed-attribute-resolved')) + .catch(onFailure); + return testmediasource(config); + }).then(function(source) { + _mediaSource = source; + _video.src = URL.createObjectURL(_mediaSource); + return source.done; + }).then(function(){ + _video.play(); + }).catch(onFailure); + }, testname); +} diff --git a/testing/web-platform/tests/encrypted-media/scripts/playback-persistent-license.js b/testing/web-platform/tests/encrypted-media/scripts/playback-persistent-license.js new file mode 100644 index 0000000000..c7e56e3aea --- /dev/null +++ b/testing/web-platform/tests/encrypted-media/scripts/playback-persistent-license.js @@ -0,0 +1,77 @@ +function runTest(config,qualifier) { + + var testname = testnamePrefix(qualifier, config.keysystem) + + ', persistent-license, ' + + /video\/([^;]*)/.exec(config.videoType)[1] + + 'playback'; + + var configuration = { initDataTypes: [ config.initDataType ], + audioCapabilities: [ { contentType: config.audioType } ], + videoCapabilities: [ { contentType: config.videoType } ], + sessionTypes: [ 'persistent-license' ] }; + + + async_test(function(test) { + var _video = config.video, + _mediaKeys, + _mediaKeySession, + _mediaSource; + + function onFailure(error) { + forceTestFailureFromPromise(test, error); + } + + function onMessage(event) { + assert_equals( event.target, _mediaKeySession ); + assert_true( event instanceof window.MediaKeyMessageEvent ); + assert_equals( event.type, 'message'); + + assert_in_array( event.messageType, [ 'license-request', 'individualization-request' ] ); + + config.messagehandler(event.messageType, event.message).then( function( response ) { + return _mediaKeySession.update(response) + }).catch(onFailure); + } + + function onEncrypted(event) { + assert_equals(event.target, _video); + assert_true(event instanceof window.MediaEncryptedEvent); + assert_equals(event.type, 'encrypted'); + + waitForEventAndRunStep('message', _mediaKeySession, onMessage, test); + _mediaKeySession.generateRequest( config.initData ? config.initDataType : event.initDataType, + config.initData || event.initData ).catch(onFailure); + } + + function onTimeupdate(event) { + if (_video.currentTime > (config.duration || 1)) { + _video.pause(); + test.done(); + } + } + + function onPlaying(event) { + // Not using waitForEventAndRunStep() to avoid too many + // EVENT(onTimeUpdate) logs. + _video.addEventListener('timeupdate', onTimeupdate, true); + } + + navigator.requestMediaKeySystemAccess(config.keysystem, [ configuration ]).then(function(access) { + return access.createMediaKeys(); + }).then(function(mediaKeys) { + _mediaKeys = mediaKeys; + return _video.setMediaKeys(_mediaKeys); + }).then(function() { + _mediaKeySession = _mediaKeys.createSession( 'persistent-license' ); + waitForEventAndRunStep('encrypted', _video, onEncrypted, test); + waitForEventAndRunStep('playing', _video, onPlaying, test); + return testmediasource(config); + }).then(function(source) { + _mediaSource = source; + _video.src = URL.createObjectURL(_mediaSource); + return source.done; + }).then(function(){ + _video.play(); + }).catch(onFailure); + }, testname); +} diff --git a/testing/web-platform/tests/encrypted-media/scripts/playback-persistent-usage-record-events.js b/testing/web-platform/tests/encrypted-media/scripts/playback-persistent-usage-record-events.js new file mode 100644 index 0000000000..e8e1e54790 --- /dev/null +++ b/testing/web-platform/tests/encrypted-media/scripts/playback-persistent-usage-record-events.js @@ -0,0 +1,109 @@ +function runTest(config,qualifier) { + + var testname = testnamePrefix(qualifier, config.keysystem) + + ', persistent-usage-record, ' + + /video\/([^;]*)/.exec(config.videoType)[1] + + ', playback, check events'; + + var configuration = { initDataTypes: [config.initDataType ], + audioCapabilities: [{contentType: config.audioType}], + videoCapabilities: [{contentType: config.videoType}], + sessionTypes: ['persistent-usage-record']}; + + + async_test(function(test) { + var _video = config.video, + _mediaKeys, + _mediaKeySession, + _sessionId, + _timeupdateEvent = false, + _events = [ ]; + + function recordEventFunc(eventType) { + return function() { _events.push(eventType); }; + } + + function onFailure(error) { + forceTestFailureFromPromise(test, error); + } + + function onMessage(event) { + assert_equals(event.target, _mediaKeySession); + assert_true(event instanceof window.MediaKeyMessageEvent); + assert_equals(event.type, 'message'); + + if (event.messageType !== 'individualization-request') { + _events.push(event.messageType); + } + + config.messagehandler(event.messageType, event.message).then(function(response) { + _events.push(event.messageType + '-response'); + return _mediaKeySession.update(response); + }).then(test.step_func(function() { + _events.push('update-resolved'); + if (event.messageType === 'license-release') { + checkEventSequence( _events, + ['encrypted','generaterequest-done', + ['license-request', 'license-request-response', 'update-resolved'], // potentially repeating + 'keystatuseschange', + 'playing', + 'remove-resolved', + 'keystatuseschange', + 'license-release', + 'license-release-response', + 'closed-attribute-resolved', + 'update-resolved' ]); + test.done(); + } + + if ( event.messageType === 'license-request' ) { + _video.setMediaKeys(_mediaKeys); + } + })).catch(onFailure); + } + + function onEncrypted(event) { + assert_equals(event.target, _video); + assert_true(event instanceof window.MediaEncryptedEvent); + _events.push(event.type); + _mediaKeySession.generateRequest( config.initDataType || event.initDataType, + config.initData || event.initData ).then( function() { + _events.push( 'generaterequest-done' ); + _sessionId = _mediaKeySession.sessionId; + }).catch(onFailure); + } + + function onTimeupdate(event) { + if (_video.currentTime > (config.duration || 1) && !_timeupdateEvent) { + _timeupdateEvent = true; + _video.pause(); + _mediaKeySession.remove().then(recordEventFunc('remove-resolved')).catch(onFailure); + } + } + + navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function(access) { + return access.createMediaKeys(); + }).then(function(mediaKeys) { + _mediaKeys = mediaKeys; + waitForEventAndRunStep('encrypted', _video, onEncrypted, test); + waitForEventAndRunStep('playing', _video, recordEventFunc('playing'), test); + + // Not using waitForEventAndRunStep() to avoid too many + // EVENT(onTimeUpdate) logs. + _video.addEventListener('timeupdate', onTimeupdate, true); + + _mediaKeySession = _mediaKeys.createSession( 'persistent-usage-record' ); + waitForEventAndRunStep('message', _mediaKeySession, onMessage, test); + waitForEventAndRunStep('keystatuseschange', _mediaKeySession, recordEventFunc('keystatuseschange'), test); + _mediaKeySession.closed.then(recordEventFunc('closed-attribute-resolved')); + return config.servercertificate ? _mediaKeys.setServerCertificate(config.servercertificate) : true; + }).then(function( success ) { + return testmediasource(config); + }).then(function(source) { + _video.src = URL.createObjectURL(source); + return source.done; + }).then(function(){ + _video.play(); + }).catch(onFailure); + }, testname); +} diff --git a/testing/web-platform/tests/encrypted-media/scripts/playback-persistent-usage-record.js b/testing/web-platform/tests/encrypted-media/scripts/playback-persistent-usage-record.js new file mode 100644 index 0000000000..1772b4bd5f --- /dev/null +++ b/testing/web-platform/tests/encrypted-media/scripts/playback-persistent-usage-record.js @@ -0,0 +1,104 @@ +function runTest(config,qualifier) { + + var testname = testnamePrefix(qualifier, config.keysystem) + + ', persistent-usage-record, ' + + /video\/([^;]*)/.exec(config.videoType)[1] + + 'playback'; + + var configuration = { initDataTypes: [ config.initDataType ], + audioCapabilities: [ { contentType: config.audioType } ], + videoCapabilities: [ { contentType: config.videoType } ], + sessionTypes: [ 'persistent-usage-record' ] }; + + + async_test(function(test) { + var _video = config.video, + _mediaKeys, + _mediaKeySession, + _mediaSource, + _releaseSequence = false; + + function onFailure(error) { + forceTestFailureFromPromise(test, error); + } + + function onMessage(event) { + assert_equals(event.target, _mediaKeySession); + // event instance verification failing on CastTV + // assert_true( event instanceof window.MediaKeyMessageEvent ); + assert_equals(event.type, 'message'); + + if (!_releaseSequence) + { + assert_in_array(event.messageType, ['license-request', 'individualization-request']); + } + else + { + assert_equals(event.messageType, 'license-release'); + } + + config.messagehandler(event.messageType, event.message).then(function(response) { + return _mediaKeySession.update(response); + }).then(function() { + if(event.messageType === 'license-request') { + return _video.setMediaKeys(_mediaKeys); + } else if(event.messageType === 'license-release') { + test.done(); + } + }).catch(onFailure); + } + + function onEncrypted(event) { + assert_equals(event.target, _video); + assert_true(event instanceof window.MediaEncryptedEvent); + assert_equals(event.type, 'encrypted'); + + waitForEventAndRunStep('message', _mediaKeySession, onMessage, test); + _mediaKeySession.generateRequest( config.initData ? config.initDataType : event.initDataType, + config.initData || event.initData ) + .catch(onFailure); + } + + function onClosed(event) { + _video.src = ""; + _video.setMediaKeys( null ); + } + + function onTimeupdate(event) { + if (_video.currentTime > ( config.duration || 1) && !_releaseSequence) { + _video.removeEventListener('timeupdate', onTimeupdate ); + _video.pause(); + _releaseSequence = true; + + _mediaKeySession.closed.then(test.step_func(onClosed)); + _mediaKeySession.remove().catch(onFailure); + + _video.removeEventListener('timeupdate', onTimeupdate); + } + } + + function onPlaying(event) { + // Not using waitForEventAndRunStep() to avoid too many + // EVENT(onTimeUpdate) logs. + _video.addEventListener('timeupdate', onTimeupdate, true); + } + + navigator.requestMediaKeySystemAccess(config.keysystem, [ configuration ]).then(function(access) { + return access.createMediaKeys(); + }).then(function(mediaKeys) { + _mediaKeys = mediaKeys; + _mediaKeySession = _mediaKeys.createSession('persistent-usage-record'); + waitForEventAndRunStep('encrypted', _video, onEncrypted, test); + waitForEventAndRunStep('playing', _video, onPlaying, test); + return config.servercertificate ? _mediaKeys.setServerCertificate(config.servercertificate) : true; + }).then(function(success) { + return testmediasource(config); + }).then(function(source) { + _mediaSource = source; + _video.src = URL.createObjectURL(_mediaSource); + return source.done; + }).then(function(){ + _video.play(); + }).catch(onFailure); + }, testname); +} diff --git a/testing/web-platform/tests/encrypted-media/scripts/playback-retrieve-persistent-license.js b/testing/web-platform/tests/encrypted-media/scripts/playback-retrieve-persistent-license.js new file mode 100644 index 0000000000..83cba34028 --- /dev/null +++ b/testing/web-platform/tests/encrypted-media/scripts/playback-retrieve-persistent-license.js @@ -0,0 +1,115 @@ +function runTest(config,qualifier) { + + var testname = testnamePrefix(qualifier, config.keysystem) + + ', persistent-license, ' + + /video\/([^;]*)/.exec(config.videoType)[1] + + ', ' + config.testcase; + + var configuration = { initDataTypes: [ config.initDataType ], + audioCapabilities: [ { contentType: config.audioType } ], + videoCapabilities: [ { contentType: config.videoType } ], + sessionTypes: [ 'persistent-license' ] }; + + + async_test( function(test) { + var _video = config.video, + _mediaKeys, + _mediaKeySession, + _mediaSource, + _sessionId; + + function onFailure(error) { + forceTestFailureFromPromise(test, error); + } + + function onEncrypted(event) { + assert_equals(event.target, _video); + assert_true(event instanceof window.MediaEncryptedEvent); + assert_equals(event.type, 'encrypted'); + + waitForEventAndRunStep('message', _mediaKeySession, onMessage, test); + _mediaKeySession.generateRequest( config.initData ? config.initDataType : event.initDataType, + config.initData || event.initData ).then( function() { + _sessionId = _mediaKeySession.sessionId; + }).catch(onFailure); + } + + function onMessage(event) { + assert_equals(event.target, _mediaKeySession); + assert_true(event instanceof window.MediaKeyMessageEvent); + assert_equals(event.type, 'message'); + + assert_in_array(event.messageType, ['license-request', 'individualization-request']); + + config.messagehandler(event.messageType, event.message).then(function(response) { + return _mediaKeySession.update(response); + }).catch(onFailure); + } + + function onPlaying(event) { + // Not using waitForEventAndRunStep() to avoid too many + // EVENT(onTimeUpdate) logs. + _video.addEventListener('timeupdate', onTimeupdate); + } + + function onTimeupdate(event) { + if (_video.currentTime > (config.duration || 1)) { + _video.removeEventListener('timeupdate', onTimeupdate); + _video.pause(); + _video.removeAttribute('src'); + _video.load(); + + _mediaKeySession.closed + .then(test.step_func(onClosed)) + .catch(onFailure); + _mediaKeySession.close() + .catch(onFailure); + } + } + + function onClosed() { + // Open a new window in which we will attempt to play with the persisted license + var win = window.open(config.windowscript); + assert_not_equals(win, null, "Popup windows not allowed?"); + + // Lisen for an event from the new window containing its test assertions + window.addEventListener('message', test.step_func(function(messageEvent) { + if (messageEvent.data.testResult) { + messageEvent.data.testResult.forEach(test.step_func(function(assertion) { + assert_equals(assertion.actual, assertion.expected, assertion.message); + })); + + win.close(); + test.done(); + } + })); + + // Delete things which can't be cloned and posted over to the new window + delete config.video; + delete config.messagehandler; + + // Post the config and session id to the new window when it is ready + win.onload = function() { + win.postMessage({config: config, sessionId: _sessionId}, '*'); + } + } + + navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function(access) { + return access.createMediaKeys(); + }).then(function(mediaKeys) { + _mediaKeys = mediaKeys; + return _video.setMediaKeys( mediaKeys ); + }).then(function() { + _mediaKeySession = _mediaKeys.createSession('persistent-license'); + waitForEventAndRunStep('encrypted', _video, onEncrypted, test); + waitForEventAndRunStep('playing', _video, onPlaying, test); + return testmediasource(config); + }).then(function(source) { + _mediaSource = source; + _video.src = URL.createObjectURL(_mediaSource); + return source.done; + }).then(function(){ + _video.play(); + }).catch(onFailure); + }, testname); +} diff --git a/testing/web-platform/tests/encrypted-media/scripts/playback-retrieve-persistent-usage-record.js b/testing/web-platform/tests/encrypted-media/scripts/playback-retrieve-persistent-usage-record.js new file mode 100644 index 0000000000..a04f97d2ca --- /dev/null +++ b/testing/web-platform/tests/encrypted-media/scripts/playback-retrieve-persistent-usage-record.js @@ -0,0 +1,114 @@ +function runTest(config,qualifier) { + + var testname = testnamePrefix(qualifier, config.keysystem) + + ', persistent-usage-record, ' + + /video\/([^;]*)/.exec(config.videoType)[1] + + ', playback, retrieve in new window'; + + var configuration = { initDataTypes: [ config.initDataType ], + audioCapabilities: [ { contentType: config.audioType } ], + videoCapabilities: [ { contentType: config.videoType } ], + sessionTypes: [ 'persistent-usage-record' ] }; + + + async_test( function( test ) { + var _video = config.video, + _mediaKeys, + _mediaKeySession, + _mediaSource, + _sessionId, + _isClosing = false; + + function onFailure(error) { + forceTestFailureFromPromise(test, error); + } + + function onEncrypted(event) { + assert_equals(event.target, _video); + assert_true(event instanceof window.MediaEncryptedEvent); + assert_equals(event.type, 'encrypted'); + + waitForEventAndRunStep('message', _mediaKeySession, onMessage, test); + _mediaKeySession.generateRequest( config.initDataType || event.initDataType, + config.initData || event.initData ).then( function() { + _sessionId = _mediaKeySession.sessionId; + }).catch(onFailure); + } + + function onMessage(event) { + assert_equals(event.target, _mediaKeySession); + assert_true(event instanceof window.MediaKeyMessageEvent); + assert_equals(event.type, 'message'); + + assert_in_array( event.messageType,['license-request', 'individualization-request']); + + config.messagehandler( event.messageType, event.message ).then(function(response) { + return _mediaKeySession.update(response); + }).then(function() { + return _video.setMediaKeys(_mediaKeys); + }).catch(onFailure); + } + + function onPlaying(event) { + // Not using waitForEventAndRunStep() to avoid too many + // EVENT(onTimeUpdate) logs. + _video.addEventListener('timeupdate', onTimeupdate, true); + } + + function onTimeupdate(event) { + if (!_isClosing && _video.currentTime > (config.duration || 1)) { + _isClosing = true; + _video.removeEventListener('timeupdate', onTimeupdate); + _video.pause(); + _mediaKeySession.closed.then( test.step_func(onClosed)); + _mediaKeySession.close(); + } + } + + function onClosed(event) { + _video.src = ""; + _video.setMediaKeys( null ); + + var win = window.open(config.windowscript); + assert_not_equals(win, null, "Popup windows not allowed?"); + + window.addEventListener('message', test.step_func(function(event) { + if (event.data.testResult) { + event.data.testResult.forEach(test.step_func(function(assertion) { + assert_equals(assertion.actual, assertion.expected, assertion.message); + })); + + win.close(); + test.done(); + } + })); + + delete config.video; + delete config.messagehandler; + + win.onload = function() { + win.postMessage({ config: config, sessionId: _sessionId }, '*'); + } + } + + navigator.requestMediaKeySystemAccess(config.keysystem, [configuration]).then(function(access) { + return access.createMediaKeys(); + }).then(function(mediaKeys) { + _mediaKeys = mediaKeys; + return _video.setMediaKeys(mediaKeys); + }).then(function(){ + _mediaKeySession = _mediaKeys.createSession( 'persistent-usage-record' ); + waitForEventAndRunStep('encrypted', _video, onEncrypted, test); + waitForEventAndRunStep('playing', _video, onPlaying, test); + return config.servercertificate ? _mediaKeys.setServerCertificate(config.servercertificate) : true; + }).then(function(success) { + return testmediasource(config); + }).then(function(source) { + _mediaSource = source; + _video.src = URL.createObjectURL(_mediaSource); + return source.done; + }).then(function(){ + _video.play(); + }).catch(onFailure); + }, testname); +} diff --git a/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-encrypted-clear-segmented-sources.js b/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-encrypted-clear-segmented-sources.js new file mode 100644 index 0000000000..8f5af2cd6b --- /dev/null +++ b/testing/web-platform/tests/encrypted-media/scripts/playback-temporary-encrypted-clear-segmented-sources.js @@ -0,0 +1,109 @@ +function runTest(configEncrypted,configClear,qualifier) { + + var testname = testnamePrefix(qualifier, configEncrypted.keysystem) + + ', temporary, ' + + /video\/([^;]*)/.exec(configEncrypted.videoType)[1] + + ', playback, encrypted and clear sources in separate segments'; + + var configuration = { initDataTypes: [ configEncrypted.initDataType ], + audioCapabilities: [ { contentType: configEncrypted.audioType } ], + videoCapabilities: [ { contentType: configEncrypted.videoType } ], + sessionTypes: [ 'temporary' ] }; + + async_test(function(test) { + var didAppendEncrypted = false, + _video = configEncrypted.video, + _mediaKeys, + _mediaKeySession, + _mediaSource, + _sourceBuffer; + + function onFailure(error) { + forceTestFailureFromPromise(test, error); + } + + function onVideoError(event) { + var message = (_video.error || {}).message || 'Got unknown error from