Bug 781952 - Part 2: Move cluster management out of service.js; r=rnewman
authorGregory Szorc <gps@mozilla.com>
Tue, 14 Aug 2012 11:34:20 -0700
changeset 110903 172d339df58589cb94c456586de9ff5ae72a8c4f
parent 110902 0dfcb4b9a89b6e7ae60744a70d62fb0ebe91bbf5
child 110904 4a0f07b83709a3dded10fe7e0eecc070551411e7
push id23725
push userrnewman@mozilla.com
push dateMon, 22 Oct 2012 19:47:10 +0000
treeherdermozilla-central@acf7f73e8b18 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrnewman
bugs781952
milestone17.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 781952 - Part 2: Move cluster management out of service.js; r=rnewman
services/sync/Makefile.in
services/sync/modules/service.js
services/sync/modules/stages/cluster.js
services/sync/modules/stages/enginesync.js
services/sync/tests/unit/test_service_cluster.js
--- a/services/sync/Makefile.in
+++ b/services/sync/Makefile.in
@@ -52,16 +52,17 @@ sync_engine_modules := \
   forms.js \
   history.js \
   passwords.js \
   prefs.js \
   tabs.js \
   $(NULL)
 
 sync_stage_modules := \
+  cluster.js \
   enginesync.js \
   $(NULL)
 
 DIRS += locales
 TEST_DIRS += tests
 
 EXTRA_COMPONENTS := \
   SyncComponents.manifest \
--- a/services/sync/modules/service.js
+++ b/services/sync/modules/service.js
@@ -29,16 +29,17 @@ Cu.import("resource://services-common/pr
 Cu.import("resource://services-sync/identity.js");
 Cu.import("resource://services-common/log4moz.js");
 Cu.import("resource://services-sync/resource.js");
 Cu.import("resource://services-sync/rest.js");
 Cu.import("resource://services-sync/status.js");
 Cu.import("resource://services-sync/policies.js");
 Cu.import("resource://services-sync/util.js");
 Cu.import("resource://services-sync/main.js");
+Cu.import("resource://services-sync/stages/cluster.js");
 Cu.import("resource://services-sync/stages/enginesync.js");
 
 const STORAGE_INFO_TYPES = [INFO_COLLECTIONS,
                             INFO_COLLECTION_USAGE,
                             INFO_COLLECTION_COUNTS,
                             INFO_QUOTA];
 
 /*
@@ -289,16 +290,18 @@ WeaveSvc.prototype = {
     ErrorHandler.init();
 
     this._log = Log4Moz.repository.getLogger("Sync.Service");
     this._log.level =
       Log4Moz.Level[Svc.Prefs.get("log.logger.service.main")];
 
     this._log.info("Loading Weave " + WEAVE_VERSION);
 
+    this._clusterManager = new ClusterManager(this);
+
     this.enabled = true;
 
     this._registerEngines();
 
     let ua = Cc["@mozilla.org/network/protocol;1?name=http"].
       getService(Ci.nsIHttpProtocolHandler).userAgent;
     this._log.info(ua);
 
@@ -418,79 +421,24 @@ WeaveSvc.prototype = {
       // The enabled status being changed back to what it was before.
       Svc.Prefs.reset("engineStatusChanged." + engine);
     } else {
       // Remember that the engine status changed locally until the next sync.
       Svc.Prefs.set("engineStatusChanged." + engine, true);
     }
   },
 
-  // gets cluster from central LDAP server and returns it, or null on error
-  _findCluster: function _findCluster() {
-    this._log.debug("Finding cluster for user " + this._identity.username);
-
-    let fail;
-    let res = new Resource(this.userAPI + this._identity.username + "/node/weave");
-    try {
-      let node = res.get();
-      switch (node.status) {
-        case 400:
-          Status.login = LOGIN_FAILED_LOGIN_REJECTED;
-          fail = "Find cluster denied: " + ErrorHandler.errorStr(node);
-          break;
-        case 404:
-          this._log.debug("Using serverURL as data cluster (multi-cluster support disabled)");
-          return this.serverURL;
-        case 0:
-        case 200:
-          if (node == "null") {
-            node = null;
-          }
-          this._log.trace("_findCluster successfully returning " + node);
-          return node;
-        default:
-          ErrorHandler.checkServerError(node);
-          fail = "Unexpected response code: " + node.status;
-          break;
-      }
-    } catch (e) {
-      this._log.debug("Network error on findCluster");
-      Status.login = LOGIN_FAILED_NETWORK_ERROR;
-      ErrorHandler.checkServerError(e);
-      fail = e;
-    }
-    throw fail;
-  },
-
-  // gets cluster from central LDAP server and sets this.clusterURL
-  _setCluster: function _setCluster() {
-    // Make sure we didn't get some unexpected response for the cluster
-    let cluster = this._findCluster();
-    this._log.debug("Cluster value = " + cluster);
-    if (cluster == null)
-      return false;
-
-    // Don't update stuff if we already have the right cluster
-    if (cluster == this.clusterURL)
-      return false;
-
-    this._log.debug("Setting cluster to " + cluster);
-    this.clusterURL = cluster;
-    Svc.Prefs.set("lastClusterUpdate", Date.now().toString());
-    return true;
-  },
-
   // Update cluster if required.
   // Returns false if the update was not required.
   _updateCluster: function _updateCluster() {
     this._log.info("Updating cluster.");
     let cTime = Date.now();
     let lastUp = parseFloat(Svc.Prefs.get("lastClusterUpdate"));
     if (!lastUp || ((cTime - lastUp) >= CLUSTER_BACKOFF)) {
-      return this._setCluster();
+      return this._clusterManager.setCluster();
     }
     return false;
   },
 
   /**
    * Perform the info fetch as part of a login or key fetch.
    */
   _fetchInfo: function _fetchInfo(url) {
@@ -650,17 +598,17 @@ WeaveSvc.prototype = {
       Status.login = MASTER_PASSWORD_LOCKED;
       return false;
     }
 
     try {
       // Make sure we have a cluster to verify against.
       // This is a little weird, if we don't get a node we pretend
       // to succeed, since that probably means we just don't have storage.
-      if (this.clusterURL == "" && !this._setCluster()) {
+      if (this.clusterURL == "" && !this._clusterManager.setCluster()) {
         Status.sync = NO_SYNC_NODE_FOUND;
         Svc.Obs.notify("weave:service:sync:delayed");
         return true;
       }
 
       // Fetch collection info on every startup.
       let test = new Resource(this.infoURL).get();
 
@@ -690,17 +638,17 @@ WeaveSvc.prototype = {
           return false;
 
         case 401:
           this._log.warn("401: login failed.");
           // Fall through to the 404 case.
 
         case 404:
           // Check that we're verifying with the correct cluster
-          if (this._setCluster()) {
+          if (this._clusterManager.setCluster()) {
             return this.verifyLogin();
           }
 
           // We must have the right cluster, but the server doesn't expect us
           Status.login = LOGIN_FAILED_LOGIN_REJECTED;
           return false;
 
         default:
new file mode 100644
--- /dev/null
+++ b/services/sync/modules/stages/cluster.js
@@ -0,0 +1,95 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const EXPORTED_SYMBOLS = ["ClusterManager"];
+
+const {utils: Cu} = Components;
+
+Cu.import("resource://services-common/log4moz.js");
+Cu.import("resource://services-sync/constants.js");
+Cu.import("resource://services-sync/policies.js");
+Cu.import("resource://services-sync/resource.js");
+Cu.import("resource://services-sync/status.js");
+Cu.import("resource://services-sync/util.js");
+
+/**
+ * Contains code for managing the Sync cluster we are in.
+ */
+function ClusterManager(service) {
+  this._log = Log4Moz.repository.getLogger("Sync.Service");
+  this._log.level = Log4Moz.Level[Svc.Prefs.get("log.logger.service.main")];
+
+  this.service = service;
+}
+ClusterManager.prototype = {
+  get identity() {
+    return this.service._identity;
+  },
+
+  /**
+   * Obtain the cluster for the current user.
+   *
+   * Returns the string URL of the cluster or null on error.
+   */
+  _findCluster: function _findCluster() {
+    this._log.debug("Finding cluster for user " + this.identity.username);
+
+    let fail;
+    let res = new Resource(this.service.userAPI + this.identity.username +
+                           "/node/weave");
+    try {
+      let node = res.get();
+      switch (node.status) {
+        case 400:
+          Status.login = LOGIN_FAILED_LOGIN_REJECTED;
+          fail = "Find cluster denied: " + ErrorHandler.errorStr(node);
+          break;
+        case 404:
+          this._log.debug("Using serverURL as data cluster (multi-cluster support disabled)");
+          return this.service.serverURL;
+        case 0:
+        case 200:
+          if (node == "null") {
+            node = null;
+          }
+          this._log.trace("_findCluster successfully returning " + node);
+          return node;
+        default:
+          ErrorHandler.checkServerError(node);
+          fail = "Unexpected response code: " + node.status;
+          break;
+      }
+    } catch (e) {
+      this._log.debug("Network error on findCluster");
+      Status.login = LOGIN_FAILED_NETWORK_ERROR;
+      ErrorHandler.checkServerError(e);
+      fail = e;
+    }
+    throw fail;
+  },
+
+  /**
+   * Determine the cluster for the current user and update state.
+   */
+  setCluster: function setCluster() {
+    // Make sure we didn't get some unexpected response for the cluster.
+    let cluster = this._findCluster();
+    this._log.debug("Cluster value = " + cluster);
+    if (cluster == null) {
+      return false;
+    }
+
+    // Don't update stuff if we already have the right cluster
+    if (cluster == this.service.clusterURL) {
+      return false;
+    }
+
+    this._log.debug("Setting cluster to " + cluster);
+    this.service.clusterURL = cluster;
+    Svc.Prefs.set("lastClusterUpdate", Date.now().toString());
+
+    return true;
+  },
+};
+Object.freeze(ClusterManager.prototype);
--- a/services/sync/modules/stages/enginesync.js
+++ b/services/sync/modules/stages/enginesync.js
@@ -54,17 +54,17 @@ EngineSynchronizer.prototype = {
       // this is a purposeful abort rather than a failure, so don't set
       // any status bits
       reason = "Can't sync: " + reason;
       this.onComplete(new Error("Can't sync: " + reason));
       return;
     }
 
     // If we don't have a node, get one. If that fails, retry in 10 minutes.
-    if (this.service.clusterURL == "" && !this.service._setCluster()) {
+    if (!this.service.clusterURL && !this.service._clusterManager.setCluster()) {
       Status.sync = NO_SYNC_NODE_FOUND;
       this._log.info("No cluster URL found. Cannot sync.");
       this.onComplete(null);
       return;
     }
 
     // Ping the server with a special info request once a day.
     let infoURL = this.service.infoURL;
--- a/services/sync/tests/unit/test_service_cluster.js
+++ b/services/sync/tests/unit/test_service_cluster.js
@@ -15,51 +15,51 @@ function test_findCluster() {
   _("Test Service._findCluster()");
   let server;
   try {
     Service.serverURL = TEST_SERVER_URL;
     Identity.account = "johndoe";
 
     _("_findCluster() throws on network errors (e.g. connection refused).");
     do_check_throws(function() {
-      Service._findCluster();
+      Service._clusterManager._findCluster();
     });
 
     server = httpd_setup({
       "/user/1.0/johndoe/node/weave": httpd_handler(200, "OK", "http://weave.user.node/"),
       "/user/1.0/jimdoe/node/weave": httpd_handler(200, "OK", "null"),
       "/user/1.0/janedoe/node/weave": httpd_handler(404, "Not Found", "Not Found"),
       "/user/1.0/juliadoe/node/weave": httpd_handler(400, "Bad Request", "Bad Request"),
       "/user/1.0/joedoe/node/weave": httpd_handler(500, "Server Error", "Server Error")
     });
 
     _("_findCluster() returns the user's cluster node");
-    let cluster = Service._findCluster();
+    let cluster = Service._clusterManager._findCluster();
     do_check_eq(cluster, "http://weave.user.node/");
 
     _("A 'null' response is converted to null.");
     Identity.account = "jimdoe";
-    cluster = Service._findCluster();
+    cluster = Service._clusterManager._findCluster();
     do_check_eq(cluster, null);
 
     _("If a 404 is encountered, the server URL is taken as the cluster URL");
     Identity.account = "janedoe";
-    cluster = Service._findCluster();
+    cluster = Service._clusterManager._findCluster();
     do_check_eq(cluster, Service.serverURL);
 
     _("A 400 response will throw an error.");
     Identity.account = "juliadoe";
     do_check_throws(function() {
-      Service._findCluster();
+      Service._clusterManager._findCluster();
     });
 
     _("Any other server response (e.g. 500) will throw an error.");
     Identity.account = "joedoe";
     do_check_throws(function() {
-      Service._findCluster();
+      Service._clusterManager._findCluster();
     });
 
   } finally {
     Svc.Prefs.resetBranch("");
     if (server) {
       server.stop(runNextTest);
     }
   }
@@ -75,26 +75,26 @@ function test_setCluster() {
   try {
     Service.serverURL = TEST_SERVER_URL;
     Identity.account = "johndoe";
 
     _("Check initial state.");
     do_check_eq(Service.clusterURL, "");
 
     _("Set the cluster URL.");
-    do_check_true(Service._setCluster());
+    do_check_true(Service._clusterManager.setCluster());
     do_check_eq(Service.clusterURL, "http://weave.user.node/");
 
     _("Setting it again won't make a difference if it's the same one.");
-    do_check_false(Service._setCluster());
+    do_check_false(Service._clusterManager.setCluster());
     do_check_eq(Service.clusterURL, "http://weave.user.node/");
 
     _("A 'null' response won't make a difference either.");
     Identity.account = "jimdoe";
-    do_check_false(Service._setCluster());
+    do_check_false(Service._clusterManager.setCluster());
     do_check_eq(Service.clusterURL, "http://weave.user.node/");
 
   } finally {
     Svc.Prefs.resetBranch("");
     server.stop(runNextTest);
   }
 }