Bug 792546 - Part 4: Move utility functions to testing-only JS module; r=rnewman
authorGregory Szorc <gps@mozilla.com>
Mon, 24 Sep 2012 13:45:49 -0700
changeset 111095 b85f209e6072102cb17c1841de1f956ee9f6a326
parent 111094 6fc02deb63dad3f73af99b488db40bf2dccb5880
child 111096 4a49a6f54e2304a1af2c740b0642b9e42c1aabfe
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersrnewman
bugs792546
milestone18.0a1
Bug 792546 - Part 4: Move utility functions to testing-only JS module; r=rnewman
services/sync/Makefile.in
services/sync/modules-testing/utils.js
services/sync/tests/unit/head_helpers.js
services/sync/tests/unit/head_http_server.js
services/sync/tests/unit/test_addons_engine.js
services/sync/tests/unit/test_bookmark_engine.js
services/sync/tests/unit/test_bookmark_smart_bookmarks.js
services/sync/tests/unit/test_clients_engine.js
services/sync/tests/unit/test_collections_recovery.js
services/sync/tests/unit/test_corrupt_keys.js
services/sync/tests/unit/test_engine_abort.js
services/sync/tests/unit/test_errorhandler.js
services/sync/tests/unit/test_errorhandler_sync_checkServerError.js
services/sync/tests/unit/test_history_engine.js
services/sync/tests/unit/test_hmac_error.js
services/sync/tests/unit/test_interval_triggers.js
services/sync/tests/unit/test_jpakeclient.js
services/sync/tests/unit/test_load_modules.js
services/sync/tests/unit/test_node_reassignment.js
services/sync/tests/unit/test_resource_ua.js
services/sync/tests/unit/test_score_triggers.js
services/sync/tests/unit/test_sendcredentials_controller.js
services/sync/tests/unit/test_service_attributes.js
services/sync/tests/unit/test_service_changePassword.js
services/sync/tests/unit/test_service_checkAccount.js
services/sync/tests/unit/test_service_cluster.js
services/sync/tests/unit/test_service_createAccount.js
services/sync/tests/unit/test_service_detect_upgrade.js
services/sync/tests/unit/test_service_getStorageInfo.js
services/sync/tests/unit/test_service_login.js
services/sync/tests/unit/test_service_passwordUTF8.js
services/sync/tests/unit/test_service_persistLogin.js
services/sync/tests/unit/test_service_startOver.js
services/sync/tests/unit/test_service_startup.js
services/sync/tests/unit/test_service_sync_401.js
services/sync/tests/unit/test_service_sync_remoteSetup.js
services/sync/tests/unit/test_service_sync_updateEnabledEngines.js
services/sync/tests/unit/test_service_verifyLogin.js
services/sync/tests/unit/test_service_wipeClient.js
services/sync/tests/unit/test_service_wipeServer.js
services/sync/tests/unit/test_syncengine.js
services/sync/tests/unit/test_syncengine_sync.js
services/sync/tests/unit/test_syncscheduler.js
services/sync/tests/unit/test_syncstoragerequest.js
services/sync/tests/unit/test_upgrade_old_sync_key.js
--- a/services/sync/Makefile.in
+++ b/services/sync/Makefile.in
@@ -60,16 +60,17 @@ sync_engine_modules := \
 sync_stage_modules := \
   cluster.js \
   enginesync.js \
   $(NULL)
 
 sync_testing_modules := \
   fakeservices.js \
   rotaryengine.js \
+  utils.js \
   $(NULL)
 
 DIRS += locales
 TEST_DIRS += tests
 
 EXTRA_COMPONENTS := \
   SyncComponents.manifest \
   Weave.js \
new file mode 100644
--- /dev/null
+++ b/services/sync/modules-testing/utils.js
@@ -0,0 +1,87 @@
+/* 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";
+
+const EXPORTED_SYMBOLS = [
+  "TEST_CLUSTER_URL",
+  "TEST_SERVER_URL",
+  "btoa", // It comes from a module import.
+  "encryptPayload",
+  "setBasicCredentials",
+  "SyncTestingInfrastructure",
+  "waitForZeroTimer",
+];
+
+const {utils: Cu} = Components;
+
+Cu.import("resource://services-common/utils.js");
+Cu.import("resource://services-crypto/utils.js");
+Cu.import("resource://testing-common/services-common/logging.js");
+Cu.import("resource://testing-common/services/sync/fakeservices.js");
+
+const TEST_SERVER_URL = "http://localhost:8080/";
+const TEST_CLUSTER_URL = TEST_SERVER_URL;
+
+/**
+ * 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).
+ */
+function waitForZeroTimer(callback) {
+  let ticks = 2;
+  function wait() {
+    if (ticks) {
+      ticks -= 1;
+      CommonUtils.nextTick(wait);
+      return;
+    }
+    callback();
+  }
+  CommonUtils.namedTimer(wait, 150, {}, "timer");
+}
+
+function setBasicCredentials(username, password, syncKey) {
+  let ns = {};
+  Cu.import("resource://services-sync/service.js", ns);
+
+  let auth = ns.Service.identity;
+  auth.username = username;
+  auth.basicPassword = password;
+  auth.syncKey = syncKey;
+}
+
+function SyncTestingInfrastructure(username, password, syncKey) {
+  let ns = {};
+  Cu.import("resource://services-sync/service.js", ns);
+
+  let auth = ns.Service.identity;
+  auth.account = username || "foo";
+  auth.basicPassword = password || "password";
+  auth.syncKey = syncKey || "foo";
+
+  ns.Service.serverURL = TEST_SERVER_URL;
+  ns.Service.clusterURL = TEST_CLUSTER_URL;
+
+  this.logStats = initTestLogging();
+  this.fakeFilesystem = new FakeFilesystemService({});
+  this.fakeGUIDService = new FakeGUIDService();
+  this.fakeCryptoService = new FakeCryptoService();
+}
+
+/**
+ * Turn WBO cleartext into fake "encrypted" payload as it goes over the wire.
+ */
+function encryptPayload(cleartext) {
+  if (typeof cleartext == "object") {
+    cleartext = JSON.stringify(cleartext);
+  }
+
+  return {
+    ciphertext: cleartext, // ciphertext == cleartext with fake crypto
+    IV: "irrelevant",
+    hmac: fakeSHA256HMAC(cleartext, CryptoUtils.makeHMACKey("")),
+  };
+}
+
--- a/services/sync/tests/unit/head_helpers.js
+++ b/services/sync/tests/unit/head_helpers.js
@@ -1,55 +1,31 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 Cu.import("resource://services-common/utils.js");
 Cu.import("resource://services-common/async.js");
 Cu.import("resource://services-sync/util.js");
 Cu.import("resource://services-sync/record.js");
 Cu.import("resource://services-sync/engines.js");
-Cu.import("resource://testing-common/services/sync/fakeservices.js");
-
-let btoa;
-let atob;
 
 let provider = {
   getFile: function(prop, persistent) {
     persistent.value = true;
     switch (prop) {
       case "ExtPrefDL":
         return [Services.dirsvc.get("CurProcD", Ci.nsIFile)];
       default:
         throw Cr.NS_ERROR_FAILURE;
     }
   },
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIDirectoryServiceProvider])
 };
 Services.dirsvc.QueryInterface(Ci.nsIDirectoryService).registerProvider(provider);
 
-let timer;
-function waitForZeroTimer(callback) {
-  // 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;
-    }
-    callback();
-  }
-  timer = Utils.namedTimer(wait, 150, {}, "timer");
-}
-
-btoa = Cu.import("resource://services-common/log4moz.js").btoa;
-atob = Cu.import("resource://services-common/log4moz.js").atob;
-
 // This is needed for loadAddonTestFunctions().
 let gGlobalScope = this;
 
 function ExtensionsTestPath(path) {
   if (path[0] != "/") {
     throw Error("Path must begin with '/': " + path);
   }
 
@@ -141,60 +117,23 @@ function uninstallAddon(addon) {
     }
   }};
 
   AddonManager.addAddonListener(listener);
   addon.uninstall();
   Async.waitForSyncCallback(cb);
 }
 
-function setBasicCredentials(username, password, syncKey) {
-  let ns = {};
-  Cu.import("resource://services-sync/service.js", ns);
 
-  let auth = ns.Service.identity;
-  auth.username = username;
-  auth.basicPassword = password;
-  auth.syncKey = syncKey;
-}
-
-function SyncTestingInfrastructure(username, password, syncKey) {
-  let ns = {};
-  Cu.import("resource://services-sync/service.js", ns);
-
-  let auth = ns.Service.identity;
-  auth.account = username || "foo";
-  auth.basicPassword = password || "password";
-  auth.syncKey = syncKey || "foo";
-
-  ns.Service.serverURL = TEST_SERVER_URL;
-  ns.Service.clusterURL = TEST_CLUSTER_URL;
-
-  this.logStats = initTestLogging();
-  this.fakeFilesystem = new FakeFilesystemService({});
-  this.fakeGUIDService = new FakeGUIDService();
-  this.fakeCryptoService = new FakeCryptoService();
-}
 
 _("Setting the identity for passphrase");
 Cu.import("resource://services-sync/identity.js");
 
 /*
  * Test setup helpers.
  */
 
-// Turn WBO cleartext into fake "encrypted" payload as it goes over the wire.
-function encryptPayload(cleartext) {
-  if (typeof cleartext == "object") {
-    cleartext = JSON.stringify(cleartext);
-  }
-
-  return {ciphertext: cleartext, // ciphertext == cleartext with fake crypto
-          IV: "irrelevant",
-          hmac: fakeSHA256HMAC(cleartext, Utils.makeHMACKey(""))};
-}
-
 function generateNewKeys(collectionKeys, collections=null) {
   let wbo = collectionKeys.generateNewKeysWBO(collections);
   let modified = new_timestamp();
   collectionKeys.setContents(wbo.cleartext, modified);
 }
 
--- a/services/sync/tests/unit/head_http_server.js
+++ b/services/sync/tests/unit/head_http_server.js
@@ -1,13 +1,10 @@
 const Cm = Components.manager;
 
-const TEST_CLUSTER_URL = "http://localhost:8080/";
-const TEST_SERVER_URL  = "http://localhost:8080/";
-
 // Shared logging for all HTTP server functions.
 Cu.import("resource://services-common/log4moz.js");
 const SYNC_HTTP_LOGGER = "Sync.Test.Server";
 const SYNC_API_VERSION = "1.1";
 
 // Use the same method that record.js does, which mirrors the server.
 // The server returns timestamps with 1/100 sec granularity. Note that this is
 // subject to change: see Bug 650435.
--- a/services/sync/tests/unit/test_addons_engine.js
+++ b/services/sync/tests/unit/test_addons_engine.js
@@ -5,16 +5,17 @@
 
 Cu.import("resource://gre/modules/AddonManager.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://services-common/async.js");
 Cu.import("resource://services-common/preferences.js");
 Cu.import("resource://services-sync/addonsreconciler.js");
 Cu.import("resource://services-sync/engines/addons.js");
 Cu.import("resource://services-sync/service.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
 
 let prefs = new Preferences();
 prefs.set("extensions.getAddons.get.url",
           "http://localhost:8888/search/guid:%IDS%");
 
 loadAddonTestFunctions();
 startupManager();
 
--- a/services/sync/tests/unit/test_bookmark_engine.js
+++ b/services/sync/tests/unit/test_bookmark_engine.js
@@ -3,16 +3,17 @@
 
 Cu.import("resource://gre/modules/PlacesUtils.jsm");
 Cu.import("resource://services-common/async.js");
 Cu.import("resource://services-common/log4moz.js");
 Cu.import("resource://services-sync/engines.js");
 Cu.import("resource://services-sync/engines/bookmarks.js");
 Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/util.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
 
 Service.engineManager.register(BookmarksEngine);
 var syncTesting = new SyncTestingInfrastructure();
 
 add_test(function bad_record_allIDs() {
   let syncTesting = new SyncTestingInfrastructure();
 
   _("Ensure that bad Places queries don't cause an error in getAllIDs.");
--- a/services/sync/tests/unit/test_bookmark_smart_bookmarks.js
+++ b/services/sync/tests/unit/test_bookmark_smart_bookmarks.js
@@ -2,16 +2,17 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 Cu.import("resource://gre/modules/PlacesUtils.jsm");
 Cu.import("resource://services-common/log4moz.js");
 Cu.import("resource://services-sync/engines.js");
 Cu.import("resource://services-sync/engines/bookmarks.js");
 Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/util.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
 
 const SMART_BOOKMARKS_ANNO = "Places/SmartBookmark";
 var IOService = Cc["@mozilla.org/network/io-service;1"]
                 .getService(Ci.nsIIOService);
 ("http://www.mozilla.com", null, null);
 
 
 Service.engineManager.register(BookmarksEngine);
--- a/services/sync/tests/unit/test_clients_engine.js
+++ b/services/sync/tests/unit/test_clients_engine.js
@@ -1,16 +1,17 @@
 /* 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/service.js");
 Cu.import("resource://services-sync/util.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
 
 const MORE_THAN_CLIENTS_TTL_REFRESH = 691200; // 8 days
 const LESS_THAN_CLIENTS_TTL_REFRESH = 86400;  // 1 day
 
 let engine = Service.clientsEngine;
 
 add_test(function test_bad_hmac() {
   _("Ensure that Clients engine deletes corrupt records.");
--- a/services/sync/tests/unit/test_collections_recovery.js
+++ b/services/sync/tests/unit/test_collections_recovery.js
@@ -1,10 +1,14 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
 // Verify that we wipe the server if we have to regenerate keys.
 Cu.import("resource://services-sync/service.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
 
 add_test(function test_missing_crypto_collection() {
   let johnHelper = track_collections_helper();
   let johnU      = johnHelper.with_updated_collection;
   let johnColls  = johnHelper.collections;
 
   let empty = false;
   function maybe_empty(handler) {
--- a/services/sync/tests/unit/test_corrupt_keys.js
+++ b/services/sync/tests/unit/test_corrupt_keys.js
@@ -5,16 +5,17 @@ Cu.import("resource://services-common/lo
 Cu.import("resource://services-sync/constants.js");
 Cu.import("resource://services-sync/engines.js");
 Cu.import("resource://services-sync/engines/tabs.js");
 Cu.import("resource://services-sync/engines/history.js");
 Cu.import("resource://services-sync/record.js");
 Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/status.js");
 Cu.import("resource://services-sync/util.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
 
 add_test(function test_locally_changed_keys() {
   let passphrase = "abcdeabcdeabcdeabcdeabcdea";
 
   let hmacErrorCount = 0;
   function counting(f) {
     return function() {
       hmacErrorCount++;
--- a/services/sync/tests/unit/test_engine_abort.js
+++ b/services/sync/tests/unit/test_engine_abort.js
@@ -1,15 +1,16 @@
 /* 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/util.js");
 Cu.import("resource://testing-common/services/sync/rotaryengine.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
 
 add_test(function test_processIncoming_abort() {
   _("An abort exception, raised in applyIncoming, will abort _processIncoming.");
   new SyncTestingInfrastructure();
   generateNewKeys(Service.collectionKeys);
 
   let engine = new RotaryEngine(Service);
 
--- a/services/sync/tests/unit/test_errorhandler.js
+++ b/services/sync/tests/unit/test_errorhandler.js
@@ -2,16 +2,17 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 Cu.import("resource://services-sync/engines/clients.js");
 Cu.import("resource://services-sync/constants.js");
 Cu.import("resource://services-sync/keys.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://testing-common/services/sync/utils.js");
 
 const TEST_MAINTENANCE_URL = "http://localhost:8080/maintenance/";
 const logsdir = FileUtils.getDir("ProfD", ["weave", "logs"], true);
 const LOG_PREFIX_SUCCESS = "success-";
 const LOG_PREFIX_ERROR   = "error-";
 
 const PROLONGED_ERROR_DURATION =
   (Svc.Prefs.get('errorhandler.networkFailureReportTimeout') * 2) * 1000;
--- a/services/sync/tests/unit/test_errorhandler_sync_checkServerError.js
+++ b/services/sync/tests/unit/test_errorhandler_sync_checkServerError.js
@@ -3,16 +3,18 @@
 
 Cu.import("resource://services-sync/constants.js");
 Cu.import("resource://services-sync/engines.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");
 Cu.import("resource://services-sync/util.js");
+Cu.import("resource://testing-common/services/sync/fakeservices.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
 
 initTestLogging("Trace");
 
 let engineManager = Service.engineManager;
 engineManager.clear();
 
 function CatapultEngine() {
   SyncEngine.call(this, "Catapult", Service);
--- a/services/sync/tests/unit/test_history_engine.js
+++ b/services/sync/tests/unit/test_history_engine.js
@@ -2,16 +2,17 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 Cu.import("resource://services-sync/constants.js");
 Cu.import("resource://services-sync/engines/history.js");
 Cu.import("resource://services-sync/engines.js");
 Cu.import("resource://services-sync/identity.js");
 Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/util.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
 
 Service.engineManager.clear();
 
 add_test(function test_processIncoming_mobile_history_batched() {
   _("SyncEngine._processIncoming works on history engine.");
 
   let FAKE_DOWNLOAD_LIMIT = 100;
 
--- a/services/sync/tests/unit/test_hmac_error.js
+++ b/services/sync/tests/unit/test_hmac_error.js
@@ -1,16 +1,16 @@
 /* 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/util.js");
-
 Cu.import("resource://testing-common/services/sync/rotaryengine.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
 
 // Track HMAC error counts.
 let hmacErrorCount = 0;
 (function () {
   let hHE = Service.handleHMACEvent;
   Service.handleHMACEvent = function () {
     hmacErrorCount++;
     return hHE.call(Service);
--- a/services/sync/tests/unit/test_interval_triggers.js
+++ b/services/sync/tests/unit/test_interval_triggers.js
@@ -1,14 +1,15 @@
 /* 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://testing-common/services/sync/utils.js");
 
 Svc.DefaultPrefs.set("registerEngines", "");
 Cu.import("resource://services-sync/service.js");
 
 let scheduler = Service.scheduler;
 let clientsEngine = Service.clientsEngine;
 
 function sync_httpd_setup() {
--- a/services/sync/tests/unit/test_jpakeclient.js
+++ b/services/sync/tests/unit/test_jpakeclient.js
@@ -1,13 +1,14 @@
 Cu.import("resource://services-common/log4moz.js");
 Cu.import("resource://services-sync/identity.js");
 Cu.import("resource://services-sync/jpakeclient.js");
 Cu.import("resource://services-sync/constants.js");
 Cu.import("resource://services-sync/util.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
 
 const JPAKE_LENGTH_SECRET     = 8;
 const JPAKE_LENGTH_CLIENTID   = 256;
 const KEYEXCHANGE_VERSION     = 3;
 
 /*
  * Simple server.
  */
--- a/services/sync/tests/unit/test_load_modules.js
+++ b/services/sync/tests/unit/test_load_modules.js
@@ -29,16 +29,17 @@ const modules = [
   "status.js",
   "userapi.js",
   "util.js",
 ];
 
 const testingModules = [
   "fakeservices.js",
   "rotaryengine.js",
+  "utils.js",
 ];
 
 function run_test() {
   for (let m of modules) {
     let res = "resource://services-sync/" + m;
     _("Attempting to load " + res);
     Cu.import(res, {});
   }
--- a/services/sync/tests/unit/test_node_reassignment.js
+++ b/services/sync/tests/unit/test_node_reassignment.js
@@ -5,16 +5,17 @@
   "requests.");
 
 Cu.import("resource://services-common/log4moz.js");
 Cu.import("resource://services-common/rest.js");
 Cu.import("resource://services-sync/constants.js");
 Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/status.js");
 Cu.import("resource://testing-common/services/sync/rotaryengine.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
 
 Service.engineManager.clear();
 
 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;
   Log4Moz.repository.getLogger("Sync.RESTRequest").level   = Log4Moz.Level.Trace;
--- a/services/sync/tests/unit/test_resource_ua.js
+++ b/services/sync/tests/unit/test_resource_ua.js
@@ -1,14 +1,15 @@
 /* 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/resource.js");
 Cu.import("resource://services-sync/service.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
 
 const TEST_GET_URL = "http://localhost:8080/1.1/johndoe/storage/meta/global";
 
 function test_resource_user_agent() {
   let meta_global = new ServerWBO('global');
 
   // Tracking info/collections.
   let collectionsHelper = track_collections_helper();
--- a/services/sync/tests/unit/test_score_triggers.js
+++ b/services/sync/tests/unit/test_score_triggers.js
@@ -2,16 +2,17 @@
    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/service.js");
 Cu.import("resource://services-sync/status.js");
 Cu.import("resource://testing-common/services/sync/rotaryengine.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
 
 Service.engineManager.clear();
 Service.engineManager.register(RotaryEngine);
 let engine = Service.engineManager.get("rotary");
 let tracker = engine._tracker;
 engine.enabled = true;
 
 // Tracking info/collections.
--- a/services/sync/tests/unit/test_sendcredentials_controller.js
+++ b/services/sync/tests/unit/test_sendcredentials_controller.js
@@ -1,15 +1,16 @@
 /* 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/jpakeclient.js");
 Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/util.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
 
 function run_test() {
   setBasicCredentials("johndoe", "ilovejane", Utils.generatePassphrase());
   Service.serverURL  = "http://weave.server/";
 
   initTestLogging("Trace");
   Log4Moz.repository.getLogger("Sync.SendCredentialsController").level = Log4Moz.Level.Trace;
   Log4Moz.repository.getLogger("Sync.SyncScheduler").level = Log4Moz.Level.Trace;
--- a/services/sync/tests/unit/test_service_attributes.js
+++ b/services/sync/tests/unit/test_service_attributes.js
@@ -1,14 +1,15 @@
 /* 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/service.js");
 Cu.import("resource://services-sync/util.js");
+Cu.import("resource://testing-common/services/sync/fakeservices.js");
 
 function test_urls() {
   _("URL related Service properties corresopnd to preference settings.");
   try {
     do_check_true(!!Service.serverURL); // actual value may change
     do_check_eq(Service.clusterURL, "");
     do_check_eq(Service.userBaseURL, undefined);
     do_check_eq(Service.infoURL, undefined);
--- a/services/sync/tests/unit/test_service_changePassword.js
+++ b/services/sync/tests/unit/test_service_changePassword.js
@@ -1,15 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 Cu.import("resource://services-common/log4moz.js");
 Cu.import("resource://services-sync/constants.js");
 Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/util.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
 
 function run_test() {
   initTestLogging("Trace");
   Log4Moz.repository.getLogger("Sync.AsyncResource").level = Log4Moz.Level.Trace;
   Log4Moz.repository.getLogger("Sync.Resource").level = Log4Moz.Level.Trace;
   Log4Moz.repository.getLogger("Sync.Service").level = Log4Moz.Level.Trace;
 
   run_next_test();
--- a/services/sync/tests/unit/test_service_checkAccount.js
+++ b/services/sync/tests/unit/test_service_checkAccount.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/service.js");
 Cu.import("resource://services-sync/util.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
 
 function run_test() {
   do_test_pending();
   let server = httpd_setup({
     "/user/1.0/johndoe": httpd_handler(200, "OK", "1"),
     "/user/1.0/janedoe": httpd_handler(200, "OK", "0"),
     // john@doe.com
     "/user/1.0/7wohs32cngzuqt466q3ge7indszva4of": httpd_handler(200, "OK", "0"),
--- a/services/sync/tests/unit/test_service_cluster.js
+++ b/services/sync/tests/unit/test_service_cluster.js
@@ -1,13 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/util.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
 
 function do_check_throws(func) {
   var raised = false;
   try {
     func();
   } catch (ex) {
     raised = true;
   }
--- a/services/sync/tests/unit/test_service_createAccount.js
+++ b/services/sync/tests/unit/test_service_createAccount.js
@@ -1,13 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 Cu.import("resource://services-sync/util.js");
 Cu.import("resource://services-sync/service.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
 
 function run_test() {
   initTestLogging("Trace");
 
   let requestBody;
   let secretHeader;
   function send(statusCode, status, body) {
     return function(request, response) {
--- a/services/sync/tests/unit/test_service_detect_upgrade.js
+++ b/services/sync/tests/unit/test_service_detect_upgrade.js
@@ -3,16 +3,17 @@
 
 Cu.import("resource://services-common/log4moz.js");
 Cu.import("resource://services-sync/constants.js");
 Cu.import("resource://services-sync/keys.js");
 Cu.import("resource://services-sync/engines/tabs.js");
 Cu.import("resource://services-sync/engines.js");
 Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/util.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
 
 Service.engineManager.register(TabEngine);
 
 add_test(function v4_upgrade() {
   let passphrase = "abcdeabcdeabcdeabcdeabcdea";
 
   let clients = new ServerCollection();
   let meta_global = new ServerWBO('global');
--- a/services/sync/tests/unit/test_service_getStorageInfo.js
+++ b/services/sync/tests/unit/test_service_getStorageInfo.js
@@ -1,15 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 Cu.import("resource://services-common/rest.js");
 Cu.import("resource://services-sync/constants.js");
 Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/util.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
 
 let collections = {steam:  65.11328,
                    petrol: 82.488281,
                    diesel: 2.25488281};
 
 function run_test() {
   setBasicCredentials("johndoe", "ilovejane");
   Service.serverURL = TEST_SERVER_URL;
--- a/services/sync/tests/unit/test_service_login.js
+++ b/services/sync/tests/unit/test_service_login.js
@@ -1,16 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 Cu.import("resource://services-common/log4moz.js");
 Cu.import("resource://services-sync/constants.js");
 Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/policies.js");
 Cu.import("resource://services-sync/util.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
 
 function login_handling(handler) {
   return function (request, response) {
     if (basic_auth_matches(request, "johndoe", "ilovejane") ||
         basic_auth_matches(request, "janedoe", "ilovejohn")) {
       handler(request, response);
     } else {
       let body = "Unauthorized";
--- a/services/sync/tests/unit/test_service_passwordUTF8.js
+++ b/services/sync/tests/unit/test_service_passwordUTF8.js
@@ -1,14 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 Cu.import("resource://services-sync/resource.js");
 Cu.import("resource://services-sync/util.js");
 Cu.import("resource://services-sync/service.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
 
 const JAPANESE = "\u34ff\u35ff\u36ff\u37ff";
 const APPLES = "\uf8ff\uf8ff\uf8ff\uf8ff";
 const LOWBYTES = "\xff\xff\xff\xff";
 
 // Poor man's /etc/passwd.  Static since there's no btoa()/atob() in xpcshell.
 let basicauth = {};
 basicauth[LOWBYTES] = "Basic am9obmRvZTr/////";
--- a/services/sync/tests/unit/test_service_persistLogin.js
+++ b/services/sync/tests/unit/test_service_persistLogin.js
@@ -1,14 +1,15 @@
 /* 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/service.js");
 Cu.import("resource://services-sync/util.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
 
 function run_test() {
   try {
     // Ensure we have a blank slate to start.
     Services.logins.removeAllLogins();
 
     setBasicCredentials("johndoe", "ilovejane", "abbbbbcccccdddddeeeeefffff");
 
--- a/services/sync/tests/unit/test_service_startOver.js
+++ b/services/sync/tests/unit/test_service_startOver.js
@@ -1,15 +1,16 @@
 /* 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/service.js");
 Cu.import("resource://services-sync/util.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
 
 function BlaEngine() {
   SyncEngine.call(this, "Bla", Service);
 }
 BlaEngine.prototype = {
   __proto__: SyncEngine.prototype,
 
   removed: false,
--- a/services/sync/tests/unit/test_service_startup.js
+++ b/services/sync/tests/unit/test_service_startup.js
@@ -1,14 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 Cu.import("resource://services-common/observers.js");
 Cu.import("resource://services-sync/engines.js");
 Cu.import("resource://services-sync/util.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
 
 Svc.Prefs.set("registerEngines", "Tab,Bookmarks,Form,History");
 Cu.import("resource://services-sync/service.js");
 
 function run_test() {
   _("When imported, Service.onStartup is called");
   initTestLogging("Trace");
 
--- a/services/sync/tests/unit/test_service_sync_401.js
+++ b/services/sync/tests/unit/test_service_sync_401.js
@@ -1,15 +1,16 @@
 /* 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/service.js");
 Cu.import("resource://services-sync/util.js");
+Cu.import("resource://testing-common/services/sync/utils.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");
--- a/services/sync/tests/unit/test_service_sync_remoteSetup.js
+++ b/services/sync/tests/unit/test_service_sync_remoteSetup.js
@@ -1,16 +1,18 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 Cu.import("resource://services-common/log4moz.js");
 Cu.import("resource://services-sync/constants.js");
 Cu.import("resource://services-sync/keys.js");
 Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/util.js");
+Cu.import("resource://testing-common/services/sync/fakeservices.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
 
 function run_test() {
   let logger = Log4Moz.repository.rootLogger;
   Log4Moz.repository.rootLogger.addAppender(new Log4Moz.DumpAppender());
 
   let guidSvc = new FakeGUIDService();
   let clients = new ServerCollection();
   let meta_global = new ServerWBO('global');
--- a/services/sync/tests/unit/test_service_sync_updateEnabledEngines.js
+++ b/services/sync/tests/unit/test_service_sync_updateEnabledEngines.js
@@ -2,16 +2,17 @@
    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/record.js");
 Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/util.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
 
 initTestLogging();
 Service.engineManager.clear();
 
 function QuietStore() {
   Store.call("Quiet");
 }
 QuietStore.prototype = {
--- a/services/sync/tests/unit/test_service_verifyLogin.js
+++ b/services/sync/tests/unit/test_service_verifyLogin.js
@@ -1,15 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 Cu.import("resource://services-common/log4moz.js");
 Cu.import("resource://services-sync/constants.js");
 Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/util.js");
+Cu.import("resource://testing-common/services/sync/utils.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");
--- a/services/sync/tests/unit/test_service_wipeClient.js
+++ b/services/sync/tests/unit/test_service_wipeClient.js
@@ -1,16 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 Cu.import("resource://services-sync/identity.js");
 Cu.import("resource://services-sync/engines.js");
 Cu.import("resource://services-sync/record.js");
 Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/util.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
 
 Service.engineManager.clear();
 
 function CanDecryptEngine() {
   SyncEngine.call(this, "CanDecrypt", Service);
 }
 CanDecryptEngine.prototype = {
   __proto__: SyncEngine.prototype,
--- a/services/sync/tests/unit/test_service_wipeServer.js
+++ b/services/sync/tests/unit/test_service_wipeServer.js
@@ -1,11 +1,13 @@
 Cu.import("resource://services-sync/util.js");
 Cu.import("resource://services-sync/record.js");
 Cu.import("resource://services-sync/resource.js");
+Cu.import("resource://testing-common/services/sync/fakeservices.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
 
 Svc.DefaultPrefs.set("registerEngines", "");
 Cu.import("resource://services-sync/service.js");
 
 function FakeCollection() {
   this.deleted = false;
 }
 FakeCollection.prototype = {
--- a/services/sync/tests/unit/test_syncengine.js
+++ b/services/sync/tests/unit/test_syncengine.js
@@ -1,14 +1,15 @@
 /* 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/util.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
 
 function makeSteamEngine() {
   return new SyncEngine('Steam', Service);
 }
 
 function test_url_attributes() {
   _("SyncEngine url attributes");
   let syncTesting = new SyncTestingInfrastructure();
--- a/services/sync/tests/unit/test_syncengine_sync.js
+++ b/services/sync/tests/unit/test_syncengine_sync.js
@@ -3,16 +3,17 @@
 
 Cu.import("resource://services-sync/constants.js");
 Cu.import("resource://services-sync/engines.js");
 Cu.import("resource://services-sync/policies.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://testing-common/services/sync/rotaryengine.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
 
 function makeRotaryEngine() {
   return new RotaryEngine(Service);
 }
 
 function cleanAndGo(server) {
   Svc.Prefs.resetBranch("");
   Svc.Prefs.set("log.logger.engine.rotary", "Trace");
--- a/services/sync/tests/unit/test_syncscheduler.js
+++ b/services/sync/tests/unit/test_syncscheduler.js
@@ -3,16 +3,17 @@
 
 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/policies.js");
 Cu.import("resource://services-sync/record.js");
 Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/status.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
 
 Service.engineManager.clear();
 
 function CatapultEngine() {
   SyncEngine.call(this, "Catapult", Service);
 }
 CatapultEngine.prototype = {
   __proto__: SyncEngine.prototype,
--- a/services/sync/tests/unit/test_syncstoragerequest.js
+++ b/services/sync/tests/unit/test_syncstoragerequest.js
@@ -1,16 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 Cu.import("resource://services-common/log4moz.js");
 Cu.import("resource://services-sync/constants.js");
 Cu.import("resource://services-sync/rest.js");
 Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/util.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
 
 const STORAGE_REQUEST_RESOURCE_URL = TEST_SERVER_URL + "resource";
 
 function run_test() {
   Log4Moz.repository.getLogger("Sync.RESTRequest").level = Log4Moz.Level.Trace;
   initTestLogging();
 
   run_next_test();
--- a/services/sync/tests/unit/test_upgrade_old_sync_key.js
+++ b/services/sync/tests/unit/test_upgrade_old_sync_key.js
@@ -1,16 +1,14 @@
 /* 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/service.js");
 
-var btoa = Cu.import("resource://services-sync/util.js").btoa;
-
 // Test upgrade of a dashed old-style sync key.
 function run_test() {
   const PBKDF2_KEY_BYTES = 16;
   initTestLogging("Trace");
 
   let passphrase = "abcde-abcde-abcde-abcde";
   do_check_false(Utils.isPassphrase(passphrase));