Bug 1137469 - If an uncaught exception occurs whilst processing an action, the dispatcher can fail, rendering parts of Loop inactive. r=mikedeboer, a=sledru
authorMark Banner <standard8@mozilla.com>
Fri, 27 Feb 2015 10:51:14 +0000
changeset 245433 63286f849ae3
parent 245432 5717cc7f29c7
child 245434 2f2a515eeae0
push id670
push userryanvm@gmail.com
push date2015-02-27 18:07 +0000
treeherdermozilla-release@63286f849ae3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmikedeboer, sledru
bugs1137469
milestone36.0
Bug 1137469 - If an uncaught exception occurs whilst processing an action, the dispatcher can fail, rendering parts of Loop inactive. r=mikedeboer, a=sledru
browser/components/loop/content/shared/js/dispatcher.js
browser/components/loop/test/shared/dispatcher_test.js
--- a/browser/components/loop/content/shared/js/dispatcher.js
+++ b/browser/components/loop/content/shared/js/dispatcher.js
@@ -67,17 +67,21 @@ loop.Dispatcher = (function() {
 
       this._active = true;
 
       if (this._debug) {
         console.log("[Dispatcher] Dispatching action", action);
       }
 
       registeredStores.forEach(function(store) {
-        store[type](action);
+        try {
+          store[type](action);
+        } catch (x) {
+          console.error("[Dispatcher] Dispatching action caused an exception: ", x);
+        }
       });
 
       this._active = false;
       this._dispatchNextAction();
     }
   };
 
   return Dispatcher;
--- a/browser/components/loop/test/shared/dispatcher_test.js
+++ b/browser/components/loop/test/shared/dispatcher_test.js
@@ -99,16 +99,41 @@ describe("loop.Dispatcher", function () 
       dispatcher.dispatch(cancelAction);
       dispatcher.dispatch(getDataAction);
 
       sinon.assert.calledOnce(cancelStore1.cancelCall);
       sinon.assert.calledOnce(getDataStore1.getWindowData);
       sinon.assert.calledOnce(getDataStore2.getWindowData);
     });
 
+    describe("Error handling", function() {
+      beforeEach(function() {
+        sandbox.stub(console, "error");
+      });
+
+      it("should handle uncaught exceptions", function() {
+        getDataStore1.getWindowData.throws("Uncaught Error");
+
+        dispatcher.dispatch(getDataAction);
+        dispatcher.dispatch(cancelAction);
+
+        sinon.assert.calledOnce(getDataStore1.getWindowData);
+        sinon.assert.calledOnce(getDataStore2.getWindowData);
+        sinon.assert.calledOnce(cancelStore1.cancelCall);
+      });
+
+      it("should log uncaught exceptions", function() {
+        getDataStore1.getWindowData.throws("Uncaught Error");
+
+        dispatcher.dispatch(getDataAction);
+
+        sinon.assert.calledOnce(console.error);
+      });
+    });
+
     describe("Queued actions", function() {
       beforeEach(function() {
         // Restore the stub, so that we can easily add a function to be
         // returned. Unfortunately, sinon doesn't make this easy.
         sandbox.stub(connectStore1, "connectCall", function() {
           dispatcher.dispatch(getDataAction);
 
           sinon.assert.notCalled(getDataStore1.getWindowData);