Bug 903741: Use new DOMError approach in PeerConnection to get error messages out + unittests r=jesup
authorJan-Ivar Bruaroey <jib@mozilla.com>
Fri, 06 Sep 2013 15:29:29 -0400
changeset 146076 9e839e0432ebed639ed1af98601d70e4913e8eaa
parent 146075 69e78915fc92cb08b22f29eeaaa87971787a291f
child 146077 7bf2b6cf8d730cc9d36d1cbfb627d1674b725f14
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersjesup
bugs903741
milestone26.0a1
Bug 903741: Use new DOMError approach in PeerConnection to get error messages out + unittests r=jesup
dom/media/PeerConnection.js
dom/media/tests/mochitest/test_peerConnection_bug825703.html
dom/media/tests/mochitest/test_peerConnection_bug835370.html
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -268,17 +268,18 @@ RTCPeerConnection.prototype = {
     if (!rtcConfig.iceServers ||
         !Services.prefs.getBoolPref("media.peerconnection.use_document_iceservers")) {
       rtcConfig = {iceServers:
         JSON.parse(Services.prefs.getCharPref("media.peerconnection.default_iceservers"))};
     }
     this._mustValidateRTCConfiguration(rtcConfig,
         "RTCPeerConnection constructor passed invalid RTCConfiguration");
     if (_globalPCList._networkdown) {
-      throw new Components.Exception("Can't create RTCPeerConnections when the network is down");
+      throw new this._win.DOMError("",
+          "Can't create RTCPeerConnections when the network is down");
     }
 
     this.makeGetterSetterEH("onaddstream");
     this.makeGetterSetterEH("onicecandidate");
     this.makeGetterSetterEH("onnegotiationneeded");
     this.makeGetterSetterEH("onsignalingstatechange");
     this.makeGetterSetterEH("onremovestream");
     this.makeGetterSetterEH("ondatachannel");
@@ -300,17 +301,18 @@ RTCPeerConnection.prototype = {
       func: this._getPC().initialize,
       args: [this._observer, this._win, rtcConfig, Services.tm.currentThread],
       wait: true
     });
   },
 
   _getPC: function() {
     if (!this._pc) {
-      throw new Components.Exception("RTCPeerConnection is gone (did you enter Offline mode?)");
+      throw new this._win.DOMError("",
+          "RTCPeerConnection is gone (did you enter Offline mode?)");
     }
     return this._pc;
   },
 
   /**
    * Add a function to the queue or run it immediately if the queue is empty.
    * Argument is an object with the func, args and wait properties; wait should
    * be set to true if the function has a success/error callback that will
@@ -418,67 +420,66 @@ RTCPeerConnection.prototype = {
     const OTHER_KNOWN_CONSTRAINTS = {
       VoiceActivityDetection:1,
       IceTransports:1,
       RequestIdentity:1
     };
     // Parse-aid: Testing for pilot error of missing outer block avoids
     // otherwise silent no-op since both mandatory and optional are optional
     if (!isObject(constraints) || Array.isArray(constraints)) {
-      throw new Components.Exception(errorMsg);
+      throw new this._win.DOMError("", errorMsg);
     }
     if (constraints.mandatory) {
       // Testing for pilot error of using [] on mandatory here throws nicer msg
       // (arrays would throw in loop below regardless but with more cryptic msg)
       if (!isObject(constraints.mandatory) || Array.isArray(constraints.mandatory)) {
-        throw new Components.Exception(errorMsg + " - malformed mandatory constraints");
+        throw new this._win.DOMError("",
+            errorMsg + " - malformed mandatory constraints");
       }
       for (let constraint in constraints.mandatory) {
         if (!(constraint in SUPPORTED_CONSTRAINTS) &&
             constraints.mandatory.hasOwnProperty(constraint)) {
-          throw new Components.Exception(errorMsg + " - " +
-                                         ((constraint in OTHER_KNOWN_CONSTRAINTS)?
-                                          "unsupported" : "unknown") +
-                                         " mandatory constraint: " + constraint);
+          throw new this._win.DOMError("", errorMsg + " - " +
+              ((constraint in OTHER_KNOWN_CONSTRAINTS)? "unsupported" : "unknown") +
+              " mandatory constraint: " + constraint);
         }
       }
     }
     if (constraints.optional) {
       if (!isArraylike(constraints.optional)) {
-        throw new Components.Exception(errorMsg +
-                                       " - malformed optional constraint array");
+        throw new this._win.DOMError("",
+            errorMsg + " - malformed optional constraint array");
       }
       let len = constraints.optional.length;
       for (let i = 0; i < len; i += 1) {
         if (!isObject(constraints.optional[i])) {
-          throw new Components.Exception(errorMsg +
-                                         " - malformed optional constraint: " +
-                                         constraints.optional[i]);
+          throw new this._win.DOMError("", errorMsg +
+              " - malformed optional constraint: " + constraints.optional[i]);
         }
         let constraints_per_entry = 0;
         for (let constraint in constraints.optional[i]) {
           if (constraints.optional[i].hasOwnProperty(constraint)) {
             if (constraints_per_entry) {
-              throw new Components.Exception(errorMsg +
+              throw new this._win.DOMError("", errorMsg +
                   " - optional constraint must be single key/value pair");
             }
             constraints_per_entry += 1;
           }
         }
       }
     }
   },
 
   // Ideally, this should be of the form _checkState(state),
   // where the state is taken from an enumeration containing
   // the valid peer connection states defined in the WebRTC
   // spec. See Bug 831756.
   _checkClosed: function() {
     if (this._closed) {
-      throw new Components.Exception("Peer connection is closed");
+      throw new this._win.DOMError("", "Peer connection is closed");
     }
   },
 
   dispatchEvent: function(event) {
     this.__DOM_IMPL__.dispatchEvent(event);
   },
 
   // Log error message to web console and window.onerror, if present.
@@ -624,21 +625,20 @@ RTCPeerConnection.prototype = {
     switch (desc.type) {
       case "offer":
         type = Ci.IPeerConnection.kActionOffer;
         break;
       case "answer":
         type = Ci.IPeerConnection.kActionAnswer;
         break;
       case "pranswer":
-        throw new Components.Exception("pranswer not yet implemented",
-                                       Cr.NS_ERROR_NOT_IMPLEMENTED);
+        throw new this._win.DOMError("", "pranswer not yet implemented");
       default:
-        throw new Components.Exception("Invalid type " + desc.type +
-                                       " provided to setLocalDescription");
+        throw new this._win.DOMError("",
+            "Invalid type " + desc.type + " provided to setLocalDescription");
     }
 
     this._queueOrRun({
       func: this._getPC().setLocalDescription,
       args: [type, desc.sdp],
       wait: true,
       type: desc.type
     });
@@ -655,72 +655,69 @@ RTCPeerConnection.prototype = {
     switch (desc.type) {
       case "offer":
         type = Ci.IPeerConnection.kActionOffer;
         break;
       case "answer":
         type = Ci.IPeerConnection.kActionAnswer;
         break;
       case "pranswer":
-        throw new Components.Exception("pranswer not yet implemented",
-                                       Cr.NS_ERROR_NOT_IMPLEMENTED);
+        throw new this._win.DOMError("", "pranswer not yet implemented");
       default:
-        throw new Components.Exception("Invalid type " + desc.type +
-                                       " provided to setRemoteDescription");
+        throw new this._win.DOMError("",
+            "Invalid type " + desc.type + " provided to setRemoteDescription");
     }
 
     this._queueOrRun({
       func: this._getPC().setRemoteDescription,
       args: [type, desc.sdp],
       wait: true,
       type: desc.type
     });
   },
 
   updateIce: function(config, constraints) {
-    throw new Components.Exception("updateIce not yet implemented",
-                                   Cr.NS_ERROR_NOT_IMPLEMENTED);
+    throw new this._win.DOMError("", "updateIce not yet implemented");
   },
 
   addIceCandidate: function(cand, onSuccess, onError) {
     if (!cand.candidate && !cand.sdpMLineIndex) {
-      throw new Components.Exception("Invalid candidate passed to addIceCandidate!");
+      throw new this._win.DOMError("",
+          "Invalid candidate passed to addIceCandidate!");
     }
     this._onAddIceCandidateSuccess = onSuccess || null;
     this._onAddIceCandidateError = onError || null;
 
     this._queueOrRun({
       func: this._getPC().addIceCandidate,
       args: [cand.candidate, cand.sdpMid || "",
              (cand.sdpMLineIndex === null)? 0 : cand.sdpMLineIndex + 1],
       wait: true
     });
   },
 
   addStream: function(stream, constraints) {
     if (stream.currentTime === undefined) {
-      throw new Components.Exception("Invalid stream passed to addStream!");
+      throw new this._win.DOMError("", "Invalid stream passed to addStream!");
     }
     // TODO: Implement constraints.
     this._queueOrRun({
       func: this._getPC().addStream,
       args: [stream],
       wait: false
     });
   },
 
   removeStream: function(stream) {
      //Bug 844295: Not implementing this functionality.
-     throw new Components.Exception("removeStream not yet implemented",
-                                    Cr.NS_ERROR_NOT_IMPLEMENTED);
+     throw new this._win.DOMError("", "removeStream not yet implemented");
   },
 
   getStreamById: function(id) {
-    throw new Components.Exception("getStreamById not yet implemented",
-                                   Cr.NS_ERROR_NOT_IMPLEMENTED);
+    throw new this._win.DOMError("", "getStreamById not yet implemented");
   },
 
   close: function() {
     this._queueOrRun({
       func: this._getPC().close,
       args: [false],
       wait: false
     });
@@ -848,17 +845,18 @@ RTCPeerConnection.prototype = {
     }
     if (dict.stream != undefined) {
       dict.id = dict.stream;
       this.reportWarning("Deprecated RTCDataChannelInit dictionary entry stream used!", null, 0);
     }
 
     if (dict.maxRetransmitTime != undefined &&
         dict.maxRetransmits != undefined) {
-      throw new Components.Exception("Both maxRetransmitTime and maxRetransmits cannot be provided");
+      throw new this._win.DOMError("",
+          "Both maxRetransmitTime and maxRetransmits cannot be provided");
     }
     let protocol;
     if (dict.protocol == undefined) {
       protocol = "";
     } else {
       protocol = dict.protocol;
     }
 
--- a/dom/media/tests/mochitest/test_peerConnection_bug825703.html
+++ b/dom/media/tests/mochitest/test_peerConnection_bug825703.html
@@ -26,47 +26,54 @@
           ok(!exception, "mozRTCPeerConnection(" +
              JSON.stringify(config) + ") succeeds");
       } else {
           ok(exception, "mozRTCPeerConnection(" +
              JSON.stringify(config) + ") throws");
       }
   }
 
-  // This is a test of the iceServers parsing code.
+  // This is a test of the iceServers parsing code + readable errors
 
   runTest(function () {
-    var pc;
+    var pc, pcs;
     var exception = null;
     var config;
 
     try { pcs = new mozRTCPeerConnection(); } catch (e) { exception = e; }
     ok(!exception, "mozRTCPeerConnection() succeeds");
+    pcs = null;
     exception = null;
 
     makePC(1, false);
 
     makePC({}, true);
 
     makePC({ iceServers: [] }, true);
 
     makePC({ iceServers: [{ url:"" }] }, false);
 
-    makePC({ iceServers: [{ url:"http:0.0.0.0" }] }, false);
-
     makePC({ iceServers: [
                 { url:"stun:127.0.0.1" },
                 { url:"stuns:localhost", foo:"" },
                 { url:"turn:[::1]:3478", username:"p", credential:"p" },
                 { url:"turns:localhost:3478?transport=udp", username:"p", credential:"p" }
                 ]}, true);
 
     makePC({ iceServers: [{ url:"turns:localhost:3478", username:"p" }] }, false);
 
     makePC({ iceServers: [{ url:"turns:localhost:3478", credential:"p" }] }, false);
 
+    makePC({ iceServers: [{ url:"http:0.0.0.0" }] }, false);
+    try {
+        pcs = new mozRTCPeerConnection({ iceServers: [{ url:"http:0.0.0.0" }] });
+    } catch (e) {
+        ok(e.message.indexOf("http") > 0,
+           "mozRTCPeerConnection() constructor has readable exceptions");
+    }
     pcs = null;
+
     SimpleTest.finish();
   });
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_peerConnection_bug835370.html
+++ b/dom/media/tests/mochitest/test_peerConnection_bug835370.html
@@ -31,17 +31,22 @@
     ok(exception, "createOffer(step1, failed, []) throws");
     exception = null;
     try { pconnects.createOffer(step1, failed, {}); } catch (e) { exception = e; }
     ok(!exception, "createOffer(step1, failed, {}) succeeds");
     exception = null;
     try { pconnect.createOffer(step1, failed, { mandatory: [] }); } catch (e) { exception = e; }
     ok(exception, "createOffer(step1, failed, { mandatory: [] }) throws");
     exception = null;
-    try { pconnect.createOffer(step1, failed, { mandatory: { FooBar: true } }); } catch (e) { exception = e; }
+    try {
+        pconnect.createOffer(step1, failed, { mandatory: { FooBar: true } });
+    } catch (e) {
+        ok(e.message.indexOf("FooBar") > 0, "createOffer has readable exceptions");
+        exception = e;
+    }
     ok(exception, "createOffer(step1, failed, { mandatory: { FooBar: true } }) throws");
     exception = null;
     try { pconnect.createOffer(step1, failed, { optional: {} }); } catch (e) { exception = e; }
     ok(exception, "createOffer(step1, failed, { optional: {} }) throws");
     exception = null;
     try { pconnects.createOffer(step1, failed, { optional: [] }); } catch (e) { exception = e; }
     ok(!exception, "createOffer(step1, failed, { optional: [] }) succeeds");
     exception = null;