Bug 1193764 - Loop's Direct calls hang if the contact hasn't connected to the server at all. r=dmose
authorMark Banner <standard8@mozilla.com>
Thu, 13 Aug 2015 09:09:21 +0100
changeset 257637 5c3a49360f3b2ed54182320928657c4f03ec4e3a
parent 257636 f79b40e799abea9e9eace0f7de0f4c2ef70ce61e
child 257638 633d7fba815494f31b73068a8e6648d0bdd37620
push id29225
push userkwierso@gmail.com
push dateThu, 13 Aug 2015 23:31:33 +0000
treeherdermozilla-central@4e883591bb5d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdmose
bugs1193764
milestone43.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1193764 - Loop's Direct calls hang if the contact hasn't connected to the server at all. r=dmose
browser/components/loop/content/js/conversationViews.js
browser/components/loop/content/js/conversationViews.jsx
browser/components/loop/content/shared/js/conversationStore.js
browser/components/loop/content/shared/js/utils.js
browser/components/loop/test/desktop-local/conversationViews_test.js
browser/components/loop/test/shared/conversationStore_test.js
--- a/browser/components/loop/content/js/conversationViews.js
+++ b/browser/components/loop/content/js/conversationViews.js
@@ -4,17 +4,16 @@
 
 var loop = loop || {};
 loop.conversationViews = (function(mozL10n) {
   "use strict";
 
   var CALL_STATES = loop.store.CALL_STATES;
   var CALL_TYPES = loop.shared.utils.CALL_TYPES;
   var FAILURE_DETAILS = loop.shared.utils.FAILURE_DETAILS;
-  var REST_ERRNOS = loop.shared.utils.REST_ERRNOS;
   var WEBSOCKET_REASONS = loop.shared.utils.WEBSOCKET_REASONS;
   var sharedActions = loop.shared.actions;
   var sharedUtils = loop.shared.utils;
   var sharedViews = loop.shared.views;
   var sharedMixins = loop.shared.mixins;
 
   // This duplicates a similar function in contacts.jsx that isn't used in the
   // conversation window. If we get too many of these, we might want to consider
@@ -476,17 +475,17 @@ loop.conversationViews = (function(mozL1
       }
       return React.createElement("p", {className: "error"}, mozL10n.get("unable_retrieve_url"));
     },
 
     _getTitleMessage: function() {
       switch (this.getStoreState().callStateReason) {
         case WEBSOCKET_REASONS.REJECT:
         case WEBSOCKET_REASONS.BUSY:
-        case REST_ERRNOS.USER_UNAVAILABLE:
+        case FAILURE_DETAILS.USER_UNAVAILABLE:
           var contactDisplayName = _getContactDisplayName(this.props.contact);
           if (contactDisplayName.length) {
             return mozL10n.get(
               "contact_unavailable_title",
               {"contactName": contactDisplayName});
           }
 
           return mozL10n.get("generic_contact_unavailable_title");
--- a/browser/components/loop/content/js/conversationViews.jsx
+++ b/browser/components/loop/content/js/conversationViews.jsx
@@ -4,17 +4,16 @@
 
 var loop = loop || {};
 loop.conversationViews = (function(mozL10n) {
   "use strict";
 
   var CALL_STATES = loop.store.CALL_STATES;
   var CALL_TYPES = loop.shared.utils.CALL_TYPES;
   var FAILURE_DETAILS = loop.shared.utils.FAILURE_DETAILS;
-  var REST_ERRNOS = loop.shared.utils.REST_ERRNOS;
   var WEBSOCKET_REASONS = loop.shared.utils.WEBSOCKET_REASONS;
   var sharedActions = loop.shared.actions;
   var sharedUtils = loop.shared.utils;
   var sharedViews = loop.shared.views;
   var sharedMixins = loop.shared.mixins;
 
   // This duplicates a similar function in contacts.jsx that isn't used in the
   // conversation window. If we get too many of these, we might want to consider
@@ -476,17 +475,17 @@ loop.conversationViews = (function(mozL1
       }
       return <p className="error">{mozL10n.get("unable_retrieve_url")}</p>;
     },
 
     _getTitleMessage: function() {
       switch (this.getStoreState().callStateReason) {
         case WEBSOCKET_REASONS.REJECT:
         case WEBSOCKET_REASONS.BUSY:
-        case REST_ERRNOS.USER_UNAVAILABLE:
+        case FAILURE_DETAILS.USER_UNAVAILABLE:
           var contactDisplayName = _getContactDisplayName(this.props.contact);
           if (contactDisplayName.length) {
             return mozL10n.get(
               "contact_unavailable_title",
               {"contactName": contactDisplayName});
           }
 
           return mozL10n.get("generic_contact_unavailable_title");
--- a/browser/components/loop/content/shared/js/conversationStore.js
+++ b/browser/components/loop/content/shared/js/conversationStore.js
@@ -527,19 +527,19 @@ loop.store = loop.store || {};
       appendContactValues("email");
       appendContactValues("tel", true);
 
       this.client.setupOutgoingCall(contactAddresses,
         this.getStoreState("callType"),
         function(err, result) {
           if (err) {
             console.error("Failed to get outgoing call data", err);
-            var failureReason = "setup";
+            var failureReason = FAILURE_DETAILS.UNKNOWN;
             if (err.errno === REST_ERRNOS.USER_UNAVAILABLE) {
-              failureReason = REST_ERRNOS.USER_UNAVAILABLE;
+              failureReason = FAILURE_DETAILS.USER_UNAVAILABLE;
             }
             this.dispatcher.dispatch(
               new sharedActions.ConnectionFailure({reason: failureReason}));
             return;
           }
 
           // Success, dispatch a new action.
           this.dispatcher.dispatch(
--- a/browser/components/loop/content/shared/js/utils.js
+++ b/browser/components/loop/content/shared/js/utils.js
@@ -71,16 +71,17 @@ var inChrome = typeof Components != "und
     REJECT: "reject",
     TIMEOUT: "timeout"
   };
 
   var FAILURE_DETAILS = {
     MEDIA_DENIED: "reason-media-denied",
     NO_MEDIA: "reason-no-media",
     UNABLE_TO_PUBLISH_MEDIA: "unable-to-publish-media",
+    USER_UNAVAILABLE: "reason-user-unavailable",
     COULD_NOT_CONNECT: "reason-could-not-connect",
     NETWORK_DISCONNECTED: "reason-network-disconnected",
     EXPIRED_OR_INVALID: "reason-expired-or-invalid",
     UNKNOWN: "reason-unknown"
   };
 
   var ROOM_INFO_FAILURES = {
     // There's no data available from the server.
--- a/browser/components/loop/test/desktop-local/conversationViews_test.js
+++ b/browser/components/loop/test/desktop-local/conversationViews_test.js
@@ -436,19 +436,19 @@ describe("loop.conversationViews", funct
         conversationStore.setStoreState({callStateReason: "setup"});
 
         view = mountTestComponent({contact: fakeContact});
 
         sinon.assert.calledWithExactly(document.mozL10n.get,
           "generic_failure_title");
       });
 
-    it("should show 'contact unavailable' when the reason is REST_ERRNOS.USER_UNAVAILABLE",
+    it("should show 'contact unavailable' when the reason is FAILURE_DETAILS.USER_UNAVAILABLE",
       function () {
-        conversationStore.setStoreState({callStateReason: REST_ERRNOS.USER_UNAVAILABLE});
+        conversationStore.setStoreState({callStateReason: FAILURE_DETAILS.USER_UNAVAILABLE});
 
         view = mountTestComponent({contact: fakeContact});
 
         sinon.assert.calledWithExactly(document.mozL10n.get,
           "contact_unavailable_title",
           {contactName: loop.conversationViews
                             ._getContactDisplayName(fakeContact)});
       });
--- a/browser/components/loop/test/shared/conversationStore_test.js
+++ b/browser/components/loop/test/shared/conversationStore_test.js
@@ -4,16 +4,17 @@
 describe("loop.store.ConversationStore", function () {
   "use strict";
 
   var expect = chai.expect;
   var CALL_STATES = loop.store.CALL_STATES;
   var WS_STATES = loop.store.WS_STATES;
   var CALL_TYPES = loop.shared.utils.CALL_TYPES;
   var WEBSOCKET_REASONS = loop.shared.utils.WEBSOCKET_REASONS;
+  var REST_ERRNOS = loop.shared.utils.REST_ERRNOS;
   var FAILURE_DETAILS = loop.shared.utils.FAILURE_DETAILS;
   var sharedActions = loop.shared.actions;
   var sharedUtils = loop.shared.utils;
   var sandbox, dispatcher, client, store, fakeSessionData, sdkDriver;
   var contact, fakeMozLoop, fakeVideoElement;
   var connectPromise, resolveConnectPromise, rejectConnectPromise;
   var wsCancelSpy, wsCloseSpy, wsDeclineSpy, wsMediaUpSpy, fakeWebsocket;
 
@@ -530,17 +531,33 @@ describe("loop.store.ConversationStore",
           store.setupWindowData(
             new sharedActions.SetupWindowData(fakeSetupWindowData));
 
           sinon.assert.calledOnce(dispatcher.dispatch);
           // Can't use instanceof here, as that matches any action
           sinon.assert.calledWithMatch(dispatcher.dispatch,
             sinon.match.hasOwn("name", "connectionFailure"));
           sinon.assert.calledWithMatch(dispatcher.dispatch,
-            sinon.match.hasOwn("reason", "setup"));
+            sinon.match.hasOwn("reason", FAILURE_DETAILS.UNKNOWN));
+        });
+
+        it("should dispatch a connection failure action on failure with user unavailable", function() {
+          client.setupOutgoingCall.callsArgWith(2, {
+            errno: REST_ERRNOS.USER_UNAVAILABLE
+          });
+
+          store.setupWindowData(
+            new sharedActions.SetupWindowData(fakeSetupWindowData));
+
+          sinon.assert.calledOnce(dispatcher.dispatch);
+          // Can't use instanceof here, as that matches any action
+          sinon.assert.calledWithMatch(dispatcher.dispatch,
+            sinon.match.hasOwn("name", "connectionFailure"));
+          sinon.assert.calledWithMatch(dispatcher.dispatch,
+            sinon.match.hasOwn("reason", FAILURE_DETAILS.USER_UNAVAILABLE));
         });
       });
     });
   });
 
   describe("#acceptCall", function() {
     beforeEach(function() {
       store._websocket = {