diff -r 000000000000 -r 6474c204b198 dom/media/tests/mochitest/head.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dom/media/tests/mochitest/head.js Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,260 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +var Cc = SpecialPowers.Cc; +var Ci = SpecialPowers.Ci; +var Cr = SpecialPowers.Cr; + +// Specifies whether we are using fake streams to run this automation +var FAKE_ENABLED = true; + + +/** + * Create the necessary HTML elements for head and body as used by Mochitests + * + * @param {object} meta + * Meta information of the test + * @param {string} meta.title + * Description of the test + * @param {string} [meta.bug] + * Bug the test was created for + * @param {boolean} [meta.visible=false] + * Visibility of the media elements + */ +function createHTML(meta) { + var test = document.getElementById('test'); + + // Create the head content + var elem = document.createElement('meta'); + elem.setAttribute('charset', 'utf-8'); + document.head.appendChild(elem); + + var title = document.createElement('title'); + title.textContent = meta.title; + document.head.appendChild(title); + + // Create the body content + var anchor = document.createElement('a'); + anchor.setAttribute('target', '_blank'); + + if (meta.bug) { + anchor.setAttribute('href', 'https://bugzilla.mozilla.org/show_bug.cgi?id=' + meta.bug); + } + + anchor.textContent = meta.title; + document.body.insertBefore(anchor, test); + + var display = document.createElement('p'); + display.setAttribute('id', 'display'); + document.body.insertBefore(display, test); + + var content = document.createElement('div'); + content.setAttribute('id', 'content'); + content.style.display = meta.visible ? 'block' : "none"; + document.body.appendChild(content); +} + + +/** + * Create the HTML element if it doesn't exist yet and attach + * it to the content node. + * + * @param {string} type + * Type of media element to create ('audio' or 'video') + * @param {string} label + * Description to use for the element + * @return {HTMLMediaElement} The created HTML media element + */ +function createMediaElement(type, label) { + var id = label + '_' + type; + var element = document.getElementById(id); + + // Sanity check that we haven't created the element already + if (element) + return element; + + element = document.createElement(type === 'audio' ? 'audio' : 'video'); + element.setAttribute('id', id); + element.setAttribute('height', 100); + element.setAttribute('width', 150); + element.setAttribute('controls', 'controls'); + document.getElementById('content').appendChild(element); + + return element; +} + + +/** + * Wrapper function for mozGetUserMedia to allow a singular area of control + * for determining whether we run this with fake devices or not. + * + * @param {Dictionary} constraints + * The constraints for this mozGetUserMedia callback + * @param {Function} onSuccess + * The success callback if the stream is successfully retrieved + * @param {Function} onError + * The error callback if the stream fails to be retrieved + */ +function getUserMedia(constraints, onSuccess, onError) { + constraints["fake"] = FAKE_ENABLED; + + info("Call getUserMedia for " + JSON.stringify(constraints)); + navigator.mozGetUserMedia(constraints, onSuccess, onError); +} + + +/** + * Setup any Mochitest for WebRTC by enabling the preference for + * peer connections. As by bug 797979 it will also enable mozGetUserMedia() + * and disable the mozGetUserMedia() permission checking. + * + * @param {Function} aCallback + * Test method to execute after initialization + */ +function runTest(aCallback) { + if (window.SimpleTest) { + // Running as a Mochitest. + SimpleTest.waitForExplicitFinish(); + SpecialPowers.pushPrefEnv({'set': [ + ['dom.messageChannel.enabled', true], + ['media.peerconnection.enabled', true], + ['media.peerconnection.identity.enabled', true], + ['media.peerconnection.identity.timeout', 12000], + ['media.navigator.permission.disabled', true]] + }, function () { + try { + aCallback(); + } + catch (err) { + generateErrorCallback()(err); + } + }); + } else { + // Steeplechase, let it call the callback. + window.run_test = function(is_initiator) { + var options = {is_local: is_initiator, + is_remote: !is_initiator}; + aCallback(options); + }; + // Also load the steeplechase test code. + var s = document.createElement("script"); + s.src = "/test.js"; + document.head.appendChild(s); + } +} + +/** + * Checks that the media stream tracks have the expected amount of tracks + * with the correct kind and id based on the type and constraints given. + * + * @param {Object} constraints specifies whether the stream should have + * audio, video, or both + * @param {String} type the type of media stream tracks being checked + * @param {sequence} mediaStreamTracks the media stream + * tracks being checked + */ +function checkMediaStreamTracksByType(constraints, type, mediaStreamTracks) { + if(constraints[type]) { + is(mediaStreamTracks.length, 1, 'One ' + type + ' track shall be present'); + + if(mediaStreamTracks.length) { + is(mediaStreamTracks[0].kind, type, 'Track kind should be ' + type); + ok(mediaStreamTracks[0].id, 'Track id should be defined'); + } + } else { + is(mediaStreamTracks.length, 0, 'No ' + type + ' tracks shall be present'); + } +} + +/** + * Check that the given media stream contains the expected media stream + * tracks given the associated audio & video constraints provided. + * + * @param {Object} constraints specifies whether the stream should have + * audio, video, or both + * @param {MediaStream} mediaStream the media stream being checked + */ +function checkMediaStreamTracks(constraints, mediaStream) { + checkMediaStreamTracksByType(constraints, 'audio', + mediaStream.getAudioTracks()); + checkMediaStreamTracksByType(constraints, 'video', + mediaStream.getVideoTracks()); +} + +/** + * Utility methods + */ + +/** + * Returns the contents of a blob as text + * + * @param {Blob} blob + The blob to retrieve the contents from + * @param {Function} onSuccess + Callback with the blobs content as parameter + */ +function getBlobContent(blob, onSuccess) { + var reader = new FileReader(); + + // Listen for 'onloadend' which will always be called after a success or failure + reader.onloadend = function (event) { + onSuccess(event.target.result); + }; + + reader.readAsText(blob); +} + +/** + * Generates a callback function fired only under unexpected circumstances + * while running the tests. The generated function kills off the test as well + * gracefully. + * + * @param {String} [message] + * An optional message to show if no object gets passed into the + * generated callback method. + */ +function generateErrorCallback(message) { + var stack = new Error().stack.split("\n"); + stack.shift(); // Don't include this instantiation frame + + /** + * @param {object} aObj + * The object fired back from the callback + */ + return function (aObj) { + if (aObj) { + if (aObj.name && aObj.message) { + ok(false, "Unexpected callback for '" + aObj.name + + "' with message = '" + aObj.message + "' at " + + JSON.stringify(stack)); + } else { + ok(false, "Unexpected callback with = '" + aObj + + "' at: " + JSON.stringify(stack)); + } + } else { + ok(false, "Unexpected callback with message = '" + message + + "' at: " + JSON.stringify(stack)); + } + SimpleTest.finish(); + } +} + +/** + * Generates a callback function fired only for unexpected events happening. + * + * @param {String} description + Description of the object for which the event has been fired + * @param {String} eventName + Name of the unexpected event + */ +function unexpectedEventAndFinish(message, eventName) { + var stack = new Error().stack.split("\n"); + stack.shift(); // Don't include this instantiation frame + + return function () { + ok(false, "Unexpected event '" + eventName + "' fired with message = '" + + message + "' at: " + JSON.stringify(stack)); + SimpleTest.finish(); + } +}