Bug 1220906 - Part 8: Get rid of Old Sync-specific stages. r?rnewman draft
authorNick Alexander <nalexander@mozilla.com>
Mon, 18 Jan 2016 17:34:20 -0800
changeset 323267 6a3b5d7320c7cef59b2dcc76b72ce05fa561f1e3
parent 323266 c0fceed50cfa92587575427e89177900649aea97
child 323268 a10177b7ea4bb426ed49a763329ea04ffada8277
push id9692
push usernalexander@mozilla.com
push dateTue, 19 Jan 2016 22:55:33 +0000
reviewersrnewman
bugs1220906
milestone46.0a1
Bug 1220906 - Part 8: Get rid of Old Sync-specific stages. r?rnewman The two stages are EnsureClusterURLStage (the FxA + Sync cluster URL is determined directly from the token provided by the token server), and MigrationSentinelSyncStage. This allowed to merge the two {Base}GlobalSessionCallback classes together, as well as removing the specializing FxAcccountGlobalSession.
mobile/android/base/android-services.mozbuild
mobile/android/services/src/main/java/org/mozilla/gecko/fxa/sync/FxAccountGlobalSession.java
mobile/android/services/src/main/java/org/mozilla/gecko/fxa/sync/FxAccountSyncAdapter.java
mobile/android/services/src/main/java/org/mozilla/gecko/sync/GlobalSession.java
mobile/android/services/src/main/java/org/mozilla/gecko/sync/MigrationSentinelSyncStage.java
mobile/android/services/src/main/java/org/mozilla/gecko/sync/SharedPreferencesNodeAssignmentCallback.java
mobile/android/services/src/main/java/org/mozilla/gecko/sync/delegates/BaseGlobalSessionCallback.java
mobile/android/services/src/main/java/org/mozilla/gecko/sync/delegates/GlobalSessionCallback.java
mobile/android/services/src/main/java/org/mozilla/gecko/sync/delegates/NodeAssignmentCallback.java
mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/EnsureClusterURLStage.java
mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/GlobalSyncStage.java
mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/NoSyncIDException.java
mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/TestClientsStage.java
mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/TestResetting.java
mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/DefaultGlobalSessionCallback.java
mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockPrefsGlobalSession.java
mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestClientsEngineStage.java
mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestGlobalSession.java
mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/MockGlobalSessionCallback.java
mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/DefaultGlobalSessionCallback.java
mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockPrefsGlobalSession.java
mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/stage/test/TestEnsureClusterURLStage.java
mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/stage/test/TestEnsureCrypto5KeysStage.java
mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/stage/test/TestFetchMetaGlobalStage.java
--- a/mobile/android/base/android-services.mozbuild
+++ b/mobile/android/base/android-services.mozbuild
@@ -848,17 +848,16 @@ sync_java_files = [TOPSRCDIR + '/mobile/
     'fxa/login/MigratedFromSync11.java',
     'fxa/login/Separated.java',
     'fxa/login/State.java',
     'fxa/login/StateFactory.java',
     'fxa/login/TokensAndKeysState.java',
     'fxa/receivers/FxAccountDeletedReceiver.java',
     'fxa/receivers/FxAccountDeletedService.java',
     'fxa/receivers/FxAccountUpgradeReceiver.java',
-    'fxa/sync/FxAccountGlobalSession.java',
     'fxa/sync/FxAccountNotificationManager.java',
     'fxa/sync/FxAccountProfileService.java',
     'fxa/sync/FxAccountSchedulePolicy.java',
     'fxa/sync/FxAccountSyncAdapter.java',
     'fxa/sync/FxAccountSyncDelegate.java',
     'fxa/sync/FxAccountSyncService.java',
     'fxa/sync/FxAccountSyncStatusHelper.java',
     'fxa/sync/SchedulePolicy.java',
@@ -876,24 +875,22 @@ sync_java_files = [TOPSRCDIR + '/mobile/
     'sync/crypto/HMACVerificationException.java',
     'sync/crypto/KeyBundle.java',
     'sync/crypto/MissingCryptoInputException.java',
     'sync/crypto/NoKeyBundleException.java',
     'sync/crypto/PBKDF2.java',
     'sync/crypto/PersistedCrypto5Keys.java',
     'sync/CryptoRecord.java',
     'sync/DelayedWorkTracker.java',
-    'sync/delegates/BaseGlobalSessionCallback.java',
     'sync/delegates/ClientsDataDelegate.java',
     'sync/delegates/FreshStartDelegate.java',
     'sync/delegates/GlobalSessionCallback.java',
     'sync/delegates/JSONRecordFetchDelegate.java',
     'sync/delegates/KeyUploadDelegate.java',
     'sync/delegates/MetaGlobalDelegate.java',
-    'sync/delegates/NodeAssignmentCallback.java',
     'sync/delegates/WipeServerDelegate.java',
     'sync/EngineSettings.java',
     'sync/ExtendedJSONObject.java',
     'sync/GlobalSession.java',
     'sync/HTTPFailureException.java',
     'sync/InfoCollections.java',
     'sync/InfoCounts.java',
     'sync/JSONRecordFetcher.java',
@@ -901,17 +898,16 @@ sync_java_files = [TOPSRCDIR + '/mobile/
     'sync/MetaGlobal.java',
     'sync/MetaGlobalException.java',
     'sync/MetaGlobalMissingEnginesException.java',
     'sync/MetaGlobalNotSetException.java',
     'sync/middleware/Crypto5MiddlewareRepository.java',
     'sync/middleware/Crypto5MiddlewareRepositorySession.java',
     'sync/middleware/MiddlewareRepository.java',
     'sync/middleware/MiddlewareRepositorySession.java',
-    'sync/MigrationSentinelSyncStage.java',
     'sync/net/AbstractBearerTokenAuthHeaderProvider.java',
     'sync/net/AuthHeaderProvider.java',
     'sync/net/BaseResource.java',
     'sync/net/BaseResourceDelegate.java',
     'sync/net/BasicAuthHeaderProvider.java',
     'sync/net/BearerAuthHeaderProvider.java',
     'sync/net/BrowserIDAuthHeaderProvider.java',
     'sync/net/ConnectionMonitorThread.java',
@@ -1018,32 +1014,29 @@ sync_java_files = [TOPSRCDIR + '/mobile/
     'sync/repositories/StoreTrackingRepositorySession.java',
     'sync/Server11PreviousPostFailedException.java',
     'sync/Server11RecordPostFailedException.java',
     'sync/setup/activities/ActivityUtils.java',
     'sync/setup/activities/WebURLFinder.java',
     'sync/setup/Constants.java',
     'sync/setup/InvalidSyncKeyException.java',
     'sync/SharedPreferencesClientsDataDelegate.java',
-    'sync/SharedPreferencesNodeAssignmentCallback.java',
     'sync/stage/AbstractNonRepositorySyncStage.java',
     'sync/stage/AbstractSessionManagingSyncStage.java',
     'sync/stage/AndroidBrowserBookmarksServerSyncStage.java',
     'sync/stage/AndroidBrowserHistoryServerSyncStage.java',
     'sync/stage/CheckPreconditionsStage.java',
     'sync/stage/CompletedStage.java',
-    'sync/stage/EnsureClusterURLStage.java',
     'sync/stage/EnsureCrypto5KeysStage.java',
     'sync/stage/FennecTabsServerSyncStage.java',
     'sync/stage/FetchInfoCollectionsStage.java',
     'sync/stage/FetchMetaGlobalStage.java',
     'sync/stage/FormHistoryServerSyncStage.java',
     'sync/stage/GlobalSyncStage.java',
     'sync/stage/NoSuchStageException.java',
-    'sync/stage/NoSyncIDException.java',
     'sync/stage/PasswordsServerSyncStage.java',
     'sync/stage/SafeConstrainedServer11Repository.java',
     'sync/stage/ServerSyncStage.java',
     'sync/stage/SyncClientsEngineStage.java',
     'sync/stage/UploadMetaGlobalStage.java',
     'sync/Sync11Configuration.java',
     'sync/SyncConfiguration.java',
     'sync/SyncConfigurationException.java',
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/sync/FxAccountGlobalSession.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/* 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/. */
-
-package org.mozilla.gecko.fxa.sync;
-
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.util.Collections;
-import java.util.EnumMap;
-import java.util.Map;
-
-import org.json.simple.parser.ParseException;
-import org.mozilla.gecko.sync.GlobalSession;
-import org.mozilla.gecko.sync.NonObjectJSONException;
-import org.mozilla.gecko.sync.SyncConfiguration;
-import org.mozilla.gecko.sync.SyncConfigurationException;
-import org.mozilla.gecko.sync.delegates.BaseGlobalSessionCallback;
-import org.mozilla.gecko.sync.delegates.ClientsDataDelegate;
-import org.mozilla.gecko.sync.stage.CheckPreconditionsStage;
-import org.mozilla.gecko.sync.stage.GlobalSyncStage;
-import org.mozilla.gecko.sync.stage.GlobalSyncStage.Stage;
-
-import android.content.Context;
-
-public class FxAccountGlobalSession extends GlobalSession {
-  public FxAccountGlobalSession(SyncConfiguration config,
-                                BaseGlobalSessionCallback callback,
-                                Context context,
-                                ClientsDataDelegate clientsDelegate)
-                                    throws SyncConfigurationException, IllegalArgumentException, IOException, ParseException, NonObjectJSONException, URISyntaxException {
-    super(config, callback, context, clientsDelegate, null);
-  }
-
-  @Override
-  public void prepareStages() {
-    super.prepareStages();
-    Map<Stage, GlobalSyncStage> stages = new EnumMap<>(Stage.class);
-    stages.putAll(this.stages);
-    stages.put(Stage.ensureClusterURL, new CheckPreconditionsStage());
-    stages.put(Stage.attemptMigrationStage, new CheckPreconditionsStage());
-    this.stages = Collections.unmodifiableMap(stages);
-  }
-}
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/sync/FxAccountSyncAdapter.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/sync/FxAccountSyncAdapter.java
@@ -1,25 +1,24 @@
 /* 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/. */
 
 package org.mozilla.gecko.fxa.sync;
 
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.LinkedBlockingQueue;
+import android.accounts.Account;
+import android.content.AbstractThreadedSyncAdapter;
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.SyncResult;
+import android.os.Bundle;
+import android.os.SystemClock;
 
-import org.mozilla.gecko.AppConstants;
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.background.common.telemetry.TelemetryWrapper;
 import org.mozilla.gecko.background.fxa.FxAccountUtils;
 import org.mozilla.gecko.background.fxa.SkewHandler;
 import org.mozilla.gecko.browserid.JSONWebTokenUtils;
 import org.mozilla.gecko.fxa.FirefoxAccounts;
 import org.mozilla.gecko.fxa.FxAccountConstants;
 import org.mozilla.gecko.fxa.authenticator.AccountPickler;
@@ -34,36 +33,36 @@ import org.mozilla.gecko.fxa.sync.FxAcco
 import org.mozilla.gecko.sync.BackoffHandler;
 import org.mozilla.gecko.sync.GlobalSession;
 import org.mozilla.gecko.sync.PrefsBackoffHandler;
 import org.mozilla.gecko.sync.SharedPreferencesClientsDataDelegate;
 import org.mozilla.gecko.sync.SyncConfiguration;
 import org.mozilla.gecko.sync.ThreadPool;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.sync.crypto.KeyBundle;
-import org.mozilla.gecko.sync.delegates.BaseGlobalSessionCallback;
+import org.mozilla.gecko.sync.delegates.GlobalSessionCallback;
 import org.mozilla.gecko.sync.delegates.ClientsDataDelegate;
 import org.mozilla.gecko.sync.net.AuthHeaderProvider;
 import org.mozilla.gecko.sync.net.HawkAuthHeaderProvider;
 import org.mozilla.gecko.sync.stage.GlobalSyncStage.Stage;
 import org.mozilla.gecko.sync.telemetry.TelemetryContract;
 import org.mozilla.gecko.tokenserver.TokenServerClient;
 import org.mozilla.gecko.tokenserver.TokenServerClientDelegate;
 import org.mozilla.gecko.tokenserver.TokenServerException;
 import org.mozilla.gecko.tokenserver.TokenServerToken;
 
-import android.accounts.Account;
-import android.content.AbstractThreadedSyncAdapter;
-import android.content.ContentProviderClient;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.SyncResult;
-import android.os.Bundle;
-import android.os.SystemClock;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
 
 public class FxAccountSyncAdapter extends AbstractThreadedSyncAdapter {
   private static final String LOG_TAG = FxAccountSyncAdapter.class.getSimpleName();
 
   public static final String SYNC_EXTRAS_RESPECT_LOCAL_RATE_LIMIT = "respect_local_rate_limit";
   public static final String SYNC_EXTRAS_RESPECT_REMOTE_SERVER_BACKOFF = "respect_remote_server_backoff";
 
   public static final int NOTIFICATION_ID = LOG_TAG.hashCode();
@@ -126,17 +125,17 @@ public class FxAccountSyncAdapter extend
       this.stageNamesToSync = Collections.unmodifiableCollection(stageNamesToSync);
     }
 
     public Collection<String> getStageNamesToSync() {
       return this.stageNamesToSync;
     }
   }
 
-  protected static class SessionCallback implements BaseGlobalSessionCallback {
+  protected static class SessionCallback implements GlobalSessionCallback {
     protected final SyncDelegate syncDelegate;
     protected final SchedulePolicy schedulePolicy;
     protected volatile BackoffHandler storageBackoffHandler;
 
     public SessionCallback(SyncDelegate syncDelegate, SchedulePolicy schedulePolicy) {
       this.syncDelegate = syncDelegate;
       this.schedulePolicy = schedulePolicy;
     }
@@ -289,17 +288,17 @@ public class FxAccountSyncAdapter extend
         } else {
           Logger.debug(LOG_TAG, "Received new storage host.");
         }
 
         // Invalidate the previous backoff, because our storage host has changed,
         // or we never had one at all, or we're OK to sync.
         storageBackoffHandler.setEarliestNextRequest(0L);
 
-        FxAccountGlobalSession globalSession = null;
+        GlobalSession globalSession = null;
         try {
           final ClientsDataDelegate clientsDataDelegate = new SharedPreferencesClientsDataDelegate(sharedPrefs, getContext());
           if (FxAccountUtils.LOG_PERSONAL_INFORMATION) {
             FxAccountUtils.pii(LOG_TAG, "Client device name is: '" + clientsDataDelegate.getClientName() + "'.");
             FxAccountUtils.pii(LOG_TAG, "Client device data last modified: " + clientsDataDelegate.getLastModifiedTimestamp());
           }
 
           // We compute skew over time using SkewHandler. This yields an unchanging
@@ -317,17 +316,17 @@ public class FxAccountSyncAdapter extend
 
           final Context context = getContext();
           final SyncConfiguration syncConfig = new SyncConfiguration(token.uid, authHeaderProvider, sharedPrefs, syncKeyBundle);
 
           Collection<String> knownStageNames = SyncConfiguration.validEngineNames();
           syncConfig.stagesToSync = Utils.getStagesToSyncFromBundle(knownStageNames, extras);
           syncConfig.setClusterURL(storageServerURI);
 
-          globalSession = new FxAccountGlobalSession(syncConfig, callback, context, clientsDataDelegate);
+          globalSession = new GlobalSession(syncConfig, callback, context, clientsDataDelegate);
           globalSession.start();
         } catch (Exception e) {
           callback.handleError(globalSession, e);
           return;
         }
       }
 
       @Override
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/GlobalSession.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/GlobalSession.java
@@ -1,85 +1,83 @@
 /* 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/. */
 
 package org.mozilla.gecko.sync;
 
+import android.content.Context;
+
+import org.json.simple.JSONArray;
+import org.json.simple.parser.ParseException;
+import org.mozilla.gecko.background.common.log.Logger;
+import org.mozilla.gecko.sync.crypto.CryptoException;
+import org.mozilla.gecko.sync.crypto.KeyBundle;
+import org.mozilla.gecko.sync.delegates.GlobalSessionCallback;
+import org.mozilla.gecko.sync.delegates.ClientsDataDelegate;
+import org.mozilla.gecko.sync.delegates.FreshStartDelegate;
+import org.mozilla.gecko.sync.delegates.JSONRecordFetchDelegate;
+import org.mozilla.gecko.sync.delegates.KeyUploadDelegate;
+import org.mozilla.gecko.sync.delegates.MetaGlobalDelegate;
+import org.mozilla.gecko.sync.delegates.WipeServerDelegate;
+import org.mozilla.gecko.sync.net.AuthHeaderProvider;
+import org.mozilla.gecko.sync.net.BaseResource;
+import org.mozilla.gecko.sync.net.HttpResponseObserver;
+import org.mozilla.gecko.sync.net.SyncResponse;
+import org.mozilla.gecko.sync.net.SyncStorageRecordRequest;
+import org.mozilla.gecko.sync.net.SyncStorageRequest;
+import org.mozilla.gecko.sync.net.SyncStorageRequestDelegate;
+import org.mozilla.gecko.sync.net.SyncStorageResponse;
+import org.mozilla.gecko.sync.stage.AndroidBrowserBookmarksServerSyncStage;
+import org.mozilla.gecko.sync.stage.AndroidBrowserHistoryServerSyncStage;
+import org.mozilla.gecko.sync.stage.CheckPreconditionsStage;
+import org.mozilla.gecko.sync.stage.CompletedStage;
+import org.mozilla.gecko.sync.stage.EnsureCrypto5KeysStage;
+import org.mozilla.gecko.sync.stage.FennecTabsServerSyncStage;
+import org.mozilla.gecko.sync.stage.FetchInfoCollectionsStage;
+import org.mozilla.gecko.sync.stage.FetchMetaGlobalStage;
+import org.mozilla.gecko.sync.stage.FormHistoryServerSyncStage;
+import org.mozilla.gecko.sync.stage.GlobalSyncStage;
+import org.mozilla.gecko.sync.stage.GlobalSyncStage.Stage;
+import org.mozilla.gecko.sync.stage.NoSuchStageException;
+import org.mozilla.gecko.sync.stage.PasswordsServerSyncStage;
+import org.mozilla.gecko.sync.stage.SyncClientsEngineStage;
+import org.mozilla.gecko.sync.stage.UploadMetaGlobalStage;
+
 import java.io.IOException;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.EnumMap;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicLong;
 
-import org.json.simple.JSONArray;
-import org.json.simple.parser.ParseException;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.crypto.CryptoException;
-import org.mozilla.gecko.sync.crypto.KeyBundle;
-import org.mozilla.gecko.sync.delegates.BaseGlobalSessionCallback;
-import org.mozilla.gecko.sync.delegates.ClientsDataDelegate;
-import org.mozilla.gecko.sync.delegates.FreshStartDelegate;
-import org.mozilla.gecko.sync.delegates.JSONRecordFetchDelegate;
-import org.mozilla.gecko.sync.delegates.KeyUploadDelegate;
-import org.mozilla.gecko.sync.delegates.MetaGlobalDelegate;
-import org.mozilla.gecko.sync.delegates.NodeAssignmentCallback;
-import org.mozilla.gecko.sync.delegates.WipeServerDelegate;
-import org.mozilla.gecko.sync.net.AuthHeaderProvider;
-import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.HttpResponseObserver;
-import org.mozilla.gecko.sync.net.SyncResponse;
-import org.mozilla.gecko.sync.net.SyncStorageRecordRequest;
-import org.mozilla.gecko.sync.net.SyncStorageRequest;
-import org.mozilla.gecko.sync.net.SyncStorageRequestDelegate;
-import org.mozilla.gecko.sync.net.SyncStorageResponse;
-import org.mozilla.gecko.sync.stage.AndroidBrowserBookmarksServerSyncStage;
-import org.mozilla.gecko.sync.stage.AndroidBrowserHistoryServerSyncStage;
-import org.mozilla.gecko.sync.stage.CheckPreconditionsStage;
-import org.mozilla.gecko.sync.stage.CompletedStage;
-import org.mozilla.gecko.sync.stage.EnsureClusterURLStage;
-import org.mozilla.gecko.sync.stage.EnsureCrypto5KeysStage;
-import org.mozilla.gecko.sync.stage.FennecTabsServerSyncStage;
-import org.mozilla.gecko.sync.stage.FetchInfoCollectionsStage;
-import org.mozilla.gecko.sync.stage.FetchMetaGlobalStage;
-import org.mozilla.gecko.sync.stage.FormHistoryServerSyncStage;
-import org.mozilla.gecko.sync.stage.GlobalSyncStage;
-import org.mozilla.gecko.sync.stage.GlobalSyncStage.Stage;
-import org.mozilla.gecko.sync.stage.NoSuchStageException;
-import org.mozilla.gecko.sync.stage.PasswordsServerSyncStage;
-import org.mozilla.gecko.sync.stage.SyncClientsEngineStage;
-import org.mozilla.gecko.sync.stage.UploadMetaGlobalStage;
-
-import android.content.Context;
 import ch.boye.httpclientandroidlib.HttpResponse;
 import ch.boye.httpclientandroidlib.client.methods.HttpUriRequest;
 
 public class GlobalSession implements HttpResponseObserver {
   private static final String LOG_TAG = "GlobalSession";
 
   public static final long STORAGE_VERSION = 5;
 
   public SyncConfiguration config = null;
 
   protected Map<Stage, GlobalSyncStage> stages;
   public Stage currentState = Stage.idle;
 
-  public final BaseGlobalSessionCallback callback;
+  public final GlobalSessionCallback callback;
   protected final Context context;
   protected final ClientsDataDelegate clientsDelegate;
-  protected final NodeAssignmentCallback nodeAssignmentCallback;
 
   /**
    * Map from engine name to new settings for an updated meta/global record.
    * Engines to remove will have <code>null</code> EngineSettings.
    */
   public final Map<String, EngineSettings> enginesToUpdate = new HashMap<String, EngineSettings>();
 
    /*
@@ -96,29 +94,28 @@ public class GlobalSession implements Ht
     return config.getAuthHeaderProvider();
   }
 
   public URI wboURI(String collection, String id) throws URISyntaxException {
     return config.wboURI(collection, id);
   }
 
   public GlobalSession(SyncConfiguration config,
-                       BaseGlobalSessionCallback callback,
+                       GlobalSessionCallback callback,
                        Context context,
-                       ClientsDataDelegate clientsDelegate, NodeAssignmentCallback nodeAssignmentCallback)
+                       ClientsDataDelegate clientsDelegate)
     throws SyncConfigurationException, IllegalArgumentException, IOException, ParseException, NonObjectJSONException {
 
     if (callback == null) {
       throw new IllegalArgumentException("Must provide a callback to GlobalSession constructor.");
     }
 
     this.callback        = callback;
     this.context         = context;
     this.clientsDelegate = clientsDelegate;
-    this.nodeAssignmentCallback = nodeAssignmentCallback;
 
     this.config = config;
     registerCommands();
     prepareStages();
 
     if (config.stagesToSync == null) {
       Logger.info(LOG_TAG, "No stages to sync specified; defaulting to all valid engine names.");
       config.stagesToSync = Collections.unmodifiableCollection(SyncConfiguration.validEngineNames());
@@ -174,21 +171,19 @@ public class GlobalSession implements Ht
       }
     });
   }
 
   protected void prepareStages() {
     Map<Stage, GlobalSyncStage> stages = new EnumMap<Stage, GlobalSyncStage>(Stage.class);
 
     stages.put(Stage.checkPreconditions,      new CheckPreconditionsStage());
-    stages.put(Stage.ensureClusterURL,        new EnsureClusterURLStage(nodeAssignmentCallback));
     stages.put(Stage.fetchInfoCollections,    new FetchInfoCollectionsStage());
     stages.put(Stage.fetchMetaGlobal,         new FetchMetaGlobalStage());
     stages.put(Stage.ensureKeysStage,         new EnsureCrypto5KeysStage());
-    stages.put(Stage.attemptMigrationStage,   new MigrationSentinelSyncStage());
 
     stages.put(Stage.syncClientsEngine,       new SyncClientsEngineStage());
 
     stages.put(Stage.syncTabs,                new FennecTabsServerSyncStage());
     stages.put(Stage.syncPasswords,           new PasswordsServerSyncStage());
     stages.put(Stage.syncBookmarks,           new AndroidBrowserBookmarksServerSyncStage());
     stages.put(Stage.syncHistory,             new AndroidBrowserHistoryServerSyncStage());
     stages.put(Stage.syncFormHistory,         new FormHistoryServerSyncStage());
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/MigrationSentinelSyncStage.java
+++ /dev/null
@@ -1,261 +0,0 @@
-/* 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/. */
-
-package org.mozilla.gecko.sync;
-
-import java.net.URISyntaxException;
-
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.background.common.telemetry.TelemetryWrapper;
-import org.mozilla.gecko.background.fxa.FxAccountUtils;
-import org.mozilla.gecko.fxa.FxAccountConstants;
-import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
-import org.mozilla.gecko.fxa.login.MigratedFromSync11;
-import org.mozilla.gecko.fxa.login.State;
-import org.mozilla.gecko.sync.net.AuthHeaderProvider;
-import org.mozilla.gecko.sync.net.SyncStorageRecordRequest;
-import org.mozilla.gecko.sync.net.SyncStorageRequestDelegate;
-import org.mozilla.gecko.sync.net.SyncStorageResponse;
-import org.mozilla.gecko.sync.stage.AbstractNonRepositorySyncStage;
-import org.mozilla.gecko.sync.stage.NoSuchStageException;
-import org.mozilla.gecko.sync.telemetry.TelemetryContract;
-
-/**
- * The purpose of this class is to talk to a Sync 1.1 server and check
- * for a Firefox Accounts migration sentinel.
- *
- * If one is found, a Firefox Account is created, and the existing
- * Firefox Sync account disabled (or deleted).
- */
-public class MigrationSentinelSyncStage extends AbstractNonRepositorySyncStage {
-  private static final String LOG_TAG = MigrationSentinelSyncStage.class.getSimpleName();
-
-  private static final String META_COLLECTION = "meta";
-
-  public static class MigrationChecker {
-    private static final String META_FXA_CREDENTIALS = "/meta/fxa_credentials";
-
-    private static final String CREDENTIALS_KEY_ID = "id";
-    private static final String CREDENTIALS_KEY_SENTINEL = "sentinel";
-
-    private static final String RECORD_ID = "fxa_credentials";
-
-    private static final String SENTINEL_KEY_EMAIL = "email";
-    private static final String SENTINEL_KEY_UID = "uid";
-    private static final String SENTINEL_KEY_VERIFIED = "verified";
-    private static final String SENTINEL_KEY_PASSWORD = "password";
-    private static final String SENTINEL_KEY_PREFS = "prefs";
-
-    private static final String PREFS_KEY_AUTH_SERVER_ENDPOINT = "identity.fxaccounts.auth.uri";
-    private static final String PREFS_KEY_TOKEN_SERVER_ENDPOINT = "services.sync.tokenServerURI";
-    private static final String PREFS_KEY_PROFILE_SERVER_ENDPOINT = "services.fxaccounts.profile.uri";
-
-    private final GlobalSession session;
-    private long fetchTimestamp = -1L;
-
-    MigrationChecker(GlobalSession session) {
-      this.session = session;
-    }
-
-    private void setTimestamp(long timestamp) {
-      if (timestamp == -1L) {
-        this.fetchTimestamp = System.currentTimeMillis();
-      } else {
-        this.fetchTimestamp = timestamp;
-      }
-    }
-
-    private boolean migrate(String email,
-                            String uid,
-                            boolean verified,
-                            String password,
-                            String authServerURI,
-                            String tokenServerURI,
-                            String profileServerURI) throws Exception {
-      final String profile = "default";
-
-      final State state = new MigratedFromSync11(email, uid, verified, password);
-
-      final AndroidFxAccount fxAccount = AndroidFxAccount.addAndroidAccount(session.context,
-          email,
-          profile,
-          authServerURI,
-          tokenServerURI,
-          profileServerURI,
-          state,
-          AndroidFxAccount.DEFAULT_AUTHORITIES_TO_SYNC_AUTOMATICALLY_MAP);
-
-      if (fxAccount == null) {
-        Logger.warn(LOG_TAG, "Could not add Android account named like: " + Utils.obfuscateEmail(email));
-        return false;
-      } else {
-        return true;
-      }
-    }
-
-    private void migrate(CryptoRecord record) throws Exception {
-      // If something goes wrong, we don't want to try this again.
-      session.config.persistLastMigrationSentinelCheckTimestamp(fetchTimestamp);
-
-      record.keyBundle = session.config.syncKeyBundle;
-      record.decrypt();
-
-      Logger.info(LOG_TAG, "Migration sentinel could be decrypted; extracting credentials.");
-
-      final ExtendedJSONObject payload = record.payload;
-      if (!RECORD_ID.equals(payload.getString(CREDENTIALS_KEY_ID))) {
-        onError(null, "Record payload 'id' was not '" + RECORD_ID + "'; ignoring.");
-        return;
-      }
-
-      final ExtendedJSONObject sentinel = payload.getObject(CREDENTIALS_KEY_SENTINEL);
-      if (sentinel == null) {
-        onError(null, "Record payload did not contain object with key '" + CREDENTIALS_KEY_SENTINEL + "'; ignoring.");
-        return;
-      }
-
-      sentinel.throwIfFieldsMissingOrMisTyped(new String[] { SENTINEL_KEY_EMAIL, SENTINEL_KEY_UID } , String.class);
-      sentinel.throwIfFieldsMissingOrMisTyped(new String[] { SENTINEL_KEY_VERIFIED } , Boolean.class);
-      final String email = sentinel.getString(SENTINEL_KEY_EMAIL);
-      final String uid = sentinel.getString(SENTINEL_KEY_UID);
-      final boolean verified = sentinel.getBoolean(SENTINEL_KEY_VERIFIED);
-      // We never expect this to be set, but we're being forward thinking here.
-      final String password = sentinel.getString(SENTINEL_KEY_PASSWORD);
-
-      final ExtendedJSONObject prefs = payload.getObject(SENTINEL_KEY_PREFS);
-      String authServerURI = null;
-      String tokenServerURI = null;
-      String profileServerURI = null;
-      if (prefs != null) {
-        authServerURI = prefs.getString(PREFS_KEY_AUTH_SERVER_ENDPOINT);
-        tokenServerURI = prefs.getString(PREFS_KEY_TOKEN_SERVER_ENDPOINT);
-        profileServerURI = prefs.getString(PREFS_KEY_PROFILE_SERVER_ENDPOINT);
-      }
-      if (authServerURI == null) {
-        authServerURI = FxAccountConstants.DEFAULT_AUTH_SERVER_ENDPOINT;
-      }
-      if (tokenServerURI == null) {
-        tokenServerURI = FxAccountConstants.DEFAULT_TOKEN_SERVER_ENDPOINT;
-      }
-      if (profileServerURI == null) {
-        profileServerURI = FxAccountConstants.DEFAULT_PROFILE_SERVER_ENDPOINT;
-      }
-
-      Logger.info(LOG_TAG, "Migration sentinel contained valid credentials.");
-      if (FxAccountUtils.LOG_PERSONAL_INFORMATION) {
-        FxAccountUtils.pii(LOG_TAG, "payload: " + payload.toJSONString());
-        FxAccountUtils.pii(LOG_TAG, "email: " + email);
-        FxAccountUtils.pii(LOG_TAG, "uid: " + uid);
-        FxAccountUtils.pii(LOG_TAG, "verified: " + verified);
-        FxAccountUtils.pii(LOG_TAG, "password: " + password);
-        FxAccountUtils.pii(LOG_TAG, "authServer: " + authServerURI);
-        FxAccountUtils.pii(LOG_TAG, "tokenServerURI: " + tokenServerURI);
-        FxAccountUtils.pii(LOG_TAG, "profileServerURI: " + profileServerURI);
-      }
-
-      if (migrate(email, uid, verified, password, authServerURI, tokenServerURI, profileServerURI)) {
-        session.callback.informMigrated(session);
-        onMigrated();
-      } else {
-        onError(null, "Could not add Android account.");
-      }
-    }
-
-    private void onMigrated() {
-      Logger.info(LOG_TAG, "Account migrated!");
-      TelemetryWrapper.addToHistogram(TelemetryContract.SYNC11_MIGRATIONS_SUCCEEDED, 1);
-      session.config.persistLastMigrationSentinelCheckTimestamp(fetchTimestamp);
-      session.abort(null, "Account migrated.");
-    }
-
-    private void onCompletedUneventfully() {
-      session.config.persistLastMigrationSentinelCheckTimestamp(fetchTimestamp);
-      session.advance();
-    }
-
-    private void onError(Exception ex, String reason) {
-      Logger.info(LOG_TAG, "Could not migrate: " + reason, ex);
-      TelemetryWrapper.addToHistogram(TelemetryContract.SYNC11_MIGRATIONS_FAILED, 1);
-      session.abort(ex, reason);
-    }
-
-    public void check() {
-      final String url = session.config.storageURL() + META_FXA_CREDENTIALS;
-      try {
-        final SyncStorageRecordRequest request = new SyncStorageRecordRequest(url);
-        request.delegate = new SyncStorageRequestDelegate() {
-
-          @Override
-          public String ifUnmodifiedSince() {
-            return null;
-          }
-
-          @Override
-          public void handleRequestSuccess(SyncStorageResponse response) {
-            Logger.info(LOG_TAG, "Found " + META_FXA_CREDENTIALS + " record; attempting migration.");
-            setTimestamp(response.normalizedWeaveTimestamp());
-
-            TelemetryWrapper.addToHistogram(TelemetryContract.SYNC11_MIGRATION_SENTINELS_SEEN, 1);
-
-            try {
-              final ExtendedJSONObject body = response.jsonObjectBody();
-              final CryptoRecord cryptoRecord = CryptoRecord.fromJSONRecord(body);
-              migrate(cryptoRecord);
-            } catch (Exception e) {
-              onError(e, "Unable to parse credential response.");
-            }
-          }
-
-          @Override
-          public void handleRequestFailure(SyncStorageResponse response) {
-            setTimestamp(response.normalizedWeaveTimestamp());
-            if (response.getStatusCode() == 404) {
-              // Great!
-              onCompletedUneventfully();
-              return;
-            }
-            onError(null, "Failed to fetch.");
-          }
-
-          @Override
-          public void handleRequestError(Exception ex) {
-            onError(ex, "Failed to fetch.");
-          }
-
-          @Override
-          public AuthHeaderProvider getAuthHeaderProvider() {
-            return session.getAuthHeaderProvider();
-          }
-        };
-
-        request.get();
-      } catch (URISyntaxException e) {
-        onError(e, "Malformed credentials URI.");
-      }
-    }
-  }
-
-  public MigrationSentinelSyncStage() {
-  }
-
-  @Override
-  protected void execute() throws NoSuchStageException {
-    final InfoCollections infoCollections = session.config.infoCollections;
-    if (infoCollections == null) {
-      session.abort(null, "No info/collections set in MigrationSentinelSyncStage.");
-      return;
-    }
-
-    final long lastModified = session.config.getLastMigrationSentinelCheckTimestamp();
-    if (!infoCollections.updateNeeded(META_COLLECTION, lastModified)) {
-      Logger.info(LOG_TAG, "No need to check fresh meta/fxa_credentials.");
-      session.advance();
-      return;
-    }
-
-    // Let's try a fetch.
-    Logger.info(LOG_TAG, "Fetching meta/fxa_credentials to check for migration sentinel.");
-    new MigrationChecker(session).check();
-  }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/SharedPreferencesNodeAssignmentCallback.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/* 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/. */
-
-package org.mozilla.gecko.sync;
-import java.net.URI;
-import java.net.URISyntaxException;
-
-import org.mozilla.gecko.sync.delegates.NodeAssignmentCallback;
-
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.Editor;
-
-public class SharedPreferencesNodeAssignmentCallback implements NodeAssignmentCallback {
-  protected final SharedPreferences sharedPreferences;
-  protected final String nodeWeaveURL;
-
-  public SharedPreferencesNodeAssignmentCallback(SharedPreferences sharedPreferences, String nodeWeaveURL)
-      throws SyncConfigurationException {
-    this.sharedPreferences = sharedPreferences;
-    if (nodeWeaveURL == null) {
-      throw new IllegalArgumentException("nodeWeaveURL must not be null");
-    }
-    try {
-      new URI(nodeWeaveURL);
-    } catch (URISyntaxException e) {
-      throw new SyncConfigurationException();
-    }
-    this.nodeWeaveURL = nodeWeaveURL;
-  }
-
-  public synchronized boolean getClusterURLIsStale() {
-    return sharedPreferences.getBoolean(SyncConfiguration.PREF_CLUSTER_URL_IS_STALE, false);
-  }
-
-  public synchronized void setClusterURLIsStale(boolean clusterURLIsStale) {
-    Editor edit = sharedPreferences.edit();
-    edit.putBoolean(SyncConfiguration.PREF_CLUSTER_URL_IS_STALE, clusterURLIsStale);
-    edit.commit();
-  }
-
-  @Override
-  public boolean wantNodeAssignment() {
-    return getClusterURLIsStale();
-  }
-
-  @Override
-  public void informNodeAuthenticationFailed(GlobalSession session, URI failedClusterURL) {
-    // TODO: communicate to the user interface that we need a new user password!
-    // TODO: only freshen the cluster URL (better yet, forget the cluster URL) after the user has provided new credentials.
-    setClusterURLIsStale(false);
-  }
-
-  @Override
-  public void informNodeAssigned(GlobalSession session, URI oldClusterURL, URI newClusterURL) {
-    setClusterURLIsStale(false);
-  }
-
-  @Override
-  public String nodeWeaveURL() {
-    return this.nodeWeaveURL;
-  }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/delegates/BaseGlobalSessionCallback.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/* 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/. */
-
-package org.mozilla.gecko.sync.delegates;
-
-import java.net.URI;
-
-import org.mozilla.gecko.sync.GlobalSession;
-import org.mozilla.gecko.sync.stage.GlobalSyncStage.Stage;
-
-public interface BaseGlobalSessionCallback {
-  /**
-   * Request that no further syncs occur within the next `backoff` milliseconds.
-   * @param backoff a duration in milliseconds.
-   */
-  void requestBackoff(long backoff);
-
-  /**
-   * Called on a 401 HTTP response.
-   */
-  void informUnauthorizedResponse(GlobalSession globalSession, URI oldClusterURL);
-
-
-  /**
-   * Called when an HTTP failure indicates that a software upgrade is required.
-   */
-  void informUpgradeRequiredResponse(GlobalSession session);
-
-  /**
-   * Called when a migration sentinel has been found and processed successfully.
-   * <p>
-   * This account should stop syncing immediately, and arrange to delete itself.
-   */
-  void informMigrated(GlobalSession session);
-
-  void handleAborted(GlobalSession globalSession, String reason);
-  void handleError(GlobalSession globalSession, Exception ex);
-  void handleSuccess(GlobalSession globalSession);
-  void handleStageCompleted(Stage currentState, GlobalSession globalSession);
-
-  /**
-   * Called when a {@link GlobalSession} wants to know if it should continue
-   * to make storage requests.
-   *
-   * @return false if the session should make no further requests.
-   */
-  boolean shouldBackOffStorage();
-}
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/delegates/GlobalSessionCallback.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/delegates/GlobalSessionCallback.java
@@ -1,8 +1,49 @@
 /* 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/. */
 
 package org.mozilla.gecko.sync.delegates;
 
-public interface GlobalSessionCallback extends BaseGlobalSessionCallback, NodeAssignmentCallback {
+import java.net.URI;
+
+import org.mozilla.gecko.sync.GlobalSession;
+import org.mozilla.gecko.sync.stage.GlobalSyncStage.Stage;
+
+public interface GlobalSessionCallback {
+  /**
+   * Request that no further syncs occur within the next `backoff` milliseconds.
+   * @param backoff a duration in milliseconds.
+   */
+  void requestBackoff(long backoff);
+
+  /**
+   * Called on a 401 HTTP response.
+   */
+  void informUnauthorizedResponse(GlobalSession globalSession, URI oldClusterURL);
+
+
+  /**
+   * Called when an HTTP failure indicates that a software upgrade is required.
+   */
+  void informUpgradeRequiredResponse(GlobalSession session);
+
+  /**
+   * Called when a migration sentinel has been found and processed successfully.
+   * <p>
+   * This account should stop syncing immediately, and arrange to delete itself.
+   */
+  void informMigrated(GlobalSession session);
+
+  void handleAborted(GlobalSession globalSession, String reason);
+  void handleError(GlobalSession globalSession, Exception ex);
+  void handleSuccess(GlobalSession globalSession);
+  void handleStageCompleted(Stage currentState, GlobalSession globalSession);
+
+  /**
+   * Called when a {@link GlobalSession} wants to know if it should continue
+   * to make storage requests.
+   *
+   * @return false if the session should make no further requests.
+   */
+  boolean shouldBackOffStorage();
 }
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/delegates/NodeAssignmentCallback.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/* 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/. */
-
-package org.mozilla.gecko.sync.delegates;
-
-import java.net.URI;
-
-import org.mozilla.gecko.sync.GlobalSession;
-
-public interface NodeAssignmentCallback {
-  /**
-   * If true, request node assignment from the server, i.e., fetch node/weave cluster URL.
-   */
-  public boolean wantNodeAssignment();
-
-  /**
-   * Called when a new node is assigned. If there already was an old node, the
-   * new node is different from the old node assignment, indicating node
-   * reassignment. If there wasn't an old node, we've been freshly assigned.
-   *
-   * @param globalSession
-   * @param oldClusterURL
-   *          The old node/weave cluster URL (possibly null).
-   * @param newClusterURL
-   *          The new node/weave cluster URL (not null).
-   */
-  public void informNodeAssigned(GlobalSession globalSession, URI oldClusterURL, URI newClusterURL);
-
-  /**
-   * Called when wantNodeAssignment() is true, and the new node assignment is
-   * the same as the old node assignment, indicating a user authentication
-   * error.
-   *
-   * @param globalSession
-   * @param failedClusterURL
-   *          The new node/weave cluster URL.
-   */
-  public void informNodeAuthenticationFailed(GlobalSession globalSession, URI failedClusterURL);
-
-  public String nodeWeaveURL();
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/EnsureClusterURLStage.java
+++ /dev/null
@@ -1,260 +0,0 @@
-/* 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/. */
-
-package org.mozilla.gecko.sync.stage;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.security.GeneralSecurityException;
-
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.NodeAuthenticationException;
-import org.mozilla.gecko.sync.NullClusterURLException;
-import org.mozilla.gecko.sync.SyncConstants;
-import org.mozilla.gecko.sync.ThreadPool;
-import org.mozilla.gecko.sync.delegates.NodeAssignmentCallback;
-import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.BaseResourceDelegate;
-
-import ch.boye.httpclientandroidlib.HttpEntity;
-import ch.boye.httpclientandroidlib.HttpResponse;
-import ch.boye.httpclientandroidlib.client.ClientProtocolException;
-
-public class EnsureClusterURLStage extends AbstractNonRepositorySyncStage {
-  private static final String LOG_TAG = EnsureClusterURLStage.class.getSimpleName();
-
-  public interface ClusterURLFetchDelegate {
-    /**
-     * 200 - Success.
-     * @param url The node/weave cluster URL returned by the server.
-     */
-    public void handleSuccess(URI url);
-
-    /**
-     * 200 - Success, but the server returned 'null', meaning no node can be
-     * assigned at this time, probably due to registration throttling.
-     */
-    public void handleThrottled();
-
-    /**
-     * 404 - User not found.
-     * 503 - Service unavailable.
-     * @param response The server's response.
-     */
-    public void handleFailure(HttpResponse response);
-
-    /**
-     * An unexpected error occurred.
-     */
-    public void handleError(Exception e);
-  }
-
-  protected final NodeAssignmentCallback callback;
-
-  public EnsureClusterURLStage(NodeAssignmentCallback callback) {
-    super();
-    this.callback = callback;
-  }
-
-  // TODO: if cluster URL has changed since last time, we need to ensure that we do
-  // a fresh start. This takes place at the GlobalSession level. Verify!
-  /**
-   * Fetch a node/weave cluster URL from a server.
-   *
-   * @param nodeWeaveURL
-   *          Where to request the cluster URL from, usually something like:
-   *          <code>https://server/pathname/version/username/node/weave</code>.
-   * @throws URISyntaxException
-   */
-  public static void fetchClusterURL(final String nodeWeaveURL,
-                                     final ClusterURLFetchDelegate delegate) throws URISyntaxException {
-    Logger.info(LOG_TAG, "In fetchClusterURL: node/weave is " + nodeWeaveURL);
-
-    BaseResource resource = new BaseResource(nodeWeaveURL);
-    resource.delegate = new BaseResourceDelegate(resource) {
-      @Override
-      public String getUserAgent() {
-        return SyncConstants.USER_AGENT;
-      }
-
-      /**
-       * Handle the response for GET https://server/pathname/version/username/node/weave.
-       *
-       * Returns the Sync Node that the client is located on.
-       * Storage operations should be directed to that node.
-       *
-       * Return value: the node URL, an unadorned (not JSON) string.
-       *
-       * node may be 'null' if no node can be assigned at this time, probably
-       * due to registration throttling.
-       *
-       * Possible errors:
-       *
-       * 503: there was an error getting a node | empty body
-       *
-       * 400: for historical reasons treated as 404.
-       *
-       * 404: user not found | empty body
-       *
-       * {@link "http://docs.services.mozilla.com/reg/apis.html"}
-       */
-      @Override
-      public void handleHttpResponse(HttpResponse response) {
-        try {
-          int status = response.getStatusLine().getStatusCode();
-          switch (status) {
-          case 200:
-            Logger.info(LOG_TAG, "Got 200 for node/weave cluster URL request (user found; succeeding).");
-            HttpEntity entity = response.getEntity();
-            if (entity == null) {
-              delegate.handleThrottled();
-              BaseResource.consumeEntity(response);
-              return;
-            }
-            String output = null;
-            try {
-              InputStream content = entity.getContent();
-              BufferedReader reader = new BufferedReader(new InputStreamReader(content, "UTF-8"), 1024);
-              output = reader.readLine();
-              BaseResource.consumeReader(reader);
-              reader.close();
-            } catch (IllegalStateException | IOException e) {
-              delegate.handleError(e);
-              BaseResource.consumeEntity(response);
-              return;
-            }
-
-            if (output == null || output.equals("null")) {
-              delegate.handleThrottled();
-              return;
-            }
-
-            try {
-              URI uri = new URI(output);
-              delegate.handleSuccess(uri);
-            } catch (URISyntaxException e) {
-              delegate.handleError(e);
-            }
-            break;
-          case 400:
-          case 404:
-            Logger.info(LOG_TAG, "Got " + status + " for node/weave cluster URL request (user not found; failing).");
-            delegate.handleFailure(response);
-            break;
-          case 503:
-            Logger.info(LOG_TAG, "Got 503 for node/weave cluster URL request (error fetching node; failing).");
-            delegate.handleFailure(response);
-            break;
-          default:
-            Logger.warn(LOG_TAG, "Got " + status + " for node/weave cluster URL request (unexpected HTTP status; failing).");
-            delegate.handleFailure(response);
-          }
-        } finally {
-          BaseResource.consumeEntity(response);
-        }
-
-        BaseResource.consumeEntity(response);
-      }
-
-      @Override
-      public void handleHttpProtocolException(ClientProtocolException e) {
-        delegate.handleError(e);
-      }
-
-      @Override
-      public void handleHttpIOException(IOException e) {
-        delegate.handleError(e);
-      }
-
-      @Override
-      public void handleTransportException(GeneralSecurityException e) {
-        delegate.handleError(e);
-      }
-    };
-
-    resource.get();
-  }
-
-  @Override
-  public void execute() throws NoSuchStageException {
-    final URI oldClusterURL = session.config.getClusterURL();
-    final boolean wantNodeAssignment = callback.wantNodeAssignment();
-
-    if (!wantNodeAssignment && oldClusterURL != null) {
-      Logger.info(LOG_TAG, "Cluster URL is already set and not stale. Continuing with sync.");
-      session.advance();
-      return;
-    }
-
-    Logger.info(LOG_TAG, "Fetching cluster URL.");
-    final ClusterURLFetchDelegate delegate = new ClusterURLFetchDelegate() {
-
-      @Override
-      public void handleSuccess(final URI url) {
-        Logger.info(LOG_TAG, "Node assignment pointed us to " + url);
-
-        if (oldClusterURL != null && oldClusterURL.equals(url)) {
-          // Our cluster URL is marked as stale and the fresh cluster URL is the same -- this is the user's problem.
-          callback.informNodeAuthenticationFailed(session, url);
-          session.abort(new NodeAuthenticationException(), "User password has changed.");
-          return;
-        }
-
-        callback.informNodeAssigned(session, oldClusterURL, url); // No matter what, we're getting a new node/weave clusterURL.
-        session.config.setClusterURL(url);
-
-        session.advance();
-      }
-
-      @Override
-      public void handleThrottled() {
-        session.abort(new NullClusterURLException(), "Got 'null' cluster URL. Aborting.");
-      }
-
-      @Override
-      public void handleFailure(HttpResponse response) {
-        int statusCode = response.getStatusLine().getStatusCode();
-        Logger.warn(LOG_TAG, "Got HTTP failure fetching node assignment: " + statusCode);
-        if (statusCode == 404) {
-          URI serverURL = null;
-          try {
-            serverURL = new URI(callback.nodeWeaveURL());
-          } catch (URISyntaxException e) {
-            // Fall through to abort.
-          }
-          if (serverURL != null) {
-            Logger.info(LOG_TAG, "Using serverURL <" + serverURL.toASCIIString() + "> as clusterURL.");
-            session.config.setClusterURL(serverURL);
-            session.advance();
-            return;
-          }
-          Logger.warn(LOG_TAG, "No serverURL set to use as fallback cluster URL. Aborting sync.");
-          // Fall through to abort.
-        } else {
-          session.interpretHTTPFailure(response);
-        }
-        session.abort(new Exception("HTTP failure."), "Got failure fetching cluster URL.");
-      }
-
-      @Override
-      public void handleError(Exception e) {
-        session.abort(e, "Got exception fetching cluster URL.");
-      }
-    };
-
-    ThreadPool.run(new Runnable() {
-      @Override
-      public void run() {
-        try {
-          fetchClusterURL(callback.nodeWeaveURL(), delegate);
-        } catch (URISyntaxException e) {
-          session.abort(e, "Invalid URL for node/weave.");
-        }
-      }});
-  }
-}
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/GlobalSyncStage.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/GlobalSyncStage.java
@@ -12,21 +12,19 @@ import java.util.Map;
 
 import org.mozilla.gecko.sync.GlobalSession;
 
 
 public interface GlobalSyncStage {
   public static enum Stage {
     idle,                       // Start state.
     checkPreconditions,         // Preparation of the basics. TODO: clear status
-    ensureClusterURL,           // Setting up where we talk to.
     fetchInfoCollections,       // Take a look at timestamps.
     fetchMetaGlobal,
     ensureKeysStage,
-    attemptMigrationStage,
     /*
     ensureSpecialRecords,
     updateEngineTimestamps,
     */
     syncClientsEngine(SyncClientsEngineStage.STAGE_NAME),
     /*
     processFirstSyncPref,
     processClientCommands,
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/stage/NoSyncIDException.java
+++ /dev/null
@@ -1,17 +0,0 @@
-/* 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/. */
-
-package org.mozilla.gecko.sync.stage;
-
-import org.mozilla.gecko.sync.SyncException;
-
-public class NoSyncIDException extends SyncException {
-  public String engineName;
-  public NoSyncIDException(String engineName) {
-    this.engineName = engineName;
-  }
-
-  private static final long serialVersionUID = -4750430900197986797L;
-
-}
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/TestClientsStage.java
+++ b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/TestClientsStage.java
@@ -45,17 +45,17 @@ public class TestClientsStage extends An
     final GlobalSessionCallback callback = new DefaultGlobalSessionCallback();
     final ClientsDataDelegate delegate = new MockClientsDataDelegate();
 
     final KeyBundle keyBundle = new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY);
     final AuthHeaderProvider authHeaderProvider = new BasicAuthHeaderProvider(TEST_USERNAME, TEST_PASSWORD);
     final SharedPreferences prefs = new MockSharedPreferences();
     final SyncConfiguration config = new SyncConfiguration(TEST_USERNAME, authHeaderProvider, prefs);
     config.syncKeyBundle = keyBundle;
-    GlobalSession session = new GlobalSession(config, callback, context, delegate, callback);
+    GlobalSession session = new GlobalSession(config, callback, context, delegate);
 
     SyncClientsEngineStage stage = new SyncClientsEngineStage() {
 
       @Override
       public synchronized ClientsDatabaseAccessor getClientsDatabaseAccessor() {
         if (db == null) {
           db = dataAccessor;
         }
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/TestResetting.java
+++ b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/TestResetting.java
@@ -158,17 +158,17 @@ public class TestResetting extends Andro
 
   private GlobalSession createDefaultGlobalSession(final GlobalSessionCallback callback) throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException, ParseException, CryptoException {
 
     final KeyBundle keyBundle = new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY);
     final AuthHeaderProvider authHeaderProvider = new BasicAuthHeaderProvider(TEST_USERNAME, TEST_PASSWORD);
     final SharedPreferences prefs = new MockSharedPreferences();
     final SyncConfiguration config = new SyncConfiguration(TEST_USERNAME, authHeaderProvider, prefs);
     config.syncKeyBundle = keyBundle;
-    return new GlobalSession(config, callback, getApplicationContext(), null, callback) {
+    return new GlobalSession(config, callback, getApplicationContext(), null) {
       @Override
       public boolean isEngineRemotelyEnabled(String engineName,
                                      EngineSettings engineSettings)
         throws MetaGlobalException {
         return true;
       }
 
       @Override
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/DefaultGlobalSessionCallback.java
+++ b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/DefaultGlobalSessionCallback.java
@@ -11,36 +11,21 @@ import org.mozilla.gecko.sync.stage.Glob
 
 public class DefaultGlobalSessionCallback implements GlobalSessionCallback {
 
   @Override
   public void requestBackoff(long backoff) {
   }
 
   @Override
-  public boolean wantNodeAssignment() {
-    return false;
-  }
-
-  @Override
   public void informUnauthorizedResponse(GlobalSession globalSession,
                                          URI oldClusterURL) {
   }
 
   @Override
-  public void informNodeAssigned(GlobalSession globalSession,
-                                 URI oldClusterURL, URI newClusterURL) {
-  }
-
-  @Override
-  public void informNodeAuthenticationFailed(GlobalSession globalSession,
-                                             URI failedClusterURL) {
-  }
-
-  @Override
   public void informUpgradeRequiredResponse(GlobalSession session) {
   }
 
   @Override
   public void informMigrated(GlobalSession globalSession) {
   }
 
   @Override
@@ -59,14 +44,9 @@ public class DefaultGlobalSessionCallbac
   public void handleStageCompleted(Stage currentState,
                                    GlobalSession globalSession) {
   }
 
   @Override
   public boolean shouldBackOffStorage() {
     return false;
   }
-
-  @Override
-  public String nodeWeaveURL() {
-    return null;
-  }
 }
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockPrefsGlobalSession.java
+++ b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/MockPrefsGlobalSession.java
@@ -26,17 +26,17 @@ public class MockPrefsGlobalSession exte
 
   public MockSharedPreferences prefs;
 
   public MockPrefsGlobalSession(
       SyncConfiguration config, GlobalSessionCallback callback, Context context,
       ClientsDataDelegate clientsDelegate)
       throws SyncConfigurationException, IllegalArgumentException, IOException,
       ParseException, NonObjectJSONException {
-    super(config, callback, context, clientsDelegate, callback);
+    super(config, callback, context, clientsDelegate);
   }
 
   public static MockPrefsGlobalSession getSession(
       String username, String password,
       KeyBundle syncKeyBundle, GlobalSessionCallback callback, Context context,
       ClientsDataDelegate clientsDelegate)
       throws SyncConfigurationException, IllegalArgumentException, IOException,
       ParseException, NonObjectJSONException {
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestClientsEngineStage.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestClientsEngineStage.java
@@ -64,17 +64,17 @@ public class TestClientsEngineStage exte
   public TestClientsEngineStage() throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException, ParseException, CryptoException, URISyntaxException {
     super();
     session = initializeSession();
   }
 
   // Static so we can set it during the constructor. This is so evil.
   private static MockGlobalSessionCallback callback;
   private static GlobalSession initializeSession() throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException, ParseException, CryptoException, URISyntaxException {
-    callback = new MockGlobalSessionCallback(TEST_SERVER);
+    callback = new MockGlobalSessionCallback();
     SyncConfiguration config = new SyncConfiguration(USERNAME, new BasicAuthHeaderProvider(USERNAME, PASSWORD), new MockSharedPreferences());
     config.syncKeyBundle = new KeyBundle(USERNAME, SYNC_KEY);
     GlobalSession session = new MockClientsGlobalSession(config, callback);
     session.config.setClusterURL(new URI(TEST_SERVER));
     session.config.setCollectionKeys(CollectionKeys.generateCollectionKeys());
     return session;
   }
 
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestGlobalSession.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestGlobalSession.java
@@ -103,17 +103,17 @@ public class TestGlobalSession {
   }
 
   /**
    * Test that handleHTTPError does in fact backoff.
    */
   @Test
   public void testBackoffCalledByHandleHTTPError() {
     try {
-      final MockGlobalSessionCallback callback = new MockGlobalSessionCallback(TEST_CLUSTER_URL);
+      final MockGlobalSessionCallback callback = new MockGlobalSessionCallback();
       SyncConfiguration config = new SyncConfiguration(TEST_USERNAME, new BasicAuthHeaderProvider(TEST_USERNAME, TEST_PASSWORD), new MockSharedPreferences(), new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY));
       final GlobalSession session = new MockGlobalSession(config, callback);
 
       final HttpResponse response = new BasicHttpResponse(
         new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 503, "Illegal method/protocol"));
       response.addHeader("X-Weave-Backoff", Long.toString(TEST_BACKOFF_IN_SECONDS)); // Backoff given in seconds.
 
       getTestWaiter().performWait(WaitHelper.onThreadRunnable(new Runnable() {
@@ -135,17 +135,17 @@ public class TestGlobalSession {
   }
 
   /**
    * Test that a trivially successful GlobalSession does not fail or backoff.
    */
   @Test
   public void testSuccessCalledAfterStages() {
     try {
-      final MockGlobalSessionCallback callback = new MockGlobalSessionCallback(TEST_CLUSTER_URL);
+      final MockGlobalSessionCallback callback = new MockGlobalSessionCallback();
       SyncConfiguration config = new SyncConfiguration(TEST_USERNAME, new BasicAuthHeaderProvider(TEST_USERNAME, TEST_PASSWORD), new MockSharedPreferences(), new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY));
       final GlobalSession session = new MockGlobalSession(config, callback);
 
       getTestWaiter().performWait(WaitHelper.onThreadRunnable(new Runnable() {
         @Override
         public void run() {
           try {
             session.start();
@@ -168,17 +168,17 @@ public class TestGlobalSession {
   }
 
   /**
    * Test that a failing GlobalSession does in fact fail and back off.
    */
   @Test
   public void testBackoffCalledInStages() {
     try {
-      final MockGlobalSessionCallback callback = new MockGlobalSessionCallback(TEST_CLUSTER_URL);
+      final MockGlobalSessionCallback callback = new MockGlobalSessionCallback();
 
       // Stage fakes a 503 and sets X-Weave-Backoff header to the given seconds.
       final GlobalSyncStage stage = new MockAbstractNonRepositorySyncStage() {
         @Override
         public void execute() {
           final HttpResponse response = new BasicHttpResponse(
             new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 503, "Illegal method/protocol"));
 
@@ -261,17 +261,17 @@ public class TestGlobalSession {
         if (stageShouldAdvance) {
           session.advance();
           return;
         }
         session.abort(null,  "Stage intentionally failed.");
       }
     };
 
-    final MockGlobalSessionCallback callback = new MockGlobalSessionCallback(TEST_CLUSTER_URL);
+    final MockGlobalSessionCallback callback = new MockGlobalSessionCallback();
     SyncConfiguration config = new SyncConfiguration(TEST_USERNAME, new BasicAuthHeaderProvider(TEST_USERNAME, TEST_PASSWORD), new MockSharedPreferences(), new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY));
     final GlobalSession session = new MockGlobalSession(config, callback)
                                       .withStage(Stage.syncBookmarks, stage);
 
     data.startHTTPServer(server);
     WaitHelper.getTestWaiter().performWait(WaitHelper.onThreadRunnable(new Runnable() {
       @Override
       public void run() {
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/MockGlobalSessionCallback.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/helpers/MockGlobalSessionCallback.java
@@ -15,44 +15,29 @@ import static org.junit.Assert.assertEqu
 /**
  * A callback for use with a GlobalSession that records what happens for later
  * inspection.
  *
  * This callback is expected to be used from within the friendly confines of a
  * WaitHelper performWait.
  */
 public class MockGlobalSessionCallback implements GlobalSessionCallback {
-  public final String nodeWeaveURL;
-
-  public MockGlobalSessionCallback(String nodeWeaveURL) {
-    this.nodeWeaveURL = nodeWeaveURL;
-  }
-
-  public MockGlobalSessionCallback() {
-    this(null);
-  }
-
   protected WaitHelper testWaiter() {
     return WaitHelper.getTestWaiter();
   }
 
   public int stageCounter = Stage.values().length - 1; // Exclude starting state.
   public boolean calledSuccess = false;
   public boolean calledError = false;
   public Exception calledErrorException = null;
   public boolean calledAborted = false;
   public boolean calledRequestBackoff = false;
-  public boolean calledInformNodeAuthenticationFailed = false;
-  public boolean calledInformNodeAssigned = false;
   public boolean calledInformUnauthorizedResponse = false;
   public boolean calledInformUpgradeRequiredResponse = false;
   public boolean calledInformMigrated = false;
-  public URI calledInformNodeAuthenticationFailedClusterURL = null;
-  public URI calledInformNodeAssignedOldClusterURL = null;
-  public URI calledInformNodeAssignedNewClusterURL = null;
   public URI calledInformUnauthorizedResponseClusterURL = null;
   public long weaveBackoff = -1;
 
   @Override
   public void handleSuccess(GlobalSession globalSession) {
     this.calledSuccess = true;
     assertEquals(0, this.stageCounter);
     this.testWaiter().performNotify();
@@ -79,29 +64,16 @@ public class MockGlobalSessionCallback i
 
   @Override
   public void requestBackoff(long backoff) {
     this.calledRequestBackoff = true;
     this.weaveBackoff = backoff;
   }
 
   @Override
-  public void informNodeAuthenticationFailed(GlobalSession session, URI clusterURL) {
-    this.calledInformNodeAuthenticationFailed = true;
-    this.calledInformNodeAuthenticationFailedClusterURL = clusterURL;
-  }
-
-  @Override
-  public void informNodeAssigned(GlobalSession session, URI oldClusterURL, URI newClusterURL) {
-    this.calledInformNodeAssigned = true;
-    this.calledInformNodeAssignedOldClusterURL = oldClusterURL;
-    this.calledInformNodeAssignedNewClusterURL = newClusterURL;
-  }
-
-  @Override
   public void informUnauthorizedResponse(GlobalSession session, URI clusterURL) {
     this.calledInformUnauthorizedResponse = true;
     this.calledInformUnauthorizedResponseClusterURL = clusterURL;
   }
 
   @Override
   public void informUpgradeRequiredResponse(GlobalSession session) {
     this.calledInformUpgradeRequiredResponse = true;
@@ -111,19 +83,9 @@ public class MockGlobalSessionCallback i
   public void informMigrated(GlobalSession session) {
     this.calledInformMigrated = true;
   }
 
   @Override
   public boolean shouldBackOffStorage() {
     return false;
   }
-
-  @Override
-  public boolean wantNodeAssignment() {
-    return false;
-  }
-
-  @Override
-  public String nodeWeaveURL() {
-    return nodeWeaveURL;
-  }
 }
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/DefaultGlobalSessionCallback.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/DefaultGlobalSessionCallback.java
@@ -11,35 +11,19 @@ import java.net.URI;
 
 public class DefaultGlobalSessionCallback implements GlobalSessionCallback {
 
   @Override
   public void requestBackoff(long backoff) {
   }
 
   @Override
-  public boolean wantNodeAssignment() {
-    return false;
-  }
-
-  @Override
   public void informUnauthorizedResponse(GlobalSession globalSession,
                                          URI oldClusterURL) {
   }
-
-  @Override
-  public void informNodeAssigned(GlobalSession globalSession,
-                                 URI oldClusterURL, URI newClusterURL) {
-  }
-
-  @Override
-  public void informNodeAuthenticationFailed(GlobalSession globalSession,
-                                             URI failedClusterURL) {
-  }
-
   @Override
   public void informUpgradeRequiredResponse(GlobalSession session) {
   }
 
   @Override
   public void informMigrated(GlobalSession globalSession) {
   }
 
@@ -59,14 +43,9 @@ public class DefaultGlobalSessionCallbac
   public void handleStageCompleted(Stage currentState,
                                    GlobalSession globalSession) {
   }
 
   @Override
   public boolean shouldBackOffStorage() {
     return false;
   }
-
-  @Override
-  public String nodeWeaveURL() {
-    return null;
-  }
 }
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockPrefsGlobalSession.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/MockPrefsGlobalSession.java
@@ -25,17 +25,17 @@ public class MockPrefsGlobalSession exte
 
   public MockSharedPreferences prefs;
 
   public MockPrefsGlobalSession(
       SyncConfiguration config, GlobalSessionCallback callback, Context context,
       ClientsDataDelegate clientsDelegate)
       throws SyncConfigurationException, IllegalArgumentException, IOException,
       ParseException, NonObjectJSONException {
-    super(config, callback, context, clientsDelegate, callback);
+    super(config, callback, context, clientsDelegate);
   }
 
   public static MockPrefsGlobalSession getSession(
       String username, String password,
       KeyBundle syncKeyBundle, GlobalSessionCallback callback, Context context,
       ClientsDataDelegate clientsDelegate)
       throws SyncConfigurationException, IllegalArgumentException, IOException,
       ParseException, NonObjectJSONException {
deleted file mode 100644
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/stage/test/TestEnsureClusterURLStage.java
+++ /dev/null
@@ -1,311 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.sync.stage.test;
-
-import ch.boye.httpclientandroidlib.HttpResponse;
-import ch.boye.httpclientandroidlib.ProtocolVersion;
-import ch.boye.httpclientandroidlib.message.BasicHttpResponse;
-import ch.boye.httpclientandroidlib.message.BasicStatusLine;
-import org.json.simple.parser.ParseException;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.android.sync.test.helpers.HTTPServerTestHelper;
-import org.mozilla.android.sync.test.helpers.MockGlobalSessionCallback;
-import org.mozilla.android.sync.test.helpers.MockServer;
-import org.mozilla.gecko.background.testhelpers.MockGlobalSession;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.sync.AlreadySyncingException;
-import org.mozilla.gecko.sync.GlobalSession;
-import org.mozilla.gecko.sync.NodeAuthenticationException;
-import org.mozilla.gecko.sync.NonObjectJSONException;
-import org.mozilla.gecko.sync.SyncConfigurationException;
-import org.mozilla.gecko.sync.crypto.CryptoException;
-import org.mozilla.gecko.sync.crypto.KeyBundle;
-import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.stage.EnsureClusterURLStage;
-import org.mozilla.gecko.sync.stage.GlobalSyncStage.Stage;
-
-import java.io.IOException;
-import java.net.URI;
-import java.net.URISyntaxException;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-
-@RunWith(TestRunner.class)
-public class TestEnsureClusterURLStage {
-  private static final int     TEST_PORT        = HTTPServerTestHelper.getTestPort();
-  private static final String  TEST_SERVER      = "http://localhost:" + TEST_PORT + "/";
-  private static final String  TEST_OLD_CLUSTER_URL = TEST_SERVER + "cluster/old/";
-  private static final String  TEST_NEW_CLUSTER_URL = TEST_SERVER + "cluster/new/";
-  static String                TEST_NW_URL      = TEST_SERVER + "/1.0/c6o7dvmr2c4ud2fyv6woz2u4zi22bcyd/node/weave"; // GET https://server/pathname/version/username/node/weave
-  private HTTPServerTestHelper data             = new HTTPServerTestHelper();
-
-  private final String TEST_USERNAME            = "johndoe";
-  private final String TEST_PASSWORD            = "password";
-  private final String TEST_SYNC_KEY            = "abcdeabcdeabcdeabcdeabcdea";
-
-  @SuppressWarnings("static-method")
-  @Before
-  public void setUp() {
-    // BaseResource rewrites localhost to 10.0.2.2, which works on Android but not on desktop.
-    BaseResource.rewriteLocalhost = false;
-  }
-
-  public class MockClusterURLFetchDelegate implements EnsureClusterURLStage.ClusterURLFetchDelegate {
-    public boolean      successCalled   = false;
-    public URI          successUrl      = null;
-    public boolean      throttleCalled  = false;
-    public boolean      failureCalled   = false;
-    public HttpResponse failureResponse = null;
-    public boolean      errorCalled     = false;
-    public Exception    errorException  = null;
-
-    @Override
-    public void handleSuccess(URI url) {
-      successCalled = true;
-      successUrl = url;
-      WaitHelper.getTestWaiter().performNotify();
-    }
-
-    @Override
-    public void handleThrottled() {
-      throttleCalled = true;
-      WaitHelper.getTestWaiter().performNotify();
-    }
-
-    @Override
-    public void handleFailure(HttpResponse response) {
-      failureCalled = true;
-      failureResponse = response;
-      WaitHelper.getTestWaiter().performNotify();
-    }
-
-    @Override
-    public void handleError(Exception e) {
-      errorCalled = true;
-      errorException = e;
-      WaitHelper.getTestWaiter().performNotify(e);
-    }
-  }
-
-  public MockClusterURLFetchDelegate doFetchClusterURL() {
-    final MockClusterURLFetchDelegate delegate = new MockClusterURLFetchDelegate();
-    WaitHelper.getTestWaiter().performWait(new Runnable() {
-      @Override
-      public void run() {
-        try {
-          EnsureClusterURLStage.fetchClusterURL(TEST_NW_URL, delegate);
-        } catch (URISyntaxException e) {
-          WaitHelper.getTestWaiter().performNotify(e);
-        }
-      }
-    });
-    return delegate;
-  }
-
-  @Test
-  public void testFetchClusterURLGood() {
-    data.startHTTPServer(new MockServer(200, TEST_NEW_CLUSTER_URL));
-    MockClusterURLFetchDelegate delegate = doFetchClusterURL();
-    data.stopHTTPServer();
-
-    assertTrue(delegate.successCalled);
-    assertEquals(TEST_NEW_CLUSTER_URL, delegate.successUrl.toASCIIString());
-  }
-
-  @Test
-  public void testFetchClusterURLThrottled() {
-    data.startHTTPServer(new MockServer(200, "null"));
-    MockClusterURLFetchDelegate delegate = doFetchClusterURL();
-    data.stopHTTPServer();
-
-    assertTrue(delegate.throttleCalled);
-  }
-
-  @Test
-  public void testFetchClusterURLFailure() {
-    data.startHTTPServer(new MockServer(404, ""));
-    MockClusterURLFetchDelegate delegate = doFetchClusterURL();
-    data.stopHTTPServer();
-
-    assertTrue(delegate.failureCalled);
-    assertEquals(404, delegate.failureResponse.getStatusLine().getStatusCode());
-  }
-
-  @Test
-  /**
-   * Test that we fetch a node/weave cluster URL if there isn't a cluster URL set.
-   */
-  public void testNodeAssignedIfNotSet() throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException, ParseException, CryptoException {
-    final MockGlobalSessionCallback callback = new MockGlobalSessionCallback(TEST_SERVER);
-    final GlobalSession session = new MockGlobalSession(TEST_USERNAME, TEST_PASSWORD,
-        new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY), callback)
-    .withStage(Stage.ensureClusterURL, new EnsureClusterURLStage(callback));
-
-    assertEquals(null, session.config.getClusterURL());
-
-    data.startHTTPServer(new MockServer(200, TEST_NEW_CLUSTER_URL));
-    WaitHelper.getTestWaiter().performWait(WaitHelper.onThreadRunnable(new Runnable() {
-      public void run() {
-        try {
-          session.start();
-        } catch (AlreadySyncingException e) {
-          WaitHelper.getTestWaiter().performNotify(e);
-        }
-      }
-    }));
-    data.stopHTTPServer();
-
-    assertEquals(true,  callback.calledSuccess);
-    assertEquals(false, callback.calledError);
-    assertEquals(false, callback.calledAborted);
-    assertEquals(false, callback.calledRequestBackoff);
-
-    assertEquals(false, callback.calledInformUnauthorizedResponse);
-    assertEquals(true,  callback.calledInformNodeAssigned);
-    assertEquals(false, callback.calledInformNodeAuthenticationFailed);
-
-    assertSame(null, callback.calledInformNodeAssignedOldClusterURL);
-    assertEquals(TEST_NEW_CLUSTER_URL, callback.calledInformNodeAssignedNewClusterURL.toASCIIString());
-  }
-
-  /**
-   * Test that, when there is no override, we don't fetch a node/weave cluster URL if there is a cluster URL set.
-   */
-  @Test
-  public void testNodeNotAssignedIfSet() throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException, ParseException, CryptoException, URISyntaxException {
-    final MockGlobalSessionCallback callback = new MockGlobalSessionCallback(TEST_SERVER);
-    final GlobalSession session = new MockGlobalSession(TEST_USERNAME, TEST_PASSWORD,
-        new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY), callback)
-    .withStage(Stage.ensureClusterURL, new EnsureClusterURLStage(callback));
-
-    session.config.setClusterURL(new URI(TEST_OLD_CLUSTER_URL));
-    assertEquals(TEST_OLD_CLUSTER_URL, session.config.getClusterURLString());
-
-    data.startHTTPServer(new MockServer(200, TEST_NEW_CLUSTER_URL));
-    WaitHelper.getTestWaiter().performWait(WaitHelper.onThreadRunnable(new Runnable() {
-      public void run() {
-        try {
-          session.start();
-        } catch (AlreadySyncingException e) {
-          WaitHelper.getTestWaiter().performNotify(e);
-        }
-      }
-    }));
-    data.stopHTTPServer();
-
-    assertEquals(true,  callback.calledSuccess);
-    assertEquals(false, callback.calledError);
-    assertEquals(false, callback.calledAborted);
-    assertEquals(false, callback.calledRequestBackoff);
-
-    assertEquals(false, callback.calledInformUnauthorizedResponse);
-    assertEquals(false, callback.calledInformNodeAssigned);
-    assertEquals(false, callback.calledInformNodeAuthenticationFailed);
-  }
-
-  /**
-   * Test that, when there is an override, we fetch a node/weave cluster URL and callback if it is new.
-   */
-  @Test
-  public void testNodeAssignedCalledWhenOverridden() throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException, ParseException, CryptoException, URISyntaxException {
-    final MockGlobalSessionCallback callback = new MockGlobalSessionCallback(TEST_SERVER) {
-      @Override
-      public boolean wantNodeAssignment() {
-        return true;
-      }
-    };
-
-    final GlobalSession session = new MockGlobalSession(TEST_USERNAME, TEST_PASSWORD,
-        new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY), callback)
-    .withStage(Stage.ensureClusterURL, new EnsureClusterURLStage(callback));
-
-    session.config.setClusterURL(new URI(TEST_OLD_CLUSTER_URL));
-    assertEquals(TEST_OLD_CLUSTER_URL, session.config.getClusterURLString());
-
-    data.startHTTPServer(new MockServer(200, TEST_NEW_CLUSTER_URL));
-    WaitHelper.getTestWaiter().performWait(WaitHelper.onThreadRunnable(new Runnable() {
-      public void run() {
-        try {
-          session.start();
-        } catch (AlreadySyncingException e) {
-          WaitHelper.getTestWaiter().performNotify(e);
-        }
-      }
-    }));
-    data.stopHTTPServer();
-
-    assertEquals(true,  callback.calledSuccess);
-    assertEquals(false, callback.calledError);
-    assertEquals(false, callback.calledAborted);
-    assertEquals(false, callback.calledRequestBackoff);
-
-    assertEquals(false, callback.calledInformUnauthorizedResponse);
-    assertEquals(true,  callback.calledInformNodeAssigned);
-    assertEquals(false, callback.calledInformNodeAuthenticationFailed);
-
-    assertEquals(TEST_OLD_CLUSTER_URL, callback.calledInformNodeAssignedOldClusterURL.toASCIIString());
-    assertEquals(TEST_NEW_CLUSTER_URL, callback.calledInformNodeAssignedNewClusterURL.toASCIIString());
-  }
-
-  /**
-   * Test that, when there is an override, we fetch a node/weave cluster URL and callback correctly if it is not new.
-   */
-  @Test
-  public void testNodeFailedCalledWhenOverridden() throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException, ParseException, CryptoException, URISyntaxException {
-    final MockGlobalSessionCallback callback = new MockGlobalSessionCallback(TEST_SERVER) {
-      @Override
-      public boolean wantNodeAssignment() {
-        return true;
-      }
-    };
-
-    final GlobalSession session = new MockGlobalSession(TEST_USERNAME, TEST_PASSWORD,
-        new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY), callback)
-    .withStage(Stage.ensureClusterURL, new EnsureClusterURLStage(callback));
-
-    session.config.setClusterURL(new URI(TEST_OLD_CLUSTER_URL));
-    assertEquals(TEST_OLD_CLUSTER_URL, session.config.getClusterURLString());
-
-    data.startHTTPServer(new MockServer(200, TEST_OLD_CLUSTER_URL));
-    WaitHelper.getTestWaiter().performWait(WaitHelper.onThreadRunnable(new Runnable() {
-      public void run() {
-        try {
-          session.start();
-        } catch (AlreadySyncingException e) {
-          WaitHelper.getTestWaiter().performNotify(e);
-        }
-      }
-    }));
-    data.stopHTTPServer();
-
-    assertEquals(false, callback.calledSuccess);
-    assertEquals(true,  callback.calledError);
-    assertEquals(false, callback.calledAborted);
-    assertEquals(false, callback.calledRequestBackoff);
-    assertTrue(callback.calledErrorException instanceof NodeAuthenticationException);
-
-    assertEquals(false, callback.calledInformUnauthorizedResponse);
-    assertEquals(false, callback.calledInformNodeAssigned);
-    assertEquals(true,  callback.calledInformNodeAuthenticationFailed);
-    assertEquals(TEST_OLD_CLUSTER_URL, callback.calledInformNodeAuthenticationFailedClusterURL.toASCIIString());
-  }
-
-  @Test
-  public void testInterpretHTTPFailureCallsMaybeNodeReassigned() throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException, ParseException, CryptoException {
-    final MockGlobalSessionCallback callback = new MockGlobalSessionCallback(TEST_SERVER);
-    final GlobalSession session = new MockGlobalSession(TEST_USERNAME, TEST_PASSWORD,
-        new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY), callback);
-
-    final HttpResponse response = new BasicHttpResponse(
-      new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 401, "User authentication failed"));
-
-    session.interpretHTTPFailure(response);                        // This is synchronous...
-    assertEquals(true, callback.calledInformUnauthorizedResponse); // ... so we can test immediately.
-  }
-}
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/stage/test/TestEnsureCrypto5KeysStage.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/stage/test/TestEnsureCrypto5KeysStage.java
@@ -55,17 +55,17 @@ public class TestEnsureCrypto5KeysStage 
   private GlobalSession session;
 
   private boolean calledResetStages;
   private Collection<String> stagesReset;
 
   @Before
   public void setUp() throws Exception {
     syncKeyBundle = new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY);
-    callback = new MockGlobalSessionCallback(TEST_CLUSTER_URL);
+    callback = new MockGlobalSessionCallback();
     session = new MockGlobalSession(TEST_USERNAME, TEST_PASSWORD,
       syncKeyBundle, callback) {
       @Override
       protected void prepareStages() {
         super.prepareStages();
         withStage(Stage.ensureKeysStage, new EnsureCrypto5KeysStage());
       }
 
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/stage/test/TestFetchMetaGlobalStage.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/stage/test/TestFetchMetaGlobalStage.java
@@ -48,17 +48,16 @@ import static org.junit.Assert.assertTru
 @RunWith(TestRunner.class)
 public class TestFetchMetaGlobalStage {
   @SuppressWarnings("unused")
   private static final String  LOG_TAG          = "TestMetaGlobalStage";
 
   private static final int     TEST_PORT        = HTTPServerTestHelper.getTestPort();
   private static final String  TEST_SERVER      = "http://localhost:" + TEST_PORT + "/";
   private static final String  TEST_CLUSTER_URL = TEST_SERVER + "cluster/";
-  static String                TEST_NW_URL      = TEST_SERVER + "/1.0/c6o7dvmr2c4ud2fyv6woz2u4zi22bcyd/node/weave"; // GET https://server/pathname/version/username/node/weave
   private HTTPServerTestHelper data             = new HTTPServerTestHelper();
 
   private final String TEST_USERNAME            = "johndoe";
   private final String TEST_PASSWORD            = "password";
   private final String TEST_SYNC_KEY            = "abcdeabcdeabcdeabcdeabcdea";
 
   private final String TEST_INFO_COLLECTIONS_JSON = "{}";
 
@@ -92,17 +91,17 @@ public class TestFetchMetaGlobalStage {
     calledWipeServer = false;
     calledUploadKeys = false;
     calledResetAllStages = false;
 
     // Set info collections to not have crypto.
     infoCollections = new InfoCollections(ExtendedJSONObject.parseJSONObject(TEST_INFO_COLLECTIONS_JSON));
 
     syncKeyBundle = new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY);
-    callback = new MockGlobalSessionCallback(TEST_CLUSTER_URL);
+    callback = new MockGlobalSessionCallback();
     session = new MockGlobalSession(TEST_USERNAME, TEST_PASSWORD,
       syncKeyBundle, callback) {
       @Override
       protected void prepareStages() {
         super.prepareStages();
         withStage(Stage.fetchMetaGlobal, new FetchMetaGlobalStage());
       }