Bug 1323328 - Part 3: Add VR display request present mochitest; r?kip
MozReview-Commit-ID: 13WuFhUFcTo
--- a/dom/vr/moz.build
+++ b/dom/vr/moz.build
@@ -22,8 +22,10 @@ UNIFIED_SOURCES = [
]
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'
LOCAL_INCLUDES += [
'/dom/base'
]
+
+MOCHITEST_MANIFESTS += ['test/mochitest.ini']
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/vr/test/VRSimulationDriver.js
@@ -0,0 +1,45 @@
+
+var VRServiceTest;
+
+var VRSimulationDriver = (function() {
+"use strict";
+
+var AttachWebVRDisplay = function() {
+ return VRServiceTest.attachVRDisplay("VRDisplayTest");
+};
+
+var SetVRDisplayPose = function(vrDisplay, position,
+ linearVelocity, linearAcceleration,
+ orientation, angularVelocity,
+ angularAcceleration) {
+ vrDisplay.setPose(position, linearVelocity, linearAcceleration,
+ orientation, angularVelocity, angularAcceleration);
+};
+
+var SetEyeResolution = function(width, height) {
+ vrDisplay.setEyeResolution(width, height);
+}
+
+var SetEyeParameter = function(vrDisplay, eye, offsetX, offsetY, offsetZ,
+ upDegree, rightDegree, downDegree, leftDegree) {
+ vrDisplay.setEyeParameter(eye, offsetX, offsetY, offsetZ, upDegree, rightDegree,
+ downDegree, leftDegree);
+}
+
+var UpdateVRDisplay = function(vrDisplay) {
+ vrDisplay.update();
+}
+
+var API = {
+ AttachWebVRDisplay: AttachWebVRDisplay,
+ SetVRDisplayPose: SetVRDisplayPose,
+ SetEyeResolution: SetEyeResolution,
+ SetEyeParameter: SetEyeParameter,
+ UpdateVRDisplay: UpdateVRDisplay,
+
+ none: false
+};
+
+return API;
+
+}());
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/vr/test/WebVRHelpers.js
@@ -0,0 +1,21 @@
+
+var WebVRHelpers = (function() {
+"use strict";
+
+var RequestPresentOnVRDisplay = function(vrDisplay, vrLayers, callback) {
+ if (callback) {
+ callback();
+ }
+
+ return vrDisplay.requestPresent(vrLayers);
+};
+
+var API = {
+ RequestPresentOnVRDisplay: RequestPresentOnVRDisplay,
+
+ none: false
+};
+
+return API;
+
+}());
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/vr/test/mochitest.ini
@@ -0,0 +1,9 @@
+[DEFAULT]
+support-files =
+ VRSimulationDriver.js
+ requestPresent.js
+ runVRTest.js
+ WebVRHelpers.js
+
+[test_vrDisplay_requestPresent.html]
+skip-if = true
new file mode 100644
--- /dev/null
+++ b/dom/vr/test/requestPresent.js
@@ -0,0 +1,34 @@
+// requestPresent.js
+//
+// This file provides helpers for testing VRDisplay requestPresent.
+
+function setupVRDisplay(test) {
+ assert_equals(typeof (navigator.getVRDisplays), "function", "'navigator.getVRDisplays()' must be defined.");
+ return VRSimulationDriver.AttachWebVRDisplay().then(() => {
+ return navigator.getVRDisplays();
+ }).then((displays) => {
+ assert_equals(displays.length, 1, "displays.length must be one after attach.");
+ vrDisplay = displays[0];
+ return validateNewVRDisplay(test, vrDisplay);
+ });
+}
+
+// Validate the settings off a freshly created VRDisplay (prior to calling
+// requestPresent).
+function validateNewVRDisplay(test, display) {
+ assert_true(display.capabilities.canPresent, "display.capabilities.canPresent must always be true for HMDs.");
+ assert_equals(display.capabilities.maxLayers, 1, "display.capabilities.maxLayers must always be 1 when display.capabilities.canPresent is true for current spec revision.");
+ assert_false(display.isPresenting, "display.isPresenting must be false before calling requestPresent.");
+ assert_equals(display.getLayers().length, 0, "display.getLayers() should have no layers if not presenting.");
+ var promise = display.exitPresent();
+ return promise_rejects(test, null, promise);
+}
+
+// Validate the settings off a VRDisplay after requestPresent promise is
+// rejected or after exitPresent is fulfilled.
+function validateDisplayNotPresenting(test, display) {
+ assert_false(display.isPresenting, "display.isPresenting must be false if requestPresent is rejected or after exitPresent is fulfilled.");
+ assert_equals(display.getLayers().length, 0, "display.getLayers() should have no layers if requestPresent is rejected or after exitPresent is fulfilled.");
+ var promise = display.exitPresent();
+ return promise_rejects(test, null, promise);
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/vr/test/runVRTest.js
@@ -0,0 +1,9 @@
+function runVRTest(callback) {
+ SpecialPowers.pushPrefEnv({"set" : [["dom.vr.enabled", true],
+ ["dom.vr.puppet.enabled", true],
+ ["dom.vr.test.enabled", true]]},
+ () => {
+ VRServiceTest = navigator.requestVRServiceTest();
+ callback();
+ });
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/vr/test/test_vrDisplay_requestPresent.html
@@ -0,0 +1,130 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>VRDisplay RequestPresent</title>
+ <meta name="timeout" content="long"/>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="VRSimulationDriver.js"></script>
+ <script src="WebVRHelpers.js"></script>
+ <script src="requestPresent.js"></script>
+ <script src="runVRTest.js"></script>
+</head>
+<body id="body">
+ <canvas id="webglCanvas"></canvas>
+ <div id="testDiv"></div>
+ <script>
+ "use strict";
+ var vrDisplay;
+ var canvas = document.getElementById('webglCanvas');
+ var div = document.getElementById('testDiv');
+ function startTest() {
+ promise_test((test) => {
+ return setupVRDisplay(test).then(() => {
+ return promise_rejects(test, null, WebVRHelpers.RequestPresentOnVRDisplay(vrDisplay, [{}]));
+ }).then(() => {
+ return validateDisplayNotPresenting(test, vrDisplay);
+ });
+ }, "WebVR requestPresent rejected with empty frames");
+
+ promise_test((test) => {
+ return setupVRDisplay(test).then(() => {
+ return promise_rejects(test, null, WebVRHelpers.RequestPresentOnVRDisplay(vrDisplay, [{ source: canvas, leftBounds: [0.0, 0.0] }]));
+ }).then(() => {
+ return validateDisplayNotPresenting(test, vrDisplay);
+ });
+ }, "WebVR requestPresent rejected with incorrect bounds (bounds arrays must be 0 or 4 long)");
+
+ promise_test((test) => {
+ return setupVRDisplay(test).then(() => {
+ return promise_rejects(test, null, WebVRHelpers.RequestPresentOnVRDisplay(vrDisplay, [{ source: div }]));
+ }).then(() => {
+ return validateDisplayNotPresenting(test, vrDisplay);
+ });
+ }, "WebVR requestPresent rejected with invalid source (must be canvas element)");
+
+ promise_test((test) => {
+ return setupVRDisplay(test).then(() => {
+ return promise_rejects(test, null, WebVRHelpers.RequestPresentOnVRDisplay(vrDisplay, [{ source: canvas, leftBounds: [div] }]));
+ }).then(() => {
+ return validateDisplayNotPresenting(test, vrDisplay);
+ });
+ }, "WebVR requestPresent rejected with invalid bounds data type (must be able to convert to float)");
+
+ const invalidBounds = [
+ [2.0, 0.0, 0.0, 0.0],
+ [0.0, 2.0, 0.0, 0.0],
+ [0.0, 0.0, 2.0, 0.0],
+ [0.0, 0.0, 0.0, 2.0],
+ [-1.0, 0.0, 0.0, 0.0],
+ [0.0, -1.0, 0.0, 0.0],
+ [0.0, 0.0, -1.0, 0.0],
+ [0.0, 0.0, 0.0, -1.0]];
+
+ invalidBounds.forEach((bound) => {
+ promise_test((test) => {
+ return setupVRDisplay(test).then(() => {
+ return promise_rejects(test, null, WebVRHelpers.RequestPresentOnVRDisplay(vrDisplay, [{ source: canvas, leftBounds: bound }]));
+ }).then(() => {
+ return validateDisplayNotPresenting(test, vrDisplay);
+ });
+ }, "WebVR requestPresent rejected with bounds in invalid range: [" + bound + "]");
+ });
+
+ promise_test((test) => {
+ return setupVRDisplay(test).then(() => {
+ var promise = vrDisplay.requestPresent({ source: canvas });
+ return promise_rejects(test, null, promise);
+ }).then(() => {
+ return validateDisplayNotPresenting(test, vrDisplay);
+ });
+ }, "WebVR requestPresent rejected without user initiated action");
+
+ promise_test((test) => {
+ return setupVRDisplay(test).then(() => {
+ return promise_rejects(test, null, WebVRHelpers.RequestPresentOnVRDisplay(vrDisplay, [{ source: canvas }, { source: canvas }]));
+ }).then(() => {
+ return validateDisplayNotPresenting(test, vrDisplay);
+ });
+ }, "WebVR requestPresent rejected with more frames than max layers");
+
+ promise_test((test) => {
+ return setupVRDisplay(test).then(() => {
+ function requestAgain() {
+ // Callback for immediate requestPresent call for further testing.
+ // Cache this promise on global object since it seems to be the only object
+ // in scope across calls.
+ window.promiseSecond = vrDisplay.requestPresent([{ source: canvas }]);
+ }
+ return WebVRHelpers.RequestPresentOnVRDisplay(vrDisplay, [{ source: canvas }], requestAgain);
+ }).then(() => {
+ // First promise succeeded
+ assert_true(vrDisplay.isPresenting, "First promise should successfully fulfill");
+ // Now, validate that the subsequent requestPresent was rejected
+ return promise_rejects(test, null, window.promiseSecond);
+ }).then(() => {
+ delete window.promiseSecond;
+ assert_true(vrDisplay.isPresenting, "Should still be presenting after rejected second promise");
+ return vrDisplay.exitPresent();
+ });
+ }, "WebVR requestPresent fails while another one is in progress");
+
+ promise_test((test) => {
+ return setupVRDisplay(test).then(() => {
+ return WebVRHelpers.RequestPresentOnVRDisplay(vrDisplay, [{ source: canvas }]);
+ }).then(() => {
+ assert_true(vrDisplay.isPresenting, "vrDisplay.isPresenting must be true if requestPresent is fulfilled.");
+ assert_equals(vrDisplay.getLayers().length, 1, "vrDisplay.getLayers() should return one layer.");
+ return vrDisplay.exitPresent();
+ }).then(() => {
+ assert_false(vrDisplay.isPresenting, "vrDisplay.isPresenting must be false if exitPresent is fulfilled.");
+ // exitPresent() should reject since we are no longer presenting.
+ return promise_rejects(test, null, vrDisplay.exitPresent());
+ });
+ }, "WebVR requestPresent fulfilled");
+ }
+
+ runVRTest(startTest);
+ </script>
+</body>
+</html>
\ No newline at end of file
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -5039,16 +5039,18 @@ pref("dom.vr.openvr.enabled", false);
pref("dom.vr.poseprediction.enabled", false);
// path to openvr DLL
pref("gfx.vr.openvr-runtime", "");
// path to OSVR DLLs
pref("gfx.vr.osvr.utilLibPath", "");
pref("gfx.vr.osvr.commonLibPath", "");
pref("gfx.vr.osvr.clientLibPath", "");
pref("gfx.vr.osvr.clientKitLibPath", "");
+// Puppet device, used for simulating VR hardware within tests and dev tools
+pref("dom.vr.puppet.enabled", false);
pref("dom.vr.test.enabled", false);
// MMS UA Profile settings
pref("wap.UAProf.url", "");
pref("wap.UAProf.tagname", "x-wap-profile");
// MMS version 1.1 = 0x11 (or decimal 17)
// MMS version 1.3 = 0x13 (or decimal 19)
// @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.34