videojs-contrib-eme
Version:
Supports Encrypted Media Extensions for playback of encrypted content in Video.js
425 lines (355 loc) • 11.6 kB
JavaScript
import QUnit from 'qunit';
import videojs from 'video.js';
import window from 'global/window';
import {
createMessageBuffer,
challengeElement
} from './playready-message';
import msPrefixed from '../src/ms-prefixed';
import utils from './utils';
QUnit.module('videojs-contrib-eme ms-prefixed', {
beforeEach() {
this.origMSMediaKeys = window.MSMediaKeys;
window.MSMediaKeys = () => {};
const session = new videojs.EventTarget();
session.keys = [];
session.update = (key) => session.keys.push(key);
// mock the video since the APIs won't be available on non IE11 browsers
const video = {
msSetMediaKeys: () => {
video.msKeys = {
createSession: () => this.session
};
}
};
this.session = session;
this.video = video;
},
afterEach() {
window.MSMediaKeys = this.origMSMediaKeys;
}
});
QUnit.test('overwrites msKeys', function(assert) {
const origMsKeys = {};
this.video.msKeys = origMsKeys;
msPrefixed({
video: this.video,
initData: '',
options: {
keySystems: {
'com.microsoft.playready': true
}
}
});
assert.notEqual(this.video.msKeys, origMsKeys, 'overwrote msKeys');
});
QUnit.test('logs error when on key error', function(assert) {
const origErrorLog = videojs.log.error;
let errorMessage;
videojs.log.error = (message) => {
errorMessage = message;
};
msPrefixed({
video: this.video,
initData: '',
options: {
keySystems: {
'com.microsoft.playready': true
}
}
});
this.session.error = {
code: 5,
systemCode: 9
};
this.session.trigger('mskeyerror');
assert.equal(errorMessage,
'Unexpected key error from key session with code: 5 and systemCode: 9',
'logged error message');
videojs.log.error = origErrorLog;
});
QUnit.test('calls getKey when provided on key message', function(assert) {
let passedOptions = null;
let passedDestinationURL = null;
let passedBuffer = null;
let passedCallback = null;
let getKeyCallback = (callback) => {
callback(null, 'a key');
};
const emeOptions = {
keySystems: {
'com.microsoft.playready': {
getKey: (options, destinationURL, buffer, callback) => {
passedOptions = options;
passedDestinationURL = destinationURL;
passedBuffer = buffer;
passedCallback = callback;
getKeyCallback(callback);
}
}
}
};
msPrefixed({
video: this.video,
initData: '',
options: emeOptions
});
assert.notOk(passedOptions, 'getKey not called');
this.session.trigger({
type: 'mskeymessage',
destinationURL: 'url',
message: {
buffer: 'buffer'
}
});
assert.equal(passedOptions, emeOptions, 'getKey called with options');
assert.equal(passedDestinationURL, 'url', 'getKey called with destinationURL');
assert.equal(passedBuffer, 'buffer', 'getKey called with buffer');
assert.equal(typeof passedCallback, 'function', 'getKey called with callback');
assert.equal(this.session.keys.length, 1, 'added key to session');
assert.equal(this.session.keys[0], 'a key', 'added correct key to session');
const origErrorLog = videojs.log.error;
let errorMessage;
videojs.log.error = (message) => {
errorMessage = message;
};
getKeyCallback = (callback) => {
callback('an error', 'an errored key');
};
this.session.trigger({
type: 'mskeymessage',
destinationURL: 'url',
message: {
buffer: 'buffer'
}
});
assert.equal(errorMessage,
'Unable to get key: an error',
'logs error when callback has an error');
assert.equal(this.session.keys.length, 1, 'did not add a new key');
videojs.log.error = origErrorLog;
});
QUnit.test('makes request when nothing provided on key message', function(assert) {
const origXhr = videojs.xhr;
const xhrCalls = [];
videojs.xhr = (config, callback) => xhrCalls.push({config, callback});
msPrefixed({
video: this.video,
initData: '',
options: {
keySystems: {
'com.microsoft.playready': true
}
}
});
this.session.trigger({
type: 'mskeymessage',
destinationURL: 'destination-url',
message: {
buffer: createMessageBuffer()
}
});
assert.equal(xhrCalls.length, 1, 'one xhr request');
assert.equal(xhrCalls[0].config.uri,
'destination-url',
'made request to destinationURL');
assert.deepEqual(
xhrCalls[0].config.headers,
{
'Content-Type': 'text/xml; charset=utf-8',
'SOAPAction': '"http://schemas.microsoft.com/DRM/2007/03/protocols/AcquireLicense"'
},
'uses headers from message');
assert.equal(xhrCalls[0].config.body, challengeElement, 'sends the challenge element');
assert.equal(xhrCalls[0].config.method, 'post', 'request is a post');
assert.equal(xhrCalls[0].config.responseType,
'arraybuffer',
'responseType is an arraybuffer');
const origErrorLog = videojs.log.error;
let errorMessage;
videojs.log.error = (message) => {
errorMessage = message;
};
const response = {
body: utils.stringToArrayBuffer('key value')
};
xhrCalls[0].callback('an error', response);
assert.equal(errorMessage,
'Unable to request key from url: destination-url',
'logs error when callback has an error');
assert.equal(this.session.keys.length, 0, 'no key added to session');
xhrCalls[0].callback(null, response);
assert.equal(this.session.keys.length, 1, 'key added to session');
assert.deepEqual(this.session.keys[0],
new Uint8Array(response.body),
'correct key added to session');
videojs.log.error = origErrorLog;
videojs.xhr = origXhr;
});
QUnit.test('makes request on key message when empty object provided in options',
function(assert) {
const origXhr = videojs.xhr;
const xhrCalls = [];
videojs.xhr = (config, callback) => xhrCalls.push({config, callback});
msPrefixed({
video: this.video,
initData: '',
options: {
keySystems: {
'com.microsoft.playready': {}
}
}
});
this.session.trigger({
type: 'mskeymessage',
destinationURL: 'destination-url',
message: {
buffer: createMessageBuffer()
}
});
assert.equal(xhrCalls.length, 1, 'one xhr request');
assert.equal(xhrCalls[0].config.uri,
'destination-url',
'made request to destinationURL');
assert.deepEqual(
xhrCalls[0].config.headers,
{
'Content-Type': 'text/xml; charset=utf-8',
'SOAPAction': '"http://schemas.microsoft.com/DRM/2007/03/protocols/AcquireLicense"'
},
'uses headers from message');
assert.equal(xhrCalls[0].config.body, challengeElement, 'sends the challenge element');
assert.equal(xhrCalls[0].config.method, 'post', 'request is a post');
assert.equal(xhrCalls[0].config.responseType,
'arraybuffer',
'responseType is an arraybuffer');
videojs.xhr = origXhr;
});
QUnit.test('makes request with provided url string on key message', function(assert) {
const origXhr = videojs.xhr;
const xhrCalls = [];
videojs.xhr = (config, callback) => xhrCalls.push({config, callback});
msPrefixed({
video: this.video,
initData: '',
options: {
keySystems: {
'com.microsoft.playready': 'provided-url'
}
}
});
this.session.trigger({
type: 'mskeymessage',
destinationURL: 'destination-url',
message: {
buffer: createMessageBuffer([{
name: 'Content-Type',
value: 'text/xml; charset=utf-8'
}, {
name: 'SOAPAction',
value: '"http://schemas.microsoft.com/DRM/2007/03/protocols/AcquireLicense"'
}])
}
});
assert.equal(xhrCalls.length, 1, 'one xhr request');
assert.equal(xhrCalls[0].config.uri,
'provided-url',
'made request to provided-url');
assert.deepEqual(
xhrCalls[0].config.headers,
{
'Content-Type': 'text/xml; charset=utf-8',
'SOAPAction': '"http://schemas.microsoft.com/DRM/2007/03/protocols/AcquireLicense"'
},
'uses headers from message');
assert.equal(xhrCalls[0].config.body, challengeElement, 'sends the challenge element');
assert.equal(xhrCalls[0].config.method, 'post', 'request is a post');
assert.equal(xhrCalls[0].config.responseType,
'arraybuffer',
'responseType is an arraybuffer');
const origErrorLog = videojs.log.error;
let errorMessage;
videojs.log.error = (message) => {
errorMessage = message;
};
const response = {
body: utils.stringToArrayBuffer('key value')
};
xhrCalls[0].callback('an error', response);
assert.equal(errorMessage,
'Unable to request key from url: provided-url',
'logs error when callback has an error');
assert.equal(this.session.keys.length, 0, 'no key added to session');
xhrCalls[0].callback(null, response);
assert.equal(this.session.keys.length, 1, 'key added to session');
assert.deepEqual(this.session.keys[0],
new Uint8Array(response.body),
'correct key added to session');
videojs.log.error = origErrorLog;
videojs.xhr = origXhr;
});
QUnit.test('makes request with provided url on key message', function(assert) {
const origXhr = videojs.xhr;
const xhrCalls = [];
videojs.xhr = (config, callback) => xhrCalls.push({config, callback});
msPrefixed({
video: this.video,
initData: '',
options: {
keySystems: {
'com.microsoft.playready': {
url: 'provided-url'
}
}
}
});
this.session.trigger({
type: 'mskeymessage',
destinationURL: 'destination-url',
message: {
buffer: createMessageBuffer([{
name: 'Content-Type',
value: 'text/xml; charset=utf-8'
}, {
name: 'SOAPAction',
value: '"http://schemas.microsoft.com/DRM/2007/03/protocols/AcquireLicense"'
}])
}
});
assert.equal(xhrCalls.length, 1, 'one xhr request');
assert.equal(xhrCalls[0].config.uri,
'provided-url',
'made request to provided-url');
assert.deepEqual(
xhrCalls[0].config.headers,
{
'Content-Type': 'text/xml; charset=utf-8',
'SOAPAction': '"http://schemas.microsoft.com/DRM/2007/03/protocols/AcquireLicense"'
},
'uses headers from message');
assert.equal(xhrCalls[0].config.body, challengeElement, 'sends the challenge element');
assert.equal(xhrCalls[0].config.method, 'post', 'request is a post');
assert.equal(xhrCalls[0].config.responseType,
'arraybuffer',
'responseType is an arraybuffer');
const origErrorLog = videojs.log.error;
let errorMessage;
videojs.log.error = (message) => {
errorMessage = message;
};
const response = {
body: utils.stringToArrayBuffer('key value')
};
xhrCalls[0].callback('an error', response);
assert.equal(errorMessage,
'Unable to request key from url: provided-url',
'logs error when callback has an error');
assert.equal(this.session.keys.length, 0, 'no key added to session');
xhrCalls[0].callback(null, response);
assert.equal(this.session.keys.length, 1, 'key added to session');
assert.deepEqual(this.session.keys[0],
new Uint8Array(response.body),
'correct key added to session');
videojs.log.error = origErrorLog;
videojs.xhr = origXhr;
});