Added conformance tests.

BUG=

Review URL: https://webrtc-codereview.appspot.com/929030

git-svn-id: http://webrtc.googlecode.com/svn/trunk@3179 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
phoglund@webrtc.org 2012-11-28 13:03:17 +00:00
parent 8d334d387b
commit 7d74bdbeac
2 changed files with 446 additions and 0 deletions

View File

@ -0,0 +1,345 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<title>GetUserMedia Browser Conformance Test</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
</head>
<!--
To quickly iterate when developing this test, make sure you select
'Always allow this site to use this webcam' option in the dropdown menu of
Chrome when it's requesting access to your webcam.
Notice that this requires the site you're browsing to use HTTPS.
-->
<body>
<h1>Conformance test for the Media Capture and Streams API</h1>
<p>This page contains a foundation of conformance tests that can be expanded
to cover most things in the W3C specification of the Media Capture and Streams
API.</p>
<p>VERSION: These tests are based on the W3C Editor's Draft of 25 September
2012.
<p>STATUS: In its current state, it only performs simple checks on the various
attributes and methods of the objects exposed by the API. There's not much
functionality tested so far.</p>
<p>PREREQUISITES: You must have a webcam available on the machine that the
test is executed at.</p>
<p>PREFIX: These tests currently utilizes the <pre>webkit</pre> prefix, so
that will have to changed in order to to test conformance with the actual
standard!</p>
<p>SPEC: <a href="http://dev.w3.org/2011/webrtc/editor/getusermedia.html">
http://dev.w3.org/2011/webrtc/editor/getusermedia.html</a></p>
<div id="log"></div>
<script src="https://w3c-test.org/resources/testharness.js"></script>
<script type="text/javascript">
setup({timeout:10000});
// Helper functions to minimize code duplication.
function failedCallback(test) {
return test.step_func(function (error) {
assert_unreached('Should not get an error callback');
});
}
function invokeGetUserMedia(test, okCallback) {
navigator.webkitGetUserMedia({ video: true, audio: true }, okCallback,
failedCallback(test));
}
// MediaStream.
var mediaStreamTest = async_test('4.2 MediaStream');
function verifyMediaStream(stream) {
test(function () {
assert_own_property(stream, 'label');
assert_true(typeof stream.label === 'string');
assert_readonly(stream, 'label');
}, "MediaStream label attribute");
test(function () {
assert_own_property(stream, 'audioTracks');
assert_true(typeof stream.audioTracks === 'object',
'audioTracks is a MediaStreamTrackList');
assert_readonly(stream, 'audioTracks');
}, "MediaStream audioTracks attribute");
test(function () {
assert_own_property(stream, 'videoTracks');
assert_true(typeof stream.videoTracks === 'object',
'videoTracks is a MediaStreamTrackList');
assert_readonly(stream, 'videoTracks');
}, "MediaStream videoTracks attribute");
test(function () {
assert_own_property(stream, 'ended');
assert_true(typeof stream.ended === 'boolean');
assert_false(stream.ended);
}, "MediaStream ended attribute");
test(function () {
assert_own_property(stream, 'onended');
assert_true(stream.onended === null);
}, "MediaStream onended EventHandler");
}
mediaStreamTest.step(function() {
var okCallback = mediaStreamTest.step_func(function (localStream) {
verifyMediaStream(localStream);
// Verify event handlers are working.
localStream.onended = onendedCallback
assert_false(localStream.ended);
localStream.stop();
});
var onendedCallback = mediaStreamTest.step_func(function () {
assert_true(localStream.ended);
mediaStreamTest.done();
});
invokeGetUserMedia(mediaStreamTest, okCallback);;
});
// LocalMediaStream.
var localMediaStreamTest = async_test('4.3 LocalMediaStream');
localMediaStreamTest.step(function() {
var okCallback = localMediaStreamTest.step_func(function (localStream) {
assert_own_property(localStream, 'stop');
assert_true(typeof localStream.stop === 'function');
localMediaStreamTest.done();
});
invokeGetUserMedia(localMediaStreamTest, okCallback);
});
// MediaStreamTrack.
var mediaStreamTrackTest = async_test('4.4 MediaStreamTrack');
function verifyTrack(type, track) {
test(function () {
assert_own_property(track, 'kind');
assert_readonly(track, 'kind');
}, 'MediaStreamTrack (' + type + ') kind attribute');
test(function () {
assert_own_property(track, 'label');
assert_true(typeof track.label === 'string',
'label is an object (DOMString)');
assert_readonly(track, 'label');
}, 'MediaStreamTrack (' + type + ') label attribute');
test(function () {
assert_own_property(track, 'enabled');
assert_true(typeof track.enabled === 'boolean',
'enabled is an object (DOMString)');
assert_true(track.enabled, 'enabled property must be true initially');
}, 'MediaStreamTrack (' + type + ') enabled attribute');
test(function () {
assert_own_property(track, 'readyState');
assert_true(typeof track.readyState === 'number');
assert_readonly(track, 'readyState');
assert_equals(track.readyState, track.LIVE,
'readyState must be LIVE initially');
}, 'MediaStreamTrack (' + type + ') readyState attribute');
test(function () {
assert_own_property(track, 'onmute');
assert_true(track.onmute === null);
}, 'MediaStreamTrack (' + type + ') onmute EventHandler');
test(function () {
assert_own_property(track, 'onunmute');
assert_true(track.onunmute === null);
}, 'MediaStreamTrack (' + type + ') onunmute EventHandler');
test(function () {
assert_own_property(track, 'onended');
assert_true(track.onended === null);
}, 'MediaStreamTrack (' + type + ') onended EventHandler');
}
mediaStreamTrackTest.step(function() {
var okCallback = mediaStreamTrackTest.step_func(function (localStream) {
verifyTrack('audio', localStream.audioTracks[0]);
verifyTrack('video', localStream.videoTracks[0]);
mediaStreamTrackTest.done();
});
invokeGetUserMedia(mediaStreamTrackTest, okCallback);
});
// URL tests.
var createObjectURLTest = async_test('4.5 URL createObjectURL method');
createObjectURLTest.step(function() {
var okCallback = createObjectURLTest.step_func(function (localStream) {
var url = webkitURL.createObjectURL(localStream);
assert_true(typeof url === 'string');
createObjectURLTest.done();
});
invokeGetUserMedia(createObjectURLTest, okCallback);
});
// MediaStreamTrackList tests.
var mediaStreamTrackListTest = async_test('4.6 MediaStreamTrackList');
function verifyTrackList(type, trackList) {
test(function () {
assert_own_property(trackList, 'length');
assert_true(typeof trackList.length === 'number');
assert_true(trackList.length === 1);
}, 'MediaStreamTrackList (' + type + ') length attribute');
test(function () {
assert_own_property(trackList, 'item');
assert_true(typeof trackList.item === 'function');
assert_true(trackList.item(0) !== null);
}, 'MediaStreamTrackList (' + type + ') item() method');
test(function () {
assert_own_property(trackList, 'add');
assert_true(typeof trackList.add === 'function');
}, 'MediaStreamTrackList (' + type + ') add() method');
test(function () {
assert_own_property(trackList, 'remove');
assert_true(typeof trackList.remove === 'function');
}, 'MediaStreamTrackList (' + type + ') remove() method');
test(function () {
assert_own_property(trackList, 'onaddtrack');
assert_true(trackList.onaddtrack === null);
}, 'MediaStreamTrackList (' + type + ') onaddtrack EventHandler');
test(function () {
assert_own_property(trackList, 'onremovetrack');
assert_true(trackList.onremovetrack === null);
}, 'MediaStreamTrackList (' + type + ') onremovetrack EventHandler');
}
mediaStreamTrackListTest.step(function() {
var okCallback = mediaStreamTrackListTest.step_func(function (localStream) {
verifyTrackList('audioTracks', localStream.audioTracks);
verifyTrackList('videoTracks', localStream.videoTracks);
mediaStreamTrackListTest.done();
});
invokeGetUserMedia(mediaStreamTrackListTest, okCallback);
});
// MediaStreams as Media Elements.
var mediaElementsTest = async_test('4.7 MediaStreams as Media Elements');
mediaElementsTest.step(function() {
var okCallback = mediaElementsTest.step_func(function (localStream) {
var url = webkitURL.createObjectURL(localStream);
var videoTag = document.getElementById('local-view');
videoTag.src = url;
assert_equals(videoTag.currentSrc, url);
assert_false(videoTag.preload);
assert_equals(videoTag.buffered.length, 1);
assert_equals(videoTag.buffered.start(0), 0);
assert_equals(videoTag.buffered.end(0), 0);
// Attempts to alter currentTime shall be ignored.
assert_true(videoTag.currentTime >= 0);
var time = videoTag.currentTime;
videoTag.currentTime = time - 100;
assert_true(videoTag.currentTime >= time);
assert_equals(videoTag.duration, infinity);
assert_false(videoTag.seeking);
assert_equals(videoTag.defaultPlaybackRate, 1.0);
// Attempts to alter defaultPlaybackRate shall fail.
assert_throws(videoTag.defaultPlaybackRate = 2.0);
assert_equals(videoTag.playbackRate, 1.0);
// Attempts to alter playbackRate shall fail.
assert_throws(videoTag.playbackRate = 2.0);
assert_equals(videoTag.played.length, 1);
assert_equals(videoTag.played.start(0), 0);
assert_true(videoTag.played.end(0) >= videoTag.currentTime);
assert_equals(videoTag.seekable.length, 0);
assert_equals(videoTag.seekable.start(), videoTag.currentTime);
assert_equals(videoTag.seekable.end(), videoTag.currentTime);
assert_equals(videoTag.startOffsetTime, NaN);
assert_false(videoTag.loop);
mediaElementsTest.done();
});
invokeGetUserMedia(mediaElementsTest, okCallback);
});
// NavigatorUserMedia.
var getUserMediaTest = async_test('5.1 NavigatorUserMedia');
getUserMediaTest.step(function() {
var okCallback = getUserMediaTest.step_func(function (localStream) {
assert_true(localStream !== null);
getUserMediaTest.done();
});
// boolean parameters, without failure callback:
navigator.webkitGetUserMedia({ video: true, audio: true }, okCallback);
navigator.webkitGetUserMedia({ video: true, audio: false }, okCallback);
navigator.webkitGetUserMedia({ video: false, audio: true }, okCallback);
// boolean parameters, with failure callback:
navigator.webkitGetUserMedia({ video: true, audio: true }, okCallback,
failedCallback(getUserMediaTest));
navigator.webkitGetUserMedia({ video: true, audio: false }, okCallback,
failedCallback(getUserMediaTest));
navigator.webkitGetUserMedia({ video: false, audio: true }, okCallback,
failedCallback(getUserMediaTest));
});
// MediaStreamConstraints.
var constraintsTest =
async_test('5.2 MediaStreamConstraints');
constraintsTest.step(function() {
var okCallback = constraintsTest.step_func(function (localStream) {
assert_true(localStream !== null);
constraintsTest.done();
});
// Constraints on video.
// See http://code.google.com/p/webrtc-samples/source/browse/trunk/demos/html/constraints-and-stats.html
// for more examples of constraints.
var constraints = {};
constraints.audio = true;
constraints.video = { mandatory: {}, optional: [] };
constraints.video.mandatory.minWidth = 640;
constraints.video.mandatory.minHeight = 480;
constraints.video.mandatory.minFrameRate = 15;
navigator.webkitGetUserMedia(constraints, okCallback,
failedCallback(constraintsTest));
});
// NavigatorUserMediaSuccessCallback.
var successCallbackTest =
async_test('5.3 NavigatorUserMediaSuccessCallback');
successCallbackTest.step(function() {
var okCallback = successCallbackTest.step_func(function (localStream) {
assert_true(localStream !== null);
assert_own_property(localStream, 'stop');
successCallbackTest.done();
});
invokeGetUserMedia(successCallbackTest, okCallback);
});
// NavigatorUserMediaError and NavigatorUserMediaErrorCallback.
var errorCallbackTest =
async_test('5.4 NavigatorUserMediaError and ' +
'NavigatorUserMediaErrorCallback');
errorCallbackTest.step(function() {
var okCallback = errorCallbackTest.step_func(function (localStream) {
assert_unreached('Should not get a success callback');
});
var errorCallback = errorCallbackTest.step_func(function (error) {
assert_own_property(error, 'PERMISSION_DENIED');
assert_readonly(error.PERMISSION_DENIED);
assert_true(typeof error.PERMISSION_DENIED === 'number');
assert_own_property(error, 'code');
assert_readonly(error.code);
assert_true(typeof error.code === 'number');
});
// Setting both audio and video to false triggers an error callback.
// TODO(kjellander): Figure out if there's a way in the spec to trigger an
// error callback.
navigator.webkitGetUserMedia({ video: false, audio: false }, okCallback,
errorCallback);
});
</script>
<video width="640" height="480" id="local-view" autoplay="autoplay"></video>
</body>
</html>

View File

@ -0,0 +1,101 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<!--
To quickly iterate when developing this test, make sure you select
'Always allow this site to use this webcam' option in the dropdown menu of
Chrome when it's requesting access to your webcam.
Notice that this requires the site you're browsing to use HTTPS.
Without that, the test might timeout before you have had the chance to accept
access to the webcam.
-->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>PeerConnection Connection Test</title>
<script src="https://w3c-test.org/resources/testharness.js"></script>
<script type="text/javascript">
var test = async_test('Can set up a basic WebRTC call.', {timeout: 5000});
var gFirstConnection = null;
var gSecondConnection = null;
var getUserMediaFailedCallback = test.step_func(function(error) {
assert_unreached('Should not get an error callback');
});
function getUserMediaOkCallback(localStream) {
gFirstConnection = new webkitRTCPeerConnection(null, null);
gFirstConnection.onicecandidate = onIceCandidateToFirst;
gFirstConnection.addStream(localStream);
gFirstConnection.createOffer(onOfferCreated);
};
var onOfferCreated = test.step_func(function(offer) {
gFirstConnection.setLocalDescription(offer);
// This would normally go across the application's signaling solution.
// In our case, the "signaling" is to call this function.
receiveCall(offer.sdp);
});
var receiveCall = test.step_func(function(offerSdp) {
gSecondConnection = new webkitRTCPeerConnection(null, null);
gSecondConnection.onicecandidate = onIceCandidateToSecond;
gSecondConnection.onaddstream = onRemoteStream;
var parsedOffer = new RTCSessionDescription({ type: 'offer',
sdp: offerSdp });
gSecondConnection.setRemoteDescription(parsedOffer);
gSecondConnection.createAnswer(onAnswerCreated);
});
var onAnswerCreated = test.step_func(function(answer) {
gSecondConnection.setLocalDescription(answer);
// Similarly, this would go over the application's signaling solution.
handleAnswer(answer.sdp);
});
var handleAnswer = test.step_func(function(answerSdp) {
var parsedAnswer = new RTCSessionDescription({ type: 'answer',
sdp: answerSdp });
gFirstConnection.setRemoteDescription(parsedAnswer);
});
var onIceCandidateToFirst = test.step_func(function(event) {
// If event.candidate is null = no more candidates.
if (event.candidate) {
var candidate = new RTCIceCandidate(event.candidate);
gSecondConnection.addIceCandidate(candidate);
}
});
var onIceCandidateToSecond = test.step_func(function(event) {
if (event.candidate) {
var candidate = new RTCIceCandidate(event.candidate);
gFirstConnection.addIceCandidate(candidate);
}
});
var onRemoteStream = test.step_func(function(e) {
test.done();
});
test.step(function() {
navigator.webkitGetUserMedia({ video: true, audio: true },
getUserMediaOkCallback,
getUserMediaFailedCallback)
});
</script>
</head>
<body>
</body>
<div id="log"></div>
</body>
</html>