Bug 684798 - Part 3: Catch server errors when wiping/disabling engines. r=rnewman
authorPhilipp von Weitershausen <philipp@weitershausen.de>
Wed, 12 Oct 2011 13:55:19 -0700
changeset 79079 f06dfa65c0beca988e13f26644be2aa498446511
parent 79078 c7a5c385d01aa5fd4f38f4f74ecb9acb643bcbbc
child 79080 2c9b36620889ee79db0547b7c4f6ab576ad66138
child 79093 353f5413395827fef072b15e6f30da40bfdeed27
push id247
push usertim.taubert@gmx.de
push dateSat, 22 Oct 2011 19:08:15 +0000
treeherderfx-team@72bb20c484a2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrnewman
bugs684798
milestone10.0a1
Bug 684798 - Part 3: Catch server errors when wiping/disabling engines. r=rnewman
services/sync/modules/engines.js
services/sync/modules/service.js
services/sync/tests/unit/test_service_sync_updateEnabledEngines.js
--- a/services/sync/modules/engines.js
+++ b/services/sync/modules/engines.js
@@ -719,17 +719,17 @@ SyncEngine.prototype = {
       this._log.debug("Engine syncIDs: " + [engineData.syncID, this.syncID]);
       this.syncID = engineData.syncID;
       this._resetClient();
     };
 
     // Delete any existing data and reupload on bad version or missing meta.
     // No crypto component here...? We could regenerate per-collection keys...
     if (needsWipe) {
-      this.wipeServer(true);
+      this.wipeServer();
     }
 
     // Save objects that need to be uploaded in this._modified. We also save
     // the timestamp of this fetch in this.lastSyncLocal. As we successfully
     // upload objects we remove them from this._modified. If an error occurs
     // or any objects fail to upload, they will remain in this._modified. At
     // the end of a sync, or after an error, we add all objects remaining in
     // this._modified to the tracker.
@@ -1243,17 +1243,20 @@ SyncEngine.prototype = {
 
   _resetClient: function SyncEngine__resetClient() {
     this.resetLastSync();
     this.previousFailed = [];
     this.toFetch = [];
   },
 
   wipeServer: function wipeServer() {
-    new Resource(this.engineURL).delete();
+    let response = new Resource(this.engineURL).delete();
+    if (response.status != 200 && response.status != 404) {
+      throw response;
+    }
     this._resetClient();
   },
 
   removeClientData: function removeClientData() {
     // Implement this method in engines that store client specific data
     // on the server.
   },
 
--- a/services/sync/modules/service.js
+++ b/services/sync/modules/service.js
@@ -1367,17 +1367,24 @@ WeaveSvc.prototype = {
         // without commands).
         // Note that we don't abort here; if there's a 401 because we've
         // been reassigned, we'll handle it around another engine.
         this._syncEngine(Clients);
       }
     }
 
     // Update engines because it might change what we sync.
-    this._updateEnabledEngines();
+    try {
+      this._updateEnabledEngines();
+    } catch (ex) {
+      this._log.debug("Updating enabled engines failed: " +
+                      Utils.exceptionStr(ex));
+      ErrorHandler.checkServerError(ex);
+      throw ex;
+    }
 
     try {
       for each (let engine in Engines.getEnabled()) {
         // If there's any problems with syncing the engine, report the failure
         if (!(this._syncEngine(engine)) || Status.enforceBackoff) {
           this._log.info("Aborting sync");
           break;
         }
--- a/services/sync/tests/unit/test_service_sync_updateEnabledEngines.js
+++ b/services/sync/tests/unit/test_service_sync_updateEnabledEngines.js
@@ -1,16 +1,18 @@
 Cu.import("resource://services-sync/engines.js");
 Cu.import("resource://services-sync/engines/clients.js");
 Cu.import("resource://services-sync/util.js");
 Cu.import("resource://services-sync/constants.js");
 Cu.import("resource://services-sync/record.js");
+Cu.import("resource://services-sync/status.js");
 
 Svc.DefaultPrefs.set("registerEngines", "");
 Cu.import("resource://services-sync/service.js");
+Cu.import("resource://services-sync/policies.js");
 
 initTestLogging();
 
 function QuietStore() {
   Store.call("Quiet");
 }
 QuietStore.prototype = {
   getAllIDs: function getAllIDs() {
@@ -79,16 +81,19 @@ function setUp() {
   return serverKeys.upload(Service.cryptoKeysURL).success;
 }
 
 const PAYLOAD = 42;
 
 
 function run_test() {
   initTestLogging("Trace");
+  Log4Moz.repository.getLogger("Sync.Service").level = Log4Moz.Level.Trace;
+  Log4Moz.repository.getLogger("Sync.ErrorHandler").level = Log4Moz.Level.Trace;
+
   run_next_test();
 }
 
 add_test(function test_newAccount() {
   _("Test: New account does not disable locally enabled engines.");
   let engine = Engines.get("steam");
   let server = sync_httpd_setup({
     "/1.1/johndoe/storage/meta/global": new ServerWBO("global", {}).handler(),
@@ -181,16 +186,60 @@ add_test(function test_disabledLocally()
     _("Engine continues to be disabled.");
     do_check_false(engine.enabled);
   } finally {
     Service.startOver();
     server.stop(run_next_test);
   }
 });
 
+add_test(function test_disabledLocally_wipe503() {
+  _("Test: Engine is enabled on remote clients and disabled locally");
+  Service.syncID = "abcdefghij";
+  let engine = Engines.get("steam");
+  let metaWBO = new ServerWBO("global", {
+    syncID: Service.syncID,
+    storageVersion: STORAGE_VERSION,
+    engines: {steam: {syncID: engine.syncID,
+                      version: engine.version}}
+  });
+  let steamCollection = new ServerWBO("steam", PAYLOAD);
+
+  function service_unavailable(request, response) {
+    let body = "Service Unavailable";
+    response.setStatusLine(request.httpVersion, 503, "Service Unavailable");
+    response.setHeader("Retry-After", "23");
+    response.bodyOutputStream.write(body, body.length);
+  }
+
+  let server = sync_httpd_setup({
+    "/1.1/johndoe/storage/meta/global": metaWBO.handler(),
+    "/1.1/johndoe/storage/steam": service_unavailable
+  });
+  setUp();
+
+  _("Disable engine locally.");
+  Service._ignorePrefObserver = true;
+  engine.enabled = true;
+  Service._ignorePrefObserver = false;
+  engine.enabled = false;
+
+  Svc.Obs.add("weave:ui:sync:error", function onSyncError() {
+    Svc.Obs.remove("weave:ui:sync:error", onSyncError);
+
+    do_check_eq(Status.sync, SERVER_MAINTENANCE);
+
+    Service.startOver();
+    server.stop(run_next_test);
+  });
+
+  _("Sync.");
+  ErrorHandler.syncAndReportErrors();
+});
+
 add_test(function test_enabledRemotely() {
   _("Test: Engine is disabled locally and enabled on a remote client");
   Service.syncID = "abcdefghij";
   let engine = Engines.get("steam");
   let metaWBO = new ServerWBO("global", {
     syncID: Service.syncID,
     storageVersion: STORAGE_VERSION,
     engines: {steam: {syncID: engine.syncID,