Bug 966434 - Update TPS to use FxA. r=jgriffin
authorHenrik Skupin <mail@hskupin.info>
Fri, 07 Mar 2014 15:54:19 -0800
changeset 190841 947e70a10659166d942fda62145d903c50f56a2d
parent 190840 f80cd801c0e379d749c795c5bf912954ee574d6c
child 190842 41877be6d704f67e60158675e776679dc27ce746
push id474
push userasasaki@mozilla.com
push dateMon, 02 Jun 2014 21:01:02 +0000
treeherdermozilla-release@967f4cf1b31c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjgriffin
bugs966434
milestone30.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 966434 - Update TPS to use FxA. r=jgriffin
services/sync/modules/service.js
services/sync/tps/extensions/tps/modules/fxaccounts.jsm
services/sync/tps/extensions/tps/modules/sync.jsm
services/sync/tps/extensions/tps/modules/tps.jsm
testing/tps/config/config.json.in
testing/tps/tps/testrunner.py
--- a/services/sync/modules/service.js
+++ b/services/sync/modules/service.js
@@ -770,30 +770,30 @@ Sync11Service.prototype = {
 
     if (info.status != 200) {
       this._log.warn("Non-200 info/collections response. Aborting.");
       throw new Error("Unable to upload symmetric keys.");
     }
 
     info = info.obj;
     if (!(CRYPTO_COLLECTION in info)) {
-      this._log.error("Consistency failure: info/collections excludes " + 
+      this._log.error("Consistency failure: info/collections excludes " +
                       "crypto after successful upload.");
       throw new Error("Symmetric key upload failed.");
     }
 
     // Can't check against local modified: clock drift.
     if (info[CRYPTO_COLLECTION] < serverModified) {
-      this._log.error("Consistency failure: info/collections crypto entry " + 
+      this._log.error("Consistency failure: info/collections crypto entry " +
                       "is stale after successful upload.");
       throw new Error("Symmetric key upload failed.");
     }
-    
+
     // Doesn't matter if the timestamp is ahead.
-    
+
     // Download and install them.
     let cryptoKeys = new CryptoWrapper(CRYPTO_COLLECTION, KEYS_WBO);
     let cryptoResp = cryptoKeys.fetch(this.resource(this.cryptoKeysURL)).response;
     if (cryptoResp.status != 200) {
       this._log.warn("Failed to download keys.");
       throw new Error("Symmetric key download failed.");
     }
     let keysChanged = this.handleFetchedKeys(this.identity.syncKeyBundle,
new file mode 100644
--- /dev/null
+++ b/services/sync/tps/extensions/tps/modules/fxaccounts.jsm
@@ -0,0 +1,57 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = [
+  "FxAccountsHelper",
+];
+
+const { utils: Cu } = Components;
+
+Cu.import("resource://gre/modules/FxAccountsClient.jsm");
+Cu.import("resource://services-common/async.js");
+Cu.import("resource://services-sync/main.js");
+Cu.import("resource://tps/logger.jsm");
+
+
+/**
+ * Helper object for Firefox Accounts authentication
+ */
+var FxAccountsHelper = {
+
+  /**
+   * Wrapper to synchronize the login of a user
+   *
+   * @param email
+   *        The email address for the account (utf8)
+   * @param password
+   *        The user's password
+   */
+  signIn: function signIn(email, password) {
+    let cb = Async.makeSpinningCallback();
+
+    var client = new FxAccountsClient();
+    client.signIn(email, password).then(credentials => {
+      // Add keys because without those setSignedInUser() will fail
+      credentials.kA = 'foo';
+      credentials.kB = 'bar';
+
+      Weave.Service.identity._fxaService.setSignedInUser(credentials).then(() => {
+        cb(null);
+      }, err => {
+        cb(err);
+      });
+    }, (err) => {
+      cb(err);
+    });
+
+    try {
+      cb.wait();
+    } catch (err) {
+      Logger.logError("signIn() failed with: " + JSON.stringify(err));
+      throw err;
+    }
+  }
+};
--- a/services/sync/tps/extensions/tps/modules/sync.jsm
+++ b/services/sync/tps/extensions/tps/modules/sync.jsm
@@ -64,16 +64,17 @@ var TPS = {
   SetupSyncAccount: function TPS__SetupSyncAccount() {
     try {
       let serverURL = prefs.getCharPref('tps.account.serverURL');
       if (serverURL) {
         Weave.Service.serverURL = serverURL;
       }
     }
     catch(e) {}
+
     Weave.Service.identity.account       = prefs.getCharPref('tps.account.username');
     Weave.Service.Identity.basicPassword = prefs.getCharPref('tps.account.password');
     Weave.Service.identity.syncKey       = prefs.getCharPref('tps.account.passphrase');
     Weave.Svc.Obs.notify("weave:service:setup-complete");
   },
 
   Sync: function TPS__Sync(options) {
     Logger.logInfo('Mozmill starting sync operation: ' + options);
--- a/services/sync/tps/extensions/tps/modules/tps.jsm
+++ b/services/sync/tps/extensions/tps/modules/tps.jsm
@@ -18,16 +18,17 @@ CU.import("resource://services-sync/cons
 CU.import("resource://services-sync/main.js");
 CU.import("resource://services-sync/util.js");
 CU.import("resource://tps/addons.jsm");
 CU.import("resource://tps/bookmarks.jsm");
 CU.import("resource://tps/logger.jsm");
 CU.import("resource://tps/passwords.jsm");
 CU.import("resource://tps/history.jsm");
 CU.import("resource://tps/forms.jsm");
+CU.import("resource://tps/fxaccounts.jsm");
 CU.import("resource://tps/prefs.jsm");
 CU.import("resource://tps/tabs.jsm");
 CU.import("resource://tps/windows.jsm");
 
 var hh = CC["@mozilla.org/network/protocol;1?name=http"]
          .getService(CI.nsIHttpProtocolHandler);
 var prefs = CC["@mozilla.org/preferences-service;1"]
             .getService(CI.nsIPrefBranch);
@@ -52,30 +53,34 @@ const ACTIONS = [ACTION_ADD, ACTION_VERI
                  ACTION_WIPE_SERVER, ACTION_SET_ENABLED];
 
 const SYNC_WIPE_CLIENT  = "wipe-client";
 const SYNC_WIPE_REMOTE  = "wipe-remote";
 const SYNC_WIPE_SERVER  = "wipe-server";
 const SYNC_RESET_CLIENT = "reset-client";
 const SYNC_START_OVER   = "start-over";
 
-const OBSERVER_TOPICS = ["weave:engine:start-tracking",
+const OBSERVER_TOPICS = ["fxaccounts:onlogin",
+                         "fxaccounts:onlogout",
+                         "weave:engine:start-tracking",
                          "weave:engine:stop-tracking",
+                         "weave:service:setup-complete",
                          "weave:service:sync:finish",
                          "weave:service:sync:error",
                          "sessionstore-windows-restored",
                          "private-browsing"];
 
 let TPS = {
   _waitingForSync: false,
   _isTracking: false,
   _test: null,
   _currentAction: -1,
   _currentPhase: -1,
   _errors: 0,
+  _setupComplete: false,
   _syncErrors: 0,
   _usSinceEpoch: 0,
   _tabsAdded: 0,
   _tabsFinished: 0,
   _phaselist: {},
   _operations_pending: 0,
   _loggedIn: false,
   _enabledEngines: null,
@@ -91,31 +96,44 @@ let TPS = {
 
   observe: function TPS__observe(subject, topic, data) {
     try {
       Logger.logInfo("----------event observed: " + topic);
       switch(topic) {
         case "private-browsing":
           Logger.logInfo("private browsing " + data);
           break;
+
+        case "fxaccounts:onlogin":
+          this._loggedIn = true;
+          break;
+
+        case "fxaccounts:onlogout":
+          this._loggedIn = false;
+          break;
+
         case "weave:service:sync:error":
           if (this._waitingForSync && this._syncErrors == 0) {
             // if this is the first sync error, retry...
             Logger.logInfo("sync error; retrying...");
             this._syncErrors++;
             this._waitingForSync = false;
             Utils.nextTick(this.RunNextTestAction, this);
           }
           else if (this._waitingForSync) {
             // ...otherwise abort the test
             this.DumpError("sync error; aborting test");
             return;
           }
           break;
 
+        case "weave:service:setup-complete":
+          this._setupComplete = true;
+          break;
+
         case "weave:service:sync:finish":
           if (this._waitingForSync) {
             this._syncErrors = 0;
             this._waitingForSync = false;
             // Wait a second before continuing, otherwise we can get
             // 'sync not complete' errors.
             Utils.namedTimer(function() {
               this.FinishAsyncOperation();
@@ -606,23 +624,23 @@ let TPS = {
 
       // Wipe the server at the end of the final test phase.
       if (currentPhase >= Object.keys(this.phases).length) {
         this_phase.push([this.WipeServer]);
       }
 
       // Store account details as prefs so they're accessible to the mozmill
       // framework.
-      prefs.setCharPref('tps.account.username', this.config.account.username);
-      prefs.setCharPref('tps.account.password', this.config.account.password);
-      prefs.setCharPref('tps.account.passphrase', this.config.account.passphrase);
-      if (this.config.account['serverURL']) {
-        prefs.setCharPref('tps.account.serverURL', this.config.account.serverURL);
+      prefs.setCharPref('tps.account.username', this.config.fx_account.username);
+      prefs.setCharPref('tps.account.password', this.config.fx_account.password);
+      // old sync
+      // prefs.setCharPref('tps.account.passphrase', this.config.fx_account.passphrase);
+      if (this.config["serverURL"]) {
+        prefs.setCharPref('tps.account.serverURL', this.config.serverURL);
       }
-
       // start processing the test actions
       this._currentAction = 0;
     }
     catch(e) {
       this.DumpError("Exception caught: " + Utils.exceptionStr(e));
       return;
     }
   },
@@ -699,16 +717,43 @@ let TPS = {
     Svc.Obs.remove(name, cb);
     Logger.logInfo(name + " observed!");
 
     let cb = Async.makeSpinningCallback();
     Utils.nextTick(cb);
     cb.wait();
   },
 
+
+  /**
+   * Waits for Sync to logged in before returning
+   */
+  waitForLoggedIn: function waitForLoggedIn() {
+    if (!this._loggedIn) {
+      this.waitForEvent("fxaccount:onlogin");
+    }
+
+    let cb = Async.makeSyncCallback();
+    Utils.nextTick(cb);
+    Async.waitForSyncCallback(cb);
+  },
+
+  /**
+   * Waits for Sync to logged in before returning
+   */
+  waitForSetupComplete: function waitForSetup() {
+    if (!this._setupComplete) {
+      this.waitForEvent("weave:service:setup-complete");
+    }
+
+    let cb = Async.makeSyncCallback();
+    Utils.nextTick(cb);
+    Async.waitForSyncCallback(cb);
+  },
+
   /**
    * Waits for Sync to start tracking before returning.
    */
   waitForTracking: function waitForTracking() {
     if (!this._isTracking) {
       this.waitForEvent("weave:engine:start-tracking");
     }
 
@@ -741,54 +786,47 @@ let TPS = {
     this.waitForTracking();
   },
 
   Login: function Login(force) {
     if (this._loggedIn && !force) {
       return;
     }
 
-    let account = this.config.account;
+    // old sync: have to add handling for this.config.sync_account
+    let account = this.config.fx_account;
+
     if (!account) {
       this.DumperError("No account information found! Did you use a valid " +
                        "config file?");
       return;
     }
 
-    if (account["serverURL"]) {
-      Weave.Service.serverURL = account["serverURL"];
+    if (this.config["serverURL"]) {
+      Weave.Service.serverURL = this.config.serverURL;
     }
 
     Logger.logInfo("Setting client credentials.");
-    if (account["admin-secret"]) {
-      // if admin-secret is specified, we'll dynamically create
-      // a new sync account
-      Weave.Svc.Prefs.set("admin-secret", account["admin-secret"]);
-      let suffix = account["account-suffix"];
-      Weave.Service.identity.account = "tps" + suffix + "@mozilla.com";
-      Weave.Service.identity.basicPassword = "tps" + suffix + "tps" + suffix;
-      Weave.Service.identity.syncKey = Weave.Utils.generatePassphrase();
-      Weave.Service.createAccount(Weave.Service.identity.account,
-                            Weave.Service.identity.basicPassword,
-                            "dummy1", "dummy2");
-    } else if (account["username"] && account["password"] &&
-               account["passphrase"]) {
-      Weave.Service.identity.account = account["username"];
-      Weave.Service.identity.basicPassword = account["password"];
-      Weave.Service.identity.syncKey = account["passphrase"];
+    if (account["username"] && account["password"]) { // && account["passphrase"]) {
+      FxAccountsHelper.signIn(account["username"], account["password"]);
+      this.waitForSetupComplete();
+
+      // Old sync code - has to be reactivated later for fallback
+      //Weave.Service.identity.account = account["username"];
+      //Weave.Service.identity.basicPassword = account["password"];
+      //Weave.Service.identity.syncKey = account["passphrase"];
     } else {
-      this.DumpError("Must specify admin-secret, or " +
-                     "username/password/passphrase in the config file");
+      this.DumpError("Must specify username/password in the config file");
       return;
     }
 
-    Weave.Service.login();
-    Logger.AssertEqual(Weave.Status.service, Weave.STATUS_OK, "Weave status not OK");
-    Weave.Svc.Obs.notify("weave:service:setup-complete");
-    this._loggedIn = true;
+    //Weave.Service.login();
+    //this._loggedIn = true;
+    //Weave.Svc.Obs.notify("weave:service:setup-complete");
+    Logger.AssertEqual(Weave.Status.service, Weave.STATUS_OK, "Weave status OK");
 
     this.waitForTracking();
   },
 
   Sync: function TPS__Sync(options) {
     Logger.logInfo("executing Sync " + (options ? options : ""));
 
     if (options == SYNC_WIPE_REMOTE) {
--- a/testing/tps/config/config.json.in
+++ b/testing/tps/config/config.json.in
@@ -1,25 +1,23 @@
-{ 
-  "account": {
-    "serverURL": "",
-    "admin-secret": "",
-    "username": "crossweaveservices@mozilla.com",
-    "password": "crossweaveservicescrossweaveservices",
-    "passphrase": "r-jwcbc-zgf42-fjn72-p5vpp-iypmi"
-  },
-  "resultstore": {
-    "host": "brasstacks.mozilla.com",
-    "path": "/resultserv/post/"
-  },
-  "email": {
-    "username": "crossweave@mozilla.com",
-    "password": "",
-    "passednotificationlist": ["crossweave@mozilla.com"],
-    "notificationlist": ["crossweave@mozilla.com"]
-  },
-  "platform": "win32",
-  "os": "win7",
-  "es": "localhost:9200",
-  "testdir": "__TESTDIR__",
-  "extensiondir": "__EXTENSIONDIR__"
-}
-
+{
+  "sync_account": {
+    "username": "crossweaveservices@mozilla.com",
+    "password": "crossweaveservicescrossweaveservices",
+    "passphrase": "r-jwcbc-zgf42-fjn72-p5vpp-iypmi"
+  },
+  "fx_account": {
+    "username": "crossweaveservices@restmail.net",
+    "password": "crossweaveservicescrossweaveservices"
+  },
+  "email": {
+    "username": "crossweave@mozilla.com",
+    "password": "",
+    "passednotificationlist": ["crossweave@mozilla.com"],
+    "notificationlist": ["crossweave@mozilla.com"]
+  },
+  "platform": "win32",
+  "os": "win7",
+  "es": "localhost:9200",
+  "serverURL": null,
+  "testdir": "__TESTDIR__",
+  "extensiondir": "__EXTENSIONDIR__"
+}
--- a/testing/tps/tps/testrunner.py
+++ b/testing/tps/tps/testrunner.py
@@ -166,19 +166,19 @@ class TPSTestRunner(object):
                 zip.write(os.path.join(root, f), os.path.join(dir, f))
 
     def run_single_test(self, testdir, testname):
         testpath = os.path.join(testdir, testname)
         self.log("Running test %s\n" % testname)
 
         # Create a random account suffix that is used when creating test
         # accounts on a staging server.
-        account_suffix = {"account-suffix": ''.join([str(random.randint(0,9))
-                                                     for i in range(1,6)])}
-        self.config['account'].update(account_suffix)
+        #account_suffix = {"account-suffix": ''.join([str(random.randint(0,9))
+        #                                             for i in range(1,6)])}
+        #self.config['sync_account'].update(account_suffix)
 
         # Read and parse the test file, merge it with the contents of the config
         # file, and write the combined output to a temporary file.
         f = open(testpath, 'r')
         testcontent = f.read()
         f.close()
         try:
             test = json.loads(testcontent)