Bug 785225 - Part 8: Don't expose SyncScheduler as a singleton; r=rnewman
authorGregory Szorc <gps@mozilla.com>
Wed, 29 Aug 2012 14:43:41 -0700
changeset 111055 6d61599eebd30b5e55a1fc60b893b52a9eb8edc4
parent 111054 1c1410d01ab985a12edf62a8e533c935b1ea55f4
child 111056 9eeef1bbadeeee885c858bd56f46ac285a6cb250
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersrnewman
bugs785225
milestone18.0a1
Bug 785225 - Part 8: Don't expose SyncScheduler as a singleton; r=rnewman
browser/base/content/sync/addDevice.js
browser/base/content/sync/genericChange.js
browser/components/nsBrowserGlue.js
services/sync/modules/main.js
services/sync/modules/policies.js
services/sync/modules/service.js
services/sync/modules/stages/enginesync.js
services/sync/tests/unit/test_interval_triggers.js
services/sync/tests/unit/test_node_reassignment.js
services/sync/tests/unit/test_score_triggers.js
services/sync/tests/unit/test_sendcredentials_controller.js
services/sync/tests/unit/test_service_login.js
services/sync/tests/unit/test_service_startOver.js
services/sync/tests/unit/test_service_sync_401.js
services/sync/tests/unit/test_service_sync_updateEnabledEngines.js
services/sync/tests/unit/test_syncengine_sync.js
services/sync/tests/unit/test_syncscheduler.js
--- a/browser/base/content/sync/addDevice.js
+++ b/browser/base/content/sync/addDevice.js
@@ -26,17 +26,17 @@ let gSyncAddDevice = {
                         pin2: this.pin3,
                         pin3: this.wizard.getButton("next")};
 
     this.throbber = document.getElementById("pairDeviceThrobber");
     this.errorRow = document.getElementById("errorRow");
 
     // Kick off a sync. That way the server will have the most recent data from
     // this computer and it will show up immediately on the new device.
-    Weave.SyncScheduler.scheduleNextSync(0);
+    Weave.Service.scheduler.scheduleNextSync(0);
   },
 
   onPageShow: function onPageShow() {
     this.wizard.getButton("back").hidden = true;
 
     switch (this.wizard.pageIndex) {
       case ADD_DEVICE_PAGE:
         this.onTextBoxInput();
@@ -87,17 +87,17 @@ let gSyncAddDevice = {
         jpakeclient.sendAndComplete(credentials);
       },
       onComplete: function onComplete() {
         delete self._jpakeclient;
         self.wizard.pageIndex = DEVICE_CONNECTED_PAGE;
 
         // Schedule a Sync for soonish to fetch the data uploaded by the
         // device with which we just paired.
-        Weave.SyncScheduler.scheduleNextSync(Weave.SyncScheduler.activeInterval);
+        Weave.Service.scheduler.scheduleNextSync(Weave.Service.scheduler.activeInterval);
       },
       onAbort: function onAbort(error) {
         delete self._jpakeclient;
 
         // Aborted by user, ignore.
         if (error == JPAKE_ERROR_USERABORT) {
           return;
         }
--- a/browser/base/content/sync/genericChange.js
+++ b/browser/base/content/sync/genericChange.js
@@ -157,17 +157,17 @@ let Change = {
 
   doChangePassphrase: function Change_doChangePassphrase() {
     let pp = Weave.Utils.normalizePassphrase(this._passphraseBox.value);
     if (this._updatingPassphrase) {
       Weave.Identity.syncKey = pp;
       if (Weave.Service.login()) {
         this._updateStatus("change.recoverykey.success", "success");
         Weave.Service.persistLogin();
-        Weave.SyncScheduler.delayedAutoConnect(0);
+        Weave.Service.scheduler.delayedAutoConnect(0);
       }
       else {
         this._updateStatus("new.passphrase.status.incorrect", "error");
       }
     }
     else {
       this._updateStatus("change.recoverykey.label", "active");
 
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -127,17 +127,17 @@ BrowserGlue.prototype = {
     let delay = 3;
     let browserEnum = Services.wm.getEnumerator("navigator:browser");
     while (browserEnum.hasMoreElements()) {
       delay += browserEnum.getNext().gBrowser.tabs.length;
     }
     delay = delay <= MAX_DELAY ? delay : MAX_DELAY;
 
     Cu.import("resource://services-sync/main.js");
-    Weave.SyncScheduler.delayedAutoConnect(delay);
+    Weave.Service.scheduler.delayedAutoConnect(delay);
   },
 #endif
 
   // nsIObserver implementation 
   observe: function BG_observe(subject, topic, data) {
     switch (topic) {
       case "xpcom-shutdown":
         this._dispose();
--- a/services/sync/modules/main.js
+++ b/services/sync/modules/main.js
@@ -5,17 +5,16 @@
 const EXPORTED_SYMBOLS = ['Weave'];
 
 let Weave = {};
 Components.utils.import("resource://services-sync/constants.js", Weave);
 let lazies = {
   "identity.js":          ["Identity"],
   "jpakeclient.js":       ["JPAKEClient", "SendCredentialsController"],
   "notifications.js":     ["Notifications", "Notification", "NotificationButton"],
-  "policies.js":          ["SyncScheduler"],
   "service.js":           ["Service"],
   "status.js":            ["Status"],
   "util.js":              ['Utils', 'Svc']
 };
 
 function lazyImport(module, dest, props) {
   function getter(prop) function() {
     let ns = {};
--- a/services/sync/modules/policies.js
+++ b/services/sync/modules/policies.js
@@ -4,26 +4,28 @@
 
 const EXPORTED_SYMBOLS = [
   "ErrorHandler",
   "SyncScheduler",
 ];
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
+Cu.import("resource://services-common/log4moz.js");
 Cu.import("resource://services-sync/constants.js");
-Cu.import("resource://services-common/log4moz.js");
-Cu.import("resource://services-sync/util.js");
 Cu.import("resource://services-sync/engines.js");
 Cu.import("resource://services-sync/engines/clients.js");
 Cu.import("resource://services-sync/status.js");
+Cu.import("resource://services-sync/util.js");
 
-Cu.import("resource://services-sync/main.js");    // So we can get to Service for callbacks.
-
-let SyncScheduler = {
+function SyncScheduler(service) {
+  this.service = service;
+  this.init();
+}
+SyncScheduler.prototype = {
   _log: Log4Moz.repository.getLogger("Sync.SyncScheduler"),
 
   _fatalLoginStatus: [LOGIN_FAILED_NO_USERNAME,
                       LOGIN_FAILED_NO_PASSWORD,
                       LOGIN_FAILED_NO_PASSPHRASE,
                       LOGIN_FAILED_INVALID_PASSPHRASE,
                       LOGIN_FAILED_LOGIN_REJECTED],
 
@@ -193,17 +195,17 @@ let SyncScheduler = {
           this.hasIncomingItems = true;
         }
         break;
       case "weave:service:setup-complete":
          Services.prefs.savePrefFile(null);
          Svc.Idle.addIdleObserver(this, Svc.Prefs.get("scheduler.idleTime"));
          break;
       case "weave:service:start-over":
-         SyncScheduler.setDefaults();
+         this.setDefaults();
          try {
            Svc.Idle.removeIdleObserver(this, Svc.Prefs.get("scheduler.idleTime"));
          } catch (ex if (ex.result == Cr.NS_ERROR_FAILURE)) {
            // In all likelihood we didn't have an idle observer registered yet.
            // It's all good.
          }
          break;
       case "idle":
@@ -294,17 +296,17 @@ let SyncScheduler = {
 
   /**
    * Check if we should be syncing and schedule the next sync, if it's not scheduled
    */
   checkSyncStatus: function checkSyncStatus() {
     // Should we be syncing now, if not, cancel any sync timers and return
     // if we're in backoff, we'll schedule the next sync.
     let ignore = [kSyncBackoffNotMet, kSyncMasterPasswordLocked];
-    let skip = Weave.Service._checkSync(ignore);
+    let skip = this.service._checkSync(ignore);
     this._log.trace("_checkSync returned \"" + skip + "\".");
     if (skip) {
       this.clearSyncTriggers();
       return;
     }
 
     // Only set the wait time to 0 if we need to sync right away
     let wait;
@@ -327,32 +329,32 @@ let SyncScheduler = {
       this._log.debug("Not initiating sync: Login status is " + Status.login);
 
       // If we're not syncing now, we need to schedule the next one.
       this._log.trace("Scheduling a sync at MASTER_PASSWORD_LOCKED_RETRY_INTERVAL");
       this.scheduleAtInterval(MASTER_PASSWORD_LOCKED_RETRY_INTERVAL);
       return;
     }
 
-    Utils.nextTick(Weave.Service.sync, Weave.Service);
+    Utils.nextTick(this.service.sync, this.service);
   },
 
   /**
    * Set a timer for the next sync
    */
   scheduleNextSync: function scheduleNextSync(interval) {
     // If no interval was specified, use the current sync interval.
     if (interval == null) {
       interval = this.syncInterval;
     }
 
     // Ensure the interval is set to no less than the backoff.
     if (Status.backoffInterval && interval < Status.backoffInterval) {
       this._log.trace("Requested interval " + interval +
-                      " ms is smaller than the backoff interval. " + 
+                      " ms is smaller than the backoff interval. " +
                       "Using backoff interval " +
                       Status.backoffInterval + " ms instead.");
       interval = Status.backoffInterval;
     }
 
     if (this.nextSync != 0) {
       // There's already a sync scheduled. Don't reschedule if there's already
       // a timer scheduled for sooner than requested.
@@ -402,23 +404,23 @@ let SyncScheduler = {
   * Automatically start syncing after the given delay (in seconds).
   *
   * Applications can define the `services.sync.autoconnectDelay` preference
   * to have this called automatically during start-up with the pref value as
   * the argument. Alternatively, they can call it themselves to control when
   * Sync should first start to sync.
   */
   delayedAutoConnect: function delayedAutoConnect(delay) {
-    if (Weave.Service._checkSetup() == STATUS_OK) {
+    if (this.service._checkSetup() == STATUS_OK) {
       Utils.namedTimer(this.autoConnect, delay * 1000, this, "_autoTimer");
     }
   },
 
   autoConnect: function autoConnect() {
-    if (Weave.Service._checkSetup() == STATUS_OK && !Weave.Service._checkSync()) {
+    if (this.service._checkSetup() == STATUS_OK && !this.service._checkSync()) {
       // Schedule a sync based on when a previous sync was scheduled.
       // scheduleNextSync() will do the right thing if that time lies in
       // the past.
       this.scheduleNextSync(this.nextSync - Date.now());
     }
 
     // Once autoConnect is called we no longer need _autoTimer.
     if (this._autoTimer) {
@@ -455,24 +457,24 @@ let SyncScheduler = {
    */
   clearSyncTriggers: function clearSyncTriggers() {
     this._log.debug("Clearing sync triggers and the global score.");
     this.globalScore = this.nextSync = 0;
 
     // Clear out any scheduled syncs
     if (this.syncTimer)
       this.syncTimer.clear();
-  }
-
+  },
 };
 
 const LOG_PREFIX_SUCCESS = "success-";
 const LOG_PREFIX_ERROR   = "error-";
 
-function ErrorHandler() {
+function ErrorHandler(service) {
+  this.service = service;
   this.init();
 }
 ErrorHandler.prototype = {
 
   /**
    * Flag that turns on error reporting for all errors, incl. network errors.
    */
   dontIgnoreErrors: false,
@@ -539,17 +541,17 @@ ErrorHandler.prototype = {
         } else {
           this.notifyOnNextTick("weave:ui:clear-error");
         }
 
         this.dontIgnoreErrors = false;
         break;
       case "weave:service:sync:error":
         if (Status.sync == CREDENTIALS_CHANGED) {
-          Weave.Service.logout();
+          this.service.logout();
         }
 
         this.resetFileLog(Svc.Prefs.get("log.appender.file.logOnError"),
                           LOG_PREFIX_ERROR);
 
         if (this.shouldReportError()) {
           this.notifyOnNextTick("weave:ui:sync:error");
         } else {
@@ -603,17 +605,17 @@ ErrorHandler.prototype = {
 
   /**
    * Trigger a sync and don't muffle any errors, particularly network errors.
    */
   syncAndReportErrors: function syncAndReportErrors() {
     this._log.debug("Beginning user-triggered sync.");
 
     this.dontIgnoreErrors = true;
-    Utils.nextTick(Weave.Service.sync, Weave.Service);
+    Utils.nextTick(this.service.sync, this.service);
   },
 
   /**
    * Finds all logs older than maxErrorAge and deletes them without tying up I/O.
    */
   cleanupLogs: function cleanupLogs() {
     let direntries = FileUtils.getDir("ProfD", ["weave", "logs"]).directoryEntries;
     let oldLogs = [];
@@ -729,21 +731,21 @@ ErrorHandler.prototype = {
 
     let lastSync = Svc.Prefs.get("lastSync");
     if (lastSync && ((Date.now() - Date.parse(lastSync)) >
         Svc.Prefs.get("errorhandler.networkFailureReportTimeout") * 1000)) {
       Status.sync = PROLONGED_SYNC_FAILURE;
       this._log.trace("shouldReportError: true (prolonged sync failure).");
       return true;
     }
- 
+
     // We got a 401 mid-sync. Wait for the next sync before actually handling
     // an error. This assumes that we'll get a 401 again on a login fetch in
     // order to report the error.
-    if (!Weave.Service.clusterURL) {
+    if (!this.service.clusterURL) {
       this._log.trace("shouldReportError: false (no cluster URL; " +
                       "possible node reassignment).");
       return false;
     }
 
     return ([Status.login, Status.sync].indexOf(SERVER_MAINTENANCE) == -1 &&
             [Status.login, Status.sync].indexOf(LOGIN_FAILED_NETWORK_ERROR) == -1);
   },
@@ -756,17 +758,17 @@ ErrorHandler.prototype = {
     switch (resp.status) {
       case 400:
         if (resp == RESPONSE_OVER_QUOTA) {
           Status.sync = OVER_QUOTA;
         }
         break;
 
       case 401:
-        Weave.Service.logout();
+        this.service.logout();
         this._log.info("Got 401 response; resetting clusterURL.");
         Svc.Prefs.reset("clusterURL");
 
         let delay = 0;
         if (Svc.Prefs.get("lastSyncReassigned")) {
           // We got a 401 in the middle of the previous sync, and we just got
           // another. Login must have succeeded in order for us to get here, so
           // the password should be correct.
@@ -774,26 +776,26 @@ ErrorHandler.prototype = {
           // give it time to recover.
           this._log.warn("Last sync also failed for 401. Delaying next sync.");
           delay = MINIMUM_BACKOFF_INTERVAL;
         } else {
           this._log.debug("New mid-sync 401 failure. Making a note.");
           Svc.Prefs.set("lastSyncReassigned", true);
         }
         this._log.info("Attempting to schedule another sync.");
-        SyncScheduler.scheduleNextSync(delay);
+        this.service.scheduler.scheduleNextSync(delay);
         break;
 
       case 500:
       case 502:
       case 503:
       case 504:
         Status.enforceBackoff = true;
         if (resp.status == 503 && resp.headers["retry-after"]) {
-          if (Weave.Service.isLoggedIn) {
+          if (this.service.isLoggedIn) {
             Status.sync = SERVER_MAINTENANCE;
           } else {
             Status.login = SERVER_MAINTENANCE;
           }
           Svc.Obs.notify("weave:service:backoff:interval",
                          parseInt(resp.headers["retry-after"], 10));
         }
         break;
@@ -803,17 +805,17 @@ ErrorHandler.prototype = {
       case Cr.NS_ERROR_UNKNOWN_HOST:
       case Cr.NS_ERROR_CONNECTION_REFUSED:
       case Cr.NS_ERROR_NET_TIMEOUT:
       case Cr.NS_ERROR_NET_RESET:
       case Cr.NS_ERROR_NET_INTERRUPT:
       case Cr.NS_ERROR_PROXY_CONNECTION_REFUSED:
         // The constant says it's about login, but in fact it just
         // indicates general network error.
-        if (Weave.Service.isLoggedIn) {
+        if (this.service.isLoggedIn) {
           Status.sync = LOGIN_FAILED_NETWORK_ERROR;
         } else {
           Status.login = LOGIN_FAILED_NETWORK_ERROR;
         }
         break;
     }
   },
 };
--- a/services/sync/modules/service.js
+++ b/services/sync/modules/service.js
@@ -53,16 +53,22 @@ const STORAGE_INFO_TYPES = [INFO_COLLECT
                             INFO_COLLECTION_USAGE,
                             INFO_COLLECTION_COUNTS,
                             INFO_QUOTA];
 
 /*
  * Service singleton
  * Main entry point into Weave's sync framework
  */
+XPCOMUtils.defineLazyGetter(this, "Service", function onService() {
+  let service = new WeaveSvc();
+  service.onStartup();
+
+  return service;
+});
 
 function WeaveSvc() {
   this._notify = Utils.notify("weave:service:");
 }
 WeaveSvc.prototype = {
 
   _lock: Utils.lock,
   _locked: false,
@@ -308,17 +314,17 @@ WeaveSvc.prototype = {
   },
 
   /**
    * Prepare to initialize the rest of Weave after waiting a little bit
    */
   onStartup: function onStartup() {
     this._migratePrefs();
 
-    this.errorHandler = new ErrorHandler();
+    this.errorHandler = new ErrorHandler(this);
 
     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);
@@ -335,18 +341,17 @@ WeaveSvc.prototype = {
       this.enabled = false;
       this._log.info("Could not load the Weave crypto component. Disabling " +
                       "Weave, since it will not work correctly.");
     }
 
     Svc.Obs.add("weave:service:setup-complete", this);
     Svc.Prefs.observe("engine.", this);
 
-    this.scheduler = SyncScheduler;
-    this.scheduler.init();
+    this.scheduler = new SyncScheduler(this);
 
     if (!this.enabled) {
       this._log.info("Firefox Sync disabled.");
     }
 
     this._updateCachedURLs();
 
     let status = this._checkSetup();
@@ -1446,15 +1451,10 @@ WeaveSvc.prototype = {
       } catch (ex) {
         this._log.debug("Server returned invalid JSON for '" + info_type +
                         "': " + this.response.body);
         return callback(ex);
       }
       this._log.trace("Successfully retrieved '" + info_type + "'.");
       return callback(null, result);
     });
-  }
-
+  },
 };
-
-// Load Weave on the first time this file is loaded
-let Service = new WeaveSvc();
-Service.onStartup();
--- a/services/sync/modules/stages/enginesync.js
+++ b/services/sync/modules/stages/enginesync.js
@@ -204,25 +204,26 @@ EngineSynchronizer.prototype = {
         return false;
       }
     }
 
     return true;
   },
 
   _updateEnabledEngines: function _updateEnabledEngines() {
-    this._log.info("Updating enabled engines: " + SyncScheduler.numClients + " clients.");
+    this._log.info("Updating enabled engines: " +
+                   this.service.scheduler.numClients + " clients.");
     let meta = Records.get(this.service.metaURL);
     if (meta.isNew || !meta.payload.engines)
       return;
 
     // If we're the only client, and no engines are marked as enabled,
     // thumb our noses at the server data: it can't be right.
     // Belt-and-suspenders approach to Bug 615926.
-    if ((SyncScheduler.numClients <= 1) &&
+    if ((this.service.scheduler.numClients <= 1) &&
         ([e for (e in meta.payload.engines) if (e != "clients")].length == 0)) {
       this._log.info("One client and no enabled engines: not touching local engine status.");
       return;
     }
 
     this.service._ignorePrefObserver = true;
 
     let enabled = this.service.enabledEngineNames;
--- a/services/sync/tests/unit/test_interval_triggers.js
+++ b/services/sync/tests/unit/test_interval_triggers.js
@@ -1,19 +1,20 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 Cu.import("resource://services-sync/engines.js");
 Cu.import("resource://services-sync/engines/clients.js");
 Cu.import("resource://services-sync/constants.js");
-Cu.import("resource://services-sync/policies.js");
 
 Svc.DefaultPrefs.set("registerEngines", "");
 Cu.import("resource://services-sync/service.js");
 
+let scheduler = Service.scheduler;
+
 function sync_httpd_setup() {
   let global = new ServerWBO("global", {
     syncID: Service.syncID,
     storageVersion: STORAGE_VERSION,
     engines: {clients: {version: Clients.version,
                         syncID: Clients.syncID}}
   });
   let clientsColl = new ServerCollection({}, true);
@@ -59,235 +60,235 @@ add_test(function test_successful_sync_a
     syncSuccesses++;
   };
   Svc.Obs.add("weave:service:sync:finish", onSyncFinish);
 
   let server = sync_httpd_setup();
   setUp();
 
   // Confirm defaults
-  do_check_false(SyncScheduler.idle);
-  do_check_false(SyncScheduler.numClients > 1);
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
-  do_check_false(SyncScheduler.hasIncomingItems);
+  do_check_false(scheduler.idle);
+  do_check_false(scheduler.numClients > 1);
+  do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
+  do_check_false(scheduler.hasIncomingItems);
 
-  _("Test as long as numClients <= 1 our sync interval is SINGLE_USER."); 
+  _("Test as long as numClients <= 1 our sync interval is SINGLE_USER.");
   // idle == true && numClients <= 1 && hasIncomingItems == false
-  SyncScheduler.idle = true;
+  scheduler.idle = true;
   Service.sync();
   do_check_eq(syncSuccesses, 1);
-  do_check_true(SyncScheduler.idle);
-  do_check_false(SyncScheduler.numClients > 1);
-  do_check_false(SyncScheduler.hasIncomingItems);
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
-  
+  do_check_true(scheduler.idle);
+  do_check_false(scheduler.numClients > 1);
+  do_check_false(scheduler.hasIncomingItems);
+  do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
+
   // idle == false && numClients <= 1 && hasIncomingItems == false
-  SyncScheduler.idle = false;
+  scheduler.idle = false;
   Service.sync();
   do_check_eq(syncSuccesses, 2);
-  do_check_false(SyncScheduler.idle);
-  do_check_false(SyncScheduler.numClients > 1);
-  do_check_false(SyncScheduler.hasIncomingItems);
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
+  do_check_false(scheduler.idle);
+  do_check_false(scheduler.numClients > 1);
+  do_check_false(scheduler.hasIncomingItems);
+  do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
 
   // idle == false && numClients <= 1 && hasIncomingItems == true
-  SyncScheduler.hasIncomingItems = true;
+  scheduler.hasIncomingItems = true;
   Service.sync();
   do_check_eq(syncSuccesses, 3);
-  do_check_false(SyncScheduler.idle);
-  do_check_false(SyncScheduler.numClients > 1);
-  do_check_true(SyncScheduler.hasIncomingItems);
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
+  do_check_false(scheduler.idle);
+  do_check_false(scheduler.numClients > 1);
+  do_check_true(scheduler.hasIncomingItems);
+  do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
 
   // idle == true && numClients <= 1 && hasIncomingItems == true
-  SyncScheduler.idle = true;
+  scheduler.idle = true;
   Service.sync();
   do_check_eq(syncSuccesses, 4);
-  do_check_true(SyncScheduler.idle);
-  do_check_false(SyncScheduler.numClients > 1);
-  do_check_true(SyncScheduler.hasIncomingItems);
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
+  do_check_true(scheduler.idle);
+  do_check_false(scheduler.numClients > 1);
+  do_check_true(scheduler.hasIncomingItems);
+  do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
 
   _("Test as long as idle && numClients > 1 our sync interval is idleInterval.");
   // idle == true && numClients > 1 && hasIncomingItems == true
   Clients._store.create({id: "foo", cleartext: "bar"});
   Service.sync();
   do_check_eq(syncSuccesses, 5);
-  do_check_true(SyncScheduler.idle);
-  do_check_true(SyncScheduler.numClients > 1);
-  do_check_true(SyncScheduler.hasIncomingItems);
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.idleInterval);
+  do_check_true(scheduler.idle);
+  do_check_true(scheduler.numClients > 1);
+  do_check_true(scheduler.hasIncomingItems);
+  do_check_eq(scheduler.syncInterval, scheduler.idleInterval);
 
   // idle == true && numClients > 1 && hasIncomingItems == false
-  SyncScheduler.hasIncomingItems = false;
+  scheduler.hasIncomingItems = false;
   Service.sync();
   do_check_eq(syncSuccesses, 6);
-  do_check_true(SyncScheduler.idle);
-  do_check_true(SyncScheduler.numClients > 1);
-  do_check_false(SyncScheduler.hasIncomingItems);
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.idleInterval);
+  do_check_true(scheduler.idle);
+  do_check_true(scheduler.numClients > 1);
+  do_check_false(scheduler.hasIncomingItems);
+  do_check_eq(scheduler.syncInterval, scheduler.idleInterval);
 
   _("Test non-idle, numClients > 1, no incoming items => activeInterval.");
   // idle == false && numClients > 1 && hasIncomingItems == false
-  SyncScheduler.idle = false;
+  scheduler.idle = false;
   Service.sync();
   do_check_eq(syncSuccesses, 7);
-  do_check_false(SyncScheduler.idle);
-  do_check_true(SyncScheduler.numClients > 1);
-  do_check_false(SyncScheduler.hasIncomingItems);
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.activeInterval);
-  
+  do_check_false(scheduler.idle);
+  do_check_true(scheduler.numClients > 1);
+  do_check_false(scheduler.hasIncomingItems);
+  do_check_eq(scheduler.syncInterval, scheduler.activeInterval);
+
   _("Test non-idle, numClients > 1, incoming items => immediateInterval.");
   // idle == false && numClients > 1 && hasIncomingItems == true
-  SyncScheduler.hasIncomingItems = true;
+  scheduler.hasIncomingItems = true;
   Service.sync();
   do_check_eq(syncSuccesses, 8);
-  do_check_false(SyncScheduler.idle);
-  do_check_true(SyncScheduler.numClients > 1);
-  do_check_false(SyncScheduler.hasIncomingItems); //gets reset to false
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.immediateInterval);
+  do_check_false(scheduler.idle);
+  do_check_true(scheduler.numClients > 1);
+  do_check_false(scheduler.hasIncomingItems); //gets reset to false
+  do_check_eq(scheduler.syncInterval, scheduler.immediateInterval);
 
   Svc.Obs.remove("weave:service:sync:finish", onSyncFinish);
   Service.startOver();
   server.stop(run_next_test);
 });
 
 add_test(function test_unsuccessful_sync_adjustSyncInterval() {
   _("Test unsuccessful sync calling adjustSyncInterval");
 
   let syncFailures = 0;
   function onSyncError() {
     _("Sync error.");
     syncFailures++;
   }
   Svc.Obs.add("weave:service:sync:error", onSyncError);
-    
+
   _("Test unsuccessful sync calls adjustSyncInterval");
   // Force sync to fail.
   Svc.Prefs.set("firstSync", "notReady");
-  
+
   let server = sync_httpd_setup();
   setUp();
 
   // Confirm defaults
-  do_check_false(SyncScheduler.idle);
-  do_check_false(SyncScheduler.numClients > 1);
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
-  do_check_false(SyncScheduler.hasIncomingItems);
+  do_check_false(scheduler.idle);
+  do_check_false(scheduler.numClients > 1);
+  do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
+  do_check_false(scheduler.hasIncomingItems);
 
-  _("Test as long as numClients <= 1 our sync interval is SINGLE_USER."); 
+  _("Test as long as numClients <= 1 our sync interval is SINGLE_USER.");
   // idle == true && numClients <= 1 && hasIncomingItems == false
-  SyncScheduler.idle = true;
+  scheduler.idle = true;
   Service.sync();
   do_check_eq(syncFailures, 1);
-  do_check_true(SyncScheduler.idle);
-  do_check_false(SyncScheduler.numClients > 1);
-  do_check_false(SyncScheduler.hasIncomingItems);
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
-  
+  do_check_true(scheduler.idle);
+  do_check_false(scheduler.numClients > 1);
+  do_check_false(scheduler.hasIncomingItems);
+  do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
+
   // idle == false && numClients <= 1 && hasIncomingItems == false
-  SyncScheduler.idle = false;
+  scheduler.idle = false;
   Service.sync();
   do_check_eq(syncFailures, 2);
-  do_check_false(SyncScheduler.idle);
-  do_check_false(SyncScheduler.numClients > 1);
-  do_check_false(SyncScheduler.hasIncomingItems);
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
+  do_check_false(scheduler.idle);
+  do_check_false(scheduler.numClients > 1);
+  do_check_false(scheduler.hasIncomingItems);
+  do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
 
   // idle == false && numClients <= 1 && hasIncomingItems == true
-  SyncScheduler.hasIncomingItems = true;
+  scheduler.hasIncomingItems = true;
   Service.sync();
   do_check_eq(syncFailures, 3);
-  do_check_false(SyncScheduler.idle);
-  do_check_false(SyncScheduler.numClients > 1);
-  do_check_true(SyncScheduler.hasIncomingItems);
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
+  do_check_false(scheduler.idle);
+  do_check_false(scheduler.numClients > 1);
+  do_check_true(scheduler.hasIncomingItems);
+  do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
 
   // idle == true && numClients <= 1 && hasIncomingItems == true
-  SyncScheduler.idle = true;
+  scheduler.idle = true;
   Service.sync();
   do_check_eq(syncFailures, 4);
-  do_check_true(SyncScheduler.idle);
-  do_check_false(SyncScheduler.numClients > 1);
-  do_check_true(SyncScheduler.hasIncomingItems);
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
-  
+  do_check_true(scheduler.idle);
+  do_check_false(scheduler.numClients > 1);
+  do_check_true(scheduler.hasIncomingItems);
+  do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
+
   _("Test as long as idle && numClients > 1 our sync interval is idleInterval.");
   // idle == true && numClients > 1 && hasIncomingItems == true
   Clients._store.create({id: "foo", cleartext: "bar"});
 
   Service.sync();
   do_check_eq(syncFailures, 5);
-  do_check_true(SyncScheduler.idle);
-  do_check_true(SyncScheduler.numClients > 1);
-  do_check_true(SyncScheduler.hasIncomingItems);
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.idleInterval);
+  do_check_true(scheduler.idle);
+  do_check_true(scheduler.numClients > 1);
+  do_check_true(scheduler.hasIncomingItems);
+  do_check_eq(scheduler.syncInterval, scheduler.idleInterval);
 
   // idle == true && numClients > 1 && hasIncomingItems == false
-  SyncScheduler.hasIncomingItems = false;
+  scheduler.hasIncomingItems = false;
   Service.sync();
   do_check_eq(syncFailures, 6);
-  do_check_true(SyncScheduler.idle);
-  do_check_true(SyncScheduler.numClients > 1);
-  do_check_false(SyncScheduler.hasIncomingItems);
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.idleInterval);
+  do_check_true(scheduler.idle);
+  do_check_true(scheduler.numClients > 1);
+  do_check_false(scheduler.hasIncomingItems);
+  do_check_eq(scheduler.syncInterval, scheduler.idleInterval);
 
   _("Test non-idle, numClients > 1, no incoming items => activeInterval.");
   // idle == false && numClients > 1 && hasIncomingItems == false
-  SyncScheduler.idle = false;
+  scheduler.idle = false;
   Service.sync();
   do_check_eq(syncFailures, 7);
-  do_check_false(SyncScheduler.idle);
-  do_check_true(SyncScheduler.numClients > 1);
-  do_check_false(SyncScheduler.hasIncomingItems);
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.activeInterval);
-  
+  do_check_false(scheduler.idle);
+  do_check_true(scheduler.numClients > 1);
+  do_check_false(scheduler.hasIncomingItems);
+  do_check_eq(scheduler.syncInterval, scheduler.activeInterval);
+
   _("Test non-idle, numClients > 1, incoming items => immediateInterval.");
   // idle == false && numClients > 1 && hasIncomingItems == true
-  SyncScheduler.hasIncomingItems = true;
+  scheduler.hasIncomingItems = true;
   Service.sync();
   do_check_eq(syncFailures, 8);
-  do_check_false(SyncScheduler.idle);
-  do_check_true(SyncScheduler.numClients > 1);
-  do_check_false(SyncScheduler.hasIncomingItems); //gets reset to false
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.immediateInterval);
+  do_check_false(scheduler.idle);
+  do_check_true(scheduler.numClients > 1);
+  do_check_false(scheduler.hasIncomingItems); //gets reset to false
+  do_check_eq(scheduler.syncInterval, scheduler.immediateInterval);
 
   Service.startOver();
   Svc.Obs.remove("weave:service:sync:error", onSyncError);
   server.stop(run_next_test);
 });
 
 add_test(function test_back_triggers_sync() {
   let server = sync_httpd_setup();
   setUp();
 
   // Single device: no sync triggered.
-  SyncScheduler.idle = true;
-  SyncScheduler.observe(null, "back", Svc.Prefs.get("scheduler.idleTime"));
-  do_check_false(SyncScheduler.idle);
+  scheduler.idle = true;
+  scheduler.observe(null, "back", Svc.Prefs.get("scheduler.idleTime"));
+  do_check_false(scheduler.idle);
 
   // Multiple devices: sync is triggered.
   Clients._store.create({id: "foo", cleartext: "bar"});
-  SyncScheduler.updateClientMode();
+  scheduler.updateClientMode();
 
   Svc.Obs.add("weave:service:sync:finish", function onSyncFinish() {
     Svc.Obs.remove("weave:service:sync:finish", onSyncFinish);
 
     Records.clearCache();
     Svc.Prefs.resetBranch("");
-    SyncScheduler.setDefaults();
+    scheduler.setDefaults();
     Clients.resetClient();
 
     Service.startOver();
     server.stop(run_next_test);
   });
 
-  SyncScheduler.idle = true;
-  SyncScheduler.observe(null, "back", Svc.Prefs.get("scheduler.idleTime"));
-  do_check_false(SyncScheduler.idle);
+  scheduler.idle = true;
+  scheduler.observe(null, "back", Svc.Prefs.get("scheduler.idleTime"));
+  do_check_false(scheduler.idle);
 });
 
 add_test(function test_adjust_interval_on_sync_error() {
   let server = sync_httpd_setup();
   setUp();
 
   let syncFailures = 0;
   function onSyncError() {
@@ -296,137 +297,137 @@ add_test(function test_adjust_interval_o
   }
   Svc.Obs.add("weave:service:sync:error", onSyncError);
 
   _("Test unsuccessful sync updates client mode & sync intervals");
   // Force a sync fail.
   Svc.Prefs.set("firstSync", "notReady");
 
   do_check_eq(syncFailures, 0);
-  do_check_false(SyncScheduler.numClients > 1);
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
+  do_check_false(scheduler.numClients > 1);
+  do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
 
   Clients._store.create({id: "foo", cleartext: "bar"});
   Service.sync();
 
   do_check_eq(syncFailures, 1);
-  do_check_true(SyncScheduler.numClients > 1);
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.activeInterval);
+  do_check_true(scheduler.numClients > 1);
+  do_check_eq(scheduler.syncInterval, scheduler.activeInterval);
 
   Svc.Obs.remove("weave:service:sync:error", onSyncError);
   Service.startOver();
   server.stop(run_next_test);
 });
 
 add_test(function test_bug671378_scenario() {
   // Test scenario similar to bug 671378. This bug appeared when a score
-  // update occurred that wasn't large enough to trigger a sync so 
+  // update occurred that wasn't large enough to trigger a sync so
   // scheduleNextSync() was called without a time interval parameter,
   // setting nextSync to a non-zero value and preventing the timer from
   // being adjusted in the next call to scheduleNextSync().
   let server = sync_httpd_setup();
   setUp();
 
   let syncSuccesses = 0;
   function onSyncFinish() {
     _("Sync success.");
     syncSuccesses++;
   };
   Svc.Obs.add("weave:service:sync:finish", onSyncFinish);
 
   // After first sync call, syncInterval & syncTimer are singleDeviceInterval.
   Service.sync();
   do_check_eq(syncSuccesses, 1);
-  do_check_false(SyncScheduler.numClients > 1);
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
-  do_check_eq(SyncScheduler.syncTimer.delay, SyncScheduler.singleDeviceInterval);
+  do_check_false(scheduler.numClients > 1);
+  do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
+  do_check_eq(scheduler.syncTimer.delay, scheduler.singleDeviceInterval);
 
   // Wrap scheduleNextSync so we are notified when it is finished.
-  SyncScheduler._scheduleNextSync = SyncScheduler.scheduleNextSync;
-  SyncScheduler.scheduleNextSync = function() {
-    SyncScheduler._scheduleNextSync();
+  scheduler._scheduleNextSync = scheduler.scheduleNextSync;
+  scheduler.scheduleNextSync = function() {
+    scheduler._scheduleNextSync();
 
     // Check on sync:finish scheduleNextSync sets the appropriate
     // syncInterval and syncTimer values.
     if (syncSuccesses == 2) {
-      do_check_neq(SyncScheduler.nextSync, 0);
-      do_check_eq(SyncScheduler.syncInterval, SyncScheduler.activeInterval);
-      do_check_true(SyncScheduler.syncTimer.delay <= SyncScheduler.activeInterval);
- 
-      SyncScheduler.scheduleNextSync = SyncScheduler._scheduleNextSync;
+      do_check_neq(scheduler.nextSync, 0);
+      do_check_eq(scheduler.syncInterval, scheduler.activeInterval);
+      do_check_true(scheduler.syncTimer.delay <= scheduler.activeInterval);
+
+      scheduler.scheduleNextSync = scheduler._scheduleNextSync;
       Svc.Obs.remove("weave:service:sync:finish", onSyncFinish);
       Service.startOver();
       server.stop(run_next_test);
     }
   };
-  
-  // Set nextSync != 0 
+
+  // Set nextSync != 0
   // syncInterval still hasn't been set by call to updateClientMode.
-  // Explicitly trying to invoke scheduleNextSync during a sync 
+  // Explicitly trying to invoke scheduleNextSync during a sync
   // (to immitate a score update that isn't big enough to trigger a sync).
   Svc.Obs.add("weave:service:sync:start", function onSyncStart() {
-    // Wait for other sync:start observers to be called so that 
+    // Wait for other sync:start observers to be called so that
     // nextSync is set to 0.
     Utils.nextTick(function() {
       Svc.Obs.remove("weave:service:sync:start", onSyncStart);
 
-      SyncScheduler.scheduleNextSync();
-      do_check_neq(SyncScheduler.nextSync, 0);
-      do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
-      do_check_eq(SyncScheduler.syncTimer.delay, SyncScheduler.singleDeviceInterval);
+      scheduler.scheduleNextSync();
+      do_check_neq(scheduler.nextSync, 0);
+      do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
+      do_check_eq(scheduler.syncTimer.delay, scheduler.singleDeviceInterval);
     });
   });
 
   Clients._store.create({id: "foo", cleartext: "bar"});
   Service.sync();
 });
 
 add_test(function test_adjust_timer_larger_syncInterval() {
   _("Test syncInterval > current timout period && nextSync != 0, syncInterval is NOT used.");
   Clients._store.create({id: "foo", cleartext: "bar"});
-  SyncScheduler.updateClientMode();
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.activeInterval);
+  scheduler.updateClientMode();
+  do_check_eq(scheduler.syncInterval, scheduler.activeInterval);
 
-  SyncScheduler.scheduleNextSync();
+  scheduler.scheduleNextSync();
 
   // Ensure we have a small interval.
-  do_check_neq(SyncScheduler.nextSync, 0);
-  do_check_eq(SyncScheduler.syncTimer.delay, SyncScheduler.activeInterval);
+  do_check_neq(scheduler.nextSync, 0);
+  do_check_eq(scheduler.syncTimer.delay, scheduler.activeInterval);
 
   // Make interval large again
   Clients._wipeClient();
-  SyncScheduler.updateClientMode();
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
+  scheduler.updateClientMode();
+  do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
 
-  SyncScheduler.scheduleNextSync();
+  scheduler.scheduleNextSync();
 
   // Ensure timer delay remains as the small interval.
-  do_check_neq(SyncScheduler.nextSync, 0);
-  do_check_true(SyncScheduler.syncTimer.delay <= SyncScheduler.activeInterval);
+  do_check_neq(scheduler.nextSync, 0);
+  do_check_true(scheduler.syncTimer.delay <= scheduler.activeInterval);
 
   //SyncSchedule.
   Service.startOver();
   run_next_test();
 });
 
 add_test(function test_adjust_timer_smaller_syncInterval() {
   _("Test current timout > syncInterval period && nextSync != 0, syncInterval is used.");
-  SyncScheduler.scheduleNextSync();
+  scheduler.scheduleNextSync();
 
   // Ensure we have a large interval.
-  do_check_neq(SyncScheduler.nextSync, 0);
-  do_check_eq(SyncScheduler.syncTimer.delay, SyncScheduler.singleDeviceInterval);
+  do_check_neq(scheduler.nextSync, 0);
+  do_check_eq(scheduler.syncTimer.delay, scheduler.singleDeviceInterval);
 
   // Make interval smaller
   Clients._store.create({id: "foo", cleartext: "bar"});
-  SyncScheduler.updateClientMode();
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.activeInterval);
+  scheduler.updateClientMode();
+  do_check_eq(scheduler.syncInterval, scheduler.activeInterval);
 
-  SyncScheduler.scheduleNextSync();
+  scheduler.scheduleNextSync();
 
   // Ensure smaller timer delay is used.
-  do_check_neq(SyncScheduler.nextSync, 0);
-  do_check_true(SyncScheduler.syncTimer.delay <= SyncScheduler.activeInterval);
+  do_check_neq(scheduler.nextSync, 0);
+  do_check_true(scheduler.syncTimer.delay <= scheduler.activeInterval);
 
   //SyncSchedule.
   Service.startOver();
   run_next_test();
 });
--- a/services/sync/tests/unit/test_node_reassignment.js
+++ b/services/sync/tests/unit/test_node_reassignment.js
@@ -4,17 +4,16 @@
 _("Test that node reassignment responses are respected on all kinds of " +
   "requests.");
 
 // Don't sync any engines by default.
 Svc.DefaultPrefs.set("registerEngines", "")
 
 Cu.import("resource://services-common/rest.js");
 Cu.import("resource://services-sync/constants.js");
-Cu.import("resource://services-sync/policies.js");
 Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/status.js");
 Cu.import("resource://services-common/log4moz.js");
 
 function run_test() {
   Log4Moz.repository.getLogger("Sync.AsyncResource").level = Log4Moz.Level.Trace;
   Log4Moz.repository.getLogger("Sync.ErrorHandler").level  = Log4Moz.Level.Trace;
   Log4Moz.repository.getLogger("Sync.Resource").level      = Log4Moz.Level.Trace;
@@ -124,17 +123,17 @@ function syncAndExpectNodeReassignment(s
       });
 
       // Allow for tests to clean up error conditions.
       between();
     }
     function onSecondSync() {
       _("Second sync completed.");
       Svc.Obs.remove(secondNotification, onSecondSync);
-      SyncScheduler.clearSyncTriggers();
+      Service.scheduler.clearSyncTriggers();
 
       // Make absolutely sure that any event listeners are done with their work
       // before we proceed.
       waitForZeroTimer(function () {
         _("Second sync nextTick.");
         do_check_true(nodeFetched);
         Service.startOver();
         server.stop(run_next_test);
@@ -306,34 +305,34 @@ add_test(function test_loop_avoidance_st
 
     // This pref will be true until a sync completes successfully.
     do_check_true(getReassigned());
 
     // The timer will be set for some distant time.
     // We store nextSync in prefs, which offers us only limited resolution.
     // Include that logic here.
     let expectedNextSync = 1000 * Math.floor((now + MINIMUM_BACKOFF_INTERVAL) / 1000);
-    _("Next sync scheduled for " + SyncScheduler.nextSync);
+    _("Next sync scheduled for " + Service.scheduler.nextSync);
     _("Expected to be slightly greater than " + expectedNextSync);
 
-    do_check_true(SyncScheduler.nextSync >= expectedNextSync);
-    do_check_true(!!SyncScheduler.syncTimer);
+    do_check_true(Service.scheduler.nextSync >= expectedNextSync);
+    do_check_true(!!Service.scheduler.syncTimer);
 
     // Undo our evil scheme.
     server.toplevelHandlers.storage = oldHandler;
 
     // Bring the timer forward to kick off a successful sync, so we can watch
     // the pref get cleared.
-    SyncScheduler.scheduleNextSync(0);
+    Service.scheduler.scheduleNextSync(0);
   }
   function onThirdSync() {
     Svc.Obs.remove(thirdNotification, onThirdSync);
 
     // That'll do for now; no more syncs.
-    SyncScheduler.clearSyncTriggers();
+    Service.scheduler.clearSyncTriggers();
 
     // Make absolutely sure that any event listeners are done with their work
     // before we proceed.
     waitForZeroTimer(function () {
       _("Third sync nextTick.");
       do_check_false(getReassigned());
       do_check_true(nodeFetched);
       Service.startOver();
@@ -443,35 +442,35 @@ add_test(function test_loop_avoidance_en
 
     // This pref will be true until a sync completes successfully.
     do_check_true(getReassigned());
 
     // The timer will be set for some distant time.
     // We store nextSync in prefs, which offers us only limited resolution.
     // Include that logic here.
     let expectedNextSync = 1000 * Math.floor((now + MINIMUM_BACKOFF_INTERVAL) / 1000);
-    _("Next sync scheduled for " + SyncScheduler.nextSync);
+    _("Next sync scheduled for " + Service.scheduler.nextSync);
     _("Expected to be slightly greater than " + expectedNextSync);
 
-    do_check_true(SyncScheduler.nextSync >= expectedNextSync);
-    do_check_true(!!SyncScheduler.syncTimer);
+    do_check_true(Service.scheduler.nextSync >= expectedNextSync);
+    do_check_true(!!Service.scheduler.syncTimer);
 
     // Undo our evil scheme.
     beforeSuccessfulSync();
 
     // Bring the timer forward to kick off a successful sync, so we can watch
     // the pref get cleared.
-    SyncScheduler.scheduleNextSync(0);
+    Service.scheduler.scheduleNextSync(0);
   }
 
   function onThirdSync() {
     Svc.Obs.remove(thirdNotification, onThirdSync);
 
     // That'll do for now; no more syncs.
-    SyncScheduler.clearSyncTriggers();
+    Service.scheduler.clearSyncTriggers();
 
     // Make absolutely sure that any event listeners are done with their work
     // before we proceed.
     waitForZeroTimer(function () {
       _("Third sync nextTick.");
       do_check_false(getReassigned());
       do_check_true(nodeFetched);
       afterSuccessfulSync();
--- a/services/sync/tests/unit/test_score_triggers.js
+++ b/services/sync/tests/unit/test_score_triggers.js
@@ -1,15 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 Cu.import("resource://services-sync/engines.js");
 Cu.import("resource://services-sync/engines/clients.js");
 Cu.import("resource://services-sync/constants.js");
-Cu.import("resource://services-sync/policies.js");
 Cu.import("resource://services-sync/status.js");
 
 Svc.DefaultPrefs.set("registerEngines", "");
 Cu.import("resource://services-sync/service.js");
 
 Engines.register(RotaryEngine);
 let engine = Engines.get("rotary");
 let tracker = engine._tracker;
@@ -78,17 +77,17 @@ add_test(function test_tracker_score_upd
 });
 
 add_test(function test_sync_triggered() {
   let server = sync_httpd_setup();
   setUp();
 
   Service.login();
 
-  SyncScheduler.syncThreshold = MULTI_DEVICE_THRESHOLD;
+  Service.scheduler.syncThreshold = MULTI_DEVICE_THRESHOLD;
   Svc.Obs.add("weave:service:sync:finish", function onSyncFinish() {
     Svc.Obs.remove("weave:service:sync:finish", onSyncFinish);
     _("Sync completed!");
     server.stop(run_next_test);
   });
 
   do_check_eq(Status.login, LOGIN_SUCCEEDED);
   tracker.score += SCORE_INCREMENT_XLARGE;
@@ -107,17 +106,17 @@ add_test(function test_clients_engine_sy
 
   const TOPIC = "weave:service:sync:finish";
   Svc.Obs.add(TOPIC, function onSyncFinish() {
     Svc.Obs.remove(TOPIC, onSyncFinish);
     _("Sync due to clients engine change completed.");
     server.stop(run_next_test);
   });
 
-  SyncScheduler.syncThreshold = MULTI_DEVICE_THRESHOLD;
+  Service.scheduler.syncThreshold = MULTI_DEVICE_THRESHOLD;
   do_check_eq(Status.login, LOGIN_SUCCEEDED);
   Clients._tracker.score += SCORE_INCREMENT_XLARGE;
 });
 
 add_test(function test_incorrect_credentials_sync_not_triggered() {
   _("Ensure that score changes don't trigger a sync if Status.login != LOGIN_SUCCEEDED.");
   let server = sync_httpd_setup();
   setUp();
--- a/services/sync/tests/unit/test_sendcredentials_controller.js
+++ b/services/sync/tests/unit/test_sendcredentials_controller.js
@@ -1,13 +1,12 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 Cu.import("resource://services-sync/constants.js");
-Cu.import("resource://services-sync/policies.js");
 Cu.import("resource://services-sync/jpakeclient.js");
 Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/util.js");
 
 function run_test() {
   setBasicCredentials("johndoe", "ilovejane", Utils.generatePassphrase());
   Service.serverURL  = "http://weave.server/";
 
@@ -32,24 +31,24 @@ function make_sendCredentials_test(topic
         // Verify it sends the correct data.
         do_check_eq(data.account,   Identity.account);
         do_check_eq(data.password,  Identity.basicPassword);
         do_check_eq(data.synckey,   Identity.syncKey);
         do_check_eq(data.serverURL, Service.serverURL);
 
         this.controller.onComplete();
         // Verify it schedules a sync for the expected interval.
-        let expectedInterval = SyncScheduler.activeInterval;
-        do_check_true(SyncScheduler.nextSync - Date.now() <= expectedInterval);
+        let expectedInterval = Service.scheduler.activeInterval;
+        do_check_true(Service.scheduler.nextSync - Date.now() <= expectedInterval);
 
         // Signal the end of another sync. We shouldn't be registered anymore,
         // so we shouldn't re-enter this method (cf sendAndCompleteCalled above)
         Svc.Obs.notify(topic);
 
-        SyncScheduler.setDefaults();
+        Service.scheduler.setDefaults();
         Utils.nextTick(run_next_test);
       }
     };
     jpakeclient.controller = new SendCredentialsController(jpakeclient, Service);
     Svc.Obs.notify(topic);
   };
 }
 
--- a/services/sync/tests/unit/test_service_login.js
+++ b/services/sync/tests/unit/test_service_login.js
@@ -154,19 +154,19 @@ add_test(function test_login_on_sync() {
 
     // Stub mpLocked.
     let mpLockedF = Utils.mpLocked;
     let mpLocked = true;
     Utils.mpLocked = function() mpLocked;
 
     // Stub scheduleNextSync. This gets called within checkSyncStatus if we're
     // ready to sync, so use it as an indicator.
-    let scheduleNextSyncF = SyncScheduler.scheduleNextSync;
+    let scheduleNextSyncF = Service.scheduler.scheduleNextSync;
     let scheduleCalled = false;
-    SyncScheduler.scheduleNextSync = function(wait) {
+    Service.scheduler.scheduleNextSync = function(wait) {
       scheduleCalled = true;
       scheduleNextSyncF.call(this, wait);
     };
 
     // Autoconnect still tries to connect in the background (useful behavior:
     // for non-MP users and unlocked MPs, this will detect version expiry
     // earlier).
     //
@@ -176,47 +176,47 @@ add_test(function test_login_on_sync() {
     // This process doesn't apply if your MP is still locked, so we make
     // checkSyncStatus accept a locked MP in place of being logged in.
     //
     // This test exercises these two branches.
 
     _("We're ready to sync if locked.");
     Service.enabled = true;
     Services.io.offline = false;
-    SyncScheduler.checkSyncStatus();
+    Service.scheduler.checkSyncStatus();
     do_check_true(scheduleCalled);
 
     _("... and also if we're not locked.");
     scheduleCalled = false;
     mpLocked = false;
-    SyncScheduler.checkSyncStatus();
+    Service.scheduler.checkSyncStatus();
     do_check_true(scheduleCalled);
-    SyncScheduler.scheduleNextSync = scheduleNextSyncF;
+    Service.scheduler.scheduleNextSync = scheduleNextSyncF;
 
     // TODO: need better tests around master password prompting. See Bug 620583.
 
     mpLocked = true;
 
     // Testing exception handling if master password dialog is canceled.
     // Do this by monkeypatching.
     let oldGetter = Identity.__lookupGetter__("syncKey");
     let oldSetter = Identity.__lookupSetter__("syncKey");
     _("Old passphrase function is " + oldGetter);
     Identity.__defineGetter__("syncKey",
                            function() {
                              throw "User canceled Master Password entry";
                            });
 
-    let oldClearSyncTriggers = SyncScheduler.clearSyncTriggers;
+    let oldClearSyncTriggers = Service.scheduler.clearSyncTriggers;
     let oldLockedSync = Service._lockedSync;
 
     let cSTCalled = false;
     let lockedSyncCalled = false;
 
-    SyncScheduler.clearSyncTriggers = function() { cSTCalled = true; };
+    Service.scheduler.clearSyncTriggers = function() { cSTCalled = true; };
     Service._lockedSync = function() { lockedSyncCalled = true; };
 
     _("If master password is canceled, login fails and we report lockage.");
     do_check_false(!!Service.login());
     do_check_eq(Status.login, MASTER_PASSWORD_LOCKED);
     do_check_eq(Status.service, LOGIN_FAILED);
     _("Locked? " + Utils.mpLocked());
     _("checkSync reports the correct term.");
--- a/services/sync/tests/unit/test_service_startOver.js
+++ b/services/sync/tests/unit/test_service_startOver.js
@@ -1,15 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 Cu.import("resource://services-sync/engines.js");
 Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/status.js");
-Cu.import("resource://services-sync/policies.js");
 Cu.import("resource://services-sync/constants.js");
 Cu.import("resource://services-sync/util.js");
 
 function BlaEngine() {
   SyncEngine.call(this, "Bla");
 }
 BlaEngine.prototype = {
   __proto__: SyncEngine.prototype,
@@ -80,26 +79,26 @@ add_test(function test_removeClientData(
   Service.startOver();
   do_check_true(engine.removed);
 
   run_next_test();
 });
 
 add_test(function test_reset_SyncScheduler() {
   // Some non-default values for SyncScheduler's attributes.
-  SyncScheduler.idle = true;
-  SyncScheduler.hasIncomingItems = true;
-  SyncScheduler.numClients = 42;
-  SyncScheduler.nextSync = Date.now();
-  SyncScheduler.syncThreshold = MULTI_DEVICE_THRESHOLD;
-  SyncScheduler.syncInterval = SyncScheduler.activeInterval;
+  Service.scheduler.idle = true;
+  Service.scheduler.hasIncomingItems = true;
+  Service.scheduler.numClients = 42;
+  Service.scheduler.nextSync = Date.now();
+  Service.scheduler.syncThreshold = MULTI_DEVICE_THRESHOLD;
+  Service.scheduler.syncInterval = Service.scheduler.activeInterval;
 
   Service.startOver();
 
-  do_check_false(SyncScheduler.idle);
-  do_check_false(SyncScheduler.hasIncomingItems);
-  do_check_eq(SyncScheduler.numClients, 0);
-  do_check_eq(SyncScheduler.nextSync, 0);
-  do_check_eq(SyncScheduler.syncThreshold, SINGLE_USER_THRESHOLD);
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
+  do_check_false(Service.scheduler.idle);
+  do_check_false(Service.scheduler.hasIncomingItems);
+  do_check_eq(Service.scheduler.numClients, 0);
+  do_check_eq(Service.scheduler.nextSync, 0);
+  do_check_eq(Service.scheduler.syncThreshold, SINGLE_USER_THRESHOLD);
+  do_check_eq(Service.scheduler.syncInterval, Service.scheduler.singleDeviceInterval);
 
   run_next_test();
 });
--- a/services/sync/tests/unit/test_service_sync_401.js
+++ b/services/sync/tests/unit/test_service_sync_401.js
@@ -1,10 +1,14 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
 Cu.import("resource://services-sync/main.js");
 Cu.import("resource://services-sync/policies.js");
+Cu.import("resource://services-sync/service.js");
 
 function login_handling(handler) {
   return function (request, response) {
     if (basic_auth_matches(request, "johndoe", "ilovejane")) {
       handler(request, response);
     } else {
       let body = "Unauthorized";
       response.setStatusLine(request.httpVersion, 401, "Unauthorized");
@@ -28,17 +32,17 @@ function run_test() {
     "/1.1/johndoe/info/collections":    login_handling(collectionsHelper.handler)
   });
 
   const GLOBAL_SCORE = 42;
 
   try {
     _("Set up test fixtures.");
     new SyncTestingInfrastructure("johndoe", "ilovejane", "foo");
-    SyncScheduler.globalScore = GLOBAL_SCORE;
+    Service.scheduler.globalScore = GLOBAL_SCORE;
     // Avoid daily ping
     Weave.Svc.Prefs.set("lastPing", Math.floor(Date.now() / 1000));
 
     let threw = false;
     Weave.Svc.Obs.add("weave:service:sync:error", function (subject, data) {
       threw = true;
     });
 
@@ -46,28 +50,28 @@ function run_test() {
     Weave.Service.login();
     do_check_true(Weave.Service.isLoggedIn);
     do_check_eq(Weave.Status.login, Weave.LOGIN_SUCCEEDED);
 
     _("Simulate having changed the password somewhere else.");
     Identity.basicPassword = "ilovejosephine";
 
     _("Let's try to sync.");
-    Weave.Service.sync();
+    Service.sync();
 
     _("Verify that sync() threw an exception.");
     do_check_true(threw);
 
     _("We're no longer logged in.");
     do_check_false(Weave.Service.isLoggedIn);
 
     _("Sync status won't have changed yet, because we haven't tried again.");
 
     _("globalScore is reset upon starting a sync.");
-    do_check_eq(SyncScheduler.globalScore, 0);
+    do_check_eq(Service.scheduler.globalScore, 0);
 
     _("Our next sync will fail appropriately.");
     try {
       Weave.Service.sync();
     } catch (ex) {
     }
     do_check_eq(Weave.Status.login, Weave.LOGIN_FAILED_LOGIN_REJECTED);
 
--- a/services/sync/tests/unit/test_service_sync_updateEnabledEngines.js
+++ b/services/sync/tests/unit/test_service_sync_updateEnabledEngines.js
@@ -1,18 +1,20 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+Cu.import("resource://services-sync/constants.js");
 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");
+Cu.import("resource://services-sync/util.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() {
@@ -22,17 +24,17 @@ QuietStore.prototype = {
 
 function SteamEngine() {
   SyncEngine.call(this, "Steam");
 }
 SteamEngine.prototype = {
   __proto__: SyncEngine.prototype,
   // We're not interested in engine sync but what the service does.
   _storeObj: QuietStore,
-  
+
   _sync: function _sync() {
     this._syncStartup();
   }
 };
 Engines.register(SteamEngine);
 
 function StirlingEngine() {
   SyncEngine.call(this, "Stirling");
@@ -44,29 +46,29 @@ StirlingEngine.prototype = {
 };
 Engines.register(StirlingEngine);
 
 // Tracking info/collections.
 let collectionsHelper = track_collections_helper();
 let upd = collectionsHelper.with_updated_collection;
 
 function sync_httpd_setup(handlers) {
-    
+
   handlers["/1.1/johndoe/info/collections"] = collectionsHelper.handler;
   delete collectionsHelper.collections.crypto;
   delete collectionsHelper.collections.meta;
-  
+
   let cr = new ServerWBO("keys");
   handlers["/1.1/johndoe/storage/crypto/keys"] =
     upd("crypto", cr.handler());
-  
+
   let cl = new ServerCollection();
   handlers["/1.1/johndoe/storage/clients"] =
     upd("clients", cl.handler());
-  
+
   return httpd_setup(handlers);
 }
 
 function setUp() {
   new SyncTestingInfrastructure("johndoe", "ilovejane",
                                 "abcdeabcdeabcdeabcdeabcdea");
   // Ensure that the server has valid keys so that logging in will work and not
   // result in a server wipe, rendering many of these tests useless.
@@ -98,17 +100,17 @@ add_test(function test_newAccount() {
 
   try {
     _("Engine is enabled from the beginning.");
     Service._ignorePrefObserver = true;
     engine.enabled = true;
     Service._ignorePrefObserver = false;
 
     _("Sync.");
-    Weave.Service.sync();
+    Service.sync();
 
     _("Engine continues to be enabled.");
     do_check_true(engine.enabled);
   } finally {
     Service.startOver();
     server.stop(run_next_test);
   }
 });
@@ -126,17 +128,17 @@ add_test(function test_enabledLocally() 
   });
   setUp();
 
   try {
     _("Enable engine locally.");
     engine.enabled = true;
 
     _("Sync.");
-    Weave.Service.sync();
+    Service.sync();
 
     _("Meta record now contains the new engine.");
     do_check_true(!!metaWBO.data.engines.steam);
 
     _("Engine continues to be enabled.");
     do_check_true(engine.enabled);
   } finally {
     Service.startOver();
@@ -165,17 +167,17 @@ add_test(function test_disabledLocally()
   try {
     _("Disable engine locally.");
     Service._ignorePrefObserver = true;
     engine.enabled = true;
     Service._ignorePrefObserver = false;
     engine.enabled = false;
 
     _("Sync.");
-    Weave.Service.sync();
+    Service.sync();
 
     _("Meta record no longer contains engine.");
     do_check_false(!!metaWBO.data.engines.steam);
 
     _("Server records are wiped.");
     do_check_eq(steamCollection.payload, undefined);
 
     _("Engine continues to be disabled.");
@@ -238,17 +240,17 @@ add_test(function test_enabledRemotely()
     syncID: Service.syncID,
     storageVersion: STORAGE_VERSION,
     engines: {steam: {syncID: engine.syncID,
                       version: engine.version}}
   });
   let server = sync_httpd_setup({
     "/1.1/johndoe/storage/meta/global":
     upd("meta", metaWBO.handler()),
-      
+
     "/1.1/johndoe/storage/steam":
     upd("steam", new ServerWBO("steam", {}).handler())
   });
   setUp();
 
   // We need to be very careful how we do this, so that we don't trigger a
   // fresh start!
   try {
@@ -256,17 +258,17 @@ add_test(function test_enabledRemotely()
     let wbo = CollectionKeys.generateNewKeysWBO();
     wbo.encrypt(Identity.syncKeyBundle);
     do_check_eq(200, wbo.upload(Service.cryptoKeysURL).status);
 
     _("Engine is disabled.");
     do_check_false(engine.enabled);
 
     _("Sync.");
-    Weave.Service.sync();
+    Service.sync();
 
     _("Engine is enabled.");
     do_check_true(engine.enabled);
 
     _("Meta record still present.");
     do_check_eq(metaWBO.data.engines.steam.syncID, engine.syncID);
   } finally {
     Service.startOver();
@@ -279,44 +281,44 @@ add_test(function test_disabledRemotelyT
   Service.syncID = "abcdefghij";
   let engine = Engines.get("steam");
   let metaWBO = new ServerWBO("global", {syncID: Service.syncID,
                                          storageVersion: STORAGE_VERSION,
                                          engines: {}});
   let server = sync_httpd_setup({
     "/1.1/johndoe/storage/meta/global":
     upd("meta", metaWBO.handler()),
-      
+
     "/1.1/johndoe/storage/steam":
     upd("steam", new ServerWBO("steam", {}).handler())
   });
   setUp();
 
   try {
     _("Enable engine locally.");
     Service._ignorePrefObserver = true;
     engine.enabled = true;
     Service._ignorePrefObserver = false;
 
     _("Sync.");
-    Weave.Service.sync();
+    Service.sync();
 
     _("Disable engine by deleting from meta/global.");
-    let d = metaWBO.data; 
+    let d = metaWBO.data;
     delete d.engines["steam"];
     metaWBO.payload = JSON.stringify(d);
     metaWBO.modified = Date.now() / 1000;
-    
+
     _("Add a second client and verify that the local pref is changed.");
     Clients._store._remoteClients["foobar"] = {name: "foobar", type: "desktop"};
-    Weave.Service.sync();
-    
+    Service.sync();
+
     _("Engine is disabled.");
     do_check_false(engine.enabled);
-    
+
   } finally {
     Service.startOver();
     server.stop(run_next_test);
   }
 });
 
 add_test(function test_disabledRemotely() {
   _("Test: Engine is enabled locally and disabled on a remote client");
@@ -333,21 +335,21 @@ add_test(function test_disabledRemotely(
 
   try {
     _("Enable engine locally.");
     Service._ignorePrefObserver = true;
     engine.enabled = true;
     Service._ignorePrefObserver = false;
 
     _("Sync.");
-    Weave.Service.sync();
+    Service.sync();
 
     _("Engine is not disabled: only one client.");
     do_check_true(engine.enabled);
-    
+
   } finally {
     Service.startOver();
     server.stop(run_next_test);
   }
 });
 
 add_test(function test_dependentEnginesEnabledLocally() {
   _("Test: Engine is disabled on remote clients and enabled locally");
@@ -364,17 +366,17 @@ add_test(function test_dependentEnginesE
   });
   setUp();
 
   try {
     _("Enable engine locally. Doing it on one is enough.");
     steamEngine.enabled = true;
 
     _("Sync.");
-    Weave.Service.sync();
+    Service.sync();
 
     _("Meta record now contains the new engines.");
     do_check_true(!!metaWBO.data.engines.steam);
     do_check_true(!!metaWBO.data.engines.stirling);
 
     _("Engines continue to be enabled.");
     do_check_true(steamEngine.enabled);
     do_check_true(stirlingEngine.enabled);
@@ -413,17 +415,17 @@ add_test(function test_dependentEnginesD
     Service._ignorePrefObserver = true;
     steamEngine.enabled = true;
     do_check_true(stirlingEngine.enabled);
     Service._ignorePrefObserver = false;
     steamEngine.enabled = false;
     do_check_false(stirlingEngine.enabled);
 
     _("Sync.");
-    Weave.Service.sync();
+    Service.sync();
 
     _("Meta record no longer contains engines.");
     do_check_false(!!metaWBO.data.engines.steam);
     do_check_false(!!metaWBO.data.engines.stirling);
 
     _("Server records are wiped.");
     do_check_eq(steamCollection.payload, undefined);
     do_check_eq(stirlingCollection.payload, undefined);
--- a/services/sync/tests/unit/test_syncengine_sync.js
+++ b/services/sync/tests/unit/test_syncengine_sync.js
@@ -1,16 +1,19 @@
-Cu.import("resource://services-sync/record.js");
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
 Cu.import("resource://services-sync/constants.js");
 Cu.import("resource://services-sync/engines.js");
 Cu.import("resource://services-sync/identity.js");
+Cu.import("resource://services-sync/policies.js");
+Cu.import("resource://services-sync/record.js");
 Cu.import("resource://services-sync/resource.js");
+Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/util.js");
-Cu.import("resource://services-sync/policies.js");
-Cu.import("resource://services-sync/service.js");
 
 function makeRotaryEngine() {
   return new RotaryEngine();
 }
 
 function cleanAndGo(server) {
   Svc.Prefs.resetBranch("");
   Svc.Prefs.set("log.logger.engine.rotary", "Trace");
@@ -1775,27 +1778,27 @@ add_test(function test_syncapplied_obser
     numApplyCalls++;
     engine_name = data;
     count = subject;
   }
 
   Svc.Obs.add("weave:engine:sync:applied", onApplied);
 
   try {
-    SyncScheduler.hasIncomingItems = false;
+    Service.scheduler.hasIncomingItems = false;
 
     // Do sync.
     engine._syncStartup();
     engine._processIncoming();
 
     do_check_attribute_count(engine._store.items, 10);
 
     do_check_eq(numApplyCalls, 1);
     do_check_eq(engine_name, "rotary");
     do_check_eq(count.applied, 10);
 
-    do_check_true(SyncScheduler.hasIncomingItems);
+    do_check_true(Service.scheduler.hasIncomingItems);
   } finally {
     cleanAndGo(server);
-    SyncScheduler.hasIncomingItems = false;
+    Service.scheduler.hasIncomingItems = false;
     Svc.Obs.remove("weave:engine:sync:applied", onApplied);
   }
 });
--- a/services/sync/tests/unit/test_syncscheduler.js
+++ b/services/sync/tests/unit/test_syncscheduler.js
@@ -1,35 +1,37 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
-Cu.import("resource://services-sync/record.js");
+Cu.import("resource://services-sync/constants.js");
 Cu.import("resource://services-sync/identity.js");
 Cu.import("resource://services-sync/engines.js");
 Cu.import("resource://services-sync/engines/clients.js");
-Cu.import("resource://services-sync/constants.js");
 Cu.import("resource://services-sync/policies.js");
+Cu.import("resource://services-sync/record.js");
+Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/status.js");
 
 Svc.DefaultPrefs.set("registerEngines", "");
-Cu.import("resource://services-sync/service.js");
 
 function CatapultEngine() {
   SyncEngine.call(this, "Catapult");
 }
 CatapultEngine.prototype = {
   __proto__: SyncEngine.prototype,
   exception: null, // tests fill this in
   _sync: function _sync() {
     throw this.exception;
   }
 };
 
 Engines.register(CatapultEngine);
 
+let scheduler = new SyncScheduler(Service);
+
 function sync_httpd_setup() {
   let global = new ServerWBO("global", {
     syncID: Service.syncID,
     storageVersion: STORAGE_VERSION,
     engines: {clients: {version: Clients.version,
                         syncID: Clients.syncID}}
   });
   let clientsColl = new ServerCollection({}, true);
@@ -68,144 +70,145 @@ function cleanUpAndGo(server) {
     }
   });
 }
 
 function run_test() {
   initTestLogging("Trace");
 
   Log4Moz.repository.getLogger("Sync.Service").level = Log4Moz.Level.Trace;
-  Log4Moz.repository.getLogger("Sync.SyncScheduler").level = Log4Moz.Level.Trace;
+  Log4Moz.repository.getLogger("Sync.scheduler").level = Log4Moz.Level.Trace;
 
   run_next_test();
 }
 
 add_test(function test_prefAttributes() {
   _("Test various attributes corresponding to preferences.");
 
   const INTERVAL = 42 * 60 * 1000;   // 42 minutes
   const THRESHOLD = 3142;
   const SCORE = 2718;
   const TIMESTAMP1 = 1275493471649;
 
   _("The 'nextSync' attribute stores a millisecond timestamp rounded down to the nearest second.");
-  do_check_eq(SyncScheduler.nextSync, 0);
-  SyncScheduler.nextSync = TIMESTAMP1;
-  do_check_eq(SyncScheduler.nextSync, Math.floor(TIMESTAMP1 / 1000) * 1000);
+  do_check_eq(scheduler.nextSync, 0);
+  scheduler.nextSync = TIMESTAMP1;
+  do_check_eq(scheduler.nextSync, Math.floor(TIMESTAMP1 / 1000) * 1000);
 
   _("'syncInterval' defaults to singleDeviceInterval.");
   do_check_eq(Svc.Prefs.get('syncInterval'), undefined);
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
+  do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
 
   _("'syncInterval' corresponds to a preference setting.");
-  SyncScheduler.syncInterval = INTERVAL;
-  do_check_eq(SyncScheduler.syncInterval, INTERVAL);
+  scheduler.syncInterval = INTERVAL;
+  do_check_eq(scheduler.syncInterval, INTERVAL);
   do_check_eq(Svc.Prefs.get('syncInterval'), INTERVAL);
 
   _("'syncThreshold' corresponds to preference, defaults to SINGLE_USER_THRESHOLD");
   do_check_eq(Svc.Prefs.get('syncThreshold'), undefined);
-  do_check_eq(SyncScheduler.syncThreshold, SINGLE_USER_THRESHOLD);
-  SyncScheduler.syncThreshold = THRESHOLD;
-  do_check_eq(SyncScheduler.syncThreshold, THRESHOLD);
+  do_check_eq(scheduler.syncThreshold, SINGLE_USER_THRESHOLD);
+  scheduler.syncThreshold = THRESHOLD;
+  do_check_eq(scheduler.syncThreshold, THRESHOLD);
 
   _("'globalScore' corresponds to preference, defaults to zero.");
   do_check_eq(Svc.Prefs.get('globalScore'), 0);
-  do_check_eq(SyncScheduler.globalScore, 0);
-  SyncScheduler.globalScore = SCORE;
-  do_check_eq(SyncScheduler.globalScore, SCORE);
+  do_check_eq(scheduler.globalScore, 0);
+  scheduler.globalScore = SCORE;
+  do_check_eq(scheduler.globalScore, SCORE);
   do_check_eq(Svc.Prefs.get('globalScore'), SCORE);
 
   _("Intervals correspond to default preferences.");
-  do_check_eq(SyncScheduler.singleDeviceInterval,
+  do_check_eq(scheduler.singleDeviceInterval,
               Svc.Prefs.get("scheduler.singleDeviceInterval") * 1000);
-  do_check_eq(SyncScheduler.idleInterval,
+  do_check_eq(scheduler.idleInterval,
               Svc.Prefs.get("scheduler.idleInterval") * 1000);
-  do_check_eq(SyncScheduler.activeInterval,
+  do_check_eq(scheduler.activeInterval,
               Svc.Prefs.get("scheduler.activeInterval") * 1000);
-  do_check_eq(SyncScheduler.immediateInterval,
+  do_check_eq(scheduler.immediateInterval,
               Svc.Prefs.get("scheduler.immediateInterval") * 1000);
 
   _("Custom values for prefs will take effect after a restart.");
   Svc.Prefs.set("scheduler.singleDeviceInterval", 42);
   Svc.Prefs.set("scheduler.idleInterval", 23);
   Svc.Prefs.set("scheduler.activeInterval", 18);
   Svc.Prefs.set("scheduler.immediateInterval", 31415);
-  SyncScheduler.setDefaults();
-  do_check_eq(SyncScheduler.idleInterval, 23000);
-  do_check_eq(SyncScheduler.singleDeviceInterval, 42000);
-  do_check_eq(SyncScheduler.activeInterval, 18000);
-  do_check_eq(SyncScheduler.immediateInterval, 31415000);
+  scheduler.setDefaults();
+  do_check_eq(scheduler.idleInterval, 23000);
+  do_check_eq(scheduler.singleDeviceInterval, 42000);
+  do_check_eq(scheduler.activeInterval, 18000);
+  do_check_eq(scheduler.immediateInterval, 31415000);
 
   Svc.Prefs.resetBranch("");
-  SyncScheduler.setDefaults();
+  scheduler.setDefaults();
   run_next_test();
 });
 
 add_test(function test_updateClientMode() {
   _("Test updateClientMode adjusts scheduling attributes based on # of clients appropriately");
-  do_check_eq(SyncScheduler.syncThreshold, SINGLE_USER_THRESHOLD);
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
-  do_check_false(SyncScheduler.numClients > 1);
-  do_check_false(SyncScheduler.idle);
+  do_check_eq(scheduler.syncThreshold, SINGLE_USER_THRESHOLD);
+  do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
+  do_check_false(scheduler.numClients > 1);
+  do_check_false(scheduler.idle);
 
   // Trigger a change in interval & threshold by adding a client.
   Clients._store.create({id: "foo", cleartext: "bar"});
-  SyncScheduler.updateClientMode();
+  scheduler.updateClientMode();
 
-  do_check_eq(SyncScheduler.syncThreshold, MULTI_DEVICE_THRESHOLD);
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.activeInterval);
-  do_check_true(SyncScheduler.numClients > 1);
-  do_check_false(SyncScheduler.idle);
+  do_check_eq(scheduler.syncThreshold, MULTI_DEVICE_THRESHOLD);
+  do_check_eq(scheduler.syncInterval, scheduler.activeInterval);
+  do_check_true(scheduler.numClients > 1);
+  do_check_false(scheduler.idle);
 
   // Resets the number of clients to 0. 
   Clients.resetClient();
-  SyncScheduler.updateClientMode();
+  scheduler.updateClientMode();
 
   // Goes back to single user if # clients is 1.
-  do_check_eq(SyncScheduler.numClients, 1);
-  do_check_eq(SyncScheduler.syncThreshold, SINGLE_USER_THRESHOLD);
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
-  do_check_false(SyncScheduler.numClients > 1);
-  do_check_false(SyncScheduler.idle);
+  do_check_eq(scheduler.numClients, 1);
+  do_check_eq(scheduler.syncThreshold, SINGLE_USER_THRESHOLD);
+  do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
+  do_check_false(scheduler.numClients > 1);
+  do_check_false(scheduler.idle);
 
   cleanUpAndGo();
 });
 
 add_test(function test_masterpassword_locked_retry_interval() {
   _("Test Status.login = MASTER_PASSWORD_LOCKED results in reschedule at MASTER_PASSWORD interval");
   let loginFailed = false;
   Svc.Obs.add("weave:service:login:error", function onLoginError() {
     Svc.Obs.remove("weave:service:login:error", onLoginError); 
     loginFailed = true;
   });
 
   let rescheduleInterval = false;
-  SyncScheduler._scheduleAtInterval = SyncScheduler.scheduleAtInterval;
-  SyncScheduler.scheduleAtInterval = function (interval) {
+
+  let oldScheduleAtInterval = SyncScheduler.prototype.scheduleAtInterval;
+  SyncScheduler.prototype.scheduleAtInterval = function (interval) {
     rescheduleInterval = true;
     do_check_eq(interval, MASTER_PASSWORD_LOCKED_RETRY_INTERVAL);
   };
 
-  Service._verifyLogin = Service.verifyLogin;
+  let oldVerifyLogin = Service.verifyLogin;
   Service.verifyLogin = function () {
     Status.login = MASTER_PASSWORD_LOCKED;
     return false;
   };
 
   let server = sync_httpd_setup();
   setUp();
 
   Service.sync();
 
   do_check_true(loginFailed);
   do_check_eq(Status.login, MASTER_PASSWORD_LOCKED);
   do_check_true(rescheduleInterval);
 
-  Service.verifyLogin = Service._verifyLogin;
-  SyncScheduler.scheduleAtInterval = SyncScheduler._scheduleAtInterval;
+  Service.verifyLogin = oldVerifyLogin;
+  SyncScheduler.prototype.scheduleAtInterval = oldScheduleAtInterval;
 
   cleanUpAndGo(server);
 });
 
 add_test(function test_calculateBackoff() {
   do_check_eq(Status.backoffInterval, 0);
 
   // Test no interval larger than the maximum backoff is used if
@@ -232,247 +235,247 @@ add_test(function test_scheduleNextSync_
     Svc.Obs.remove("weave:service:sync:finish", onSyncFinish);
     cleanUpAndGo(server);
   });
 
   let server = sync_httpd_setup();
   setUp();
 
   // We're late for a sync...
-  SyncScheduler.scheduleNextSync(-1);
+  scheduler.scheduleNextSync(-1);
 });
 
 add_test(function test_scheduleNextSync_future_noBackoff() {
   _("scheduleNextSync() uses the current syncInterval if no interval is provided.");
   // Test backoffInterval is 0 as expected.
   do_check_eq(Status.backoffInterval, 0);
 
   _("Test setting sync interval when nextSync == 0");
-  SyncScheduler.nextSync = 0;
-  SyncScheduler.scheduleNextSync();
+  scheduler.nextSync = 0;
+  scheduler.scheduleNextSync();
 
   // nextSync - Date.now() might be smaller than expectedInterval
   // since some time has passed since we called scheduleNextSync().
-  do_check_true(SyncScheduler.nextSync - Date.now()
-                <= SyncScheduler.syncInterval);
-  do_check_eq(SyncScheduler.syncTimer.delay, SyncScheduler.syncInterval);
+  do_check_true(scheduler.nextSync - Date.now()
+                <= scheduler.syncInterval);
+  do_check_eq(scheduler.syncTimer.delay, scheduler.syncInterval);
 
   _("Test setting sync interval when nextSync != 0");
-  SyncScheduler.nextSync = Date.now() + SyncScheduler.singleDeviceInterval;
-  SyncScheduler.scheduleNextSync();
+  scheduler.nextSync = Date.now() + scheduler.singleDeviceInterval;
+  scheduler.scheduleNextSync();
 
   // nextSync - Date.now() might be smaller than expectedInterval
   // since some time has passed since we called scheduleNextSync().
-  do_check_true(SyncScheduler.nextSync - Date.now()
-                <= SyncScheduler.syncInterval);
-  do_check_true(SyncScheduler.syncTimer.delay <= SyncScheduler.syncInterval);
+  do_check_true(scheduler.nextSync - Date.now()
+                <= scheduler.syncInterval);
+  do_check_true(scheduler.syncTimer.delay <= scheduler.syncInterval);
 
   _("Scheduling requests for intervals larger than the current one will be ignored.");
   // Request a sync at a longer interval. The sync that's already scheduled
   // for sooner takes precedence.
-  let nextSync = SyncScheduler.nextSync;
-  let timerDelay = SyncScheduler.syncTimer.delay;
-  let requestedInterval = SyncScheduler.syncInterval * 10;
-  SyncScheduler.scheduleNextSync(requestedInterval);
-  do_check_eq(SyncScheduler.nextSync, nextSync);
-  do_check_eq(SyncScheduler.syncTimer.delay, timerDelay);
+  let nextSync = scheduler.nextSync;
+  let timerDelay = scheduler.syncTimer.delay;
+  let requestedInterval = scheduler.syncInterval * 10;
+  scheduler.scheduleNextSync(requestedInterval);
+  do_check_eq(scheduler.nextSync, nextSync);
+  do_check_eq(scheduler.syncTimer.delay, timerDelay);
 
   // We can schedule anything we want if there isn't a sync scheduled.
-  SyncScheduler.nextSync = 0;
-  SyncScheduler.scheduleNextSync(requestedInterval);
-  do_check_true(SyncScheduler.nextSync <= Date.now() + requestedInterval);
-  do_check_eq(SyncScheduler.syncTimer.delay, requestedInterval);
+  scheduler.nextSync = 0;
+  scheduler.scheduleNextSync(requestedInterval);
+  do_check_true(scheduler.nextSync <= Date.now() + requestedInterval);
+  do_check_eq(scheduler.syncTimer.delay, requestedInterval);
 
   // Request a sync at the smallest possible interval (0 triggers now).
-  SyncScheduler.scheduleNextSync(1);
-  do_check_true(SyncScheduler.nextSync <= Date.now() + 1);
-  do_check_eq(SyncScheduler.syncTimer.delay, 1);
+  scheduler.scheduleNextSync(1);
+  do_check_true(scheduler.nextSync <= Date.now() + 1);
+  do_check_eq(scheduler.syncTimer.delay, 1);
 
   cleanUpAndGo();
 });
 
 add_test(function test_scheduleNextSync_future_backoff() {
  _("scheduleNextSync() will honour backoff in all scheduling requests.");
   // Let's take a backoff interval that's bigger than the default sync interval.
   const BACKOFF = 7337;
-  Status.backoffInterval = SyncScheduler.syncInterval + BACKOFF;
+  Status.backoffInterval = scheduler.syncInterval + BACKOFF;
 
   _("Test setting sync interval when nextSync == 0");
-  SyncScheduler.nextSync = 0;
-  SyncScheduler.scheduleNextSync();
+  scheduler.nextSync = 0;
+  scheduler.scheduleNextSync();
 
   // nextSync - Date.now() might be smaller than expectedInterval
   // since some time has passed since we called scheduleNextSync().
-  do_check_true(SyncScheduler.nextSync - Date.now()
+  do_check_true(scheduler.nextSync - Date.now()
                 <= Status.backoffInterval);
-  do_check_eq(SyncScheduler.syncTimer.delay, Status.backoffInterval);
+  do_check_eq(scheduler.syncTimer.delay, Status.backoffInterval);
 
   _("Test setting sync interval when nextSync != 0");
-  SyncScheduler.nextSync = Date.now() + SyncScheduler.singleDeviceInterval;
-  SyncScheduler.scheduleNextSync();
+  scheduler.nextSync = Date.now() + scheduler.singleDeviceInterval;
+  scheduler.scheduleNextSync();
 
   // nextSync - Date.now() might be smaller than expectedInterval
   // since some time has passed since we called scheduleNextSync().
-  do_check_true(SyncScheduler.nextSync - Date.now()
+  do_check_true(scheduler.nextSync - Date.now()
                 <= Status.backoffInterval);
-  do_check_true(SyncScheduler.syncTimer.delay <= Status.backoffInterval);
+  do_check_true(scheduler.syncTimer.delay <= Status.backoffInterval);
 
   // Request a sync at a longer interval. The sync that's already scheduled
   // for sooner takes precedence.
-  let nextSync = SyncScheduler.nextSync;
-  let timerDelay = SyncScheduler.syncTimer.delay;
-  let requestedInterval = SyncScheduler.syncInterval * 10;
+  let nextSync = scheduler.nextSync;
+  let timerDelay = scheduler.syncTimer.delay;
+  let requestedInterval = scheduler.syncInterval * 10;
   do_check_true(requestedInterval > Status.backoffInterval);
-  SyncScheduler.scheduleNextSync(requestedInterval);
-  do_check_eq(SyncScheduler.nextSync, nextSync);
-  do_check_eq(SyncScheduler.syncTimer.delay, timerDelay);
+  scheduler.scheduleNextSync(requestedInterval);
+  do_check_eq(scheduler.nextSync, nextSync);
+  do_check_eq(scheduler.syncTimer.delay, timerDelay);
 
   // We can schedule anything we want if there isn't a sync scheduled.
-  SyncScheduler.nextSync = 0;
-  SyncScheduler.scheduleNextSync(requestedInterval);
-  do_check_true(SyncScheduler.nextSync <= Date.now() + requestedInterval);
-  do_check_eq(SyncScheduler.syncTimer.delay, requestedInterval);
+  scheduler.nextSync = 0;
+  scheduler.scheduleNextSync(requestedInterval);
+  do_check_true(scheduler.nextSync <= Date.now() + requestedInterval);
+  do_check_eq(scheduler.syncTimer.delay, requestedInterval);
 
   // Request a sync at the smallest possible interval (0 triggers now).
-  SyncScheduler.scheduleNextSync(1);
-  do_check_true(SyncScheduler.nextSync <= Date.now() + Status.backoffInterval);
-  do_check_eq(SyncScheduler.syncTimer.delay, Status.backoffInterval);
+  scheduler.scheduleNextSync(1);
+  do_check_true(scheduler.nextSync <= Date.now() + Status.backoffInterval);
+  do_check_eq(scheduler.syncTimer.delay, Status.backoffInterval);
 
   cleanUpAndGo();
 });
 
 add_test(function test_handleSyncError() {
   let server = sync_httpd_setup();
   setUp();
  
   // Force sync to fail.
   Svc.Prefs.set("firstSync", "notReady");
 
   _("Ensure expected initial environment.");
-  do_check_eq(SyncScheduler._syncErrors, 0);
+  do_check_eq(scheduler._syncErrors, 0);
   do_check_false(Status.enforceBackoff);
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
+  do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
   do_check_eq(Status.backoffInterval, 0);
 
   // Trigger sync with an error several times & observe
   // functionality of handleSyncError()
   _("Test first error calls scheduleNextSync on default interval");
   Service.sync();
-  do_check_true(SyncScheduler.nextSync <= Date.now() + SyncScheduler.singleDeviceInterval);
-  do_check_eq(SyncScheduler.syncTimer.delay, SyncScheduler.singleDeviceInterval);
-  do_check_eq(SyncScheduler._syncErrors, 1);
+  do_check_true(scheduler.nextSync <= Date.now() + scheduler.singleDeviceInterval);
+  do_check_eq(scheduler.syncTimer.delay, scheduler.singleDeviceInterval);
+  do_check_eq(scheduler._syncErrors, 1);
   do_check_false(Status.enforceBackoff);
-  SyncScheduler.syncTimer.clear();
+  scheduler.syncTimer.clear();
 
   _("Test second error still calls scheduleNextSync on default interval");
   Service.sync();
-  do_check_true(SyncScheduler.nextSync <= Date.now() + SyncScheduler.singleDeviceInterval);
-  do_check_eq(SyncScheduler.syncTimer.delay, SyncScheduler.singleDeviceInterval);
-  do_check_eq(SyncScheduler._syncErrors, 2);
+  do_check_true(scheduler.nextSync <= Date.now() + scheduler.singleDeviceInterval);
+  do_check_eq(scheduler.syncTimer.delay, scheduler.singleDeviceInterval);
+  do_check_eq(scheduler._syncErrors, 2);
   do_check_false(Status.enforceBackoff);
-  SyncScheduler.syncTimer.clear();
+  scheduler.syncTimer.clear();
 
   _("Test third error sets Status.enforceBackoff and calls scheduleAtInterval");
   Service.sync();
-  let maxInterval = SyncScheduler._syncErrors * (2 * MINIMUM_BACKOFF_INTERVAL);
+  let maxInterval = scheduler._syncErrors * (2 * MINIMUM_BACKOFF_INTERVAL);
   do_check_eq(Status.backoffInterval, 0);
-  do_check_true(SyncScheduler.nextSync <= (Date.now() + maxInterval));
-  do_check_true(SyncScheduler.syncTimer.delay <= maxInterval);
-  do_check_eq(SyncScheduler._syncErrors, 3);
+  do_check_true(scheduler.nextSync <= (Date.now() + maxInterval));
+  do_check_true(scheduler.syncTimer.delay <= maxInterval);
+  do_check_eq(scheduler._syncErrors, 3);
   do_check_true(Status.enforceBackoff);
 
   // Status.enforceBackoff is false but there are still errors.
   Status.resetBackoff();
   do_check_false(Status.enforceBackoff);
-  do_check_eq(SyncScheduler._syncErrors, 3);
-  SyncScheduler.syncTimer.clear();
+  do_check_eq(scheduler._syncErrors, 3);
+  scheduler.syncTimer.clear();
 
   _("Test fourth error still calls scheduleAtInterval even if enforceBackoff was reset");
   Service.sync();
-  maxInterval = SyncScheduler._syncErrors * (2 * MINIMUM_BACKOFF_INTERVAL);
-  do_check_true(SyncScheduler.nextSync <= Date.now() + maxInterval);
-  do_check_true(SyncScheduler.syncTimer.delay <= maxInterval);
-  do_check_eq(SyncScheduler._syncErrors, 4);
+  maxInterval = scheduler._syncErrors * (2 * MINIMUM_BACKOFF_INTERVAL);
+  do_check_true(scheduler.nextSync <= Date.now() + maxInterval);
+  do_check_true(scheduler.syncTimer.delay <= maxInterval);
+  do_check_eq(scheduler._syncErrors, 4);
   do_check_true(Status.enforceBackoff);
-  SyncScheduler.syncTimer.clear();
+  scheduler.syncTimer.clear();
 
   cleanUpAndGo(server);
 });
 
 add_test(function test_client_sync_finish_updateClientMode() {
   let server = sync_httpd_setup();
   setUp();
 
   // Confirm defaults.
-  do_check_eq(SyncScheduler.syncThreshold, SINGLE_USER_THRESHOLD);
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
-  do_check_false(SyncScheduler.idle);
+  do_check_eq(scheduler.syncThreshold, SINGLE_USER_THRESHOLD);
+  do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
+  do_check_false(scheduler.idle);
 
   // Trigger a change in interval & threshold by adding a client.
   Clients._store.create({id: "foo", cleartext: "bar"});
-  do_check_false(SyncScheduler.numClients > 1);
-  SyncScheduler.updateClientMode();
+  do_check_false(scheduler.numClients > 1);
+  scheduler.updateClientMode();
   Service.sync();
 
-  do_check_eq(SyncScheduler.syncThreshold, MULTI_DEVICE_THRESHOLD);
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.activeInterval);
-  do_check_true(SyncScheduler.numClients > 1);
-  do_check_false(SyncScheduler.idle);
+  do_check_eq(scheduler.syncThreshold, MULTI_DEVICE_THRESHOLD);
+  do_check_eq(scheduler.syncInterval, scheduler.activeInterval);
+  do_check_true(scheduler.numClients > 1);
+  do_check_false(scheduler.idle);
 
   // Resets the number of clients to 0. 
   Clients.resetClient();
   Service.sync();
 
   // Goes back to single user if # clients is 1.
-  do_check_eq(SyncScheduler.numClients, 1);
-  do_check_eq(SyncScheduler.syncThreshold, SINGLE_USER_THRESHOLD);
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
-  do_check_false(SyncScheduler.numClients > 1);
-  do_check_false(SyncScheduler.idle);
+  do_check_eq(scheduler.numClients, 1);
+  do_check_eq(scheduler.syncThreshold, SINGLE_USER_THRESHOLD);
+  do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
+  do_check_false(scheduler.numClients > 1);
+  do_check_false(scheduler.idle);
 
   cleanUpAndGo(server);
 });
 
 add_test(function test_autoconnect_nextSync_past() {
   // nextSync will be 0 by default, so it's way in the past.
 
   Svc.Obs.add("weave:service:sync:finish", function onSyncFinish() {
     Svc.Obs.remove("weave:service:sync:finish", onSyncFinish);
     cleanUpAndGo(server);
   });
 
   let server = sync_httpd_setup();
   setUp();
 
-  SyncScheduler.delayedAutoConnect(0);
+  scheduler.delayedAutoConnect(0);
 });
 
 add_test(function test_autoconnect_nextSync_future() {
-  let previousSync = Date.now() + SyncScheduler.syncInterval / 2;
-  SyncScheduler.nextSync = previousSync;
+  let previousSync = Date.now() + scheduler.syncInterval / 2;
+  scheduler.nextSync = previousSync;
   // nextSync rounds to the nearest second.
-  let expectedSync = SyncScheduler.nextSync;
+  let expectedSync = scheduler.nextSync;
   let expectedInterval = expectedSync - Date.now() - 1000;
 
   // Ensure we don't actually try to sync (or log in for that matter).
   function onLoginStart() {
     do_throw("Should not get here!");
   }
   Svc.Obs.add("weave:service:login:start", onLoginStart);
 
   waitForZeroTimer(function () {
-    do_check_eq(SyncScheduler.nextSync, expectedSync);
-    do_check_true(SyncScheduler.syncTimer.delay >= expectedInterval);
+    do_check_eq(scheduler.nextSync, expectedSync);
+    do_check_true(scheduler.syncTimer.delay >= expectedInterval);
 
     Svc.Obs.remove("weave:service:login:start", onLoginStart);
     cleanUpAndGo();
   });
 
   setBasicCredentials("johndoe", "ilovejane", "abcdeabcdeabcdeabcdeabcdea");
-  SyncScheduler.delayedAutoConnect(0);
+  scheduler.delayedAutoConnect(0);
 });
 
 add_test(function test_autoconnect_mp_locked() {
   let server = sync_httpd_setup();
   setUp();
 
   // Pretend user did not unlock master password.
   let origLocked = Utils.mpLocked;
@@ -497,17 +500,17 @@ add_test(function test_autoconnect_mp_lo
       delete Identity.syncKey;
       Identity.__defineGetter__("syncKey", origGetter);
       Identity.__defineSetter__("syncKey", origSetter);
 
       cleanUpAndGo(server);
     });
   });
 
-  SyncScheduler.delayedAutoConnect(0);
+  scheduler.delayedAutoConnect(0);
 });
 
 add_test(function test_no_autoconnect_during_wizard() {
   let server = sync_httpd_setup();
   setUp();
 
   // Simulate the Sync setup wizard.
   Svc.Prefs.set("firstSync", "notReady");
@@ -518,17 +521,17 @@ add_test(function test_no_autoconnect_du
   }
   Svc.Obs.add("weave:service:login:start", onLoginStart);
 
   waitForZeroTimer(function () {
     Svc.Obs.remove("weave:service:login:start", onLoginStart);
     cleanUpAndGo(server);
   });
 
-  SyncScheduler.delayedAutoConnect(0);
+  scheduler.delayedAutoConnect(0);
 });
 
 add_test(function test_no_autoconnect_status_not_ok() {
   let server = sync_httpd_setup();
 
   // Ensure we don't actually try to sync (or log in for that matter).
   function onLoginStart() {
     do_throw("Should not get here!");
@@ -539,126 +542,126 @@ add_test(function test_no_autoconnect_st
     Svc.Obs.remove("weave:service:login:start", onLoginStart);
 
     do_check_eq(Status.service, CLIENT_NOT_CONFIGURED);
     do_check_eq(Status.login, LOGIN_FAILED_NO_USERNAME);
 
     cleanUpAndGo(server);
   });
 
-  SyncScheduler.delayedAutoConnect(0);
+  scheduler.delayedAutoConnect(0);
 });
 
 add_test(function test_autoconnectDelay_pref() {
   Svc.Obs.add("weave:service:sync:finish", function onSyncFinish() {
     Svc.Obs.remove("weave:service:sync:finish", onSyncFinish);
     cleanUpAndGo(server);
   });
 
   Svc.Prefs.set("autoconnectDelay", 1);
 
   let server = sync_httpd_setup();
   setUp();
 
   Svc.Obs.notify("weave:service:ready");
 
   // autoconnectDelay pref is multiplied by 1000.
-  do_check_eq(SyncScheduler._autoTimer.delay, 1000);
+  do_check_eq(scheduler._autoTimer.delay, 1000);
   do_check_eq(Status.service, STATUS_OK);
 });
 
 add_test(function test_idle_adjustSyncInterval() {
   // Confirm defaults.
-  do_check_eq(SyncScheduler.idle, false);
+  do_check_eq(scheduler.idle, false);
 
   // Single device: nothing changes.
-  SyncScheduler.observe(null, "idle", Svc.Prefs.get("scheduler.idleTime"));
-  do_check_eq(SyncScheduler.idle, true);
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
+  scheduler.observe(null, "idle", Svc.Prefs.get("scheduler.idleTime"));
+  do_check_eq(scheduler.idle, true);
+  do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
 
   // Multiple devices: switch to idle interval.
-  SyncScheduler.idle = false;
+  scheduler.idle = false;
   Clients._store.create({id: "foo", cleartext: "bar"});
-  SyncScheduler.updateClientMode();
-  SyncScheduler.observe(null, "idle", Svc.Prefs.get("scheduler.idleTime"));
-  do_check_eq(SyncScheduler.idle, true);
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.idleInterval);
+  scheduler.updateClientMode();
+  scheduler.observe(null, "idle", Svc.Prefs.get("scheduler.idleTime"));
+  do_check_eq(scheduler.idle, true);
+  do_check_eq(scheduler.syncInterval, scheduler.idleInterval);
 
   cleanUpAndGo();
 });
 
 add_test(function test_back_triggersSync() {
   // Confirm defaults.
-  do_check_false(SyncScheduler.idle);
+  do_check_false(scheduler.idle);
   do_check_eq(Status.backoffInterval, 0);
 
   // Set up: Define 2 clients and put the system in idle.
-  SyncScheduler.numClients = 2;
-  SyncScheduler.observe(null, "idle", Svc.Prefs.get("scheduler.idleTime"));
-  do_check_true(SyncScheduler.idle);
+  scheduler.numClients = 2;
+  scheduler.observe(null, "idle", Svc.Prefs.get("scheduler.idleTime"));
+  do_check_true(scheduler.idle);
 
   // We don't actually expect the sync (or the login, for that matter) to
   // succeed. We just want to ensure that it was attempted.
   Svc.Obs.add("weave:service:login:error", function onLoginError() {
     Svc.Obs.remove("weave:service:login:error", onLoginError);
     cleanUpAndGo();
   });
 
   // Send a 'back' event to trigger sync soonish.
-  SyncScheduler.observe(null, "back", Svc.Prefs.get("scheduler.idleTime"));
+  scheduler.observe(null, "back", Svc.Prefs.get("scheduler.idleTime"));
 });
 
 add_test(function test_back_triggersSync_observesBackoff() {
   // Confirm defaults.
-  do_check_false(SyncScheduler.idle);
+  do_check_false(scheduler.idle);
 
   // Set up: Set backoff, define 2 clients and put the system in idle.
   const BACKOFF = 7337;
-  Status.backoffInterval = SyncScheduler.idleInterval + BACKOFF;
-  SyncScheduler.numClients = 2;
-  SyncScheduler.observe(null, "idle", Svc.Prefs.get("scheduler.idleTime"));
-  do_check_eq(SyncScheduler.idle, true);
+  Status.backoffInterval = scheduler.idleInterval + BACKOFF;
+  scheduler.numClients = 2;
+  scheduler.observe(null, "idle", Svc.Prefs.get("scheduler.idleTime"));
+  do_check_eq(scheduler.idle, true);
 
   function onLoginStart() {
     do_throw("Shouldn't have kicked off a sync!");
   }
   Svc.Obs.add("weave:service:login:start", onLoginStart);
 
   timer = Utils.namedTimer(function () {
     Svc.Obs.remove("weave:service:login:start", onLoginStart);
 
-    do_check_true(SyncScheduler.nextSync <= Date.now() + Status.backoffInterval);
-    do_check_eq(SyncScheduler.syncTimer.delay, Status.backoffInterval);
+    do_check_true(scheduler.nextSync <= Date.now() + Status.backoffInterval);
+    do_check_eq(scheduler.syncTimer.delay, Status.backoffInterval);
 
     cleanUpAndGo();
   }, IDLE_OBSERVER_BACK_DELAY * 1.5, {}, "timer");
 
   // Send a 'back' event to try to trigger sync soonish.
-  SyncScheduler.observe(null, "back", Svc.Prefs.get("scheduler.idleTime"));
+  scheduler.observe(null, "back", Svc.Prefs.get("scheduler.idleTime"));
 });
 
 add_test(function test_back_debouncing() {
   _("Ensure spurious back-then-idle events, as observed on OS X, don't trigger a sync.");
 
   // Confirm defaults.
-  do_check_eq(SyncScheduler.idle, false);
+  do_check_eq(scheduler.idle, false);
 
   // Set up: Define 2 clients and put the system in idle.
-  SyncScheduler.numClients = 2;
-  SyncScheduler.observe(null, "idle", Svc.Prefs.get("scheduler.idleTime"));
-  do_check_eq(SyncScheduler.idle, true);
+  scheduler.numClients = 2;
+  scheduler.observe(null, "idle", Svc.Prefs.get("scheduler.idleTime"));
+  do_check_eq(scheduler.idle, true);
 
   function onLoginStart() {
     do_throw("Shouldn't have kicked off a sync!");
   }
   Svc.Obs.add("weave:service:login:start", onLoginStart);
 
   // Create spurious back-then-idle events as observed on OS X:
-  SyncScheduler.observe(null, "back", Svc.Prefs.get("scheduler.idleTime"));
-  SyncScheduler.observe(null, "idle", Svc.Prefs.get("scheduler.idleTime"));
+  scheduler.observe(null, "back", Svc.Prefs.get("scheduler.idleTime"));
+  scheduler.observe(null, "idle", Svc.Prefs.get("scheduler.idleTime"));
 
   timer = Utils.namedTimer(function () {
     Svc.Obs.remove("weave:service:login:start", onLoginStart);
     cleanUpAndGo();
   }, IDLE_OBSERVER_BACK_DELAY * 1.5, {}, "timer");
 });
 
 add_test(function test_no_sync_node() {
@@ -666,74 +669,74 @@ add_test(function test_no_sync_node() {
   // it is not overwritten on sync:finish
   let server = sync_httpd_setup();
   setUp();
 
   Service.serverURL = TEST_SERVER_URL;
 
   Service.sync();
   do_check_eq(Status.sync, NO_SYNC_NODE_FOUND);
-  do_check_eq(SyncScheduler.syncTimer.delay, NO_SYNC_NODE_INTERVAL);
+  do_check_eq(scheduler.syncTimer.delay, NO_SYNC_NODE_INTERVAL);
 
   cleanUpAndGo(server);
 });
 
 add_test(function test_sync_failed_partial_500s() {
   _("Test a 5xx status calls handleSyncError.");
-  SyncScheduler._syncErrors = MAX_ERROR_COUNT_BEFORE_BACKOFF;
+  scheduler._syncErrors = MAX_ERROR_COUNT_BEFORE_BACKOFF;
   let server = sync_httpd_setup();
 
   let engine = Engines.get("catapult");
   engine.enabled = true;
   engine.exception = {status: 500};
 
   do_check_eq(Status.sync, SYNC_SUCCEEDED);
 
   do_check_true(setUp());
 
   Service.sync();
 
   do_check_eq(Status.service, SYNC_FAILED_PARTIAL);
 
-  let maxInterval = SyncScheduler._syncErrors * (2 * MINIMUM_BACKOFF_INTERVAL);
+  let maxInterval = scheduler._syncErrors * (2 * MINIMUM_BACKOFF_INTERVAL);
   do_check_eq(Status.backoffInterval, 0);
   do_check_true(Status.enforceBackoff);
-  do_check_eq(SyncScheduler._syncErrors, 4);
-  do_check_true(SyncScheduler.nextSync <= (Date.now() + maxInterval));
-  do_check_true(SyncScheduler.syncTimer.delay <= maxInterval);
+  do_check_eq(scheduler._syncErrors, 4);
+  do_check_true(scheduler.nextSync <= (Date.now() + maxInterval));
+  do_check_true(scheduler.syncTimer.delay <= maxInterval);
 
   cleanUpAndGo(server);
 });
 
 add_test(function test_sync_failed_partial_400s() {
   _("Test a non-5xx status doesn't call handleSyncError.");
-  SyncScheduler._syncErrors = MAX_ERROR_COUNT_BEFORE_BACKOFF;
+  scheduler._syncErrors = MAX_ERROR_COUNT_BEFORE_BACKOFF;
   let server = sync_httpd_setup();
 
   let engine = Engines.get("catapult");
   engine.enabled = true;
   engine.exception = {status: 400};
 
   // Have multiple devices for an active interval.
   Clients._store.create({id: "foo", cleartext: "bar"});
 
   do_check_eq(Status.sync, SYNC_SUCCEEDED);
 
   do_check_true(setUp());
 
   Service.sync();
 
   do_check_eq(Status.service, SYNC_FAILED_PARTIAL);
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.activeInterval);
+  do_check_eq(scheduler.syncInterval, scheduler.activeInterval);
 
   do_check_eq(Status.backoffInterval, 0);
   do_check_false(Status.enforceBackoff);
-  do_check_eq(SyncScheduler._syncErrors, 0);
-  do_check_true(SyncScheduler.nextSync <= (Date.now() + SyncScheduler.activeInterval));
-  do_check_true(SyncScheduler.syncTimer.delay <= SyncScheduler.activeInterval);
+  do_check_eq(scheduler._syncErrors, 0);
+  do_check_true(scheduler.nextSync <= (Date.now() + scheduler.activeInterval));
+  do_check_true(scheduler.syncTimer.delay <= scheduler.activeInterval);
 
   cleanUpAndGo(server);
 });
 
 add_test(function test_sync_X_Weave_Backoff() {
   let server = sync_httpd_setup();
   setUp();
 
@@ -760,35 +763,35 @@ add_test(function test_sync_X_Weave_Back
   rec.encrypt();
   rec.upload(Clients.engineURL + rec.id);
 
   // Sync once to log in and get everything set up. Let's verify our initial
   // values.
   Service.sync();
   do_check_eq(Status.backoffInterval, 0);
   do_check_eq(Status.minimumNextSync, 0);
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.activeInterval);
-  do_check_true(SyncScheduler.nextSync <=
-                Date.now() + SyncScheduler.syncInterval);
+  do_check_eq(scheduler.syncInterval, scheduler.activeInterval);
+  do_check_true(scheduler.nextSync <=
+                Date.now() + scheduler.syncInterval);
   // Sanity check that we picked the right value for BACKOFF:
-  do_check_true(SyncScheduler.syncInterval < BACKOFF * 1000);
+  do_check_true(scheduler.syncInterval < BACKOFF * 1000);
 
   // Turn on server maintenance and sync again.
   serverBackoff = true;
   Service.sync();
 
   do_check_true(Status.backoffInterval >= BACKOFF * 1000);
   // Allowing 1 second worth of of leeway between when Status.minimumNextSync
   // was set and when this line gets executed.
   let minimumExpectedDelay = (BACKOFF - 1) * 1000;
   do_check_true(Status.minimumNextSync >= Date.now() + minimumExpectedDelay);
 
   // Verify that the next sync is actually going to wait that long.
-  do_check_true(SyncScheduler.nextSync >= Date.now() + minimumExpectedDelay);
-  do_check_true(SyncScheduler.syncTimer.delay >= minimumExpectedDelay);
+  do_check_true(scheduler.nextSync >= Date.now() + minimumExpectedDelay);
+  do_check_true(scheduler.syncTimer.delay >= minimumExpectedDelay);
 
   cleanUpAndGo(server);
 });
 
 add_test(function test_sync_503_Retry_After() {
   let server = sync_httpd_setup();
   setUp();
 
@@ -818,36 +821,36 @@ add_test(function test_sync_503_Retry_Af
   rec.upload(Clients.engineURL + rec.id);
 
   // Sync once to log in and get everything set up. Let's verify our initial
   // values.
   Service.sync();
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.backoffInterval, 0);
   do_check_eq(Status.minimumNextSync, 0);
-  do_check_eq(SyncScheduler.syncInterval, SyncScheduler.activeInterval);
-  do_check_true(SyncScheduler.nextSync <=
-                Date.now() + SyncScheduler.syncInterval);
+  do_check_eq(scheduler.syncInterval, scheduler.activeInterval);
+  do_check_true(scheduler.nextSync <=
+                Date.now() + scheduler.syncInterval);
   // Sanity check that we picked the right value for BACKOFF:
-  do_check_true(SyncScheduler.syncInterval < BACKOFF * 1000);
+  do_check_true(scheduler.syncInterval < BACKOFF * 1000);
 
   // Turn on server maintenance and sync again.
   serverMaintenance = true;
   Service.sync();
 
   do_check_true(Status.enforceBackoff);
   do_check_true(Status.backoffInterval >= BACKOFF * 1000);
   // Allowing 1 second worth of of leeway between when Status.minimumNextSync
   // was set and when this line gets executed.
   let minimumExpectedDelay = (BACKOFF - 1) * 1000;
   do_check_true(Status.minimumNextSync >= Date.now() + minimumExpectedDelay);
 
   // Verify that the next sync is actually going to wait that long.
-  do_check_true(SyncScheduler.nextSync >= Date.now() + minimumExpectedDelay);
-  do_check_true(SyncScheduler.syncTimer.delay >= minimumExpectedDelay);
+  do_check_true(scheduler.nextSync >= Date.now() + minimumExpectedDelay);
+  do_check_true(scheduler.syncTimer.delay >= minimumExpectedDelay);
 
   cleanUpAndGo(server);
 });
 
 add_test(function test_loginError_recoverable_reschedules() {
   _("Verify that a recoverable login error schedules a new sync.");
   setBasicCredentials("johndoe", "ilovejane", "abcdeabcdeabcdeabcdeabcdea");
   Service.serverURL = TEST_SERVER_URL;
@@ -855,43 +858,43 @@ add_test(function test_loginError_recove
   Service.persistLogin();
   Status.resetSync(); // reset Status.login
 
   Svc.Obs.add("weave:service:login:error", function onLoginError() {
     Svc.Obs.remove("weave:service:login:error", onLoginError);
     Utils.nextTick(function aLittleBitAfterLoginError() {
       do_check_eq(Status.login, LOGIN_FAILED_NETWORK_ERROR);
 
-      let expectedNextSync = Date.now() + SyncScheduler.syncInterval;
-      do_check_true(SyncScheduler.nextSync > Date.now());
-      do_check_true(SyncScheduler.nextSync <= expectedNextSync);
-      do_check_true(SyncScheduler.syncTimer.delay > 0);
-      do_check_true(SyncScheduler.syncTimer.delay <= SyncScheduler.syncInterval);
+      let expectedNextSync = Date.now() + scheduler.syncInterval;
+      do_check_true(scheduler.nextSync > Date.now());
+      do_check_true(scheduler.nextSync <= expectedNextSync);
+      do_check_true(scheduler.syncTimer.delay > 0);
+      do_check_true(scheduler.syncTimer.delay <= scheduler.syncInterval);
 
       Svc.Obs.remove("weave:service:sync:start", onSyncStart);
       cleanUpAndGo();
     });
   });
 
   // Let's set it up so that a sync is overdue, both in terms of previously
   // scheduled syncs and the global score. We still do not expect an immediate
   // sync because we just tried (duh).
-  SyncScheduler.nextSync = Date.now() - 100000;
-  SyncScheduler.globalScore = SINGLE_USER_THRESHOLD + 1;
+  scheduler.nextSync = Date.now() - 100000;
+  scheduler.globalScore = SINGLE_USER_THRESHOLD + 1;
   function onSyncStart() {
     do_throw("Shouldn't have started a sync!");
   }
   Svc.Obs.add("weave:service:sync:start", onSyncStart);
 
   // Sanity check.
-  do_check_eq(SyncScheduler.syncTimer, null);
+  do_check_eq(scheduler.syncTimer, null);
   do_check_eq(Status.checkSetup(), STATUS_OK);
   do_check_eq(Status.login, LOGIN_SUCCEEDED);
 
-  SyncScheduler.scheduleNextSync(0);
+  scheduler.scheduleNextSync(0);
 });
 
 add_test(function test_loginError_fatal_clearsTriggers() {
   _("Verify that a fatal login error clears sync triggers.");
   setBasicCredentials("johndoe", "ilovejane", "abcdeabcdeabcdeabcdeabcdea");
   Service.serverURL = TEST_SERVER_URL;
   Service.clusterURL = TEST_CLUSTER_URL;
   Service.persistLogin();
@@ -901,49 +904,49 @@ add_test(function test_loginError_fatal_
     "/1.1/johndoe/info/collections": httpd_handler(401, "Unauthorized")
   });
 
   Svc.Obs.add("weave:service:login:error", function onLoginError() {
     Svc.Obs.remove("weave:service:login:error", onLoginError);
     Utils.nextTick(function aLittleBitAfterLoginError() {
       do_check_eq(Status.login, LOGIN_FAILED_LOGIN_REJECTED);
 
-      do_check_eq(SyncScheduler.nextSync, 0);
-      do_check_eq(SyncScheduler.syncTimer, null);
+      do_check_eq(scheduler.nextSync, 0);
+      do_check_eq(scheduler.syncTimer, null);
 
       cleanUpAndGo(server);
     });
   });
 
   // Sanity check.
-  do_check_eq(SyncScheduler.nextSync, 0);
-  do_check_eq(SyncScheduler.syncTimer, null);
+  do_check_eq(scheduler.nextSync, 0);
+  do_check_eq(scheduler.syncTimer, null);
   do_check_eq(Status.checkSetup(), STATUS_OK);
   do_check_eq(Status.login, LOGIN_SUCCEEDED);
 
-  SyncScheduler.scheduleNextSync(0);
+  scheduler.scheduleNextSync(0);
 });
 
 add_test(function test_proper_interval_on_only_failing() {
   _("Ensure proper behavior when only failed records are applied.");
 
   // If an engine reports that no records succeeded, we shouldn't decrease the
   // sync interval.
-  do_check_false(SyncScheduler.hasIncomingItems);
+  do_check_false(scheduler.hasIncomingItems);
   const INTERVAL = 10000000;
-  SyncScheduler.syncInterval = INTERVAL;
+  scheduler.syncInterval = INTERVAL;
 
   Svc.Obs.notify("weave:service:sync:applied", {
     applied: 2,
     succeeded: 0,
     failed: 2,
     newFailed: 2,
     reconciled: 0
   });
 
   Utils.nextTick(function() {
-    SyncScheduler.adjustSyncInterval();
-    do_check_false(SyncScheduler.hasIncomingItems);
-    do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
+    scheduler.adjustSyncInterval();
+    do_check_false(scheduler.hasIncomingItems);
+    do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
 
     run_next_test();
   });
 });