Back out bug 684798 parts 1 thru 3.
authorPhilipp von Weitershausen <philipp@weitershausen.de>
Thu, 20 Oct 2011 16:21:17 -0700
changeset 79079 353f5413395827fef072b15e6f30da40bfdeed27
parent 79065 f06dfa65c0beca988e13f26644be2aa498446511
child 79080 96c48e41ce91f96ff3e69e6abba997e64010f624
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
bugs684798
milestone10.0a1
Back out bug 684798 parts 1 thru 3.
services/sync/modules/engines.js
services/sync/modules/policies.js
services/sync/modules/service.js
services/sync/tests/unit/head_http_server.js
services/sync/tests/unit/test_errorhandler.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_wipeServer.js
--- a/services/sync/modules/engines.js
+++ b/services/sync/modules/engines.js
@@ -719,17 +719,17 @@ SyncEngine.prototype = {
       this._log.debug("Engine syncIDs: " + [engineData.syncID, this.syncID]);
       this.syncID = engineData.syncID;
       this._resetClient();
     };
 
     // Delete any existing data and reupload on bad version or missing meta.
     // No crypto component here...? We could regenerate per-collection keys...
     if (needsWipe) {
-      this.wipeServer();
+      this.wipeServer(true);
     }
 
     // Save objects that need to be uploaded in this._modified. We also save
     // the timestamp of this fetch in this.lastSyncLocal. As we successfully
     // upload objects we remove them from this._modified. If an error occurs
     // or any objects fail to upload, they will remain in this._modified. At
     // the end of a sync, or after an error, we add all objects remaining in
     // this._modified to the tracker.
@@ -1243,20 +1243,17 @@ SyncEngine.prototype = {
 
   _resetClient: function SyncEngine__resetClient() {
     this.resetLastSync();
     this.previousFailed = [];
     this.toFetch = [];
   },
 
   wipeServer: function wipeServer() {
-    let response = new Resource(this.engineURL).delete();
-    if (response.status != 200 && response.status != 404) {
-      throw response;
-    }
+    new Resource(this.engineURL).delete();
     this._resetClient();
   },
 
   removeClientData: function removeClientData() {
     // Implement this method in engines that store client specific data
     // on the server.
   },
 
--- a/services/sync/modules/policies.js
+++ b/services/sync/modules/policies.js
@@ -564,22 +564,17 @@ let ErrorHandler = {
         }
         this.dontIgnoreErrors = false;
         this.notifyOnNextTick("weave:ui:sync:finish");
         break;
     }
   },
 
   notifyOnNextTick: function notifyOnNextTick(topic) {
-    Utils.nextTick(function() {
-      this._log.trace("Notifying " + topic +
-                      ". Status.login is " + Status.login +
-                      ". Status.sync is " + Status.sync);
-      Svc.Obs.notify(topic);
-    }, this);
+    Utils.nextTick(function() Svc.Obs.notify(topic));
   },
 
   /**
    * Trigger a sync and don't muffle any errors, particularly network errors.
    */
   syncAndReportErrors: function syncAndReportErrors() {
     this._log.debug("Beginning user-triggered sync.");
 
--- a/services/sync/modules/service.js
+++ b/services/sync/modules/service.js
@@ -697,21 +697,18 @@ WeaveSvc.prototype = {
         // Last-ditch case.
         return false;
       }
       else {
         // No update needed: we're good!
         return true;
       }
 
-    } catch (ex) {
+    } catch (e) {
       // This means no keys are present, or there's a network error.
-      this._log.debug("Failed to fetch and verify keys: "
-                      + Utils.exceptionStr(ex));
-      ErrorHandler.checkServerError(ex);
       return false;
     }
   },
 
   verifyLogin: function verifyLogin()
     this._notify("verify-login", "", function() {
       if (!this.username) {
         this._log.warn("No username in verifyLogin.");
@@ -825,17 +822,16 @@ WeaveSvc.prototype = {
     let wbo = CollectionKeys.generateNewKeysWBO();
     this._log.info("Encrypting new key bundle.");
     wbo.encrypt(this.syncKeyBundle);
 
     this._log.info("Uploading...");
     let uploadRes = wbo.upload(this.cryptoKeysURL);
     if (uploadRes.status != 200) {
       this._log.warn("Got status " + uploadRes.status + " uploading new keys. What to do? Throw!");
-      ErrorHandler.checkServerError(uploadRes);
       throw new Error("Unable to upload symmetric keys.");
     }
     this._log.info("Got status " + uploadRes.status + " uploading keys.");
     let serverModified = uploadRes.obj;   // Modified timestamp according to server.
     this._log.debug("Server reports crypto modified: " + serverModified);
 
     // Now verify that info/collections shows them!
     this._log.debug("Verifying server collection records.");
@@ -1367,24 +1363,17 @@ WeaveSvc.prototype = {
         // without commands).
         // Note that we don't abort here; if there's a 401 because we've
         // been reassigned, we'll handle it around another engine.
         this._syncEngine(Clients);
       }
     }
 
     // Update engines because it might change what we sync.
-    try {
-      this._updateEnabledEngines();
-    } catch (ex) {
-      this._log.debug("Updating enabled engines failed: " +
-                      Utils.exceptionStr(ex));
-      ErrorHandler.checkServerError(ex);
-      throw ex;
-    }
+    this._updateEnabledEngines();
 
     try {
       for each (let engine in Engines.getEnabled()) {
         // If there's any problems with syncing the engine, report the failure
         if (!(this._syncEngine(engine)) || Status.enforceBackoff) {
           this._log.info("Aborting sync");
           break;
         }
@@ -1562,99 +1551,72 @@ WeaveSvc.prototype = {
   },
 
   _freshStart: function WeaveSvc__freshStart() {
     this._log.info("Fresh start. Resetting client and considering key upgrade.");
     this.resetClient();
     CollectionKeys.clear();
     this.upgradeSyncKey(this.syncID);
 
-    // Wipe the server.
-    let wipeTimestamp = this.wipeServer();
-
-    // Upload a new meta/global record.
     let meta = new WBORecord("meta", "global");
     meta.payload.syncID = this.syncID;
     meta.payload.storageVersion = STORAGE_VERSION;
     meta.isNew = true;
 
     this._log.debug("New metadata record: " + JSON.stringify(meta.payload));
-    let res = new Resource(this.metaURL);
-    // It would be good to set the X-If-Unmodified-Since header to `timestamp`
-    // for this PUT to ensure at least some level of transactionality.
-    // Unfortunately, the servers don't support it after a wipe right now
-    // (bug 693893), so we're going to defer this until bug 692700.
-    let resp = res.put(meta);
-    if (!resp.success) {
-      // If we got into a race condition, we'll abort the sync this way, too.
-      // That's fine. We'll just wait till the next sync. The client that we're
-      // racing is probably busy uploading stuff right now anyway.
+    let resp = new Resource(this.metaURL).put(meta);
+    if (!resp.success)
       throw resp;
-    }
     Records.set(this.metaURL, meta);
 
     // Wipe everything we know about except meta because we just uploaded it
     let collections = [Clients].concat(Engines.getAll()).map(function(engine) {
       return engine.name;
     });
+    this.wipeServer(collections);
 
     // Generate, upload, and download new keys. Do this last so we don't wipe
     // them...
     this.generateNewSymmetricKeys();
   },
 
   /**
    * Wipe user data from the server.
    *
    * @param collections [optional]
-   *        Array of collections to wipe. If not given, all collections are
-   *        wiped by issuing a DELETE request for `storageURL`.
+   *        Array of collections to wipe. If not given, all collections are wiped.
    *
-   * @return the server's timestamp of the (last) DELETE.
+   * @param includeKeys [optional]
+   *        If true, keys/pubkey and keys/privkey are deleted from the server.
+   *        This is false by default, which will cause the usual upgrade paths
+   *        to leave those keys on the server. This is to solve Bug 614737: old
+   *        clients check for keys *before* checking storage versions.
+   *
+   *        Note that this parameter only has an effect if `collections` is not
+   *        passed. If you explicitly pass a list of collections, they will be
+   *        processed regardless of the value of `includeKeys`.
    */
-  wipeServer: function wipeServer(collections)
+  wipeServer: function wipeServer(collections, includeKeyPairs)
     this._notify("wipe-server", "", function() {
-      let response;
       if (!collections) {
-        // Strip the trailing slash.
-        let res = new Resource(this.storageURL.slice(0, -1));
-        res.setHeader("X-Confirm-Delete", "1");
-        try {
-          response = res.delete();
-        } catch (ex) {
-          this._log.debug("Failed to wipe server: " + Utils.exceptionStr(ex));
-          throw ex;
+        collections = [];
+        let info = new Resource(this.infoURL).get();
+        for (let name in info.obj) {
+          if (includeKeyPairs || (name != "keys"))
+            collections.push(name);
         }
-        if (response.status != 200 && response.status != 404) {
-          this._log.debug("Aborting wipeServer. Server responded with " +
-                          response.status + " response for " + this.storageURL);
-          throw response;
-        }
-        return response.headers["x-weave-timestamp"];
       }
-      let timestamp;
       for each (let name in collections) {
         let url = this.storageURL + name;
-        try {
-          response = new Resource(url).delete();
-        } catch (ex) {
-          this._log.debug("Failed to wipe '" + name + "' collection: " +
-                          Utils.exceptionStr(ex));
-          throw ex;
-        }
+        let response = new Resource(url).delete();
         if (response.status != 200 && response.status != 404) {
-          this._log.debug("Aborting wipeServer. Server responded with " +
-                          response.status + " response for " + url);
-          throw response;
-        }
-        if ("x-weave-timestamp" in response.headers) {
-          timestamp = response.headers["x-weave-timestamp"];
+          throw "Aborting wipeServer. Server responded with "
+                + response.status + " response for " + url;
         }
       }
-      return timestamp;
     })(),
 
   /**
    * Wipe all local user data.
    *
    * @param engines [optional]
    *        Array of engine names to wipe. If not given, all engines are used.
    */
@@ -1712,16 +1674,17 @@ WeaveSvc.prototype = {
    * Reset local service information like logs, sync times, caches.
    */
   resetService: function WeaveSvc_resetService()
     this._catch(this._notify("reset-service", "", function() {
       this._log.info("Service reset.");
 
       // Pretend we've never synced to the server and drop cached data
       this.syncID = "";
+      Svc.Prefs.reset("lastSync");
       Records.clearCache();
     }))(),
 
   /**
    * Reset the client by getting rid of any local server data and client data.
    *
    * @param engines [optional]
    *        Array of engine names to reset. If not given, all engines are used.
--- a/services/sync/tests/unit/head_http_server.js
+++ b/services/sync/tests/unit/head_http_server.js
@@ -5,27 +5,16 @@ 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.
 function new_timestamp() {
   return Math.round(Date.now() / 10) / 100;
 }
 
-function return_timestamp(request, response, timestamp) {
-  if (!timestamp) {
-    timestamp = new_timestamp();
-  }
-  let body = "" + timestamp;
-  response.setHeader("X-Weave-Timestamp", body);
-  response.setStatusLine(request.httpVersion, 200, "OK");
-  response.bodyOutputStream.write(body, body.length);
-  return timestamp;
-}
-
 function httpd_setup (handlers) {
   let server = new nsHttpServer();
   let port   = 8080;
   for (let path in handlers) {
     server.registerPathHandler(path, handlers[path]);
   }
   try {
     server.start(port);
@@ -614,17 +603,17 @@ SyncServer.prototype = {
   },
 
   /**
    * Return a server timestamp for a record.
    * The server returns timestamps with 1/100 sec granularity. Note that this is
    * subject to change: see Bug 650435.
    */
   timestamp: function timestamp() {
-    return new_timestamp();
+    return Math.round(Date.now() / 10) / 100;
   },
 
   /**
    * Create a new user, complete with an empty set of collections.
    *
    * @param username
    *        The username to use. An Error will be thrown if a user by that name
    *        already exists.
--- a/services/sync/tests/unit/test_errorhandler.js
+++ b/services/sync/tests/unit/test_errorhandler.js
@@ -15,17 +15,18 @@ const LOG_PREFIX_ERROR   = "error-";
 
 const PROLONGED_ERROR_DURATION =
   (Svc.Prefs.get('errorhandler.networkFailureReportTimeout') * 2) * 1000;
 
 const NON_PROLONGED_ERROR_DURATION =
   (Svc.Prefs.get('errorhandler.networkFailureReportTimeout') / 2) * 1000;
 
 function setLastSync(lastSyncValue) {
-  Svc.Prefs.set("lastSync", (new Date(Date.now() - lastSyncValue)).toString());
+  Svc.Prefs.set("lastSync", (new Date(Date.now() -
+    lastSyncValue)).toString());
 }
 
 function CatapultEngine() {
   SyncEngine.call(this, "Catapult");
 }
 CatapultEngine.prototype = {
   __proto__: SyncEngine.prototype,
   exception: null, // tests fill this in
@@ -73,45 +74,33 @@ function sync_httpd_setup() {
   let clientsColl = new ServerCollection({}, true);
 
   // Tracking info/collections.
   let collectionsHelper = track_collections_helper();
   let upd = collectionsHelper.with_updated_collection;
 
   let handler_401 = httpd_handler(401, "Unauthorized");
   return httpd_setup({
-    // Normal server behaviour.
     "/1.1/johndoe/storage/meta/global": upd("meta", global.handler()),
     "/1.1/johndoe/info/collections": collectionsHelper.handler,
     "/1.1/johndoe/storage/crypto/keys":
       upd("crypto", (new ServerWBO("keys")).handler()),
     "/1.1/johndoe/storage/clients": upd("clients", clientsColl.handler()),
 
-    // Credentials are wrong or node reallocated.
     "/1.1/janedoe/storage/meta/global": handler_401,
     "/1.1/janedoe/info/collections": handler_401,
 
-    // Maintenance or overloaded (503 + Retry-After) at info/collections.
-    "/maintenance/1.1/broken.info/info/collections": service_unavailable,
-
-    // Maintenance or overloaded (503 + Retry-After) at meta/global.
-    "/maintenance/1.1/broken.meta/storage/meta/global": service_unavailable,
-    "/maintenance/1.1/broken.meta/info/collections": collectionsHelper.handler,
+    "/maintenance/1.1/johnsmith/info/collections": service_unavailable,
 
-    // Maintenance or overloaded (503 + Retry-After) at crypto/keys.
-    "/maintenance/1.1/broken.keys/storage/meta/global": upd("meta", global.handler()),
-    "/maintenance/1.1/broken.keys/info/collections": collectionsHelper.handler,
-    "/maintenance/1.1/broken.keys/storage/crypto/keys": service_unavailable,
+    "/maintenance/1.1/janesmith/storage/meta/global": service_unavailable,
+    "/maintenance/1.1/janesmith/info/collections": collectionsHelper.handler,
 
-    // Maintenance or overloaded (503 + Retry-After) at wiping collection.
-    "/maintenance/1.1/broken.wipe/info/collections": collectionsHelper.handler,
-    "/maintenance/1.1/broken.wipe/storage/meta/global": upd("meta", global.handler()),
-    "/maintenance/1.1/broken.wipe/storage/crypto/keys":
-      upd("crypto", (new ServerWBO("keys")).handler()),
-    "/maintenance/1.1/broken.wipe/storage": service_unavailable
+    "/maintenance/1.1/foo/storage/meta/global": upd("meta", global.handler()),
+    "/maintenance/1.1/foo/info/collections": collectionsHelper.handler,
+    "/maintenance/1.1/foo/storage/crypto/keys": service_unavailable,
   });
 }
 
 function setUp() {
   Service.username = "johndoe";
   Service.password = "ilovejane";
   Service.passphrase = "abcdeabcdeabcdeabcdeabcdea";
   Service.clusterURL = "http://localhost:8080/";
@@ -739,19 +728,19 @@ add_test(function test_sync_server_maint
   Service.sync();
 });
 
 add_test(function test_info_collections_login_server_maintenance_error() {
   // Test info/collections server maintenance errors are not reported.
   let server = sync_httpd_setup();
   setUp();
 
-  Service.username = "broken.info";
   Service.clusterURL = "http://localhost:8080/maintenance/";
 
+  Service.username = "johnsmith";
   let backoffInterval;
   Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
     Svc.Obs.remove("weave:service:backoff:interval", observe);
     backoffInterval = subject;
   });
 
   function onUIUpdate() {
     do_throw("Shouldn't get here!");
@@ -778,19 +767,19 @@ add_test(function test_info_collections_
   Service.sync();
 });
 
 add_test(function test_meta_global_login_server_maintenance_error() {
   // Test meta/global server maintenance errors are not reported.
   let server = sync_httpd_setup();
   setUp();
 
-  Service.username = "broken.meta";
   Service.clusterURL = "http://localhost:8080/maintenance/";
 
+  Service.username = "janesmith";
   let backoffInterval;
   Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
     Svc.Obs.remove("weave:service:backoff:interval", observe);
     backoffInterval = subject;
   });
 
   function onUIUpdate() {
     do_throw("Shouldn't get here!");
@@ -817,18 +806,18 @@ add_test(function test_meta_global_login
   Service.sync();
 });
 
 add_test(function test_crypto_keys_login_server_maintenance_error() {
   // Test crypto/keys server maintenance errors are not reported.
   let server = sync_httpd_setup();
   setUp();
 
-  Service.username = "broken.keys";
   Service.clusterURL = "http://localhost:8080/maintenance/";
+  Service.username = "foo";
   // Force re-download of keys
   CollectionKeys.clear();
 
   let backoffInterval;
   Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
     Svc.Obs.remove("weave:service:backoff:interval", observe);
     backoffInterval = subject;
   });
@@ -884,19 +873,19 @@ add_test(function test_sync_prolonged_se
   Service.sync();
 });
 
 add_test(function test_info_collections_login_prolonged_server_maintenance_error(){
   // Test info/collections prolonged server maintenance errors are reported.
   let server = sync_httpd_setup();
   setUp();
 
-  Service.username = "broken.info";
   Service.clusterURL = "http://localhost:8080/maintenance/";
 
+  Service.username = "johnsmith";
   let backoffInterval;
   Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
     Svc.Obs.remove("weave:service:backoff:interval", observe);
     backoffInterval = subject;
   });
 
   Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
     Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
@@ -916,19 +905,19 @@ add_test(function test_info_collections_
   Service.sync();
 });
 
 add_test(function test_meta_global_login_prolonged_server_maintenance_error(){
   // Test meta/global prolonged server maintenance errors are reported.
   let server = sync_httpd_setup();
   setUp();
 
-  Service.username = "broken.meta";
   Service.clusterURL = "http://localhost:8080/maintenance/";
 
+  Service.username = "janesmith";
   let backoffInterval;
   Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
     Svc.Obs.remove("weave:service:backoff:interval", observe);
     backoffInterval = subject;
   });
 
   Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
     Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
@@ -943,23 +932,23 @@ add_test(function test_meta_global_login
 
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
   setLastSync(PROLONGED_ERROR_DURATION);
   Service.sync();
 });
 
-add_test(function test_download_crypto_keys_login_prolonged_server_maintenance_error(){
+add_test(function test_crypto_keys_login_prolonged_server_maintenance_error(){
   // Test crypto/keys prolonged server maintenance errors are reported.
   let server = sync_httpd_setup();
   setUp();
 
-  Service.username = "broken.keys";
   Service.clusterURL = "http://localhost:8080/maintenance/";
+  Service.username = "foo";
   // Force re-download of keys
   CollectionKeys.clear();
 
   let backoffInterval;
   Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
     Svc.Obs.remove("weave:service:backoff:interval", observe);
     backoffInterval = subject;
   });
@@ -977,84 +966,16 @@ add_test(function test_download_crypto_k
 
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
   setLastSync(PROLONGED_ERROR_DURATION);
   Service.sync();
 });
 
-add_test(function test_upload_crypto_keys_login_prolonged_server_maintenance_error(){
-  // Test crypto/keys prolonged server maintenance errors are reported.
-  let server = sync_httpd_setup();
-
-  // Start off with an empty account, do not upload a key.
-  Service.username = "broken.keys";
-  Service.password = "ilovejane";
-  Service.passphrase = "abcdeabcdeabcdeabcdeabcdea";
-  Service.clusterURL = "http://localhost:8080/maintenance/";
-
-  let backoffInterval;
-  Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
-    Svc.Obs.remove("weave:service:backoff:interval", observe);
-    backoffInterval = subject;
-  });
-
-  Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
-    Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
-    do_check_true(Status.enforceBackoff);
-    do_check_eq(backoffInterval, 42);
-    do_check_eq(Status.service, SYNC_FAILED);
-    do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
-
-    clean();
-    server.stop(run_next_test);
-  });
-
-  do_check_false(Status.enforceBackoff);
-  do_check_eq(Status.service, STATUS_OK);
-
-  setLastSync(PROLONGED_ERROR_DURATION);
-  Service.sync();
-});
-
-add_test(function test_wipeServer_login_prolonged_server_maintenance_error(){
-  // Test crypto/keys prolonged server maintenance errors are reported.
-  let server = sync_httpd_setup();
-
-  // Start off with an empty account, do not upload a key.
-  Service.username = "broken.wipe";
-  Service.password = "ilovejane";
-  Service.passphrase = "abcdeabcdeabcdeabcdeabcdea";
-  Service.clusterURL = "http://localhost:8080/maintenance/";
-
-  let backoffInterval;
-  Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
-    Svc.Obs.remove("weave:service:backoff:interval", observe);
-    backoffInterval = subject;
-  });
-
-  Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
-    Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
-    do_check_true(Status.enforceBackoff);
-    do_check_eq(backoffInterval, 42);
-    do_check_eq(Status.service, SYNC_FAILED);
-    do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
-
-    clean();
-    server.stop(run_next_test);
-  });
-
-  do_check_false(Status.enforceBackoff);
-  do_check_eq(Status.service, STATUS_OK);
-
-  setLastSync(PROLONGED_ERROR_DURATION);
-  Service.sync();
-});
-
 add_test(function test_sync_syncAndReportErrors_server_maintenance_error() {
   // Test server maintenance errors are reported
   // when calling syncAndReportErrors.
   let server = sync_httpd_setup();
   setUp();
 
   const BACKOFF = 42;
   let engine = Engines.get("catapult");
@@ -1078,19 +999,19 @@ add_test(function test_sync_syncAndRepor
 });
 
 add_test(function test_info_collections_login_syncAndReportErrors_server_maintenance_error() {
   // Test info/collections server maintenance errors are reported
   // when calling syncAndReportErrors.
   let server = sync_httpd_setup();
   setUp();
 
-  Service.username = "broken.info";
   Service.clusterURL = "http://localhost:8080/maintenance/";
 
+  Service.username = "johnsmith";
   let backoffInterval;
   Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
     Svc.Obs.remove("weave:service:backoff:interval", observe);
     backoffInterval = subject;
   });
 
   Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
     Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
@@ -1111,19 +1032,19 @@ add_test(function test_info_collections_
 });
 
 add_test(function test_meta_global_login_syncAndReportErrors_server_maintenance_error() {
   // Test meta/global server maintenance errors are reported
   // when calling syncAndReportErrors.
   let server = sync_httpd_setup();
   setUp();
 
-  Service.username = "broken.meta";
   Service.clusterURL = "http://localhost:8080/maintenance/";
 
+  Service.username = "janesmith";
   let backoffInterval;
   Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
     Svc.Obs.remove("weave:service:backoff:interval", observe);
     backoffInterval = subject;
   });
 
   Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
     Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
@@ -1138,24 +1059,24 @@ add_test(function test_meta_global_login
 
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
   setLastSync(NON_PROLONGED_ERROR_DURATION);
   ErrorHandler.syncAndReportErrors();
 });
 
-add_test(function test_download_crypto_keys_login_syncAndReportErrors_server_maintenance_error() {
+add_test(function test_crypto_keys_login_syncAndReportErrors_server_maintenance_error() {
   // Test crypto/keys server maintenance errors are reported
   // when calling syncAndReportErrors.
   let server = sync_httpd_setup();
   setUp();
 
-  Service.username = "broken.keys";
   Service.clusterURL = "http://localhost:8080/maintenance/";
+  Service.username = "foo";
   // Force re-download of keys
   CollectionKeys.clear();
 
   let backoffInterval;
   Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
     Svc.Obs.remove("weave:service:backoff:interval", observe);
     backoffInterval = subject;
   });
@@ -1173,86 +1094,16 @@ add_test(function test_download_crypto_k
 
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
   setLastSync(NON_PROLONGED_ERROR_DURATION);
   ErrorHandler.syncAndReportErrors();
 });
 
-add_test(function test_upload_crypto_keys_login_syncAndReportErrors_server_maintenance_error() {
-  // Test crypto/keys server maintenance errors are reported
-  // when calling syncAndReportErrors.
-  let server = sync_httpd_setup();
-
-  // Start off with an empty account, do not upload a key.
-  Service.username = "broken.keys";
-  Service.password = "ilovejane";
-  Service.passphrase = "abcdeabcdeabcdeabcdeabcdea";
-  Service.clusterURL = "http://localhost:8080/maintenance/";
-
-  let backoffInterval;
-  Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
-    Svc.Obs.remove("weave:service:backoff:interval", observe);
-    backoffInterval = subject;
-  });
-
-  Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
-    Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
-    do_check_true(Status.enforceBackoff);
-    do_check_eq(backoffInterval, 42);
-    do_check_eq(Status.service, LOGIN_FAILED);
-    do_check_eq(Status.login, SERVER_MAINTENANCE);
-
-    clean();
-    server.stop(run_next_test);
-  });
-
-  do_check_false(Status.enforceBackoff);
-  do_check_eq(Status.service, STATUS_OK);
-
-  setLastSync(NON_PROLONGED_ERROR_DURATION);
-  ErrorHandler.syncAndReportErrors();
-});
-
-add_test(function test_wipeServer_login_syncAndReportErrors_server_maintenance_error() {
-  // Test crypto/keys server maintenance errors are reported
-  // when calling syncAndReportErrors.
-  let server = sync_httpd_setup();
-
-  // Start off with an empty account, do not upload a key.
-  Service.username = "broken.wipe";
-  Service.password = "ilovejane";
-  Service.passphrase = "abcdeabcdeabcdeabcdeabcdea";
-  Service.clusterURL = "http://localhost:8080/maintenance/";
-
-  let backoffInterval;
-  Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
-    Svc.Obs.remove("weave:service:backoff:interval", observe);
-    backoffInterval = subject;
-  });
-
-  Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
-    Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
-    do_check_true(Status.enforceBackoff);
-    do_check_eq(backoffInterval, 42);
-    do_check_eq(Status.service, LOGIN_FAILED);
-    do_check_eq(Status.login, SERVER_MAINTENANCE);
-
-    clean();
-    server.stop(run_next_test);
-  });
-
-  do_check_false(Status.enforceBackoff);
-  do_check_eq(Status.service, STATUS_OK);
-
-  setLastSync(NON_PROLONGED_ERROR_DURATION);
-  ErrorHandler.syncAndReportErrors();
-});
-
 add_test(function test_sync_syncAndReportErrors_prolonged_server_maintenance_error() {
   // Test prolonged server maintenance errors are
   // reported when calling syncAndReportErrors.
   let server = sync_httpd_setup();
   setUp();
 
   const BACKOFF = 42;
   let engine = Engines.get("catapult");
@@ -1276,19 +1127,19 @@ add_test(function test_sync_syncAndRepor
 });
 
 add_test(function test_info_collections_login_syncAndReportErrors_prolonged_server_maintenance_error() {
   // Test info/collections server maintenance errors are reported
   // when calling syncAndReportErrors.
   let server = sync_httpd_setup();
   setUp();
 
-  Service.username = "broken.info";
   Service.clusterURL = "http://localhost:8080/maintenance/";
 
+  Service.username = "johnsmith";
   let backoffInterval;
   Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
     Svc.Obs.remove("weave:service:backoff:interval", observe);
     backoffInterval = subject;
   });
 
   Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
     Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
@@ -1309,19 +1160,19 @@ add_test(function test_info_collections_
 });
 
 add_test(function test_meta_global_login_syncAndReportErrors_prolonged_server_maintenance_error() {
   // Test meta/global server maintenance errors are reported
   // when calling syncAndReportErrors.
   let server = sync_httpd_setup();
   setUp();
 
-  Service.username = "broken.meta";
   Service.clusterURL = "http://localhost:8080/maintenance/";
 
+  Service.username = "janesmith";
   let backoffInterval;
   Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
     Svc.Obs.remove("weave:service:backoff:interval", observe);
     backoffInterval = subject;
   });
 
   Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
     Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
@@ -1336,24 +1187,24 @@ add_test(function test_meta_global_login
 
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
   setLastSync(PROLONGED_ERROR_DURATION);
   ErrorHandler.syncAndReportErrors();
 });
 
-add_test(function test_download_crypto_keys_login_syncAndReportErrors_prolonged_server_maintenance_error() {
+add_test(function test_crypto_keys_login_syncAndReportErrors_prolonged_server_maintenance_error() {
   // Test crypto/keys server maintenance errors are reported
   // when calling syncAndReportErrors.
   let server = sync_httpd_setup();
   setUp();
 
-  Service.username = "broken.keys";
   Service.clusterURL = "http://localhost:8080/maintenance/";
+  Service.username = "foo";
   // Force re-download of keys
   CollectionKeys.clear();
 
   let backoffInterval;
   Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
     Svc.Obs.remove("weave:service:backoff:interval", observe);
     backoffInterval = subject;
   });
@@ -1371,86 +1222,16 @@ add_test(function test_download_crypto_k
 
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
   setLastSync(PROLONGED_ERROR_DURATION);
   ErrorHandler.syncAndReportErrors();
 });
 
-add_test(function test_upload_crypto_keys_login_syncAndReportErrors_prolonged_server_maintenance_error() {
-  // Test crypto/keys server maintenance errors are reported
-  // when calling syncAndReportErrors.
-  let server = sync_httpd_setup();
-
-  // Start off with an empty account, do not upload a key.
-  Service.username = "broken.keys";
-  Service.password = "ilovejane";
-  Service.passphrase = "abcdeabcdeabcdeabcdeabcdea";
-  Service.clusterURL = "http://localhost:8080/maintenance/";
-
-  let backoffInterval;
-  Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
-    Svc.Obs.remove("weave:service:backoff:interval", observe);
-    backoffInterval = subject;
-  });
-
-  Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
-    Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
-    do_check_true(Status.enforceBackoff);
-    do_check_eq(backoffInterval, 42);
-    do_check_eq(Status.service, LOGIN_FAILED);
-    do_check_eq(Status.login, SERVER_MAINTENANCE);
-
-    clean();
-    server.stop(run_next_test);
-  });
-
-  do_check_false(Status.enforceBackoff);
-  do_check_eq(Status.service, STATUS_OK);
-
-  setLastSync(PROLONGED_ERROR_DURATION);
-  ErrorHandler.syncAndReportErrors();
-});
-
-add_test(function test_wipeServer_login_syncAndReportErrors_prolonged_server_maintenance_error() {
-  // Test crypto/keys server maintenance errors are reported
-  // when calling syncAndReportErrors.
-  let server = sync_httpd_setup();
-
-  // Start off with an empty account, do not upload a key.
-  Service.username = "broken.wipe";
-  Service.password = "ilovejane";
-  Service.passphrase = "abcdeabcdeabcdeabcdeabcdea";
-  Service.clusterURL = "http://localhost:8080/maintenance/";
-
-  let backoffInterval;
-  Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
-    Svc.Obs.remove("weave:service:backoff:interval", observe);
-    backoffInterval = subject;
-  });
-
-  Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
-    Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
-    do_check_true(Status.enforceBackoff);
-    do_check_eq(backoffInterval, 42);
-    do_check_eq(Status.service, LOGIN_FAILED);
-    do_check_eq(Status.login, SERVER_MAINTENANCE);
-
-    clean();
-    server.stop(run_next_test);
-  });
-
-  do_check_false(Status.enforceBackoff);
-  do_check_eq(Status.service, STATUS_OK);
-
-  setLastSync(PROLONGED_ERROR_DURATION);
-  ErrorHandler.syncAndReportErrors();
-});
-
 add_test(function test_sync_engine_generic_fail() {
   let server = sync_httpd_setup();
 
   let engine = Engines.get("catapult");
   engine.enabled = true;
   engine.sync = function sync() {
     Svc.Obs.notify("weave:engine:sync:error", "", "catapult");
   };
--- a/services/sync/tests/unit/test_service_sync_remoteSetup.js
+++ b/services/sync/tests/unit/test_service_sync_remoteSetup.js
@@ -24,38 +24,17 @@ function run_test() {
       handler.apply(this, arguments);
     };
   }
 
   let keysWBO = new ServerWBO("keys");
   let cryptoColl = new ServerCollection({keys: keysWBO});
   let metaColl = new ServerCollection({global: meta_global});
   do_test_pending();
-
-  /**
-   * Handle the bulk DELETE request sent by wipeServer.
-   */
-  function storageHandler(request, response) {
-    do_check_eq("DELETE", request.method);
-    do_check_true(request.hasHeader("X-Confirm-Delete"));
-
-    _("Wiping out all collections.");
-    cryptoColl.delete({});
-    clients.delete({});
-    metaColl.delete({});
-
-    let ts = new_timestamp();
-    collectionsHelper.update_collection("crypto", ts);
-    collectionsHelper.update_collection("clients", ts);
-    collectionsHelper.update_collection("meta", ts);
-    return_timestamp(request, response, ts);
-  }
-
   let server = httpd_setup({
-    "/1.1/johndoe/storage": storageHandler,
     "/1.1/johndoe/storage/crypto/keys": upd("crypto", keysWBO.handler()),
     "/1.1/johndoe/storage/crypto": upd("crypto", cryptoColl.handler()),
     "/1.1/johndoe/storage/clients": upd("clients", clients.handler()),
     "/1.1/johndoe/storage/meta/global": upd("meta", wasCalledHandler(meta_global)),
     "/1.1/johndoe/storage/meta": upd("meta", wasCalledHandler(metaColl)),
     "/1.1/johndoe/info/collections": collectionsHelper.handler
   });
 
--- a/services/sync/tests/unit/test_service_sync_updateEnabledEngines.js
+++ b/services/sync/tests/unit/test_service_sync_updateEnabledEngines.js
@@ -1,18 +1,16 @@
 Cu.import("resource://services-sync/engines.js");
 Cu.import("resource://services-sync/engines/clients.js");
 Cu.import("resource://services-sync/util.js");
 Cu.import("resource://services-sync/constants.js");
 Cu.import("resource://services-sync/record.js");
-Cu.import("resource://services-sync/status.js");
 
 Svc.DefaultPrefs.set("registerEngines", "");
 Cu.import("resource://services-sync/service.js");
-Cu.import("resource://services-sync/policies.js");
 
 initTestLogging();
 
 function QuietStore() {
   Store.call("Quiet");
 }
 QuietStore.prototype = {
   getAllIDs: function getAllIDs() {
@@ -63,56 +61,40 @@ function sync_httpd_setup(handlers) {
     upd("clients", cl.handler());
   
   return httpd_setup(handlers);
 }
 
 function setUp() {
   Service.username = "johndoe";
   Service.password = "ilovejane";
-  Service.passphrase = "abcdeabcdeabcdeabcdeabcdea";
+  Service.passphrase = "sekrit";
   Service.clusterURL = "http://localhost:8080/";
-  // So that we can poke at meta/global.
   new FakeCryptoService();
-
-  // Ensure that the server has valid keys so that logging in will work and not
-  // result in a server wipe, rendering many of these tests useless.
-  generateNewKeys();
-  let serverKeys = CollectionKeys.asWBO("crypto", "keys");
-  serverKeys.encrypt(Service.syncKeyBundle);
-  return serverKeys.upload(Service.cryptoKeysURL).success;
 }
 
 const PAYLOAD = 42;
 
-
-function run_test() {
-  initTestLogging("Trace");
-  Log4Moz.repository.getLogger("Sync.Service").level = Log4Moz.Level.Trace;
-  Log4Moz.repository.getLogger("Sync.ErrorHandler").level = Log4Moz.Level.Trace;
-
-  run_next_test();
-}
-
 add_test(function test_newAccount() {
   _("Test: New account does not disable locally enabled engines.");
   let engine = Engines.get("steam");
   let server = sync_httpd_setup({
     "/1.1/johndoe/storage/meta/global": new ServerWBO("global", {}).handler(),
     "/1.1/johndoe/storage/steam": new ServerWBO("steam", {}).handler()
   });
   setUp();
 
   try {
     _("Engine is enabled from the beginning.");
     Service._ignorePrefObserver = true;
     engine.enabled = true;
     Service._ignorePrefObserver = false;
 
     _("Sync.");
+    Weave.Service.login();
     Weave.Service.sync();
 
     _("Engine continues to be enabled.");
     do_check_true(engine.enabled);
   } finally {
     Service.startOver();
     server.stop(run_next_test);
   }
@@ -131,16 +113,17 @@ add_test(function test_enabledLocally() 
   });
   setUp();
 
   try {
     _("Enable engine locally.");
     engine.enabled = true;
 
     _("Sync.");
+    Weave.Service.login();
     Weave.Service.sync();
 
     _("Meta record now contains the new engine.");
     do_check_true(!!metaWBO.data.engines.steam);
 
     _("Engine continues to be enabled.");
     do_check_true(engine.enabled);
   } finally {
@@ -155,91 +138,47 @@ add_test(function test_disabledLocally()
   let engine = Engines.get("steam");
   let metaWBO = new ServerWBO("global", {
     syncID: Service.syncID,
     storageVersion: STORAGE_VERSION,
     engines: {steam: {syncID: engine.syncID,
                       version: engine.version}}
   });
   let steamCollection = new ServerWBO("steam", PAYLOAD);
-
   let server = sync_httpd_setup({
     "/1.1/johndoe/storage/meta/global": metaWBO.handler(),
     "/1.1/johndoe/storage/steam": steamCollection.handler()
   });
   setUp();
 
   try {
     _("Disable engine locally.");
     Service._ignorePrefObserver = true;
     engine.enabled = true;
     Service._ignorePrefObserver = false;
     engine.enabled = false;
 
     _("Sync.");
+    Weave.Service.login();
     Weave.Service.sync();
 
     _("Meta record no longer contains engine.");
     do_check_false(!!metaWBO.data.engines.steam);
 
     _("Server records are wiped.");
     do_check_eq(steamCollection.payload, undefined);
 
     _("Engine continues to be disabled.");
     do_check_false(engine.enabled);
   } finally {
     Service.startOver();
     server.stop(run_next_test);
   }
 });
 
-add_test(function test_disabledLocally_wipe503() {
-  _("Test: Engine is enabled on remote clients and disabled locally");
-  Service.syncID = "abcdefghij";
-  let engine = Engines.get("steam");
-  let metaWBO = new ServerWBO("global", {
-    syncID: Service.syncID,
-    storageVersion: STORAGE_VERSION,
-    engines: {steam: {syncID: engine.syncID,
-                      version: engine.version}}
-  });
-  let steamCollection = new ServerWBO("steam", PAYLOAD);
-
-  function service_unavailable(request, response) {
-    let body = "Service Unavailable";
-    response.setStatusLine(request.httpVersion, 503, "Service Unavailable");
-    response.setHeader("Retry-After", "23");
-    response.bodyOutputStream.write(body, body.length);
-  }
-
-  let server = sync_httpd_setup({
-    "/1.1/johndoe/storage/meta/global": metaWBO.handler(),
-    "/1.1/johndoe/storage/steam": service_unavailable
-  });
-  setUp();
-
-  _("Disable engine locally.");
-  Service._ignorePrefObserver = true;
-  engine.enabled = true;
-  Service._ignorePrefObserver = false;
-  engine.enabled = false;
-
-  Svc.Obs.add("weave:ui:sync:error", function onSyncError() {
-    Svc.Obs.remove("weave:ui:sync:error", onSyncError);
-
-    do_check_eq(Status.sync, SERVER_MAINTENANCE);
-
-    Service.startOver();
-    server.stop(run_next_test);
-  });
-
-  _("Sync.");
-  ErrorHandler.syncAndReportErrors();
-});
-
 add_test(function test_enabledRemotely() {
   _("Test: Engine is disabled locally and enabled on a remote client");
   Service.syncID = "abcdefghij";
   let engine = Engines.get("steam");
   let metaWBO = new ServerWBO("global", {
     syncID: Service.syncID,
     storageVersion: STORAGE_VERSION,
     engines: {steam: {syncID: engine.syncID,
@@ -261,16 +200,17 @@ add_test(function test_enabledRemotely()
     let wbo = CollectionKeys.generateNewKeysWBO();
     wbo.encrypt(Service.syncKeyBundle);
     do_check_eq(200, wbo.upload(Service.cryptoKeysURL).status);
 
     _("Engine is disabled.");
     do_check_false(engine.enabled);
 
     _("Sync.");
+    Weave.Service.login();
     Weave.Service.sync();
 
     _("Engine is enabled.");
     do_check_true(engine.enabled);
 
     _("Meta record still present.");
     do_check_eq(metaWBO.data.engines.steam.syncID, engine.syncID);
   } finally {
@@ -297,16 +237,17 @@ add_test(function test_disabledRemotelyT
 
   try {
     _("Enable engine locally.");
     Service._ignorePrefObserver = true;
     engine.enabled = true;
     Service._ignorePrefObserver = false;
 
     _("Sync.");
+    Weave.Service.login();
     Weave.Service.sync();
 
     _("Disable engine by deleting from meta/global.");
     let d = metaWBO.data; 
     delete d.engines["steam"];
     metaWBO.payload = JSON.stringify(d);
     metaWBO.modified = Date.now() / 1000;
     
@@ -338,16 +279,17 @@ add_test(function test_disabledRemotely(
 
   try {
     _("Enable engine locally.");
     Service._ignorePrefObserver = true;
     engine.enabled = true;
     Service._ignorePrefObserver = false;
 
     _("Sync.");
+    Weave.Service.login();
     Weave.Service.sync();
 
     _("Engine is not disabled: only one client.");
     do_check_true(engine.enabled);
     
   } finally {
     Service.startOver();
     server.stop(run_next_test);
@@ -369,16 +311,17 @@ add_test(function test_dependentEnginesE
   });
   setUp();
 
   try {
     _("Enable engine locally. Doing it on one is enough.");
     steamEngine.enabled = true;
 
     _("Sync.");
+    Weave.Service.login();
     Weave.Service.sync();
 
     _("Meta record now contains the new engines.");
     do_check_true(!!metaWBO.data.engines.steam);
     do_check_true(!!metaWBO.data.engines.stirling);
 
     _("Engines continue to be enabled.");
     do_check_true(steamEngine.enabled);
@@ -400,17 +343,16 @@ add_test(function test_dependentEnginesD
     engines: {steam: {syncID: steamEngine.syncID,
                       version: steamEngine.version},
               stirling: {syncID: stirlingEngine.syncID,
                          version: stirlingEngine.version}}
   });
 
   let steamCollection = new ServerWBO("steam", PAYLOAD);
   let stirlingCollection = new ServerWBO("stirling", PAYLOAD);
-
   let server = sync_httpd_setup({
     "/1.1/johndoe/storage/meta/global":     metaWBO.handler(),
     "/1.1/johndoe/storage/steam":           steamCollection.handler(),
     "/1.1/johndoe/storage/stirling":        stirlingCollection.handler()
   });
   setUp();
 
   try {
@@ -418,16 +360,17 @@ add_test(function test_dependentEnginesD
     Service._ignorePrefObserver = true;
     steamEngine.enabled = true;
     do_check_true(stirlingEngine.enabled);
     Service._ignorePrefObserver = false;
     steamEngine.enabled = false;
     do_check_false(stirlingEngine.enabled);
 
     _("Sync.");
+    Weave.Service.login();
     Weave.Service.sync();
 
     _("Meta record no longer contains engines.");
     do_check_false(!!metaWBO.data.engines.steam);
     do_check_false(!!metaWBO.data.engines.stirling);
 
     _("Server records are wiped.");
     do_check_eq(steamCollection.payload, undefined);
@@ -436,8 +379,12 @@ add_test(function test_dependentEnginesD
     _("Engines continue to be disabled.");
     do_check_false(steamEngine.enabled);
     do_check_false(stirlingEngine.enabled);
   } finally {
     Service.startOver();
     server.stop(run_next_test);
   }
 });
+
+function run_test() {
+  run_next_test();
+}
--- a/services/sync/tests/unit/test_service_wipeServer.js
+++ b/services/sync/tests/unit/test_service_wipeServer.js
@@ -8,214 +8,137 @@ Cu.import("resource://services-sync/serv
 function FakeCollection() {
   this.deleted = false;
 }
 FakeCollection.prototype = {
   handler: function() {
     let self = this;
     return function(request, response) {
       let body = "";
-      self.timestamp = new_timestamp();
-      let timestamp = "" + self.timestamp;
       if (request.method == "DELETE") {
-          body = timestamp;
+          body = JSON.stringify(Date.now() / 1000);
           self.deleted = true;
       }
-      response.setHeader("X-Weave-Timestamp", timestamp);
       response.setStatusLine(request.httpVersion, 200, "OK");
       response.bodyOutputStream.write(body, body.length);
     };
   }
 };
 
+function serviceUnavailable(request, response) {
+  let body = "Service Unavailable";
+  response.setStatusLine(request.httpVersion, 503, "Service Unavailable");
+  response.bodyOutputStream.write(body, body.length);
+}
+
 function setUpTestFixtures() {
   let cryptoService = new FakeCryptoService();
 
   Service.clusterURL = "http://localhost:8080/";
   Service.username = "johndoe";
   Service.passphrase = "aabcdeabcdeabcdeabcdeabcde";
 }
 
-
-function run_test() {
-  initTestLogging("Trace");
-  run_next_test();
-}
-
-add_test(function test_wipeServer_list_success() {
+function test_withCollectionList_fail() {
   _("Service.wipeServer() deletes collections given as argument.");
 
   let steam_coll = new FakeCollection();
   let diesel_coll = new FakeCollection();
 
   let server = httpd_setup({
     "/1.1/johndoe/storage/steam": steam_coll.handler(),
-    "/1.1/johndoe/storage/diesel": diesel_coll.handler(),
-    "/1.1/johndoe/storage/petrol": httpd_handler(404, "Not Found")
-  });
-
-  try {
-    setUpTestFixtures();
-
-    _("Confirm initial environment.");
-    do_check_false(steam_coll.deleted);
-    do_check_false(diesel_coll.deleted);
-
-    _("wipeServer() will happily ignore the non-existent collection and use the timestamp of the last DELETE that was successful.");
-    let timestamp = Service.wipeServer(["steam", "diesel", "petrol"]);
-    do_check_eq(timestamp, diesel_coll.timestamp);
-
-    _("wipeServer stopped deleting after encountering an error with the 'petrol' collection, thus only 'steam' has been deleted.");
-    do_check_true(steam_coll.deleted);
-    do_check_true(diesel_coll.deleted);
-
-  } finally {
-    server.stop(run_next_test);
-    Svc.Prefs.resetBranch("");
-  }
-});
-
-add_test(function test_wipeServer_list_503() {
-  _("Service.wipeServer() deletes collections given as argument.");
-
-  let steam_coll = new FakeCollection();
-  let diesel_coll = new FakeCollection();
-
-  let server = httpd_setup({
-    "/1.1/johndoe/storage/steam": steam_coll.handler(),
-    "/1.1/johndoe/storage/petrol": httpd_handler(503, "Service Unavailable"),
+    "/1.1/johndoe/storage/petrol": serviceUnavailable,
     "/1.1/johndoe/storage/diesel": diesel_coll.handler()
   });
+  do_test_pending();
 
   try {
     setUpTestFixtures();
 
     _("Confirm initial environment.");
     do_check_false(steam_coll.deleted);
     do_check_false(diesel_coll.deleted);
 
     _("wipeServer() will happily ignore the non-existent collection, delete the 'steam' collection and abort after an receiving an error on the 'petrol' collection.");
     let error;
     try {
       Service.wipeServer(["non-existent", "steam", "petrol", "diesel"]);
-      do_throw("Should have thrown!");
     } catch(ex) {
       error = ex;
     }
     _("wipeServer() threw this exception: " + error);
-    do_check_eq(error.status, 503);
+    do_check_true(error != undefined);
 
     _("wipeServer stopped deleting after encountering an error with the 'petrol' collection, thus only 'steam' has been deleted.");
     do_check_true(steam_coll.deleted);
     do_check_false(diesel_coll.deleted);
 
   } finally {
-    server.stop(run_next_test);
+    server.stop(do_test_finished);
     Svc.Prefs.resetBranch("");
   }
-});
+}
 
-add_test(function test_wipeServer_all_success() {
-  _("Service.wipeServer() deletes all the things.");
+function test_wipeServer_leaves_collections() {
+  _("Service.wipeServer() deletes everything but keys.");
   
-  /**
-   * Handle the bulk DELETE request sent by wipeServer.
-   */
-  let deleted = false;
-  let serverTimestamp;
-  function storageHandler(request, response) {
-    do_check_eq("DELETE", request.method);
-    do_check_true(request.hasHeader("X-Confirm-Delete"));
-    deleted = true;
-    serverTimestamp = return_timestamp(request, response);
-  }
-
-  let server = httpd_setup({
-    "/1.1/johndoe/storage": storageHandler
-  });
-  setUpTestFixtures();
+  let steam_coll = new FakeCollection();
+  let diesel_coll = new FakeCollection();
+  let keys_coll = new FakeCollection();
 
-  _("Try deletion.");
-  let returnedTimestamp = Service.wipeServer();
-  do_check_true(deleted);
-  do_check_eq(returnedTimestamp, serverTimestamp);
-
-  server.stop(run_next_test);
-  Svc.Prefs.resetBranch("");
-});
-
-add_test(function test_wipeServer_all_404() {
-  _("Service.wipeServer() accepts a 404.");
-  
-  /**
-   * Handle the bulk DELETE request sent by wipeServer. Returns a 404.
-   */
-  let deleted = false;
-  let serverTimestamp;
-  function storageHandler(request, response) {
-    do_check_eq("DELETE", request.method);
-    do_check_true(request.hasHeader("X-Confirm-Delete"));
-    deleted = true;
-    serverTimestamp = new_timestamp();
-    response.setHeader("X-Weave-Timestamp", "" + serverTimestamp);
-    response.setStatusLine(request.httpVersion, 404, "Not Found");
+  function info_collections(request, response) {
+    let collections = {};
+    let timestamp = Date.now() / 1000;
+    if (!steam_coll.deleted)
+      collections.steam = timestamp
+    if (!diesel_coll.deleted)
+      collections.diesel = timestamp;
+    if (!keys_coll.deleted)
+      collections.keys = timestamp;
+    let body = JSON.stringify(collections);
+    response.setStatusLine(request.httpVersion, 200, "OK");
+    response.bodyOutputStream.write(body, body.length);
   }
 
   let server = httpd_setup({
-    "/1.1/johndoe/storage": storageHandler
+    "/1.1/johndoe/storage/steam": steam_coll.handler(),
+    "/1.1/johndoe/storage/diesel": diesel_coll.handler(),
+    "/1.1/johndoe/storage/keys": keys_coll.handler(),
+    "/1.1/johndoe/info/collections": info_collections
   });
-  setUpTestFixtures();
-
-  _("Try deletion.");
-  let returnedTimestamp = Service.wipeServer();
-  do_check_true(deleted);
-  do_check_eq(returnedTimestamp, serverTimestamp);
-
-  server.stop(run_next_test);
-  Svc.Prefs.resetBranch("");
-});
+  do_test_pending();
 
-add_test(function test_wipeServer_all_503() {
-  _("Service.wipeServer() throws if it encounters a non-200/404 response.");
-  
-  /**
-   * Handle the bulk DELETE request sent by wipeServer. Returns a 503.
-   */
-  function storageHandler(request, response) {
-    do_check_eq("DELETE", request.method);
-    do_check_true(request.hasHeader("X-Confirm-Delete"));
-    response.setStatusLine(request.httpVersion, 503, "Service Unavailable");
-  }
-
-  let server = httpd_setup({
-    "/1.1/johndoe/storage": storageHandler
-  });
-  setUpTestFixtures();
+  try {
+    setUpTestFixtures();
+    _("Info URL: " + Service.infoURL);
 
-  _("Try deletion.");
-  let error;
-  try {
+    _("Confirm initial environment.");
+    do_check_false(steam_coll.deleted);
+    do_check_false(diesel_coll.deleted);
+    do_check_false(keys_coll.deleted);
+    
+    _("Collections: " + new Resource(Service.infoURL).get());
+    _("Try deletion.");
     Service.wipeServer();
-    do_throw("Should have thrown!");
-  } catch (ex) {
-    error = ex;
+    _("Collections: " + new Resource(Service.infoURL).get());
+    
+    _("Make sure keys is still present.");
+    do_check_true(steam_coll.deleted);
+    do_check_true(diesel_coll.deleted);
+    do_check_false(keys_coll.deleted);
+    
+    _("Delete everything.");
+    Service.wipeServer(null, true);
+    do_check_true(steam_coll.deleted);
+    do_check_true(diesel_coll.deleted);
+    do_check_true(keys_coll.deleted);
+    
+  } finally {
+    server.stop(do_test_finished);
+    Svc.Prefs.resetBranch("");
   }
-  do_check_eq(error.status, 503);
-
-  server.stop(run_next_test);
-  Svc.Prefs.resetBranch("");
-});
+}
 
-add_test(function test_wipeServer_all_connectionRefused() {
-  _("Service.wipeServer() throws if it encounters a network problem.");
-  setUpTestFixtures();
-
-  _("Try deletion.");
-  try {
-    Service.wipeServer();
-    do_throw("Should have thrown!");
-  } catch (ex) {
-    do_check_eq(ex.result, Cr.NS_ERROR_CONNECTION_REFUSED);
-  }
-
-  run_next_test();
-  Svc.Prefs.resetBranch("");
-});
+function run_test() {
+  initTestLogging("Trace");
+  test_withCollectionList_fail();
+  test_wipeServer_leaves_collections();
+}