Bug 668622 - Move sync at startup logic (autoConnect, etc.) to SyncScheduler. r=philikon
authorMarina Samuel <msamuel@mozilla.com>
Thu, 21 Jul 2011 12:20:55 -0700
changeset 73363 e02f888137e5b1e91a129d076d77399c2b0c1477
parent 73362 6f062884563c79f2fa6e3783bbd79d5910d360fb
child 73364 7648521ecb5aca73b583cdd1a4727b68e35df173
push id20854
push userpweitershausen@mozilla.com
push dateTue, 26 Jul 2011 23:28:18 +0000
treeherdermozilla-central@548d1cc025f2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersphilikon
bugs668622
milestone8.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 668622 - Move sync at startup logic (autoConnect, etc.) to SyncScheduler. r=philikon
browser/components/nsBrowserGlue.js
services/sync/modules/main.js
services/sync/modules/policies.js
services/sync/modules/service.js
services/sync/tests/unit/test_syncscheduler.js
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -146,19 +146,18 @@ BrowserGlue.prototype = {
     const MAX_DELAY = 300;
     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;
 
-    let syncTemp = {};
-    Cu.import("resource://services-sync/service.js", syncTemp);
-    syncTemp.Weave.Service.delayedAutoConnect(delay);
+    Cu.import("resource://services-sync/main.js");
+    Weave.SyncScheduler.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
@@ -47,16 +47,17 @@ let lazies = {
   "engines/forms.js":     ["FormEngine"],
   "engines/history.js":   ["HistoryEngine"],
   "engines/prefs.js":     ["PrefsEngine"],
   "engines/passwords.js": ["PasswordEngine"],
   "engines/tabs.js":      ["TabEngine"],
   "identity.js":          ["Identity", "ID"],
   "jpakeclient.js":       ["JPAKEClient"],
   "notifications.js":     ["Notifications", "Notification", "NotificationButton"],
+  "policies.js":          ["SyncScheduler"],
   "resource.js":          ["Resource", "AsyncResource", "Auth",
                            "BasicAuthenticator", "NoOpAuthenticator"],
   "service.js":           ["Service"],
   "status.js":            ["Status"],
   "util.js":              ['Utils', 'Svc', 'Str']
 };
 
 function lazyImport(module, dest, props) {
--- a/services/sync/modules/policies.js
+++ b/services/sync/modules/policies.js
@@ -87,16 +87,17 @@ let SyncScheduler = {
     Svc.Obs.add("network:offline-status-changed", this);
     Svc.Obs.add("weave:service:sync:start", this);
     Svc.Obs.add("weave:service:sync:finish", this);
     Svc.Obs.add("weave:engine:sync:finish", this);
     Svc.Obs.add("weave:service:login:error", this);
     Svc.Obs.add("weave:service:logout:finish", this);
     Svc.Obs.add("weave:service:sync:error", this);
     Svc.Obs.add("weave:service:backoff:interval", this);
+    Svc.Obs.add("weave:service:ready", this);
     Svc.Obs.add("weave:engine:sync:applied", this);
     Svc.Idle.addIdleObserver(this, Svc.Prefs.get("scheduler.idleTime"));
   },
 
   observe: function observe(subject, topic, data) {
     switch(topic) {
       case "weave:engine:score:updated":
         Utils.namedTimer(this.calculateScore, SCORE_UPDATE_DELAY, this,
@@ -156,16 +157,24 @@ let SyncScheduler = {
         this.adjustSyncInterval();
         this.handleSyncError();
         break;
       case "weave:service:backoff:interval":
         let interval = (data + Math.random() * data * 0.25) * 1000; // required backoff + up to 25%
         Status.backoffInterval = interval;
         Status.minimumNextSync = Date.now() + data;
         break;
+      case "weave:service:ready":
+        // Applications can specify this preference if they want autoconnect
+        // to happen after a fixed delay.
+        let delay = Svc.Prefs.get("autoconnectDelay");
+        if (delay) {
+          this.delayedAutoConnect(delay);
+        }
+        break;
       case "weave:engine:sync:applied":
         let numItems = subject.applied;
         this._log.trace("Engine " + data + " applied " + numItems + " items.");
         if (numItems) 
           this.hasIncomingItems = true;
         break;
       case "idle":
         this._log.trace("We're idle.");
@@ -325,16 +334,41 @@ let SyncScheduler = {
       interval = Math.max(minimumInterval, interval);
 
     let d = new Date(Date.now() + interval);
     this._log.config("Starting backoff, next sync at:" + d.toString());
 
     this.scheduleNextSync(interval);
   },
 
+ /**
+  * 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) {
+      Utils.namedTimer(this.autoConnect, delay * 1000, this, "_autoTimer");
+    }
+  },
+
+  autoConnect: function autoConnect() {
+    if (Weave.Service._checkSetup() == STATUS_OK && !Weave.Service._checkSync()) {
+      Utils.nextTick(Weave.Service.sync, Weave.Service);
+    }
+
+    // Once autoConnect is called we no longer need _autoTimer.
+    if (this._autoTimer) {
+      this._autoTimer.clear();
+    }
+  },
+
   _syncErrors: 0,
   /**
    * Deal with sync errors appropriately
    */
   handleSyncError: function handleSyncError() {
     this._syncErrors++;
 
     // Do nothing on the first couple of failures, if we're not in
--- a/services/sync/modules/service.js
+++ b/services/sync/modules/service.js
@@ -404,23 +404,16 @@ WeaveSvc.prototype = {
              new SyncKeyBundle(PWDMGR_PASSPHRASE_REALM, this.username));
 
     this._updateCachedURLs();
 
     let status = this._checkSetup();
     if (status != STATUS_DISABLED && status != CLIENT_NOT_CONFIGURED)
       Svc.Obs.notify("weave:engine:start-tracking");
 
-    // Applications can specify this preference if they want autoconnect
-    // to happen after a fixed delay.
-    let delay = Svc.Prefs.get("autoconnectDelay");
-    if (delay) {
-      this.delayedAutoConnect(delay);
-    }
-
     // Send an event now that Weave service is ready.  We don't do this
     // synchronously so that observers can import this module before
     // registering an observer.
     Utils.nextTick(function() {
       Status.ready = true;
       Svc.Obs.notify("weave:service:ready");
     });
   },
@@ -1038,41 +1031,16 @@ WeaveSvc.prototype = {
     // Find weave logins and remove them.
     this.password = "";
     this.passphrase = "";
     Services.logins.findLogins({}, PWDMGR_HOST, "", "").map(function(login) {
       Services.logins.removeLogin(login);
     });
   },
 
- /**
-  * 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 (this._checkSetup() == STATUS_OK) {
-      Utils.namedTimer(this._autoConnect, delay * 1000, this, "_autoTimer");
-    }
-  },
-
-  _autoConnect: function _autoConnect() {
-    if (this._checkSetup() == STATUS_OK && !this._checkSync()) {
-      Utils.nextTick(this.sync, this);
-    }
-
-    // Once _autoConnect is called we no longer need _autoTimer.
-    if (this._autoTimer) {
-      this._autoTimer.clear();
-    }
-  },
-
   persistLogin: function persistLogin() {
     // Canceled master password prompt can prevent these from succeeding.
     try {
       ID.get("WeaveID").persist();
       ID.get("WeaveCryptoID").persist();
     }
     catch(ex) {}
   },
--- a/services/sync/tests/unit/test_syncscheduler.js
+++ b/services/sync/tests/unit/test_syncscheduler.js
@@ -338,17 +338,17 @@ add_test(function test_autoconnect() {
 
     Service.startOver();
     server.stop(run_next_test);
   });
 
   let server = sync_httpd_setup();
   setUp();
 
-  Service.delayedAutoConnect(0);
+  SyncScheduler.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;
@@ -371,17 +371,17 @@ add_test(function test_autoconnect_mp_lo
       delete Service.passphrase;
       Service.__defineGetter__("passphrase", origPP);
 
       Service.startOver();
       server.stop(run_next_test);
     });
   });
 
-  Service.delayedAutoConnect(0);
+  SyncScheduler.delayedAutoConnect(0);
 });
 
 let timer;
 add_test(function test_no_autoconnect_during_wizard() {
   let server = sync_httpd_setup();
   setUp();
 
   // Simulate the Sync setup wizard.
@@ -390,32 +390,84 @@ add_test(function test_no_autoconnect_du
   // 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);
 
   // First wait >100ms (nsITimers can take up to that much time to fire, so
   // we can account for the timer in delayedAutoconnect) and then two event
-  // loop ticks (to account for the Utils.nextTick() in _autoConnect).
+  // loop ticks (to account for the Utils.nextTick() in autoConnect).
   let ticks = 2;
   function wait() {
     if (ticks) {
       ticks -= 1;
       Utils.nextTick(wait);
       return;
     }
     Svc.Obs.remove("weave:service:login:start", onLoginStart);
 
     Service.startOver();
     server.stop(run_next_test);    
   }
   timer = Utils.namedTimer(wait, 150, {}, "timer");
 
-  Service.delayedAutoConnect(0);
+  SyncScheduler.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!");
+  }
+  Svc.Obs.add("weave:service:login:start", onLoginStart);
+
+  // First wait >100ms (nsITimers can take up to that much time to fire, so
+  // we can account for the timer in delayedAutoconnect) and then two event
+  // loop ticks (to account for the Utils.nextTick() in autoConnect).
+  let ticks = 2;
+  function wait() {
+    if (ticks) {
+      ticks -= 1;
+      Utils.nextTick(wait);
+      return;
+    }
+    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);
+    
+    Service.startOver();
+    server.stop(run_next_test); 
+  }
+  timer = Utils.namedTimer(wait, 150, {}, "timer");
+
+  SyncScheduler.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);
+
+    Service.startOver();
+    server.stop(run_next_test);
+  });
+
+  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(Status.service, STATUS_OK);
 });
 
 add_test(function test_idle_adjustSyncInterval() {
   // Confirm defaults.
   do_check_eq(SyncScheduler.idle, false);
 
   // Single device: nothing changes.
   SyncScheduler.observe(null, "idle", Svc.Prefs.get("scheduler.idleTime"));