Merge m-c to birch.
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 18 Jul 2013 14:47:54 -0400
changeset 151174 af4e3ce8c487a8e0477451bf1748cfed51f9ab4c
parent 151173 7d4859613f3d0ca2f20778d1412ddf82e4e8c59c (current diff)
parent 151134 16375716cc691ea352e741243a5a554af0e1b187 (diff)
child 151398 0d0263a58f06f92d9648d23c9368cd05ea5241f9
child 151400 0688470dfaeb79a46ce5ea483a1fa41010dd4ccd
push id2859
push userakeybl@mozilla.com
push dateMon, 16 Sep 2013 19:14:59 +0000
treeherdermozilla-beta@87d3c51cd2bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone25.0a1
first release with
nightly linux32
af4e3ce8c487 / 25.0a1 / 20130719030204 / files
nightly linux64
af4e3ce8c487 / 25.0a1 / 20130719030204 / files
nightly mac
af4e3ce8c487 / 25.0a1 / 20130719030204 / files
nightly win32
af4e3ce8c487 / 25.0a1 / 20130719030204 / files
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
Merge m-c to birch.
--- a/gfx/layers/TiledLayerBuffer.h
+++ b/gfx/layers/TiledLayerBuffer.h
@@ -220,16 +220,17 @@ static inline int floor_div(int a, int b
 }
 
 template<typename Derived, typename Tile> Tile
 TiledLayerBuffer<Derived, Tile>::GetTile(const nsIntPoint& aTileOrigin) const
 {
   // TODO Cache firstTileOriginX/firstTileOriginY
   // Find the tile x/y of the first tile and the target tile relative to the (0, 0)
   // origin, the difference is the tile x/y relative to the start of the tile buffer.
+  volatile float resolution = mResolution; // bug 881018 investigation
   int firstTileX = floor_div(mValidRegion.GetBounds().x, GetScaledTileLength());
   int firstTileY = floor_div(mValidRegion.GetBounds().y, GetScaledTileLength());
   return GetTile(floor_div(aTileOrigin.x, GetScaledTileLength()) - firstTileX,
                  floor_div(aTileOrigin.y, GetScaledTileLength()) - firstTileY);
 }
 
 template<typename Derived, typename Tile> Tile
 TiledLayerBuffer<Derived, Tile>::GetTile(int x, int y) const
--- a/gfx/layers/composite/TiledContentHost.cpp
+++ b/gfx/layers/composite/TiledContentHost.cpp
@@ -223,17 +223,17 @@ TiledContentHost::RenderLayerBuffer(Tile
                                     const nsIntRegion& aMaskRegion,
                                     nsIntRect aVisibleRect,
                                     gfx::Matrix4x4 aTransform)
 {
   if (!mCompositor) {
     NS_WARNING("Can't render tiled content host - no compositor");
     return;
   }
-  float resolution = aLayerBuffer.GetResolution();
+  volatile float resolution = aLayerBuffer.GetResolution(); // bug 881018 investigation
   gfxSize layerScale(1, 1);
   // We assume that the current frame resolution is the one used in our primary
   // layer buffer. Compensate for a changing frame resolution.
   if (aLayerBuffer.GetFrameResolution() != mVideoMemoryTiledBuffer.GetFrameResolution()) {
     const gfxSize& layerResolution = aLayerBuffer.GetFrameResolution();
     const gfxSize& localResolution = mVideoMemoryTiledBuffer.GetFrameResolution();
     layerScale.width = layerResolution.width / localResolution.width;
     layerScale.height = layerResolution.height / localResolution.height;
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -2034,19 +2034,22 @@ AppendToTop(nsDisplayListBuilder* aBuild
 
 void
 nsGfxScrollFrameInner::AppendScrollPartsTo(nsDisplayListBuilder*   aBuilder,
                                            const nsRect&           aDirtyRect,
                                            const nsDisplayListSet& aLists,
                                            bool&                   aCreateLayer,
                                            bool                    aPositioned)
 {
+  bool overlayScrollbars =
+    LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars) != 0;
+
   for (nsIFrame* kid = mOuter->GetFirstPrincipalChild(); kid; kid = kid->GetNextSibling()) {
     if (kid == mScrolledFrame ||
-        (kid->IsPositioned() != aPositioned))
+        (kid->IsPositioned() || overlayScrollbars) != aPositioned)
       continue;
 
     nsDisplayListCollection partList;
     mOuter->BuildDisplayListForChild(aBuilder, kid, aDirtyRect, partList,
                                      nsIFrame::DISPLAY_CHILD_FORCE_STACKING_CONTEXT);
 
     // Don't append textarea resizers to the positioned descendants because
     // we don't want them to float on top of overlapping elements.
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -2208,44 +2208,28 @@ nsStyleDisplay::nsStyleDisplay(const nsS
   /* Copy over transform origin. */
   mTransformOrigin[0] = aSource.mTransformOrigin[0];
   mTransformOrigin[1] = aSource.mTransformOrigin[1];
   mTransformOrigin[2] = aSource.mTransformOrigin[2];
   mPerspectiveOrigin[0] = aSource.mPerspectiveOrigin[0];
   mPerspectiveOrigin[1] = aSource.mPerspectiveOrigin[1];
 }
 
-static uint8_t
-MapRelativePositionToStatic(uint8_t aPositionValue)
-{
-  return aPositionValue == NS_STYLE_POSITION_RELATIVE ?
-      NS_STYLE_POSITION_STATIC : aPositionValue;
-}
-
 nsChangeHint nsStyleDisplay::CalcDifference(const nsStyleDisplay& aOther) const
 {
   nsChangeHint hint = nsChangeHint(0);
 
-  // Changes between position:static and position:relative don't need
-  // to reconstruct frames.
   if (!EqualURIs(mBinding, aOther.mBinding)
-      || MapRelativePositionToStatic(mPosition) !=
-           MapRelativePositionToStatic(aOther.mPosition)
+      || mPosition != aOther.mPosition
       || mDisplay != aOther.mDisplay
       || (mFloats == NS_STYLE_FLOAT_NONE) != (aOther.mFloats == NS_STYLE_FLOAT_NONE)
       || mOverflowX != aOther.mOverflowX
       || mOverflowY != aOther.mOverflowY
-      || mResize != aOther.mResize) {
+      || mResize != aOther.mResize)
     NS_UpdateHint(hint, nsChangeHint_ReconstructFrame);
-  }
-
-  if (mPosition != aOther.mPosition) {
-    NS_UpdateHint(hint,
-      NS_CombineHint(nsChangeHint_NeedReflow, nsChangeHint_RepaintFrame));
-  }
 
   if (mFloats != aOther.mFloats) {
     // Changing which side we float on doesn't affect descendants directly
     NS_UpdateHint(hint,
        NS_SubtractHint(nsChangeHint_AllReflowHints,
                        NS_CombineHint(nsChangeHint_ClearDescendantIntrinsics,
                                       nsChangeHint_NeedDirtyReflow)));
   }
--- a/services/common/modules-testing/bagheeraserver.js
+++ b/services/common/modules-testing/bagheeraserver.js
@@ -17,22 +17,20 @@ Cu.import("resource://testing-common/htt
  * This is an implementation of the Bagheera server.
  *
  * The purpose of the server is to facilitate testing of the Bagheera
  * client and the Firefox Health report. It is *not* meant to be a
  * production grade server.
  *
  * The Bagheera server is essentially a glorified document store.
  */
-this.BagheeraServer = function BagheeraServer(serverURI="http://localhost") {
+this.BagheeraServer = function BagheeraServer() {
   this._log = Log4Moz.repository.getLogger("metrics.BagheeraServer");
 
-  this.serverURI = serverURI;
   this.server = new HttpServer();
-  this.port = 8080;
   this.namespaces = {};
 
   this.allowAllNamespaces = false;
 }
 
 BagheeraServer.prototype = {
   /**
    * Whether this server has a namespace defined.
@@ -121,25 +119,24 @@ BagheeraServer.prototype = {
   createNamespace: function createNamespace(ns) {
     if (ns in this.namespaces) {
       throw new Error("Namespace already exists: " + ns);
     }
 
     this.namespaces[ns] = {};
   },
 
-  start: function start(port) {
-    if (!port) {
-      throw new Error("port argument must be specified.");
-    }
-
-    this.port = port;
-
+  start: function start(port=-1) {
     this.server.registerPrefixHandler("/", this._handleRequest.bind(this));
     this.server.start(port);
+    let i = this.server.identity;
+
+    this.serverURI = i.primaryScheme + "://" + i.primaryHost + ":" +
+                     i.primaryPort + "/";
+    this.port = i.primaryPort;
   },
 
   stop: function stop(cb) {
     let handler = {onStopped: cb};
 
     this.server.stop(handler);
   },
 
--- a/services/common/modules-testing/storageserver.js
+++ b/services/common/modules-testing/storageserver.js
@@ -877,48 +877,50 @@ this.StorageServer = function StorageSer
   // Install our own default handler. This allows us to mess around with the
   // whole URL space.
   let handler = this.server._handler;
   handler._handleDefault = this.handleDefault.bind(this, handler);
 }
 StorageServer.prototype = {
   DEFAULT_QUOTA: 1024 * 1024, // # bytes.
 
-  port:   8080,
   server: null,    // HttpServer.
   users:  null,    // Map of username => {collections, password}.
 
   /**
    * If true, the server will allow any arbitrary user to be used.
    *
    * No authentication will be performed. Whatever user is detected from the
    * URL or auth headers will be created (if needed) and used.
    */
   allowAllUsers: false,
 
   /**
    * Start the StorageServer's underlying HTTP server.
    *
    * @param port
-   *        The numeric port on which to start. A falsy value implies the
-   *        default (8080).
+   *        The numeric port on which to start. A falsy value implies to
+   *        select any available port.
    * @param cb
    *        A callback function (of no arguments) which is invoked after
    *        startup.
    */
   start: function start(port, cb) {
     if (this.started) {
       this._log.warn("Warning: server already started on " + this.port);
       return;
     }
-    if (port) {
-      this.port = port;
+    if (!port) {
+      port = -1;
     }
+    this.port = port;
+
     try {
       this.server.start(this.port);
+      this.port = this.server.identity.primaryPort;
       this.started = true;
       if (cb) {
         cb();
       }
     } catch (ex) {
       _("==========================================");
       _("Got exception starting Storage HTTP server on port " + this.port);
       _("Error: " + CommonUtils.exceptionStr(ex));
@@ -927,20 +929,20 @@ StorageServer.prototype = {
       do_throw(ex);
     }
   },
 
   /**
    * Start the server synchronously.
    *
    * @param port
-   *        The numeric port on which to start. A falsy value implies the
-   *        default (8080).
+   *        The numeric port on which to start. The default is to choose
+   *        any available port.
    */
-  startSynchronous: function startSynchronous(port) {
+  startSynchronous: function startSynchronous(port=-1) {
     let cb = Async.makeSpinningCallback();
     this.start(port, cb);
     cb.wait();
   },
 
   /**
    * Stop the StorageServer's HTTP server.
    *
--- a/services/common/tests/unit/head_global.js
+++ b/services/common/tests/unit/head_global.js
@@ -1,16 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu, manager: Cm} = Components;
 
-// Where to bind test HTTP servers to.
-const TEST_SERVER_URL = "http://localhost:8080/";
-
 let gSyncProfile = do_get_profile();
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 let XULAppInfo = {
   vendor: "Mozilla",
   name: "XPCShell",
   ID: "xpcshell@tests.mozilla.org",
--- a/services/common/tests/unit/head_helpers.js
+++ b/services/common/tests/unit/head_helpers.js
@@ -41,43 +41,36 @@ function do_check_throws(aFunc, aResult,
  *
  * @param [arg0, arg1, arg2, ...]
  *        Any number of arguments to print out
  * @usage _("Hello World") -> prints "Hello World"
  * @usage _(1, 2, 3) -> prints "1 2 3"
  */
 let _ = function(some, debug, text, to) print(Array.slice(arguments).join(" "));
 
-/**
- * Obtain a port number to run a server on.
- *
- * In the ideal world, this would be dynamic so multiple servers could be run
- * in parallel.
- */
-function get_server_port() {
-  return 8080;
-}
-
-function httpd_setup (handlers, port) {
-  let port   = port || 8080;
+function httpd_setup (handlers, port=-1) {
   let server = new HttpServer();
   for (let path in handlers) {
     server.registerPathHandler(path, handlers[path]);
   }
   try {
     server.start(port);
   } catch (ex) {
     _("==========================================");
     _("Got exception starting HTTP server on port " + port);
     _("Error: " + CommonUtils.exceptionStr(ex));
     _("Is there a process already listening on port " + port + "?");
     _("==========================================");
     do_throw(ex);
   }
 
+  // Set the base URI for convenience.
+  let i = server.identity;
+  server.baseURI = i.primaryScheme + "://" + i.primaryHost + ":" + i.primaryPort;
+
   return server;
 }
 
 function httpd_handler(statusCode, status, body) {
   return function handler(request, response) {
     _("Processing request");
     // Allow test functions to inspect the request.
     request.body = readBytesFromInputStream(request.bodyInputStream);
--- a/services/common/tests/unit/test_bagheera_client.js
+++ b/services/common/tests/unit/test_bagheera_client.js
@@ -4,42 +4,38 @@
 "use strict";
 
 Cu.import("resource://services-common/bagheeraclient.js");
 Cu.import("resource://services-common/rest.js");
 Cu.import("resource://testing-common/services-common/bagheeraserver.js");
 Cu.import("resource://gre/modules/Promise.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 
-const PORT = 8080;
+function getClientAndServer() {
+  let server = new BagheeraServer();
+  server.start();
 
-function getClientAndServer(port=PORT) {
-  let uri = "http://localhost";
-  let server = new BagheeraServer(uri);
-
-  server.start(port);
-
-  let client = new BagheeraClient(uri + ":" + port);
+  let client = new BagheeraClient(server.serverURI);
 
   return [client, server];
 }
 
 function run_test() {
   initTestLogging("Trace");
   run_next_test();
 }
 
 add_test(function test_constructor() {
-  let client = new BagheeraClient("http://localhost:8080/");
+  let client = new BagheeraClient("http://localhost:1234/");
 
   run_next_test();
 });
 
 add_test(function test_post_json_transport_failure() {
-  let client = new BagheeraClient("http://localhost:8080/");
+  let client = new BagheeraClient("http://localhost:1234/");
 
   client.uploadJSON("foo", "bar", {}).then(function onResult(result) {
     do_check_false(result.transportSuccess);
 
     run_next_test();
   });
 });
 
@@ -133,9 +129,9 @@ add_test(function test_delete_document()
   client.deleteDocument("foo", "bar").then(function onResult(result) {
     do_check_true(result.transportSuccess);
     do_check_true(result.serverSuccess);
 
     do_check_null(server.getDocument("foo", "bar"));
 
     server.stop(run_next_test);
   });
-});
\ No newline at end of file
+});
--- a/services/common/tests/unit/test_bagheera_server.js
+++ b/services/common/tests/unit/test_bagheera_server.js
@@ -1,17 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 Cu.import("resource://testing-common/services-common/bagheeraserver.js");
 
-const PORT = 8080;
-
 function run_test() {
   run_next_test();
 }
 
 add_test(function test_server_empty() {
   let server = new BagheeraServer();
 
   do_check_false(server.hasNamespace("foo"));
@@ -19,27 +17,14 @@ add_test(function test_server_empty() {
   do_check_null(server.getDocument("foo", "bar"));
 
   server.createNamespace("foo");
   do_check_true(server.hasNamespace("foo"));
 
   run_next_test();
 });
 
-add_test(function test_server_start_no_port() {
-  let server = new BagheeraServer();
-
-  try {
-    server.start();
-  } catch (ex) {
-    do_check_true(ex.message.startsWith("port argument must be"));
-  }
-
-  run_next_test();
-});
-
 add_test(function test_server_start() {
   let server = new BagheeraServer();
-  server.start(PORT);
-
+  server.start();
   server.stop(run_next_test);
 });
 
--- a/services/common/tests/unit/test_restrequest.js
+++ b/services/common/tests/unit/test_restrequest.js
@@ -1,18 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 Cu.import("resource://gre/modules/NetUtil.jsm");
 Cu.import("resource://services-common/log4moz.js");
 Cu.import("resource://services-common/rest.js");
 Cu.import("resource://services-common/utils.js");
 
-const TEST_RESOURCE_URL = TEST_SERVER_URL + "resource";
-
 //DEBUG = true;
 
 function run_test() {
   Log4Moz.repository.getLogger("Services.Common.RESTRequest").level =
     Log4Moz.Level.Trace;
   initTestLogging("Trace");
 
   run_next_test();
@@ -69,20 +67,20 @@ add_test(function test_proxy_auth_redire
     response.setStatusLine(metadata.httpVersion, 200, "OK");
     response.bodyOutputStream.write(body, body.length);
   }
 
   let server = httpd_setup({
     "/original": original,
     "/pac3":     pacHandler
   });
-  PACSystemSettings.PACURI = "http://localhost:8080/pac3";
+  PACSystemSettings.PACURI = server.baseURI + "/pac3";
   installFakePAC();
 
-  let res = new RESTRequest("http://localhost:8080/original");
+  let res = new RESTRequest(server.baseURI + "/original");
   res.get(function (error) {
     do_check_true(pacFetched);
     do_check_true(fetched);
     do_check_true(!error);
     do_check_true(this.response.success);
     do_check_eq("TADA!", this.response.body);
     uninstallFakePAC();
     server.stop(run_next_test);
@@ -107,18 +105,17 @@ add_test(function test_forbidden_port() 
 
 /**
  * Demonstrate API short-hand: create a request and dispatch it immediately.
  */
 add_test(function test_simple_get() {
   let handler = httpd_handler(200, "OK", "Huzzah!");
   let server = httpd_setup({"/resource": handler});
 
-  let uri = TEST_RESOURCE_URL;
-  let request = new RESTRequest(uri).get(function (error) {
+  let request = new RESTRequest(server.baseURI + "/resource").get(function (error) {
     do_check_eq(error, null);
 
     do_check_eq(this.status, this.COMPLETED);
     do_check_true(this.response.success);
     do_check_eq(this.response.status, 200);
     do_check_eq(this.response.body, "Huzzah!");
 
     server.stop(run_next_test);
@@ -129,17 +126,17 @@ add_test(function test_simple_get() {
 
 /**
  * Test HTTP GET with all bells and whistles.
  */
 add_test(function test_get() {
   let handler = httpd_handler(200, "OK", "Huzzah!");
   let server = httpd_setup({"/resource": handler});
 
-  let request = new RESTRequest(TEST_RESOURCE_URL);
+  let request = new RESTRequest(server.baseURI + "/resource");
   do_check_eq(request.status, request.NOT_SENT);
 
   request.onProgress = request.onComplete = function () {
     do_throw("This function should have been overwritten!");
   };
 
   let onProgress_called = false;
   function onProgress() {
@@ -193,28 +190,28 @@ add_test(function test_get_utf8() {
     let converter = Cc["@mozilla.org/intl/converter-output-stream;1"]
                     .createInstance(Ci.nsIConverterOutputStream);
     converter.init(res.bodyOutputStream, "UTF-8", 0, 0x0000);
     converter.writeString(response);
     converter.close();
   }});
 
   // Check if charset in Content-Type is propertly interpreted.
-  let request1 = new RESTRequest(TEST_RESOURCE_URL);
+  let request1 = new RESTRequest(server.baseURI + "/resource");
   request1.get(function(error) {
     do_check_null(error);
 
     do_check_eq(request1.response.status, 200);
     do_check_eq(request1.response.body, response);
     do_check_eq(request1.response.headers["content-type"],
                 contentType + charsetSuffix);
 
     // Check that we default to UTF-8 if Content-Type doesn't have a charset.
     charset = false;
-    let request2 = new RESTRequest(TEST_RESOURCE_URL);
+    let request2 = new RESTRequest(server.baseURI + "/resource");
     request2.get(function(error) {
       do_check_null(error);
 
       do_check_eq(request2.response.status, 200);
       do_check_eq(request2.response.body, response);
       do_check_eq(request2.response.headers["content-type"], contentType);
       do_check_eq(request2.response.charset, "utf-8");
 
@@ -240,30 +237,30 @@ add_test(function test_charsets() {
     let converter = Cc["@mozilla.org/intl/converter-output-stream;1"]
                     .createInstance(Ci.nsIConverterOutputStream);
     converter.init(res.bodyOutputStream, "us-ascii", 0, 0x0000);
     converter.writeString(response);
     converter.close();
   }});
 
   // Check that provided charset overrides hint.
-  let request1 = new RESTRequest(TEST_RESOURCE_URL);
+  let request1 = new RESTRequest(server.baseURI + "/resource");
   request1.charset = "not-a-charset";
   request1.get(function(error) {
     do_check_null(error);
 
     do_check_eq(request1.response.status, 200);
     do_check_eq(request1.response.body, response);
     do_check_eq(request1.response.headers["content-type"],
                 contentType + charsetSuffix);
     do_check_eq(request1.response.charset, "us-ascii");
 
     // Check that hint is used if Content-Type doesn't have a charset.
     charset = false;
-    let request2 = new RESTRequest(TEST_RESOURCE_URL);
+    let request2 = new RESTRequest(server.baseURI + "/resource");
     request2.charset = "us-ascii";
     request2.get(function(error) {
       do_check_null(error);
 
       do_check_eq(request2.response.status, 200);
       do_check_eq(request2.response.body, response);
       do_check_eq(request2.response.headers["content-type"], contentType);
       do_check_eq(request2.response.charset, "us-ascii");
@@ -275,17 +272,17 @@ add_test(function test_charsets() {
 
 /**
  * Test HTTP PUT with a simple string argument and default Content-Type.
  */
 add_test(function test_put() {
   let handler = httpd_handler(200, "OK", "Got it!");
   let server = httpd_setup({"/resource": handler});
 
-  let request = new RESTRequest(TEST_RESOURCE_URL);
+  let request = new RESTRequest(server.baseURI + "/resource");
   do_check_eq(request.status, request.NOT_SENT);
 
   request.onProgress = request.onComplete = function () {
     do_throw("This function should have been overwritten!");
   };
 
   let onProgress_called = false;
   function onProgress() {
@@ -324,17 +321,17 @@ add_test(function test_put() {
 
 /**
  * Test HTTP POST with a simple string argument and default Content-Type.
  */
 add_test(function test_post() {
   let handler = httpd_handler(200, "OK", "Got it!");
   let server = httpd_setup({"/resource": handler});
 
-  let request = new RESTRequest(TEST_RESOURCE_URL);
+  let request = new RESTRequest(server.baseURI + "/resource");
   do_check_eq(request.status, request.NOT_SENT);
 
   request.onProgress = request.onComplete = function () {
     do_throw("This function should have been overwritten!");
   };
 
   let onProgress_called = false;
   function onProgress() {
@@ -373,17 +370,17 @@ add_test(function test_post() {
 
 /**
  * Test HTTP DELETE.
  */
 add_test(function test_delete() {
   let handler = httpd_handler(200, "OK", "Got it!");
   let server = httpd_setup({"/resource": handler});
 
-  let request = new RESTRequest(TEST_RESOURCE_URL);
+  let request = new RESTRequest(server.baseURI + "/resource");
   do_check_eq(request.status, request.NOT_SENT);
 
   request.onProgress = request.onComplete = function () {
     do_throw("This function should have been overwritten!");
   };
 
   let onProgress_called = false;
   function onProgress() {
@@ -419,17 +416,17 @@ add_test(function test_delete() {
 
 /**
  * Test an HTTP response with a non-200 status code.
  */
 add_test(function test_get_404() {
   let handler = httpd_handler(404, "Not Found", "Cannae find it!");
   let server = httpd_setup({"/resource": handler});
 
-  let request = new RESTRequest(TEST_RESOURCE_URL);
+  let request = new RESTRequest(server.baseURI + "/resource");
   request.get(function (error) {
     do_check_eq(error, null);
 
     do_check_eq(this.status, this.COMPLETED);
     do_check_false(this.response.success);
     do_check_eq(this.response.status, 404);
     do_check_eq(this.response.body, "Cannae find it!");
 
@@ -445,17 +442,17 @@ add_test(function test_put_json() {
   let handler = httpd_handler(200, "OK");
   let server = httpd_setup({"/resource": handler});
 
   let sample_data = {
     some: "sample_data",
     injson: "format",
     number: 42
   };
-  let request = new RESTRequest(TEST_RESOURCE_URL);
+  let request = new RESTRequest(server.baseURI + "/resource");
   request.put(sample_data, function (error) {
     do_check_eq(error, null);
 
     do_check_eq(this.status, this.COMPLETED);
     do_check_true(this.response.success);
     do_check_eq(this.response.status, 200);
     do_check_eq(this.response.body, "");
 
@@ -475,17 +472,17 @@ add_test(function test_post_json() {
   let handler = httpd_handler(200, "OK");
   let server = httpd_setup({"/resource": handler});
 
   let sample_data = {
     some: "sample_data",
     injson: "format",
     number: 42
   };
-  let request = new RESTRequest(TEST_RESOURCE_URL);
+  let request = new RESTRequest(server.baseURI + "/resource");
   request.post(sample_data, function (error) {
     do_check_eq(error, null);
 
     do_check_eq(this.status, this.COMPLETED);
     do_check_true(this.response.success);
     do_check_eq(this.response.status, 200);
     do_check_eq(this.response.body, "");
 
@@ -499,17 +496,17 @@ add_test(function test_post_json() {
 
 /**
  * HTTP PUT with a custom Content-Type header.
  */
 add_test(function test_put_override_content_type() {
   let handler = httpd_handler(200, "OK");
   let server = httpd_setup({"/resource": handler});
 
-  let request = new RESTRequest(TEST_RESOURCE_URL);
+  let request = new RESTRequest(server.baseURI + "/resource");
   request.setHeader("Content-Type", "application/lolcat");
   request.put("O HAI!!1!", function (error) {
     do_check_eq(error, null);
 
     do_check_eq(this.status, this.COMPLETED);
     do_check_true(this.response.success);
     do_check_eq(this.response.status, 200);
     do_check_eq(this.response.body, "");
@@ -524,17 +521,17 @@ add_test(function test_put_override_cont
 
 /**
  * HTTP POST with a custom Content-Type header.
  */
 add_test(function test_post_override_content_type() {
   let handler = httpd_handler(200, "OK");
   let server = httpd_setup({"/resource": handler});
 
-  let request = new RESTRequest(TEST_RESOURCE_URL);
+  let request = new RESTRequest(server.baseURI + "/resource");
   request.setHeader("Content-Type", "application/lolcat");
   request.post("O HAI!!1!", function (error) {
     do_check_eq(error, null);
 
     do_check_eq(this.status, this.COMPLETED);
     do_check_true(this.response.success);
     do_check_eq(this.response.status, 200);
     do_check_eq(this.response.body, "");
@@ -554,17 +551,17 @@ add_test(function test_get_no_headers() 
   let handler = httpd_handler(200, "OK");
   let server = httpd_setup({"/resource": handler});
 
   let ignore_headers = ["host", "user-agent", "accept", "accept-language",
                         "accept-encoding", "accept-charset", "keep-alive",
                         "connection", "pragma", "cache-control",
                         "content-length"];
 
-  new RESTRequest(TEST_RESOURCE_URL).get(function (error) {
+  new RESTRequest(server.baseURI + "/resource").get(function (error) {
     do_check_eq(error, null);
 
     do_check_eq(this.response.status, 200);
     do_check_eq(this.response.body, "");
 
     let server_headers = handler.request.headers;
     while (server_headers.hasMoreElements()) {
       let header = server_headers.getNext().toString();
@@ -579,33 +576,33 @@ add_test(function test_get_no_headers() 
 
 /**
  * Test changing the URI after having created the request.
  */
 add_test(function test_changing_uri() {
   let handler = httpd_handler(200, "OK");
   let server = httpd_setup({"/resource": handler});
 
-  let request = new RESTRequest("http://localhost:8080/the-wrong-resource");
-  request.uri = CommonUtils.makeURI(TEST_RESOURCE_URL);
+  let request = new RESTRequest("http://localhost:1234/the-wrong-resource");
+  request.uri = CommonUtils.makeURI(server.baseURI + "/resource");
   request.get(function (error) {
     do_check_eq(error, null);
     do_check_eq(this.response.status, 200);
     server.stop(run_next_test);
   });
 });
 
 /**
  * Test setting HTTP request headers.
  */
 add_test(function test_request_setHeader() {
   let handler = httpd_handler(200, "OK");
   let server = httpd_setup({"/resource": handler});
 
-  let request = new RESTRequest(TEST_RESOURCE_URL);
+  let request = new RESTRequest(server.baseURI + "/resource");
 
   request.setHeader("X-What-Is-Weave", "awesome");
   request.setHeader("X-WHAT-is-Weave", "more awesomer");
   request.setHeader("Another-Header", "Hello World");
 
   request.get(function (error) {
     do_check_eq(error, null);
 
@@ -624,17 +621,17 @@ add_test(function test_request_setHeader
  */
 add_test(function test_response_headers() {
   function handler(request, response) {
     response.setHeader("X-What-Is-Weave", "awesome");
     response.setHeader("Another-Header", "Hello World");
     response.setStatusLine(request.httpVersion, 200, "OK");
   }
   let server = httpd_setup({"/resource": handler});
-  let request = new RESTRequest(TEST_RESOURCE_URL);
+  let request = new RESTRequest(server.baseURI + "/resource");
 
   request.get(function (error) {
     do_check_eq(error, null);
 
     do_check_eq(this.response.status, 200);
     do_check_eq(this.response.body, "");
 
     do_check_eq(this.response.headers["x-what-is-weave"], "awesome");
@@ -644,17 +641,17 @@ add_test(function test_response_headers(
   });
 });
 
 /**
  * The onComplete() handler gets called in case of any network errors
  * (e.g. NS_ERROR_CONNECTION_REFUSED).
  */
 add_test(function test_connection_refused() {
-  let request = new RESTRequest(TEST_RESOURCE_URL);
+  let request = new RESTRequest("http://localhost:1234/resource");
   request.onProgress = function onProgress() {
     do_throw("Shouldn't have called request.onProgress()!");
   };
   request.get(function (error) {
     do_check_eq(error.result, Cr.NS_ERROR_CONNECTION_REFUSED);
     do_check_eq(error.message, "NS_ERROR_CONNECTION_REFUSED");
     do_check_eq(this.status, this.COMPLETED);
     run_next_test();
@@ -666,17 +663,17 @@ add_test(function test_connection_refuse
  * Abort a request that just sent off.
  */
 add_test(function test_abort() {
   function handler() {
     do_throw("Shouldn't have gotten here!");
   }
   let server = httpd_setup({"/resource": handler});
 
-  let request = new RESTRequest(TEST_RESOURCE_URL);
+  let request = new RESTRequest(server.baseURI + "/resource");
 
   // Aborting a request that hasn't been sent yet is pointless and will throw.
   do_check_throws(function () {
     request.abort();
   });
 
   request.onProgress = request.onComplete = function () {
     do_throw("Shouldn't have gotten here!");
@@ -704,19 +701,22 @@ add_test(function test_timeout() {
   let server_connection;
   server._handler.handleResponse = function(connection) {
     // This is a handler that doesn't do anything, just keeps the connection
     // open, thereby mimicking a timing out connection. We keep a reference to
     // the open connection for later so it can be properly disposed of. That's
     // why you really only want to make one HTTP request to this server ever.
     server_connection = connection;
   };
-  server.start(8080);
+  server.start();
+  let identity = server.identity;
+  let uri = identity.primaryScheme + "://" + identity.primaryHost + ":" +
+            identity.primaryPort;
 
-  let request = new RESTRequest(TEST_RESOURCE_URL);
+  let request = new RESTRequest(uri + "/resource");
   request.timeout = 0.1; // 100 milliseconds
   request.get(function (error) {
     do_check_eq(error.result, Cr.NS_ERROR_NET_TIMEOUT);
     do_check_eq(this.status, this.ABORTED);
 
     _("Closing connection.");
     server_connection.close();
     _("Shutting down server.");
@@ -726,17 +726,17 @@ add_test(function test_timeout() {
 
 /**
  * An exception thrown in 'onProgress' propagates to the 'onComplete' handler.
  */
 add_test(function test_exception_in_onProgress() {
   let handler = httpd_handler(200, "OK", "Foobar");
   let server = httpd_setup({"/resource": handler});
 
-  let request = new RESTRequest(TEST_RESOURCE_URL);
+  let request = new RESTRequest(server.baseURI + "/resource");
   request.onProgress = function onProgress() {
     it.does.not.exist();
   };
   request.get(function onComplete(error) {
     do_check_eq(error, "ReferenceError: it is not defined");
     do_check_eq(this.status, this.ABORTED);
 
     server.stop(run_next_test);
@@ -748,46 +748,48 @@ add_test(function test_new_channel() {
 
   function checkUA(metadata) {
     let ua = metadata.getHeader("User-Agent");
     _("User-Agent is " + ua);
     do_check_eq("foo bar", ua);
   }
 
   let redirectRequested = false;
+  let redirectURL;
   function redirectHandler(metadata, response) {
     checkUA(metadata);
     redirectRequested = true;
 
     let body = "Redirecting";
     response.setStatusLine(metadata.httpVersion, 307, "TEMPORARY REDIRECT");
-    response.setHeader("Location", "http://localhost:8081/resource");
+    response.setHeader("Location", redirectURL);
     response.bodyOutputStream.write(body, body.length);
   }
 
   let resourceRequested = false;
   function resourceHandler(metadata, response) {
     checkUA(metadata);
     resourceRequested = true;
 
     let body = "Test";
     response.setHeader("Content-Type", "text/plain");
     response.bodyOutputStream.write(body, body.length);
   }
 
-  let server1 = httpd_setup({"/redirect": redirectHandler}, 8080);
-  let server2 = httpd_setup({"/resource": resourceHandler}, 8081);
+  let server1 = httpd_setup({"/redirect": redirectHandler});
+  let server2 = httpd_setup({"/resource": resourceHandler});
+  redirectURL = server2.baseURI + "/resource";
 
   function advance() {
     server1.stop(function () {
       server2.stop(run_next_test);
     });
   }
 
-  let request = new RESTRequest("http://localhost:8080/redirect");
+  let request = new RESTRequest(server1.baseURI + "/redirect");
   request.setHeader("User-Agent", "foo bar");
 
   // Swizzle in our own fakery, because this redirect is neither
   // internal nor URI-preserving. RESTRequest's policy is to only
   // copy headers under certain circumstances.
   let protoMethod = request.shouldCopyOnRedirect;
   request.shouldCopyOnRedirect = function wrapped(o, n, f) {
     // Check the default policy.
@@ -813,19 +815,19 @@ add_test(function test_not_sending_cooki
     response.setStatusLine(metadata.httpVersion, 200, "OK");
     response.bodyOutputStream.write(body, body.length);
     do_check_false(metadata.hasHeader("Cookie"));
   }
   let server = httpd_setup({"/test": handler});
 
   let cookieSer = Cc["@mozilla.org/cookieService;1"]
                     .getService(Ci.nsICookieService);
-  let uri = CommonUtils.makeURI("http://localhost:8080");
+  let uri = CommonUtils.makeURI(server.baseURI);
   cookieSer.setCookieString(uri, null, "test=test; path=/;", null);
 
-  let res = new RESTRequest("http://localhost:8080/test");
+  let res = new RESTRequest(server.baseURI + "/test");
   res.get(function (error) {
     do_check_null(error);
     do_check_true(this.response.success);
     do_check_eq("COOKIE!", this.response.body);
     server.stop(run_next_test);
   });
 });
--- a/services/common/tests/unit/test_storage_server.js
+++ b/services/common/tests/unit/test_storage_server.js
@@ -1,26 +1,27 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 Cu.import("resource://services-common/async.js");
 Cu.import("resource://services-common/rest.js");
 Cu.import("resource://services-common/utils.js");
 Cu.import("resource://testing-common/services-common/storageserver.js");
 
-const PORT = 8080;
 const DEFAULT_USER = "123";
 const DEFAULT_PASSWORD = "password";
 
 /**
  * Helper function to prepare a RESTRequest against the server.
  */
-function localRequest(path, user=DEFAULT_USER, password=DEFAULT_PASSWORD) {
+function localRequest(server, path, user=DEFAULT_USER, password=DEFAULT_PASSWORD) {
   _("localRequest: " + path);
-  let url = "http://127.0.0.1:" + PORT + path;
+  let identity = server.server.identity;
+  let url = identity.primaryScheme + "://" + identity.primaryHost + ":" +
+            identity.primaryPort + path;
   _("url: " + url);
   let req = new RESTRequest(url);
 
   let header = basic_auth_header(user, password);
   req.setHeader("Authorization", header);
   req.setHeader("Accept", "application/json");
 
   return req;
@@ -115,28 +116,27 @@ add_test(function test_creation() {
   _("Ensure a simple server can be created.");
 
   // Explicit callback for this one.
   let server = new StorageServer({
     __proto__: StorageServerCallback,
   });
   do_check_true(!!server);
 
-  server.start(PORT, function () {
+  server.start(-1, function () {
     _("Started on " + server.port);
-    do_check_eq(server.port, PORT);
     server.stop(run_next_test);
   });
 });
 
 add_test(function test_synchronous_start() {
   _("Ensure starting using startSynchronous works.");
 
   let server = new StorageServer();
-  server.startSynchronous(PORT);
+  server.startSynchronous();
   server.stop(run_next_test);
 });
 
 add_test(function test_url_parsing() {
   _("Ensure server parses URLs properly.");
 
   let server = new StorageServer();
 
@@ -179,46 +179,46 @@ add_test(function test_url_parsing() {
 
   run_next_test();
 });
 
 add_test(function test_basic_http() {
   let server = new StorageServer();
   server.registerUser("345", "password");
   do_check_true(server.userExists("345"));
-  server.startSynchronous(PORT);
+  server.startSynchronous();
 
   _("Started on " + server.port);
   do_check_eq(server.requestCount, 0);
-  let req = localRequest("/2.0/storage/crypto/keys");
+  let req = localRequest(server, "/2.0/storage/crypto/keys");
   _("req is " + req);
   req.get(function (err) {
     do_check_eq(null, err);
     do_check_eq(server.requestCount, 1);
     server.stop(run_next_test);
   });
 });
 
 add_test(function test_info_collections() {
   let server = new StorageServer();
   server.registerUser("123", "password");
-  server.startSynchronous(PORT);
+  server.startSynchronous();
 
   let path = "/2.0/123/info/collections";
 
   _("info/collections on empty server should be empty object.");
-  let request = localRequest(path, "123", "password");
+  let request = localRequest(server, path, "123", "password");
   let error = doGetRequest(request);
   do_check_eq(error, null);
   do_check_eq(request.response.status, 200);
   do_check_eq(request.response.body, "{}");
 
   _("Creating an empty collection should result in collection appearing.");
   let coll = server.createCollection("123", "col1");
-  let request = localRequest(path, "123", "password");
+  let request = localRequest(server, path, "123", "password");
   let error = doGetRequest(request);
   do_check_eq(error, null);
   do_check_eq(request.response.status, 200);
   let info = JSON.parse(request.response.body);
   do_check_attribute_count(info, 1);
   do_check_true("col1" in info);
   do_check_eq(info.col1, coll.timestamp);
 
@@ -228,21 +228,22 @@ add_test(function test_info_collections(
 add_test(function test_bso_get_existing() {
   _("Ensure that BSO retrieval works.");
 
   let server = new StorageServer();
   server.registerUser("123", "password");
   server.createContents("123", {
     test: {"bso": {"foo": "bar"}}
   });
-  server.startSynchronous(PORT);
+  server.startSynchronous();
 
   let coll = server.user("123").collection("test");
 
-  let request = localRequest("/2.0/123/storage/test/bso", "123", "password");
+  let request = localRequest(server, "/2.0/123/storage/test/bso", "123",
+                             "password");
   let error = doGetRequest(request);
   do_check_eq(error, null);
   do_check_eq(request.response.status, 200);
   do_check_eq(request.response.headers["content-type"], "application/json");
   let bso = JSON.parse(request.response.body);
   do_check_attribute_count(bso, 3);
   do_check_eq(bso.id, "bso");
   do_check_eq(bso.modified, coll.bso("bso").modified);
@@ -253,24 +254,24 @@ add_test(function test_bso_get_existing(
   server.stop(run_next_test);
 });
 
 add_test(function test_percent_decoding() {
   _("Ensure query string arguments with percent encoded are handled.");
 
   let server = new StorageServer();
   server.registerUser("123", "password");
-  server.startSynchronous(PORT);
+  server.startSynchronous();
 
   let coll = server.user("123").createCollection("test");
   coll.insert("001", {foo: "bar"});
   coll.insert("002", {bar: "foo"});
 
-  let request = localRequest("/2.0/123/storage/test?ids=001%2C002", "123",
-                             "password");
+  let request = localRequest(server, "/2.0/123/storage/test?ids=001%2C002",
+                             "123", "password");
   let error = doGetRequest(request);
   do_check_null(error);
   do_check_eq(request.response.status, 200);
   let items = JSON.parse(request.response.body).items;
   do_check_attribute_count(items, 2);
 
   server.stop(run_next_test);
 });
@@ -278,19 +279,19 @@ add_test(function test_percent_decoding(
 add_test(function test_bso_404() {
   _("Ensure the server responds with a 404 if a BSO does not exist.");
 
   let server = new StorageServer();
   server.registerUser("123", "password");
   server.createContents("123", {
     test: {}
   });
-  server.startSynchronous(PORT);
+  server.startSynchronous();
 
-  let request = localRequest("/2.0/123/storage/test/foo");
+  let request = localRequest(server, "/2.0/123/storage/test/foo");
   let error = doGetRequest(request);
   do_check_eq(error, null);
 
   do_check_eq(request.response.status, 404);
   do_check_false("content-type" in request.response.headers);
 
   server.stop(run_next_test);
 });
@@ -298,34 +299,36 @@ add_test(function test_bso_404() {
 add_test(function test_bso_if_modified_since_304() {
   _("Ensure the server responds properly to X-If-Modified-Since for BSOs.");
 
   let server = new StorageServer();
   server.registerUser("123", "password");
   server.createContents("123", {
     test: {bso: {foo: "bar"}}
   });
-  server.startSynchronous(PORT);
+  server.startSynchronous();
 
   let coll = server.user("123").collection("test");
   do_check_neq(coll, null);
 
   // Rewind clock just in case.
   coll.timestamp -= 10000;
   coll.bso("bso").modified -= 10000;
 
-  let request = localRequest("/2.0/123/storage/test/bso", "123", "password");
+  let request = localRequest(server, "/2.0/123/storage/test/bso",
+                             "123", "password");
   request.setHeader("X-If-Modified-Since", "" + server.serverTime());
   let error = doGetRequest(request);
   do_check_eq(null, error);
 
   do_check_eq(request.response.status, 304);
   do_check_false("content-type" in request.response.headers);
 
-  let request = localRequest("/2.0/123/storage/test/bso", "123", "password");
+  let request = localRequest(server, "/2.0/123/storage/test/bso",
+                             "123", "password");
   request.setHeader("X-If-Modified-Since", "" + (server.serverTime() - 20000));
   let error = doGetRequest(request);
   do_check_eq(null, error);
   do_check_eq(request.response.status, 200);
   do_check_eq(request.response.headers["content-type"], "application/json");
 
   server.stop(run_next_test);
 });
@@ -333,220 +336,228 @@ add_test(function test_bso_if_modified_s
 add_test(function test_bso_if_unmodified_since() {
   _("Ensure X-If-Unmodified-Since works properly on BSOs.");
 
   let server = new StorageServer();
   server.registerUser("123", "password");
   server.createContents("123", {
     test: {bso: {foo: "bar"}}
   });
-  server.startSynchronous(PORT);
+  server.startSynchronous();
 
   let coll = server.user("123").collection("test");
   do_check_neq(coll, null);
 
   let time = coll.timestamp;
 
   _("Ensure we get a 412 for specified times older than server time.");
-  let request = localRequest("/2.0/123/storage/test/bso", "123", "password");
+  let request = localRequest(server, "/2.0/123/storage/test/bso",
+                             "123", "password");
   request.setHeader("X-If-Unmodified-Since", time - 5000);
   request.setHeader("Content-Type", "application/json");
   let payload = JSON.stringify({"payload": "foobar"});
   let error = doPutRequest(request, payload);
   do_check_eq(null, error);
   do_check_eq(request.response.status, 412);
 
   _("Ensure we get a 204 if update goes through.");
-  let request = localRequest("/2.0/123/storage/test/bso", "123", "password");
+  let request = localRequest(server, "/2.0/123/storage/test/bso",
+                             "123", "password");
   request.setHeader("Content-Type", "application/json");
   request.setHeader("X-If-Unmodified-Since", time + 1);
   let error = doPutRequest(request, payload);
   do_check_eq(null, error);
   do_check_eq(request.response.status, 204);
   do_check_true(coll.timestamp > time);
 
   // Not sure why a client would send X-If-Unmodified-Since if a BSO doesn't
   // exist. But, why not test it?
   _("Ensure we get a 201 if creation goes through.");
-  let request = localRequest("/2.0/123/storage/test/none", "123", "password");
+  let request = localRequest(server, "/2.0/123/storage/test/none",
+                             "123", "password");
   request.setHeader("Content-Type", "application/json");
   request.setHeader("X-If-Unmodified-Since", time);
   let error = doPutRequest(request, payload);
   do_check_eq(null, error);
   do_check_eq(request.response.status, 201);
 
   server.stop(run_next_test);
 });
 
 add_test(function test_bso_delete_not_exist() {
   _("Ensure server behaves properly when deleting a BSO that does not exist.");
 
   let server = new StorageServer();
   server.registerUser("123", "password");
   server.user("123").createCollection("empty");
-  server.startSynchronous(PORT);
+  server.startSynchronous();
 
   server.callback.onItemDeleted = function onItemDeleted(username, collection,
                                                          id) {
     do_throw("onItemDeleted should not have been called.");
   };
 
-  let request = localRequest("/2.0/123/storage/empty/nada", "123", "password");
+  let request = localRequest(server, "/2.0/123/storage/empty/nada",
+                             "123", "password");
   let error = doDeleteRequest(request);
   do_check_eq(error, null);
   do_check_eq(request.response.status, 404);
   do_check_false("content-type" in request.response.headers);
 
   server.stop(run_next_test);
 });
 
 add_test(function test_bso_delete_exists() {
   _("Ensure proper semantics when deleting a BSO that exists.");
 
   let server = new StorageServer();
   server.registerUser("123", "password");
-  server.startSynchronous(PORT);
+  server.startSynchronous();
 
   let coll = server.user("123").createCollection("test");
   let bso = coll.insert("myid", {foo: "bar"});
   let timestamp = coll.timestamp;
 
   server.callback.onItemDeleted = function onDeleted(username, collection, id) {
     delete server.callback.onItemDeleted;
     do_check_eq(username, "123");
     do_check_eq(collection, "test");
     do_check_eq(id, "myid");
   };
 
-  let request = localRequest("/2.0/123/storage/test/myid", "123", "password");
+  let request = localRequest(server, "/2.0/123/storage/test/myid",
+                             "123", "password");
   let error = doDeleteRequest(request);
   do_check_eq(error, null);
   do_check_eq(request.response.status, 204);
   do_check_eq(coll.bsos().length, 0);
   do_check_true(coll.timestamp > timestamp);
 
   _("On next request the BSO should not exist.");
-  let request = localRequest("/2.0/123/storage/test/myid", "123", "password");
+  let request = localRequest(server, "/2.0/123/storage/test/myid",
+                             "123", "password");
   let error = doGetRequest(request);
   do_check_eq(error, null);
   do_check_eq(request.response.status, 404);
 
   server.stop(run_next_test);
 });
 
 add_test(function test_bso_delete_unmodified() {
   _("Ensure X-If-Unmodified-Since works when deleting BSOs.");
 
   let server = new StorageServer();
-  server.startSynchronous(PORT);
+  server.startSynchronous();
   server.registerUser("123", "password");
   let coll = server.user("123").createCollection("test");
   let bso = coll.insert("myid", {foo: "bar"});
 
   let modified = bso.modified;
 
   _("Issuing a DELETE with an older time should fail.");
   let path = "/2.0/123/storage/test/myid";
-  let request = localRequest(path, "123", "password");
+  let request = localRequest(server, path, "123", "password");
   request.setHeader("X-If-Unmodified-Since", modified - 1000);
   let error = doDeleteRequest(request);
   do_check_eq(error, null);
   do_check_eq(request.response.status, 412);
   do_check_false("content-type" in request.response.headers);
   do_check_neq(coll.bso("myid"), null);
 
   _("Issuing a DELETE with a newer time should work.");
-  let request = localRequest(path, "123", "password");
+  let request = localRequest(server, path, "123", "password");
   request.setHeader("X-If-Unmodified-Since", modified + 1000);
   let error = doDeleteRequest(request);
   do_check_eq(error, null);
   do_check_eq(request.response.status, 204);
   do_check_true(coll.bso("myid").deleted);
 
   server.stop(run_next_test);
 });
 
 add_test(function test_collection_get_unmodified_since() {
   _("Ensure conditional unmodified get on collection works when it should.");
 
   let server = new StorageServer();
   server.registerUser("123", "password");
-  server.startSynchronous(PORT);
+  server.startSynchronous();
   let collection = server.user("123").createCollection("testcoll");
   collection.insert("bso0", {foo: "bar"});
 
   let serverModified = collection.timestamp;
 
-  let request1 = localRequest("/2.0/123/storage/testcoll", "123", "password");
+  let request1 = localRequest(server, "/2.0/123/storage/testcoll",
+                              "123", "password");
   request1.setHeader("X-If-Unmodified-Since", serverModified);
   let error = doGetRequest(request1);
   do_check_null(error);
   do_check_eq(request1.response.status, 200);
 
-  let request2 = localRequest("/2.0/123/storage/testcoll", "123", "password");
+  let request2 = localRequest(server, "/2.0/123/storage/testcoll",
+                              "123", "password");
   request2.setHeader("X-If-Unmodified-Since", serverModified - 1);
   let error = doGetRequest(request2);
   do_check_null(error);
   do_check_eq(request2.response.status, 412);
 
   server.stop(run_next_test);
 });
 
 add_test(function test_bso_get_unmodified_since() {
   _("Ensure conditional unmodified get on BSO works appropriately.");
 
   let server = new StorageServer();
   server.registerUser("123", "password");
-  server.startSynchronous(PORT);
+  server.startSynchronous();
   let collection = server.user("123").createCollection("testcoll");
   let bso = collection.insert("bso0", {foo: "bar"});
 
   let serverModified = bso.modified;
 
-  let request1 = localRequest("/2.0/123/storage/testcoll/bso0", "123",
-                              "password");
+  let request1 = localRequest(server, "/2.0/123/storage/testcoll/bso0",
+                              "123", "password");
   request1.setHeader("X-If-Unmodified-Since", serverModified);
   let error = doGetRequest(request1);
   do_check_null(error);
   do_check_eq(request1.response.status, 200);
 
-  let request2 = localRequest("/2.0/123/storage/testcoll/bso0", "123",
-                              "password");
+  let request2 = localRequest(server, "/2.0/123/storage/testcoll/bso0",
+                              "123", "password");
   request2.setHeader("X-If-Unmodified-Since", serverModified - 1);
   let error = doGetRequest(request2);
   do_check_null(error);
   do_check_eq(request2.response.status, 412);
 
   server.stop(run_next_test);
 });
 
 add_test(function test_missing_collection_404() {
   _("Ensure a missing collection returns a 404.");
 
   let server = new StorageServer();
   server.registerUser("123", "password");
-  server.startSynchronous(PORT);
+  server.startSynchronous();
 
-  let request = localRequest("/2.0/123/storage/none", "123", "password");
+  let request = localRequest(server, "/2.0/123/storage/none", "123", "password");
   let error = doGetRequest(request);
   do_check_eq(error, null);
   do_check_eq(request.response.status, 404);
   do_check_false("content-type" in request.response.headers);
 
   server.stop(run_next_test);
 });
 
 add_test(function test_get_storage_405() {
   _("Ensure that a GET on /storage results in a 405.");
 
   let server = new StorageServer();
   server.registerUser("123", "password");
-  server.startSynchronous(PORT);
+  server.startSynchronous();
 
-  let request = localRequest("/2.0/123/storage", "123", "password");
+  let request = localRequest(server, "/2.0/123/storage", "123", "password");
   let error = doGetRequest(request);
   do_check_eq(error, null);
   do_check_eq(request.response.status, 405);
   do_check_eq(request.response.headers["allow"], "DELETE");
 
   server.stop(run_next_test);
 });
 
@@ -555,108 +566,108 @@ add_test(function test_delete_storage() 
 
   let server = new StorageServer();
   server.registerUser("123", "password");
   server.createContents("123", {
     foo: {a: {foo: "bar"}, b: {bar: "foo"}},
     baz: {c: {bob: "law"}, blah: {law: "blog"}}
   });
 
-  server.startSynchronous(PORT);
+  server.startSynchronous();
 
-  let request = localRequest("/2.0/123/storage", "123", "password");
+  let request = localRequest(server, "/2.0/123/storage", "123", "password");
   let error = doDeleteRequest(request);
   do_check_eq(error, null);
   do_check_eq(request.response.status, 204);
   do_check_attribute_count(server.users["123"].collections, 0);
 
   server.stop(run_next_test);
 });
 
 add_test(function test_x_num_records() {
   let server = new StorageServer();
   server.registerUser("123", "password");
 
   server.createContents("123", {
     crypto: {foos: {foo: "bar"},
              bars: {foo: "baz"}}
   });
-  server.startSynchronous(PORT);
-  let bso = localRequest("/2.0/123/storage/crypto/foos");
+  server.startSynchronous();
+  let bso = localRequest(server, "/2.0/123/storage/crypto/foos");
   bso.get(function (err) {
     // BSO fetches don't have one.
     do_check_false("x-num-records" in this.response.headers);
-    let col = localRequest("/2.0/123/storage/crypto");
+    let col = localRequest(server, "/2.0/123/storage/crypto");
     col.get(function (err) {
       // Collection fetches do.
       do_check_eq(this.response.headers["x-num-records"], "2");
       server.stop(run_next_test);
     });
   });
 });
 
 add_test(function test_put_delete_put() {
   _("Bug 790397: Ensure BSO deleted flag is reset on PUT.");
 
   let server = new StorageServer();
   server.registerUser("123", "password");
   server.createContents("123", {
     test: {bso: {foo: "bar"}}
   });
-  server.startSynchronous(PORT);
+  server.startSynchronous();
 
   _("Ensure we can PUT an existing record.");
-  let request1 = localRequest("/2.0/123/storage/test/bso", "123", "password");
+  let request1 = localRequest(server, "/2.0/123/storage/test/bso", "123", "password");
   request1.setHeader("Content-Type", "application/json");
   let payload1 = JSON.stringify({"payload": "foobar"});
   let error1 = doPutRequest(request1, payload1);
   do_check_eq(null, error1);
   do_check_eq(request1.response.status, 204);
 
   _("Ensure we can DELETE it.");
-  let request2 = localRequest("/2.0/123/storage/test/bso", "123", "password");
+  let request2 = localRequest(server, "/2.0/123/storage/test/bso", "123", "password");
   let error2 = doDeleteRequest(request2);
   do_check_eq(error2, null);
   do_check_eq(request2.response.status, 204);
   do_check_false("content-type" in request2.response.headers);
 
   _("Ensure we can PUT a previously deleted record.");
-  let request3 = localRequest("/2.0/123/storage/test/bso", "123", "password");
+  let request3 = localRequest(server, "/2.0/123/storage/test/bso", "123", "password");
   request3.setHeader("Content-Type", "application/json");
   let payload3 = JSON.stringify({"payload": "foobar"});
   let error3 = doPutRequest(request3, payload3);
   do_check_eq(null, error3);
   do_check_eq(request3.response.status, 201);
 
   _("Ensure we can GET the re-uploaded record.");
-  let request4 = localRequest("/2.0/123/storage/test/bso", "123", "password");
+  let request4 = localRequest(server, "/2.0/123/storage/test/bso", "123", "password");
   let error4 = doGetRequest(request4);
   do_check_eq(error4, null);
   do_check_eq(request4.response.status, 200);
   do_check_eq(request4.response.headers["content-type"], "application/json");
 
   server.stop(run_next_test);
 });
 
 add_test(function test_collection_get_newer() {
   _("Ensure get with newer argument on collection works.");
 
   let server = new StorageServer();
   server.registerUser("123", "password");
-  server.startSynchronous(PORT);
+  server.startSynchronous();
 
   let coll = server.user("123").createCollection("test");
   let bso1 = coll.insert("001", {foo: "bar"});
   let bso2 = coll.insert("002", {bar: "foo"});
 
   // Don't want both records to have the same timestamp.
   bso2.modified = bso1.modified + 1000;
 
   function newerRequest(newer) {
-    return localRequest("/2.0/123/storage/test?newer=" + newer,
+    return localRequest(server, "/2.0/123/storage/test?newer=" + newer,
                         "123", "password");
   }
 
   let request1 = newerRequest(0);
   let error1 = doGetRequest(request1);
   do_check_null(error1);
   do_check_eq(request1.response.status, 200);
   let items1 = JSON.parse(request1.response.body).items;
@@ -672,9 +683,9 @@ add_test(function test_collection_get_ne
   let request3 = newerRequest(bso2.modified + 1);
   let error3 = doGetRequest(request3);
   do_check_null(error3);
   do_check_eq(request3.response.status, 200);
   let items3 = JSON.parse(request3.response.body).items;
   do_check_attribute_count(items3, 0);
 
   server.stop(run_next_test);
-});
\ No newline at end of file
+});
--- a/services/common/tests/unit/test_storageservice_client.js
+++ b/services/common/tests/unit/test_storageservice_client.js
@@ -1,16 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 Cu.import("resource://services-common/storageservice.js");
 Cu.import("resource://testing-common/services-common/storageserver.js");
 
-const BASE_URI = "http://localhost:8080/2.0";
-
 function run_test() {
   initTestLogging("Trace");
 
   run_next_test();
 }
 
 function getRandomUser() {
   return "" + (Math.floor(Math.random() * 100000) + 1);
@@ -22,56 +20,59 @@ function getEmptyServer(user=getRandomUs
 
   return storageServerForUsers(users, {
     meta:    {},
     clients: {},
     crypto:  {},
   });
 }
 
-function getClient(user=getRandomUser(), password="password") {
-  let client = new StorageServiceClient(BASE_URI + "/" + user);
+function getClient(server, user=getRandomUser(), password="password") {
+  let identity = server.server.identity;
+  let url = identity.primaryScheme + "://" + identity.primaryHost + ":" +
+            identity.primaryPort + "/2.0/" + user;
+  let client = new StorageServiceClient(url);
   client.addListener({
     onDispatch: function onDispatch(request) {
       let up = user + ":" + password;
       request.request.setHeader("authorization", "Basic " + btoa(up));
     }
   });
 
   return client;
 }
 
 function getServerAndClient(user=getRandomUser(), password="password") {
   let server = getEmptyServer(user, password);
-  let client = getClient(user, password);
+  let client = getClient(server, user, password);
 
   return [server, client, user, password];
 }
 
 add_test(function test_auth_failure_listener() {
   _("Ensure the onAuthFailure listener is invoked.");
 
   let server = getEmptyServer();
-  let client = getClient("324", "INVALID");
+  let client = getClient(server, "324", "INVALID");
   client.addListener({
     onAuthFailure: function onAuthFailure(client, request) {
       _("onAuthFailure");
       server.stop(run_next_test);
     }
   });
 
   let request = client.getCollectionInfo();
   request.dispatch();
 });
 
 add_test(function test_duplicate_listeners() {
   _("Ensure that duplicate listeners aren't installed multiple times.");
 
   let server = getEmptyServer();
-  let client = getClient("1234567", "BAD_PASSWORD");
+  let client = getClient(server, "1234567", "BAD_PASSWORD");
 
   let invokeCount = 0;
   let listener = {
     onAuthFailure: function onAuthFailure() {
       invokeCount++;
     }
   };
 
@@ -581,18 +582,19 @@ add_test(function test_set_bso_condition
 
     server.stop(run_next_test);
   });
 });
 
 add_test(function test_set_bso_argument_errors() {
   _("Ensure BSO set detects invalid arguments.");
 
+  let server = getEmptyServer();
   let bso = new BasicStorageObject();
-  let client = getClient();
+  let client = getClient(server);
 
   let threw = false;
   try {
     client.setBSO(bso);
   } catch (ex) {
     threw = true;
     do_check_eq(ex.name, "Error");
     do_check_neq(ex.message.indexOf("does not have collection defined"), -1);
@@ -620,17 +622,17 @@ add_test(function test_set_bso_argument_
     threw = true;
     do_check_eq(ex.name, "Error");
     do_check_neq(ex.message.indexOf("does not have ID defined"), -1);
   } finally {
     do_check_true(threw);
     threw = false;
   }
 
-  run_next_test();
+  server.stop(run_next_test);
 });
 
 add_test(function test_set_bsos_simple() {
   _("Ensure setBSOs with basic options works.");
 
   let [server, client, username] = getServerAndClient();
   let user = server.user(username);
 
@@ -654,17 +656,18 @@ add_test(function test_set_bsos_simple()
 
     server.stop(run_next_test);
   });
 });
 
 add_test(function test_set_bsos_invalid_bso() {
   _("Ensure that adding an invalid BSO throws.");
 
-  let client = getClient();
+  let server = getEmptyServer();
+  let client = getClient(server);
   let request = client.setBSOs("testcoll");
 
   let threw = false;
 
   // Empty argument is invalid.
   try {
     request.addBSO(null);
   } catch (ex) {
@@ -679,17 +682,17 @@ add_test(function test_set_bsos_invalid_
     request.addBSO(bso);
   } catch (ex) {
     threw = true;
   } finally {
     do_check_true(threw);
     threw = false;
   }
 
-  run_next_test();
+  server.stop(run_next_test);
 });
 
 add_test(function test_set_bsos_newline() {
   _("Ensure that newlines in BSO payloads are formatted properly.");
 
   let [server, client, username] = getServerAndClient();
   let user = server.user(username);
 
--- a/services/common/tests/unit/test_tokenauthenticatedrequest.js
+++ b/services/common/tests/unit/test_tokenauthenticatedrequest.js
@@ -16,36 +16,37 @@ add_test(function test_authenticated_req
 
   let message = "Great Success!";
 
   // TODO: We use a preset key here, but use getTokenFromBrowserIDAssertion()
   // from TokenServerClient to get a real one when possible. (Bug 745800)
   let id = "eyJleHBpcmVzIjogMTM2NTAxMDg5OC4x";
   let key = "qTZf4ZFpAMpMoeSsX3zVRjiqmNs=";
   let method = "GET";
-  let uri = CommonUtils.makeURI(TEST_SERVER_URL + "foo");
 
   let nonce = btoa(CryptoUtils.generateRandomBytes(16));
   let ts = Math.floor(Date.now() / 1000);
   let extra = {ts: ts, nonce: nonce};
 
-  let sig = CryptoUtils.computeHTTPMACSHA1(id, key, method, uri, extra);
-  let auth = sig.getHeader();
+  let auth;
 
   let server = httpd_setup({"/foo": function(request, response) {
       do_check_true(request.hasHeader("Authorization"));
       do_check_eq(auth, request.getHeader("Authorization"));
 
       response.setStatusLine(request.httpVersion, 200, "OK");
       response.bodyOutputStream.write(message, message.length);
     }
   });
+  let uri = CommonUtils.makeURI(server.baseURI + "/foo");
+  let sig = CryptoUtils.computeHTTPMACSHA1(id, key, method, uri, extra);
+  auth = sig.getHeader();
 
   let req = new TokenAuthenticatedRESTRequest(uri, {id: id, key: key}, extra);
   let cb = Async.makeSpinningCallback();
   req.get(cb);
   let result = cb.wait();
 
   do_check_eq(null, result);
   do_check_eq(message, req.response.body);
 
   server.stop(run_next_test);
-});
\ No newline at end of file
+});
--- a/services/common/tests/unit/test_tokenserverclient.js
+++ b/services/common/tests/unit/test_tokenserverclient.js
@@ -31,17 +31,17 @@ add_test(function test_working_bid_excha
         uid:          "uid",
       });
       response.bodyOutputStream.write(body, body.length);
     }
   });
 
   let client = new TokenServerClient();
   let cb = Async.makeSpinningCallback();
-  let url = TEST_SERVER_URL + "1.0/foo/1.0";
+  let url = server.baseURI + "/1.0/foo/1.0";
   client.getTokenFromBrowserIDAssertion(url, "assertion", cb);
   let result = cb.wait();
   do_check_eq("object", typeof(result));
   do_check_attribute_count(result, 4);
   do_check_eq(service, result.endpoint);
   do_check_eq("id", result.id);
   do_check_eq("key", result.key);
   do_check_eq("uid", result.uid);
@@ -88,17 +88,17 @@ add_test(function test_conditions_requir
         errors: [{description: description, location: "body", name: ""}],
         urls: {tos: tosURL}
       });
       response.bodyOutputStream.write(body, body.length);
     }
   });
 
   let client = new TokenServerClient();
-  let url = TEST_SERVER_URL + "1.0/foo/1.0";
+  let url = server.baseURI + "/1.0/foo/1.0";
 
   function onResponse(error, token) {
     do_check_true(error instanceof TokenServerClientServerError);
     do_check_eq(error.cause, "conditions-required");
     do_check_null(token);
 
     do_check_eq(error.urls.tos, tosURL);
 
@@ -120,17 +120,17 @@ add_test(function test_invalid_403_no_co
         errors: [{description: "irrelevant", location: "body", name: ""}],
         urls: {foo: "http://bar"}
       });
       response.bodyOutputStream.write(body, body.length);
     }
   });
 
   let client = new TokenServerClient();
-  let url = TEST_SERVER_URL + "1.0/foo/1.0";
+  let url = server.baseURI + "/1.0/foo/1.0";
 
   function onResponse(error, token) {
     do_check_true(error instanceof TokenServerClientServerError);
     do_check_eq(error.cause, "malformed-response");
     do_check_null(token);
 
     do_check_null(error.urls);
 
@@ -151,17 +151,17 @@ add_test(function test_invalid_403_bad_j
       let body = JSON.stringify({
         foo: "bar"
       });
       response.bodyOutputStream.write(body, body.length);
     }
   });
 
   let client = new TokenServerClient();
-  let url = TEST_SERVER_URL + "1.0/foo/1.0";
+  let url = server.baseURI + "/1.0/foo/1.0";
 
   function onResponse(error, token) {
     do_check_true(error instanceof TokenServerClientServerError);
     do_check_eq(error.cause, "malformed-response");
     do_check_null(token);
     do_check_null(error.urls);
 
     server.stop(run_next_test);
@@ -179,17 +179,17 @@ add_test(function test_403_no_urls() {
       response.setHeader("Content-Type", "application/json; charset=utf-8");
 
       let body = "{}";
       response.bodyOutputStream.write(body, body.length);
     }
   });
 
   let client = new TokenServerClient();
-  let url = TEST_SERVER_URL + "1.0/foo/1.0";
+  let url = server.baseURI + "/1.0/foo/1.0";
 
   client.getTokenFromBrowserIDAssertion(url, "assertion",
                                         function onResponse(error, result) {
     do_check_true(error instanceof TokenServerClientServerError);
     do_check_eq(error.cause, "malformed-response");
     do_check_null(result);
 
     server.stop(run_next_test);
@@ -214,17 +214,17 @@ add_test(function test_send_conditions_a
         api_endpoint: "http://example.com/",
         uid:          "uid",
       });
       response.bodyOutputStream.write(body, body.length);
     }
   });
 
   let client = new TokenServerClient();
-  let url = TEST_SERVER_URL + "1.0/foo/1.0";
+  let url = server.baseURI + "/1.0/foo/1.0";
 
   function onResponse(error, token) {
     do_check_null(error);
 
     // Other tests validate other things.
 
     server.stop(run_next_test);
   }
@@ -233,17 +233,17 @@ add_test(function test_send_conditions_a
 });
 
 add_test(function test_error_404_empty() {
   _("Ensure that 404 responses without proper response are handled properly.");
 
   let server = httpd_setup();
 
   let client = new TokenServerClient();
-  let url = TEST_SERVER_URL + "foo";
+  let url = server.baseURI + "/foo";
   client.getTokenFromBrowserIDAssertion(url, "assertion", function(error, r) {
     do_check_true(error instanceof TokenServerClientServerError);
     do_check_eq(error.cause, "malformed-response");
 
     do_check_neq(null, error.response);
     do_check_null(r);
 
     server.stop(run_next_test);
@@ -271,17 +271,17 @@ add_test(function test_error_404_proper_
     do_check_true(error instanceof TokenServerClientServerError);
     do_check_eq(error.cause, "unknown-service");
     do_check_null(token);
 
     server.stop(run_next_test);
   }
 
   let client = new TokenServerClient();
-  let url = TEST_SERVER_URL + "1.0/foo/1.0";
+  let url = server.baseURI + "/1.0/foo/1.0";
   client.getTokenFromBrowserIDAssertion(url, "assertion", onResponse);
 });
 
 add_test(function test_bad_json() {
   _("Ensure that malformed JSON is handled properly.");
 
   let server = httpd_setup({
     "/1.0/foo/1.0": function(request, response) {
@@ -289,17 +289,17 @@ add_test(function test_bad_json() {
       response.setHeader("Content-Type", "application/json");
 
       let body = '{"id": "id", baz}'
       response.bodyOutputStream.write(body, body.length);
     }
   });
 
   let client = new TokenServerClient();
-  let url = TEST_SERVER_URL + "1.0/foo/1.0";
+  let url = server.baseURI + "/1.0/foo/1.0";
   client.getTokenFromBrowserIDAssertion(url, "assertion", function(error, r) {
     do_check_neq(null, error);
     do_check_eq("TokenServerClientServerError", error.name);
     do_check_eq(error.cause, "malformed-response");
     do_check_neq(null, error.response);
     do_check_eq(null, r);
 
     server.stop(run_next_test);
@@ -315,17 +315,17 @@ add_test(function test_400_response() {
       response.setHeader("Content-Type", "application/json; charset=utf-8");
 
       let body = "{}"; // Actual content may not be used.
       response.bodyOutputStream.write(body, body.length);
     }
   });
 
   let client = new TokenServerClient();
-  let url = TEST_SERVER_URL + "1.0/foo/1.0";
+  let url = server.baseURI + "/1.0/foo/1.0";
   client.getTokenFromBrowserIDAssertion(url, "assertion", function(error, r) {
     do_check_neq(null, error);
     do_check_eq("TokenServerClientServerError", error.name);
     do_check_neq(null, error.response);
     do_check_eq(error.cause, "malformed-request");
 
     server.stop(run_next_test);
   });
@@ -339,17 +339,17 @@ add_test(function test_unhandled_media_t
       response.setStatusLine(request.httpVersion, 200, "OK");
       response.setHeader("Content-Type", "text/plain");
 
       let body = "hello, world";
       response.bodyOutputStream.write(body, body.length);
     }
   });
 
-  let url = TEST_SERVER_URL + "1.0/foo/1.0";
+  let url = server.baseURI + "/1.0/foo/1.0";
   let client = new TokenServerClient();
   client.getTokenFromBrowserIDAssertion(url, "assertion", function(error, r) {
     do_check_neq(null, error);
     do_check_eq("TokenServerClientServerError", error.name);
     do_check_neq(null, error.response);
     do_check_eq(null, r);
 
     server.stop(run_next_test);
@@ -369,17 +369,17 @@ add_test(function test_rich_media_types(
         key:          "key",
         api_endpoint: "foo",
         uid:          "uid",
       });
       response.bodyOutputStream.write(body, body.length);
     }
   });
 
-  let url = TEST_SERVER_URL + "foo";
+  let url = server.baseURI + "/foo";
   let client = new TokenServerClient();
   client.getTokenFromBrowserIDAssertion(url, "assertion", function(error, r) {
     do_check_eq(null, error);
 
     server.stop(run_next_test);
   });
 });
 
@@ -396,17 +396,17 @@ add_test(function test_exception_during_
         key:          "key",
         api_endpoint: "foo",
         uid:          "uid",
       });
       response.bodyOutputStream.write(body, body.length);
     }
   });
 
-  let url = TEST_SERVER_URL + "foo";
+  let url = server.baseURI + "/foo";
   let client = new TokenServerClient();
   let cb = Async.makeSpinningCallback();
   let callbackCount = 0;
 
   client.getTokenFromBrowserIDAssertion(url, "assertion", function(error, r) {
     do_check_eq(null, error);
 
     cb();
--- a/services/healthreport/tests/xpcshell/test_healthreporter.js
+++ b/services/healthreport/tests/xpcshell/test_healthreporter.js
@@ -17,35 +17,33 @@ Cu.import("resource://gre/modules/servic
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://testing-common/httpd.js");
 Cu.import("resource://testing-common/services-common/bagheeraserver.js");
 Cu.import("resource://testing-common/services/metrics/mocks.jsm");
 Cu.import("resource://testing-common/services/healthreport/utils.jsm");
 
 
-const SERVER_HOSTNAME = "localhost";
-const SERVER_PORT = 8080;
-const SERVER_URI = "http://" + SERVER_HOSTNAME + ":" + SERVER_PORT;
+const DUMMY_URI = "http://localhost:62013/";
 const MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;
 
 const HealthReporterState = bsp.HealthReporterState;
 
 
 function defineNow(policy, now) {
   print("Adjusting fake system clock to " + now);
   Object.defineProperty(policy, "now", {
     value: function customNow() {
       return now;
     },
     writable: true,
   });
 }
 
-function getJustReporter(name, uri=SERVER_URI, inspected=false) {
+function getJustReporter(name, uri=DUMMY_URI, inspected=false) {
   let branch = "healthreport.testing." + name + ".";
 
   let prefs = new Preferences(branch + "healthreport.");
   prefs.set("documentServerURI", uri);
   prefs.set("dbName", name);
 
   let reporter;
 
@@ -79,23 +77,22 @@ function getReporter(name, uri, inspecte
       HealthReportProvider);
 
     throw new Task.Result(reporter);
   });
 }
 
 function getReporterAndServer(name, namespace="test") {
   return Task.spawn(function get() {
-    let reporter = yield getReporter(name, SERVER_URI);
-    reporter.serverNamespace = namespace;
+    let server = new BagheeraServer();
+    server.createNamespace(namespace);
+    server.start();
 
-    let server = new BagheeraServer(SERVER_URI);
-    server.createNamespace(namespace);
-
-    server.start(SERVER_PORT);
+    let reporter = yield getReporter(name, server.serverURI);
+    reporter.serverNamespace = namespace;
 
     throw new Task.Result([reporter, server]);
   });
 }
 
 function shutdownServer(server) {
   let deferred = Promise.defer();
   server.stop(deferred.resolve.bind(deferred));
@@ -162,17 +159,17 @@ add_task(function test_shutdown_normal()
 
   // We can't send "quit-application" notification because the xpcshell runner
   // will shut down!
   reporter._initiateShutdown();
   reporter._waitForShutdown();
 });
 
 add_task(function test_shutdown_storage_in_progress() {
-  let reporter = yield getJustReporter("shutdown_storage_in_progress", SERVER_URI, true);
+  let reporter = yield getJustReporter("shutdown_storage_in_progress", DUMMY_URI, true);
 
   reporter.onStorageCreated = function () {
     print("Faking shutdown during storage initialization.");
     reporter._initiateShutdown();
   };
 
   reporter.init();
 
@@ -180,17 +177,17 @@ add_task(function test_shutdown_storage_
   do_check_eq(reporter.providerManagerShutdownCount, 0);
   do_check_eq(reporter.storageCloseCount, 1);
 });
 
 // Ensure that a shutdown triggered while provider manager is initializing
 // results in shutdown and storage closure.
 add_task(function test_shutdown_provider_manager_in_progress() {
   let reporter = yield getJustReporter("shutdown_provider_manager_in_progress",
-                                       SERVER_URI, true);
+                                       DUMMY_URI, true);
 
   reporter.onProviderManagerInitialized = function () {
     print("Faking shutdown during provider manager initialization.");
     reporter._initiateShutdown();
   };
 
   reporter.init();
 
@@ -198,17 +195,17 @@ add_task(function test_shutdown_provider
   reporter._waitForShutdown();
   do_check_eq(reporter.providerManagerShutdownCount, 1);
   do_check_eq(reporter.storageCloseCount, 1);
 });
 
 // Simulates an error during provider manager initialization and verifies we shut down.
 add_task(function test_shutdown_when_provider_manager_errors() {
   let reporter = yield getJustReporter("shutdown_when_provider_manager_errors",
-                                       SERVER_URI, true);
+                                       DUMMY_URI, true);
 
   reporter.onInitializeProviderManagerFinished = function () {
     print("Throwing fake error.");
     throw new Error("Fake error during provider manager initialization.");
   };
 
   reporter.init();
 
@@ -581,17 +578,17 @@ add_task(function test_idle_daily() {
   } finally {
     reporter._shutdown();
   }
 });
 
 add_task(function test_data_submission_transport_failure() {
   let reporter = yield getReporter("data_submission_transport_failure");
   try {
-    reporter.serverURI = "http://localhost:8080/";
+    reporter.serverURI = DUMMY_URI;
     reporter.serverNamespace = "test00";
 
     let deferred = Promise.defer();
     let request = new DataSubmissionRequest(deferred, new Date(Date.now + 30000));
     reporter.requestDataUpload(request);
 
     yield deferred.promise;
     do_check_eq(request.state, request.SUBMISSION_FAILURE_SOFT);
@@ -868,20 +865,20 @@ add_task(function test_failure_if_not_in
     error = false;
   }
 
   // getJSONPayload always works (to facilitate error upload).
   yield reporter.getJSONPayload();
 });
 
 add_task(function test_upload_on_init_failure() {
-  let reporter = yield getJustReporter("upload_on_init_failure", SERVER_URI, true);
-  let server = new BagheeraServer(SERVER_URI);
+  let server = new BagheeraServer();
+  server.start();
+  let reporter = yield getJustReporter("upload_on_init_failure", server.serverURI, true);
   server.createNamespace(reporter.serverNamespace);
-  server.start(SERVER_PORT);
 
   reporter.onInitializeProviderManagerFinished = function () {
     throw new Error("Fake error during provider manager initialization.");
   };
 
   let deferred = Promise.defer();
 
   let oldOnResult = reporter._onBagheeraResult;
--- a/services/sync/modules-testing/utils.js
+++ b/services/sync/modules-testing/utils.js
@@ -1,34 +1,29 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 this.EXPORTED_SYMBOLS = [
-  "TEST_CLUSTER_URL",
-  "TEST_SERVER_URL",
   "btoa", // It comes from a module import.
   "encryptPayload",
   "setBasicCredentials",
   "SyncTestingInfrastructure",
   "waitForZeroTimer",
 ];
 
 const {utils: Cu} = Components;
 
 Cu.import("resource://services-common/utils.js");
 Cu.import("resource://services-crypto/utils.js");
 Cu.import("resource://testing-common/services-common/logging.js");
 Cu.import("resource://testing-common/services/sync/fakeservices.js");
 
-this.TEST_SERVER_URL = "http://localhost:8080/";
-this.TEST_CLUSTER_URL = TEST_SERVER_URL;
-
 /**
  * First wait >100ms (nsITimers can take up to that much time to fire, so
  * we can account for the timer in delayedAutoconnect) and then two event
  * loop ticks (to account for the Utils.nextTick() in autoConnect).
  */
 this.waitForZeroTimer = function waitForZeroTimer(callback) {
   let ticks = 2;
   function wait() {
@@ -48,28 +43,31 @@ this.setBasicCredentials =
   Cu.import("resource://services-sync/service.js", ns);
 
   let auth = ns.Service.identity;
   auth.username = username;
   auth.basicPassword = password;
   auth.syncKey = syncKey;
 }
 
-this.SyncTestingInfrastructure =
- function SyncTestingInfrastructure(username, password, syncKey) {
+this.SyncTestingInfrastructure = function (server, username, password, syncKey) {
   let ns = {};
   Cu.import("resource://services-sync/service.js", ns);
 
   let auth = ns.Service.identity;
   auth.account = username || "foo";
   auth.basicPassword = password || "password";
   auth.syncKey = syncKey || "abcdeabcdeabcdeabcdeabcdea";
 
-  ns.Service.serverURL = TEST_SERVER_URL;
-  ns.Service.clusterURL = TEST_CLUSTER_URL;
+  let i = server.identity;
+  let uri = i.primaryScheme + "://" + i.primaryHost + ":" +
+            i.primaryPort + "/";
+
+  ns.Service.serverURL = uri;
+  ns.Service.clusterURL = uri;
 
   this.logStats = initTestLogging();
   this.fakeFilesystem = new FakeFilesystemService({});
   this.fakeGUIDService = new FakeGUIDService();
   this.fakeCryptoService = new FakeCryptoService();
 }
 
 /**
--- a/services/sync/tests/unit/head_http_server.js
+++ b/services/sync/tests/unit/head_http_server.js
@@ -530,52 +530,53 @@ function SyncServer(callback) {
   this._log     = Log4Moz.repository.getLogger(SYNC_HTTP_LOGGER);
 
   // Install our own default handler. This allows us to mess around with the
   // whole URL space.
   let handler = this.server._handler;
   handler._handleDefault = this.handleDefault.bind(this, handler);
 }
 SyncServer.prototype = {
-  port:   8080,
   server: null,    // HttpServer.
   users:  null,    // Map of username => {collections, password}.
 
   /**
    * Start the SyncServer's underlying HTTP server.
    *
    * @param port
    *        The numeric port on which to start. A falsy value implies the
-   *        default (8080).
+   *        default, a randomly chosen port.
    * @param cb
    *        A callback function (of no arguments) which is invoked after
    *        startup.
    */
   start: function start(port, cb) {
     if (this.started) {
       this._log.warn("Warning: server already started on " + this.port);
       return;
     }
-    if (port) {
-      this.port = port;
-    }
     try {
-      this.server.start(this.port);
+      this.server.start(port);
+      let i = this.server.identity;
+      this.port = i.primaryPort;
+      this.baseURI = i.primaryScheme + "://" + i.primaryHost + ":" +
+                     i.primaryPort + "/";
       this.started = true;
       if (cb) {
         cb();
       }
     } catch (ex) {
       _("==========================================");
-      _("Got exception starting Sync HTTP server on port " + this.port);
+      _("Got exception starting Sync HTTP server.");
       _("Error: " + Utils.exceptionStr(ex));
-      _("Is there a process already listening on port " + this.port + "?");
+      _("Is there a process already listening on port " + port + "?");
       _("==========================================");
       do_throw(ex);
     }
+
   },
 
   /**
    * Stop the SyncServer's HTTP server.
    *
    * @param cb
    *        A callback function. Invoked after the server has been stopped.
    *
--- a/services/sync/tests/unit/test_addons_engine.js
+++ b/services/sync/tests/unit/test_addons_engine.js
@@ -153,31 +153,31 @@ add_test(function test_disabled_install_
 
   Svc.Prefs.set("addons.ignoreRepositoryChecking", true);
 
   const USER       = "foo";
   const PASSWORD   = "password";
   const PASSPHRASE = "abcdeabcdeabcdeabcdeabcdea";
   const ADDON_ID   = "addon1@tests.mozilla.org";
 
-  new SyncTestingInfrastructure(USER, PASSWORD, PASSPHRASE);
+  let server = new SyncServer();
+  server.start();
+  new SyncTestingInfrastructure(server.server, USER, PASSWORD, PASSPHRASE);
 
   generateNewKeys(Service.collectionKeys);
 
   let contents = {
     meta: {global: {engines: {addons: {version: engine.version,
                                       syncID:  engine.syncID}}}},
     crypto: {},
     addons: {}
   };
 
-  let server = new SyncServer();
   server.registerUser(USER, "password");
   server.createContents(USER, contents);
-  server.start();
 
   let amoServer = new HttpServer();
   amoServer.registerFile("/search/guid:addon1%40tests.mozilla.org",
                          do_get_file("addon1-search.xml"));
 
   let installXPI = ExtensionsTestPath("/addons/test_install1.xpi");
   amoServer.registerFile("/addon1.xpi", do_get_file(installXPI));
   amoServer.start(8888);
@@ -242,18 +242,16 @@ function run_test() {
   Log4Moz.repository.getLogger("Sync.Engine.Addons").level =
     Log4Moz.Level.Trace;
   Log4Moz.repository.getLogger("Sync.Store.Addons").level = Log4Moz.Level.Trace;
   Log4Moz.repository.getLogger("Sync.Tracker.Addons").level =
     Log4Moz.Level.Trace;
   Log4Moz.repository.getLogger("Sync.AddonsRepository").level =
     Log4Moz.Level.Trace;
 
-  new SyncTestingInfrastructure();
-
   reconciler.startListening();
 
   // Don't flush to disk in the middle of an event listener!
   // This causes test hangs on WinXP.
   reconciler._shouldPersist = false;
 
   advance_test();
 }
--- a/services/sync/tests/unit/test_bookmark_engine.js
+++ b/services/sync/tests/unit/test_bookmark_engine.js
@@ -8,20 +8,21 @@ Cu.import("resource://services-common/lo
 Cu.import("resource://services-sync/engines.js");
 Cu.import("resource://services-sync/engines/bookmarks.js");
 Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/util.js");
 Cu.import("resource://testing-common/services/sync/utils.js");
 Cu.import("resource://gre/modules/Promise.jsm");
 
 Service.engineManager.register(BookmarksEngine);
-var syncTesting = new SyncTestingInfrastructure();
 
 add_test(function bad_record_allIDs() {
-  let syncTesting = new SyncTestingInfrastructure();
+  let server = new SyncServer();
+  server.start();
+  let syncTesting = new SyncTestingInfrastructure(server.server);
 
   _("Ensure that bad Places queries don't cause an error in getAllIDs.");
   let engine = new BookmarksEngine(Service);
   let store = engine._store;
   let badRecordID = PlacesUtils.bookmarks.insertBookmark(
       PlacesUtils.bookmarks.toolbarFolder,
       Utils.makeURI("place:folder=1138"),
       PlacesUtils.bookmarks.DEFAULT_INDEX,
@@ -38,21 +39,23 @@ add_test(function bad_record_allIDs() {
   let all = store.getAllIDs();
 
   _("All IDs: " + JSON.stringify(all));
   do_check_true("menu" in all);
   do_check_true("toolbar" in all);
 
   _("Clean up.");
   PlacesUtils.bookmarks.removeItem(badRecordID);
-  run_next_test();
+  server.stop(run_next_test);
 });
 
 add_test(function test_ID_caching() {
-  let syncTesting = new SyncTestingInfrastructure();
+  let server = new SyncServer();
+  server.start();
+  let syncTesting = new SyncTestingInfrastructure(server.server);
 
   _("Ensure that Places IDs are not cached.");
   let engine = new BookmarksEngine(Service);
   let store = engine._store;
   _("All IDs: " + JSON.stringify(store.getAllIDs()));
 
   let mobileID = store.idForGUID("mobile");
   _("Change the GUID for that item, and drop the mobile anno.");
@@ -78,34 +81,34 @@ add_test(function test_ID_caching() {
   _("New mobile ID: " + newMobileID);
   do_check_true(!!newMobileID);
   do_check_neq(newMobileID, mobileID);
 
   // And it's repeatable, even with creation enabled.
   do_check_eq(newMobileID, store.idForGUID("mobile", false));
 
   do_check_eq(store.GUIDForId(mobileID), "abcdefghijkl");
-  run_next_test();
+  server.stop(run_next_test);
 });
 
 function serverForFoo(engine) {
   return serverForUsers({"foo": "password"}, {
     meta: {global: {engines: {bookmarks: {version: engine.version,
                                           syncID: engine.syncID}}}},
     bookmarks: {}
   });
 }
 
 add_test(function test_processIncoming_error_orderChildren() {
   _("Ensure that _orderChildren() is called even when _processIncoming() throws an error.");
-  new SyncTestingInfrastructure();
 
   let engine = new BookmarksEngine(Service);
   let store  = engine._store;
   let server = serverForFoo(engine);
+  new SyncTestingInfrastructure(server.server);
 
   let collection = server.user("foo").collection("bookmarks");
 
   try {
 
     let folder1_id = PlacesUtils.bookmarks.createFolder(
       PlacesUtils.bookmarks.toolbarFolder, "Folder 1", 0);
     let folder1_guid = store.GUIDForId(folder1_id);
@@ -161,21 +164,20 @@ add_test(function test_processIncoming_e
     Svc.Prefs.resetBranch("");
     Service.recordManager.clearCache();
     server.stop(run_next_test);
   }
 });
 
 add_task(function test_restorePromptsReupload() {
   _("Ensure that restoring from a backup will reupload all records.");
-  new SyncTestingInfrastructure();
-
   let engine = new BookmarksEngine(Service);
   let store  = engine._store;
   let server = serverForFoo(engine);
+  new SyncTestingInfrastructure(server.server);
 
   let collection = server.user("foo").collection("bookmarks");
 
   Svc.Obs.notify("weave:engine:start-tracking");   // We skip usual startup...
 
   try {
 
     let folder1_id = PlacesUtils.bookmarks.createFolder(
@@ -328,21 +330,20 @@ add_test(function test_mismatched_types(
     "description":null,
     "children":
       ["HCRq40Rnxhrd", "YeyWCV1RVsYw", "GCceVZMhvMbP", "sYi2hevdArlF",
        "vjbZlPlSyGY8", "UtjUhVyrpeG6", "rVq8WMG2wfZI", "Lx0tcy43ZKhZ",
        "oT74WwV8_j4P", "IztsItWVSo3-"],
     "parentid": "toolbar"
   };
 
-  new SyncTestingInfrastructure();
-
   let engine = new BookmarksEngine(Service);
   let store  = engine._store;
   let server = serverForFoo(engine);
+  new SyncTestingInfrastructure(server.server);
 
   _("GUID: " + store.GUIDForId(6, true));
 
   try {
     let bms = PlacesUtils.bookmarks;
     let oldR = new FakeRecord(BookmarkFolder, oldRecord);
     let newR = new FakeRecord(Livemark, newRecord);
     oldR._parent = PlacesUtils.bookmarks.toolbarFolder;
@@ -371,24 +372,23 @@ add_test(function test_mismatched_types(
     Service.recordManager.clearCache();
     server.stop(run_next_test);
   }
 });
 
 add_test(function test_bookmark_guidMap_fail() {
   _("Ensure that failures building the GUID map cause early death.");
 
-  new SyncTestingInfrastructure();
-
   let engine = new BookmarksEngine(Service);
   let store = engine._store;
 
   let store  = engine._store;
   let server = serverForFoo(engine);
   let coll   = server.user("foo").collection("bookmarks");
+  new SyncTestingInfrastructure(server.server);
 
   // Add one item to the server.
   let itemID = PlacesUtils.bookmarks.createFolder(
     PlacesUtils.bookmarks.toolbarFolder, "Folder 1", 0);
   let itemGUID    = store.GUIDForId(itemID);
   let itemPayload = store.createRecord(itemGUID).cleartext;
   coll.insert(itemGUID, encryptPayload(itemPayload));
 
@@ -470,20 +470,19 @@ add_test(function test_bookmark_tag_but_
   store.update(record);
 
   run_next_test();
 });
 
 add_test(function test_misreconciled_root() {
   _("Ensure that we don't reconcile an arbitrary record with a root.");
 
-  new SyncTestingInfrastructure();
-
   let engine = new BookmarksEngine(Service);
   let store = engine._store;
+  let server = serverForFoo(engine);
 
   // Log real hard for this test.
   store._log.trace = store._log.debug;
   engine._log.trace = engine._log.debug;
 
   engine._syncStartup();
 
   // Let's find out where the toolbar is right now.
@@ -529,16 +528,16 @@ add_test(function test_misreconciled_roo
   // the real GUID, instead using a generated one. Sync does the translation.
   let toolbarAfter = store.createRecord("toolbar", "bookmarks");
   let parentGUIDAfter = toolbarAfter.parentid;
   let parentIDAfter = store.idForGUID(parentGUIDAfter);
   do_check_eq(store.GUIDForId(toolbarIDBefore), "toolbar");
   do_check_eq(parentGUIDBefore, parentGUIDAfter);
   do_check_eq(parentIDBefore, parentIDAfter);
 
-  run_next_test();
+  server.stop(run_next_test);
 });
 
 function run_test() {
   initTestLogging("Trace");
   generateNewKeys(Service.collectionKeys);
   run_next_test();
 }
--- a/services/sync/tests/unit/test_bookmark_smart_bookmarks.js
+++ b/services/sync/tests/unit/test_bookmark_smart_bookmarks.js
@@ -17,18 +17,16 @@ var IOService = Cc["@mozilla.org/network
 
 Service.engineManager.register(BookmarksEngine);
 let engine = Service.engineManager.get("bookmarks");
 let store = engine._store;
 
 // Clean up after other tests. Only necessary in XULRunner.
 store.wipe();
 
-var syncTesting = new SyncTestingInfrastructure();
-
 function newSmartBookmark(parent, uri, position, title, queryID) {
   let id = PlacesUtils.bookmarks.insertBookmark(parent, uri, position, title);
   PlacesUtils.annotations.setItemAnnotation(id, SMART_BOOKMARKS_ANNO,
                                             queryID, 0,
                                             PlacesUtils.annotations.EXPIRE_NEVER);
   return id;
 }
 
@@ -55,17 +53,18 @@ function serverForFoo(engine) {
                                           syncID: engine.syncID}}}},
     bookmarks: {}
   });
 }
 
 // Verify that Places smart bookmarks have their annotation uploaded and
 // handled locally.
 add_test(function test_annotation_uploaded() {
-  new SyncTestingInfrastructure();
+  let server = serverForFoo(engine);
+  new SyncTestingInfrastructure(server.server);
 
   let startCount = smartBookmarkCount();
 
   _("Start count is " + startCount);
 
   if (startCount > 0) {
     // This can happen in XULRunner.
     clearBookmarks();
@@ -103,17 +102,16 @@ add_test(function test_annotation_upload
 
   _("Make sure the new record carries with it the annotation.");
   do_check_eq("MostVisited", record.queryId);
 
   _("Our count has increased since we started.");
   do_check_eq(smartBookmarkCount(), startCount + 1);
 
   _("Sync record to the server.");
-  let server = serverForFoo(engine);
   let collection = server.user("foo").collection("bookmarks");
 
   try {
     engine.sync();
     let wbos = collection.keys(function (id) {
                  return ["menu", "toolbar", "mobile"].indexOf(id) == -1;
                });
     do_check_eq(wbos.length, 1);
@@ -170,31 +168,31 @@ add_test(function test_annotation_upload
     store.wipe();
     Svc.Prefs.resetBranch("");
     Service.recordManager.clearCache();
     server.stop(run_next_test);
   }
 });
 
 add_test(function test_smart_bookmarks_duped() {
-  new SyncTestingInfrastructure();
+  let server = serverForFoo(engine);
+  new SyncTestingInfrastructure(server.server);
 
   let parent = PlacesUtils.toolbarFolderId;
   let uri =
     Utils.makeURI("place:sort=" +
                   Ci.nsINavHistoryQueryOptions.SORT_BY_VISITCOUNT_DESCENDING +
                   "&maxResults=10");
   let title = "Most Visited";
   let mostVisitedID = newSmartBookmark(parent, uri, -1, title, "MostVisited");
   let mostVisitedGUID = store.GUIDForId(mostVisitedID);
 
   let record = store.createRecord(mostVisitedGUID);
 
   _("Prepare sync.");
-  let server = serverForFoo(engine);
   let collection = server.user("foo").collection("bookmarks");
 
   try {
     engine._syncStartup();
 
     _("Verify that mapDupe uses the anno, discovering a dupe regardless of URI.");
     do_check_eq(mostVisitedGUID, engine._mapDupe(record));
 
--- a/services/sync/tests/unit/test_clients_engine.js
+++ b/services/sync/tests/unit/test_clients_engine.js
@@ -53,18 +53,17 @@ add_test(function test_bad_hmac() {
     generateNewKeys(Service.collectionKeys);
     let serverKeys = Service.collectionKeys.asWBO("crypto", "keys");
     serverKeys.encrypt(Service.identity.syncKeyBundle);
     do_check_true(serverKeys.upload(Service.resource(Service.cryptoKeysURL)).success);
   }
 
   try {
     let passphrase     = "abcdeabcdeabcdeabcdeabcdea";
-    Service.serverURL  = TEST_SERVER_URL;
-    Service.clusterURL = TEST_CLUSTER_URL;
+    Service.serverURL  = server.baseURI;
     Service.login("foo", "ilovejane", passphrase);
 
     generateNewKeys(Service.collectionKeys);
 
     _("First sync, client record is uploaded");
     do_check_eq(engine.lastRecordUpload, 0);
     check_clients_count(0);
     engine._sync();
@@ -164,28 +163,28 @@ add_test(function test_properties() {
     Svc.Prefs.resetBranch("");
     run_next_test();
   }
 });
 
 add_test(function test_sync() {
   _("Ensure that Clients engine uploads a new client record once a week.");
 
-  new SyncTestingInfrastructure();
-  generateNewKeys(Service.collectionKeys);
-
   let contents = {
     meta: {global: {engines: {clients: {version: engine.version,
                                         syncID: engine.syncID}}}},
     clients: {},
     crypto: {}
   };
   let server = serverForUsers({"foo": "password"}, contents);
   let user   = server.user("foo");
 
+  new SyncTestingInfrastructure(server.server);
+  generateNewKeys(Service.collectionKeys);
+
   function clientWBO() {
     return user.collection("clients").wbo(engine.localID);
   }
 
   try {
 
     _("First sync. Client record is uploaded.");
     do_check_eq(clientWBO(), undefined);
@@ -402,28 +401,28 @@ add_test(function test_process_incoming_
 
   // logout command causes processIncomingCommands to return explicit false.
   do_check_false(engine.processIncomingCommands());
 });
 
 add_test(function test_command_sync() {
   _("Ensure that commands are synced across clients.");
 
-  new SyncTestingInfrastructure();
-
   engine._store.wipe();
   generateNewKeys(Service.collectionKeys);
 
   let contents = {
     meta: {global: {engines: {clients: {version: engine.version,
                                         syncID: engine.syncID}}}},
     clients: {},
     crypto: {}
   };
   let server   = serverForUsers({"foo": "password"}, contents);
+  new SyncTestingInfrastructure(server.server);
+
   let user     = server.user("foo");
   let remoteId = Utils.makeGUID();
 
   function clientWBO(id) {
     return user.collection("clients").wbo(id);
   }
 
   _("Create remote client record");
--- a/services/sync/tests/unit/test_collections_recovery.js
+++ b/services/sync/tests/unit/test_collections_recovery.js
@@ -20,31 +20,30 @@ add_test(function test_missing_crypto_co
         response.bodyOutputStream.write(body, body.length);
       } else {
         handler(request, response);
       }
     };
   }
 
   setBasicCredentials("johndoe", "ilovejane", "a-aaaaa-aaaaa-aaaaa-aaaaa-aaaaa");
-  Service.serverURL = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
 
   let handlers = {
     "/1.1/johndoe/info/collections": maybe_empty(johnHelper.handler),
     "/1.1/johndoe/storage/crypto/keys": johnU("crypto", new ServerWBO("keys").handler()),
     "/1.1/johndoe/storage/meta/global": johnU("meta",   new ServerWBO("global").handler())
   };
   let collections = ["clients", "bookmarks", "forms", "history",
                      "passwords", "prefs", "tabs"];
   for each (let coll in collections) {
     handlers["/1.1/johndoe/storage/" + coll] =
       johnU(coll, new ServerCollection({}, true).handler());
   }
   let server = httpd_setup(handlers);
+  Service.serverURL = server.baseURI;
 
   try {
     let fresh = 0;
     let orig  = Service._freshStart;
     Service._freshStart = function() {
       _("Called _freshStart.");
       orig.call(Service);
       fresh++;
--- a/services/sync/tests/unit/test_corrupt_keys.js
+++ b/services/sync/tests/unit/test_corrupt_keys.js
@@ -51,18 +51,18 @@ add_task(function test_locally_changed_k
                             weaveLastUsed: 1
                           }}]}]};
     delete Svc.Session;
     Svc.Session = {
       getBrowserState: function () JSON.stringify(myTabs)
     };
 
     setBasicCredentials("johndoe", "password", passphrase);
-    Service.serverURL = TEST_SERVER_URL;
-    Service.clusterURL = TEST_CLUSTER_URL;
+    Service.serverURL = server.baseURI;
+    Service.clusterURL = server.baseURI;
 
     Service.engineManager.register(HistoryEngine);
 
     function corrupt_local_keys() {
       Service.collectionKeys._default.keyPair = [Svc.Crypto.generateRandomKey(),
                                                  Svc.Crypto.generateRandomKey()];
     }
 
--- a/services/sync/tests/unit/test_engine_abort.js
+++ b/services/sync/tests/unit/test_engine_abort.js
@@ -5,36 +5,35 @@ Cu.import("resource://services-sync/engi
 Cu.import("resource://services-sync/record.js");
 Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/util.js");
 Cu.import("resource://testing-common/services/sync/rotaryengine.js");
 Cu.import("resource://testing-common/services/sync/utils.js");
 
 add_test(function test_processIncoming_abort() {
   _("An abort exception, raised in applyIncoming, will abort _processIncoming.");
-  new SyncTestingInfrastructure();
-  generateNewKeys(Service.collectionKeys);
-
   let engine = new RotaryEngine(Service);
 
-  _("Create some server data.");
-  let meta_global = Service.recordManager.set(engine.metaURL,
-                                              new WBORecord(engine.metaURL));
-  meta_global.payload.engines = {rotary: {version: engine.version,
-                                          syncID: engine.syncID}};
-
   let collection = new ServerCollection();
   let id = Utils.makeGUID();
   let payload = encryptPayload({id: id, denomination: "Record No. " + id});
   collection.insert(id, payload);
 
   let server = sync_httpd_setup({
       "/1.1/foo/storage/rotary": collection.handler()
   });
 
+  new SyncTestingInfrastructure(server);
+  generateNewKeys(Service.collectionKeys);
+
+  _("Create some server data.");
+  let meta_global = Service.recordManager.set(engine.metaURL,
+                                              new WBORecord(engine.metaURL));
+  meta_global.payload.engines = {rotary: {version: engine.version,
+                                          syncID: engine.syncID}};
   _("Fake applyIncoming to abort.");
   engine._store.applyIncoming = function (record) {
     let ex = {code: Engine.prototype.eEngineAbortApplyIncoming,
               cause: "Nooo"};
     _("Throwing: " + JSON.stringify(ex));
     throw ex;
   };
 
--- a/services/sync/tests/unit/test_errorhandler.js
+++ b/services/sync/tests/unit/test_errorhandler.js
@@ -6,17 +6,17 @@ Cu.import("resource://services-sync/cons
 Cu.import("resource://services-sync/engines.js");
 Cu.import("resource://services-sync/keys.js");
 Cu.import("resource://services-sync/policies.js");
 Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/status.js");
 Cu.import("resource://services-sync/util.js");
 Cu.import("resource://testing-common/services/sync/utils.js");
 
-const TEST_MAINTENANCE_URL = "http://localhost:8080/maintenance/";
+const FAKE_SERVER_URL = "http://dummy:9000/";
 const logsdir = FileUtils.getDir("ProfD", ["weave", "logs"], true);
 const LOG_PREFIX_SUCCESS = "success-";
 const LOG_PREFIX_ERROR   = "error-";
 
 const PROLONGED_ERROR_DURATION =
   (Svc.Prefs.get('errorhandler.networkFailureReportTimeout') * 2) * 1000;
 
 const NON_PROLONGED_ERROR_DURATION =
@@ -120,20 +120,20 @@ function sync_httpd_setup() {
     "/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/broken.wipe/storage/clients": upd("clients", clientsColl.handler()),
     "/maintenance/1.1/broken.wipe/storage/catapult": service_unavailable
   });
 }
 
-function setUp() {
+function setUp(server) {
   setBasicCredentials("johndoe", "ilovejane", "abcdeabcdeabcdeabcdeabcdea");
-  Service.serverURL  = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
+  Service.serverURL  = server.baseURI + "/";
+  Service.clusterURL = server.baseURI + "/";
 
   return generateAndUploadKeys();
 }
 
 function generateAndUploadKeys() {
   generateNewKeys(Service.collectionKeys);
   let serverKeys = Service.collectionKeys.asWBO("crypto", "keys");
   serverKeys.encrypt(Service.identity.syncKeyBundle);
@@ -143,17 +143,17 @@ function generateAndUploadKeys() {
 function clean() {
   Service.startOver();
   Status.resetSync();
   Status.resetBackoff();
 }
 
 add_test(function test_401_logout() {
   let server = sync_httpd_setup();
-  setUp();
+  setUp(server);
 
   // By calling sync, we ensure we're logged in.
   Service.sync();
   do_check_eq(Status.sync, SYNC_SUCCEEDED);
   do_check_true(Service.isLoggedIn);
 
   Svc.Obs.add("weave:service:sync:error", onSyncError);
   function onSyncError() {
@@ -183,17 +183,17 @@ add_test(function test_401_logout() {
 
   _("Starting first sync.");
   Service.sync();
   _("First sync done.");
 });
 
 add_test(function test_credentials_changed_logout() {
   let server = sync_httpd_setup();
-  setUp();
+  setUp(server);
 
   // By calling sync, we ensure we're logged in.
   Service.sync();
   do_check_eq(Status.sync, SYNC_SUCCEEDED);
   do_check_true(Service.isLoggedIn);
 
   generateCredentialsChangedFailure();
   Service.sync();
@@ -223,18 +223,18 @@ add_test(function test_no_lastSync_pref(
 });
 
 add_test(function test_shouldReportError() {
   Status.login = MASTER_PASSWORD_LOCKED;
   do_check_false(errorHandler.shouldReportError());
 
   // Give ourselves a clusterURL so that the temporary 401 no-error situation
   // doesn't come into play.
-  Service.serverURL  = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
+  Service.serverURL  = FAKE_SERVER_URL;
+  Service.clusterURL = FAKE_SERVER_URL;
 
   // Test dontIgnoreErrors, non-network, non-prolonged, login error reported
   Status.resetSync();
   setLastSync(NON_PROLONGED_ERROR_DURATION);
   errorHandler.dontIgnoreErrors = true;
   Status.login = LOGIN_FAILED_NO_PASSWORD;
   do_check_true(errorHandler.shouldReportError());
 
@@ -402,17 +402,17 @@ add_test(function test_shouldReportError
   do_check_true(errorHandler.shouldReportError());
 
   run_next_test();
 });
 
 add_test(function test_shouldReportError_master_password() {
   _("Test error ignored due to locked master password");
   let server = sync_httpd_setup();
-  setUp();
+  setUp(server);
 
   // Monkey patch Service.verifyLogin to imitate
   // master password being locked.
   Service._verifyLogin = Service.verifyLogin;
   Service.verifyLogin = function () {
     Status.login = MASTER_PASSWORD_LOCKED;
     return false;
   };
@@ -426,17 +426,17 @@ add_test(function test_shouldReportError
   clean();
   server.stop(run_next_test);
 });
 
 add_test(function test_login_syncAndReportErrors_non_network_error() {
   // Test non-network errors are reported
   // when calling syncAndReportErrors
   let server = sync_httpd_setup();
-  setUp();
+  setUp(server);
   Service.identity.basicPassword = null;
 
   Svc.Obs.add("weave:ui:login:error", function onSyncError() {
     Svc.Obs.remove("weave:ui:login:error", onSyncError);
     do_check_eq(Status.login, LOGIN_FAILED_NO_PASSWORD);
 
     clean();
     server.stop(run_next_test);
@@ -445,17 +445,17 @@ add_test(function test_login_syncAndRepo
   setLastSync(NON_PROLONGED_ERROR_DURATION);
   errorHandler.syncAndReportErrors();
 });
 
 add_test(function test_sync_syncAndReportErrors_non_network_error() {
   // Test non-network errors are reported
   // when calling syncAndReportErrors
   let server = sync_httpd_setup();
-  setUp();
+  setUp(server);
 
   // By calling sync, we ensure we're logged in.
   Service.sync();
   do_check_eq(Status.sync, SYNC_SUCCEEDED);
   do_check_true(Service.isLoggedIn);
 
   generateCredentialsChangedFailure();
 
@@ -470,17 +470,17 @@ add_test(function test_sync_syncAndRepor
   setLastSync(NON_PROLONGED_ERROR_DURATION);
   errorHandler.syncAndReportErrors();
 });
 
 add_test(function test_login_syncAndReportErrors_prolonged_non_network_error() {
   // Test prolonged, non-network errors are
   // reported when calling syncAndReportErrors.
   let server = sync_httpd_setup();
-  setUp();
+  setUp(server);
   Service.identity.basicPassword = null;
 
   Svc.Obs.add("weave:ui:login:error", function onSyncError() {
     Svc.Obs.remove("weave:ui:login:error", onSyncError);
     do_check_eq(Status.login, LOGIN_FAILED_NO_PASSWORD);
 
     clean();
     server.stop(run_next_test);
@@ -489,17 +489,17 @@ add_test(function test_login_syncAndRepo
   setLastSync(PROLONGED_ERROR_DURATION);
   errorHandler.syncAndReportErrors();
 });
 
 add_test(function test_sync_syncAndReportErrors_prolonged_non_network_error() {
   // Test prolonged, non-network errors are
   // reported when calling syncAndReportErrors.
   let server = sync_httpd_setup();
-  setUp();
+  setUp(server);
 
   // By calling sync, we ensure we're logged in.
   Service.sync();
   do_check_eq(Status.sync, SYNC_SUCCEEDED);
   do_check_true(Service.isLoggedIn);
 
   generateCredentialsChangedFailure();
 
@@ -513,18 +513,18 @@ add_test(function test_sync_syncAndRepor
 
   setLastSync(PROLONGED_ERROR_DURATION);
   errorHandler.syncAndReportErrors();
 });
 
 add_test(function test_login_syncAndReportErrors_network_error() {
   // Test network errors are reported when calling syncAndReportErrors.
   setBasicCredentials("broken.wipe", "ilovejane", "abcdeabcdeabcdeabcdeabcdea");
-  Service.serverURL  = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
+  Service.serverURL  = FAKE_SERVER_URL;
+  Service.clusterURL = FAKE_SERVER_URL;
 
   Svc.Obs.add("weave:ui:login:error", function onSyncError() {
     Svc.Obs.remove("weave:ui:login:error", onSyncError);
     do_check_eq(Status.login, LOGIN_FAILED_NETWORK_ERROR);
 
     clean();
     run_next_test();
   });
@@ -550,18 +550,18 @@ add_test(function test_sync_syncAndRepor
   setLastSync(NON_PROLONGED_ERROR_DURATION);
   errorHandler.syncAndReportErrors();
 });
 
 add_test(function test_login_syncAndReportErrors_prolonged_network_error() {
   // Test prolonged, network errors are reported
   // when calling syncAndReportErrors.
   setBasicCredentials("johndoe", "ilovejane", "abcdeabcdeabcdeabcdeabcdea");
-  Service.serverURL  = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
+  Service.serverURL  = FAKE_SERVER_URL;
+  Service.clusterURL = FAKE_SERVER_URL;
 
   Svc.Obs.add("weave:ui:login:error", function onSyncError() {
     Svc.Obs.remove("weave:ui:login:error", onSyncError);
     do_check_eq(Status.login, LOGIN_FAILED_NETWORK_ERROR);
 
     clean();
     run_next_test();
   });
@@ -586,17 +586,17 @@ add_test(function test_sync_syncAndRepor
 
   setLastSync(PROLONGED_ERROR_DURATION);
   errorHandler.syncAndReportErrors();
 });
 
 add_test(function test_login_prolonged_non_network_error() {
   // Test prolonged, non-network errors are reported
   let server = sync_httpd_setup();
-  setUp();
+  setUp(server);
   Service.identity.basicPassword = null;
 
   Svc.Obs.add("weave:ui:login:error", function onSyncError() {
     Svc.Obs.remove("weave:ui:login:error", onSyncError);
     do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
 
     clean();
     server.stop(run_next_test);
@@ -604,17 +604,17 @@ add_test(function test_login_prolonged_n
 
   setLastSync(PROLONGED_ERROR_DURATION);
   Service.sync();
 });
 
 add_test(function test_sync_prolonged_non_network_error() {
   // Test prolonged, non-network errors are reported
   let server = sync_httpd_setup();
-  setUp();
+  setUp(server);
 
   // By calling sync, we ensure we're logged in.
   Service.sync();
   do_check_eq(Status.sync, SYNC_SUCCEEDED);
   do_check_true(Service.isLoggedIn);
 
   generateCredentialsChangedFailure();
 
@@ -628,18 +628,18 @@ add_test(function test_sync_prolonged_no
 
   setLastSync(PROLONGED_ERROR_DURATION);
   Service.sync();
 });
 
 add_test(function test_login_prolonged_network_error() {
   // Test prolonged, network errors are reported
   setBasicCredentials("johndoe", "ilovejane", "abcdeabcdeabcdeabcdeabcdea");
-  Service.serverURL  = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
+  Service.serverURL  = FAKE_SERVER_URL;
+  Service.clusterURL = FAKE_SERVER_URL;
 
   Svc.Obs.add("weave:ui:login:error", function onSyncError() {
     Svc.Obs.remove("weave:ui:login:error", onSyncError);
     do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
 
     clean();
     run_next_test();
   });
@@ -663,17 +663,17 @@ add_test(function test_sync_prolonged_ne
 
   setLastSync(PROLONGED_ERROR_DURATION);
   Service.sync();
 });
 
 add_test(function test_login_non_network_error() {
   // Test non-network errors are reported
   let server = sync_httpd_setup();
-  setUp();
+  setUp(server);
   Service.identity.basicPassword = null;
 
   Svc.Obs.add("weave:ui:login:error", function onSyncError() {
     Svc.Obs.remove("weave:ui:login:error", onSyncError);
     do_check_eq(Status.login, LOGIN_FAILED_NO_PASSWORD);
 
     clean();
     server.stop(run_next_test);
@@ -681,17 +681,17 @@ add_test(function test_login_non_network
 
   setLastSync(NON_PROLONGED_ERROR_DURATION);
   Service.sync();
 });
 
 add_test(function test_sync_non_network_error() {
   // Test non-network errors are reported
   let server = sync_httpd_setup();
-  setUp();
+  setUp(server);
 
   // By calling sync, we ensure we're logged in.
   Service.sync();
   do_check_eq(Status.sync, SYNC_SUCCEEDED);
   do_check_true(Service.isLoggedIn);
 
   generateCredentialsChangedFailure();
 
@@ -704,18 +704,18 @@ add_test(function test_sync_non_network_
   });
 
   setLastSync(NON_PROLONGED_ERROR_DURATION);
   Service.sync();
 });
 
 add_test(function test_login_network_error() {
   setBasicCredentials("johndoe", "ilovejane", "abcdeabcdeabcdeabcdeabcdea");
-  Service.serverURL  = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
+  Service.serverURL  = FAKE_SERVER_URL;
+  Service.clusterURL = FAKE_SERVER_URL;
 
   // Test network errors are not reported.
   Svc.Obs.add("weave:ui:clear-error", function onClearError() {
     Svc.Obs.remove("weave:ui:clear-error", onClearError);
 
     do_check_eq(Status.login, LOGIN_FAILED_NETWORK_ERROR);
 
     Services.io.offline = false;
@@ -742,17 +742,17 @@ add_test(function test_sync_network_erro
 
   setLastSync(NON_PROLONGED_ERROR_DURATION);
   Service.sync();
 });
 
 add_test(function test_sync_server_maintenance_error() {
   // Test server maintenance errors are not reported.
   let server = sync_httpd_setup();
-  setUp();
+  setUp(server);
 
   const BACKOFF = 42;
   let engine = engineManager.get("catapult");
   engine.enabled = true;
   engine.exception = {status: 503,
                       headers: {"retry-after": BACKOFF}};
 
   function onSyncError() {
@@ -775,22 +775,22 @@ add_test(function test_sync_server_maint
 
   setLastSync(NON_PROLONGED_ERROR_DURATION);
   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();
+  setUp(server);
 
   Service.username = "broken.info";
   setBasicCredentials("broken.info", "irrelevant", "irrelevant");
-  Service.serverURL = TEST_MAINTENANCE_URL;
-  Service.clusterURL = TEST_MAINTENANCE_URL;
+  Service.serverURL = server.baseURI + "/maintenance/";
+  Service.clusterURL = server.baseURI + "/maintenance/";
 
   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() {
@@ -816,21 +816,21 @@ add_test(function test_info_collections_
 
   setLastSync(NON_PROLONGED_ERROR_DURATION);
   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();
+  setUp(server);
 
   setBasicCredentials("broken.meta", "irrelevant", "irrelevant");
-  Service.serverURL = TEST_MAINTENANCE_URL;
-  Service.clusterURL = TEST_MAINTENANCE_URL;
+  Service.serverURL = server.baseURI + "/maintenance/";
+  Service.clusterURL = server.baseURI + "/maintenance/";
 
   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() {
@@ -856,21 +856,21 @@ add_test(function test_meta_global_login
 
   setLastSync(NON_PROLONGED_ERROR_DURATION);
   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();
+  setUp(server);
 
   setBasicCredentials("broken.keys", "irrelevant", "irrelevant");
-  Service.serverURL = TEST_MAINTENANCE_URL;
-  Service.clusterURL = TEST_MAINTENANCE_URL;
+  Service.serverURL = server.baseURI + "/maintenance/";
+  Service.clusterURL = server.baseURI + "/maintenance/";
 
   // Force re-download of keys
   Service.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;
@@ -899,17 +899,17 @@ add_test(function test_crypto_keys_login
 
   setLastSync(NON_PROLONGED_ERROR_DURATION);
   Service.sync();
 });
 
 add_test(function test_sync_prolonged_server_maintenance_error() {
   // Test prolonged server maintenance errors are reported.
   let server = sync_httpd_setup();
-  setUp();
+  setUp(server);
 
   const BACKOFF = 42;
   let engine = engineManager.get("catapult");
   engine.enabled = true;
   engine.exception = {status: 503,
                       headers: {"retry-after": BACKOFF}};
 
   Svc.Obs.add("weave:ui:sync:error", function onUIUpdate() {
@@ -925,21 +925,21 @@ add_test(function test_sync_prolonged_se
 
   setLastSync(PROLONGED_ERROR_DURATION);
   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();
+  setUp(server);
 
   setBasicCredentials("broken.info", "irrelevant", "irrelevant");
-  Service.serverURL = TEST_MAINTENANCE_URL;
-  Service.clusterURL = TEST_MAINTENANCE_URL;
+  Service.serverURL = server.baseURI + "/maintenance/";
+  Service.clusterURL = server.baseURI + "/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() {
@@ -958,21 +958,21 @@ add_test(function test_info_collections_
 
   setLastSync(PROLONGED_ERROR_DURATION);
   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();
+  setUp(server);
 
   setBasicCredentials("broken.meta", "irrelevant", "irrelevant");
-  Service.serverURL = TEST_MAINTENANCE_URL;
-  Service.clusterURL = TEST_MAINTENANCE_URL;
+  Service.serverURL = server.baseURI + "/maintenance/";
+  Service.clusterURL = server.baseURI + "/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() {
@@ -991,21 +991,21 @@ add_test(function test_meta_global_login
 
   setLastSync(PROLONGED_ERROR_DURATION);
   Service.sync();
 });
 
 add_test(function test_download_crypto_keys_login_prolonged_server_maintenance_error(){
   // Test crypto/keys prolonged server maintenance errors are reported.
   let server = sync_httpd_setup();
-  setUp();
+  setUp(server);
 
   setBasicCredentials("broken.keys", "irrelevant", "irrelevant");
-  Service.serverURL = TEST_MAINTENANCE_URL;
-  Service.clusterURL = TEST_MAINTENANCE_URL;
+  Service.serverURL = server.baseURI + "/maintenance/";
+  Service.clusterURL = server.baseURI + "/maintenance/";
   // Force re-download of keys
   Service.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;
   });
@@ -1029,18 +1029,18 @@ add_test(function test_download_crypto_k
 });
 
 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.
   setBasicCredentials("broken.keys", "ilovejane", "abcdeabcdeabcdeabcdeabcdea");
-  Service.serverURL = TEST_MAINTENANCE_URL;
-  Service.clusterURL = TEST_MAINTENANCE_URL;
+  Service.serverURL = server.baseURI + "/maintenance/";
+  Service.clusterURL = server.baseURI + "/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() {
@@ -1063,18 +1063,18 @@ add_test(function test_upload_crypto_key
 
 add_test(function test_wipeServer_login_prolonged_server_maintenance_error(){
   // Test that we report prolonged server maintenance errors that occur whilst
   // wiping the server.
   let server = sync_httpd_setup();
 
   // Start off with an empty account, do not upload a key.
   setBasicCredentials("broken.wipe", "ilovejane", "abcdeabcdeabcdeabcdeabcdea");
-  Service.serverURL = TEST_MAINTENANCE_URL;
-  Service.clusterURL = TEST_MAINTENANCE_URL;
+  Service.serverURL = server.baseURI + "/maintenance/";
+  Service.clusterURL = server.baseURI + "/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() {
@@ -1097,18 +1097,18 @@ add_test(function test_wipeServer_login_
 
 add_test(function test_wipeRemote_prolonged_server_maintenance_error(){
   // Test that we report prolonged server maintenance errors that occur whilst
   // wiping all remote devices.
   let server = sync_httpd_setup();
 
   server.registerPathHandler("/1.1/broken.wipe/storage/catapult", service_unavailable);
   setBasicCredentials("broken.wipe", "ilovejane", "abcdeabcdeabcdeabcdeabcdea");
-  Service.serverURL = TEST_MAINTENANCE_URL;
-  Service.clusterURL = TEST_MAINTENANCE_URL;
+  Service.serverURL = server.baseURI + "/maintenance/";
+  Service.clusterURL = server.baseURI + "/maintenance/";
   generateAndUploadKeys();
 
   let engine = engineManager.get("catapult");
   engine.exception = null;
   engine.enabled = true;
 
   let backoffInterval;
   Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
@@ -1135,17 +1135,17 @@ add_test(function test_wipeRemote_prolon
   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();
+  setUp(server);
 
   const BACKOFF = 42;
   let engine = engineManager.get("catapult");
   engine.enabled = true;
   engine.exception = {status: 503,
                       headers: {"retry-after": BACKOFF}};
 
   Svc.Obs.add("weave:ui:sync:error", function onUIUpdate() {
@@ -1162,21 +1162,21 @@ add_test(function test_sync_syncAndRepor
   setLastSync(NON_PROLONGED_ERROR_DURATION);
   errorHandler.syncAndReportErrors();
 });
 
 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();
+  setUp(server);
 
   setBasicCredentials("broken.info", "irrelevant", "irrelevant");
-  Service.serverURL = TEST_MAINTENANCE_URL;
-  Service.clusterURL = TEST_MAINTENANCE_URL;
+  Service.serverURL = server.baseURI + "/maintenance/";
+  Service.clusterURL = server.baseURI + "/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() {
@@ -1196,21 +1196,21 @@ add_test(function test_info_collections_
   setLastSync(NON_PROLONGED_ERROR_DURATION);
   errorHandler.syncAndReportErrors();
 });
 
 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();
+  setUp(server);
 
   setBasicCredentials("broken.meta", "irrelevant", "irrelevant");
-  Service.serverURL = TEST_MAINTENANCE_URL;
-  Service.clusterURL = TEST_MAINTENANCE_URL;
+  Service.serverURL = server.baseURI + "/maintenance/";
+  Service.clusterURL = server.baseURI + "/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() {
@@ -1230,21 +1230,21 @@ add_test(function test_meta_global_login
   setLastSync(NON_PROLONGED_ERROR_DURATION);
   errorHandler.syncAndReportErrors();
 });
 
 add_test(function test_download_crypto_keys_login_syncAndReportErrors_server_maintenance_error() {
   // Test crypto/keys server maintenance errors are reported
   // when calling syncAndReportErrors.
   let server = sync_httpd_setup();
-  setUp();
+  setUp(server);
 
   setBasicCredentials("broken.keys", "irrelevant", "irrelevant");
-  Service.serverURL = TEST_MAINTENANCE_URL;
-  Service.clusterURL = TEST_MAINTENANCE_URL;
+  Service.serverURL = server.baseURI + "/maintenance/";
+  Service.clusterURL = server.baseURI + "/maintenance/";
   // Force re-download of keys
   Service.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;
   });
@@ -1269,18 +1269,18 @@ add_test(function test_download_crypto_k
 
 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.
   setBasicCredentials("broken.keys", "ilovejane", "abcdeabcdeabcdeabcdeabcdea");
-  Service.serverURL = TEST_MAINTENANCE_URL;
-  Service.clusterURL = TEST_MAINTENANCE_URL;
+  Service.serverURL = server.baseURI + "/maintenance/";
+  Service.clusterURL = server.baseURI + "/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() {
@@ -1303,18 +1303,18 @@ add_test(function test_upload_crypto_key
 
 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.
   setBasicCredentials("broken.wipe", "ilovejane", "abcdeabcdeabcdeabcdeabcdea");
-  Service.serverURL = TEST_MAINTENANCE_URL;
-  Service.clusterURL = TEST_MAINTENANCE_URL;
+  Service.serverURL = server.baseURI + "/maintenance/";
+  Service.clusterURL = server.baseURI + "/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() {
@@ -1336,18 +1336,18 @@ add_test(function test_wipeServer_login_
 });
 
 add_test(function test_wipeRemote_syncAndReportErrors_server_maintenance_error(){
   // Test that we report prolonged server maintenance errors that occur whilst
   // wiping all remote devices.
   let server = sync_httpd_setup();
 
   setBasicCredentials("broken.wipe", "ilovejane", "abcdeabcdeabcdeabcdeabcdea");
-  Service.serverURL = TEST_MAINTENANCE_URL;
-  Service.clusterURL = TEST_MAINTENANCE_URL;
+  Service.serverURL = server.baseURI + "/maintenance/";
+  Service.clusterURL = server.baseURI + "/maintenance/";
   generateAndUploadKeys();
 
   let engine = engineManager.get("catapult");
   engine.exception = null;
   engine.enabled = true;
 
   let backoffInterval;
   Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
@@ -1374,17 +1374,17 @@ add_test(function test_wipeRemote_syncAn
   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();
+  setUp(server);
 
   const BACKOFF = 42;
   let engine = engineManager.get("catapult");
   engine.enabled = true;
   engine.exception = {status: 503,
                       headers: {"retry-after": BACKOFF}};
 
   Svc.Obs.add("weave:ui:sync:error", function onUIUpdate() {
@@ -1401,21 +1401,21 @@ add_test(function test_sync_syncAndRepor
   setLastSync(PROLONGED_ERROR_DURATION);
   errorHandler.syncAndReportErrors();
 });
 
 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();
+  setUp(server);
 
   setBasicCredentials("broken.info", "irrelevant", "irrelevant");
-  Service.serverURL = TEST_MAINTENANCE_URL;
-  Service.clusterURL = TEST_MAINTENANCE_URL;
+  Service.serverURL = server.baseURI + "/maintenance/";
+  Service.clusterURL = server.baseURI + "/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() {
@@ -1435,21 +1435,21 @@ add_test(function test_info_collections_
   setLastSync(PROLONGED_ERROR_DURATION);
   errorHandler.syncAndReportErrors();
 });
 
 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();
+  setUp(server);
 
   setBasicCredentials("broken.meta", "irrelevant", "irrelevant");
-  Service.serverURL = TEST_MAINTENANCE_URL;
-  Service.clusterURL = TEST_MAINTENANCE_URL;
+  Service.serverURL = server.baseURI + "/maintenance/";
+  Service.clusterURL = server.baseURI + "/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() {
@@ -1469,21 +1469,21 @@ add_test(function test_meta_global_login
   setLastSync(PROLONGED_ERROR_DURATION);
   errorHandler.syncAndReportErrors();
 });
 
 add_test(function test_download_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();
+  setUp(server);
 
   setBasicCredentials("broken.keys", "irrelevant", "irrelevant");
-  Service.serverURL = TEST_MAINTENANCE_URL;
-  Service.clusterURL = TEST_MAINTENANCE_URL;
+  Service.serverURL = server.baseURI + "/maintenance/";
+  Service.clusterURL = server.baseURI + "/maintenance/";
   // Force re-download of keys
   Service.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;
   });
@@ -1508,18 +1508,18 @@ add_test(function test_download_crypto_k
 
 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.
   setBasicCredentials("broken.keys", "ilovejane", "abcdeabcdeabcdeabcdeabcdea");
-  Service.serverURL = TEST_MAINTENANCE_URL;
-  Service.clusterURL = TEST_MAINTENANCE_URL;
+  Service.serverURL = server.baseURI + "/maintenance/";
+  Service.clusterURL = server.baseURI + "/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() {
@@ -1542,18 +1542,18 @@ add_test(function test_upload_crypto_key
 
 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.
   setBasicCredentials("broken.wipe", "ilovejane", "abcdeabcdeabcdeabcdeabcdea");
-  Service.serverURL = TEST_MAINTENANCE_URL;
-  Service.clusterURL = TEST_MAINTENANCE_URL;
+  Service.serverURL = server.baseURI + "/maintenance/";
+  Service.clusterURL = server.baseURI + "/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() {
@@ -1610,17 +1610,17 @@ add_test(function test_sync_engine_gener
       do_check_eq(logfile.leafName.slice(0, LOG_PREFIX_ERROR.length),
                   LOG_PREFIX_ERROR);
 
       clean();
       server.stop(run_next_test);
     });
   });
 
-  do_check_true(setUp());
+  do_check_true(setUp(server));
   Service.sync();
 });
 
 add_test(function test_logs_on_sync_error_despite_shouldReportError() {
   _("Ensure that an error is still logged when weave:service:sync:error " +
     "is notified, despite shouldReportError returning false.");
 
   let log = Log4Moz.repository.getLogger("Sync.ErrorHandler");
@@ -1703,11 +1703,11 @@ add_test(function test_engine_applyFaile
     do_check_eq(logfile.leafName.slice(0, LOG_PREFIX_ERROR.length),
                 LOG_PREFIX_ERROR);
 
     clean();
     server.stop(run_next_test);
   });
 
   do_check_eq(Status.engines["catapult"], undefined);
-  do_check_true(setUp());
+  do_check_true(setUp(server));
   Service.sync();
 });
--- a/services/sync/tests/unit/test_errorhandler_sync_checkServerError.js
+++ b/services/sync/tests/unit/test_errorhandler_sync_checkServerError.js
@@ -48,79 +48,79 @@ function sync_httpd_setup() {
     "/1.1/johndoe/info/collections":    collectionsHelper.handler,
     "/1.1/johndoe/storage/meta/global": upd("meta",    globalWBO.handler()),
     "/1.1/johndoe/storage/clients":     upd("clients", clientsColl.handler()),
     "/1.1/johndoe/storage/crypto/keys": upd("crypto",  keysWBO.handler())
   };
   return httpd_setup(handlers);
 }
 
-function setUp() {
+function setUp(server) {
   setBasicCredentials("johndoe", "ilovejane", "aabcdeabcdeabcdeabcdeabcde");
-  Service.serverURL = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
+  Service.serverURL = server.baseURI + "/";
+  Service.clusterURL = server.baseURI + "/";
   new FakeCryptoService();
 }
 
-function generateAndUploadKeys() {
+function generateAndUploadKeys(server) {
   generateNewKeys(Service.collectionKeys);
   let serverKeys = Service.collectionKeys.asWBO("crypto", "keys");
   serverKeys.encrypt(Service.identity.syncKeyBundle);
-  let res = Service.resource("http://localhost:8080/1.1/johndoe/storage/crypto/keys");
+  let res = Service.resource(server.baseURI + "/1.1/johndoe/storage/crypto/keys");
   return serverKeys.upload(res).success;
 }
 
 
 add_test(function test_backoff500() {
   _("Test: HTTP 500 sets backoff status.");
-  setUp();
   let server = sync_httpd_setup();
+  setUp(server);
 
   let engine = engineManager.get("catapult");
   engine.enabled = true;
   engine.exception = {status: 500};
 
   try {
     do_check_false(Status.enforceBackoff);
 
     // Forcibly create and upload keys here -- otherwise we don't get to the 500!
-    do_check_true(generateAndUploadKeys());
+    do_check_true(generateAndUploadKeys(server));
 
     Service.login();
     Service.sync();
     do_check_true(Status.enforceBackoff);
     do_check_eq(Status.sync, SYNC_SUCCEEDED);
     do_check_eq(Status.service, SYNC_FAILED_PARTIAL);
   } finally {
     Status.resetBackoff();
     Service.startOver();
   }
   server.stop(run_next_test);
 });
 
 add_test(function test_backoff503() {
   _("Test: HTTP 503 with Retry-After header leads to backoff notification and sets backoff status.");
-  setUp();
   let server = sync_httpd_setup();
+  setUp(server);
 
   const BACKOFF = 42;
   let engine = engineManager.get("catapult");
   engine.enabled = true;
   engine.exception = {status: 503,
                       headers: {"retry-after": BACKOFF}};
 
   let backoffInterval;
   Svc.Obs.add("weave:service:backoff:interval", function (subject) {
     backoffInterval = subject;
   });
 
   try {
     do_check_false(Status.enforceBackoff);
 
-    do_check_true(generateAndUploadKeys());
+    do_check_true(generateAndUploadKeys(server));
 
     Service.login();
     Service.sync();
 
     do_check_true(Status.enforceBackoff);
     do_check_eq(backoffInterval, BACKOFF);
     do_check_eq(Status.service, SYNC_FAILED_PARTIAL);
     do_check_eq(Status.sync, SERVER_MAINTENANCE);
@@ -129,124 +129,130 @@ add_test(function test_backoff503() {
     Status.resetSync();
     Service.startOver();
   }
   server.stop(run_next_test);
 });
 
 add_test(function test_overQuota() {
   _("Test: HTTP 400 with body error code 14 means over quota.");
-  setUp();
   let server = sync_httpd_setup();
+  setUp(server);
 
   let engine = engineManager.get("catapult");
   engine.enabled = true;
   engine.exception = {status: 400,
                       toString: function() "14"};
 
   try {
     do_check_eq(Status.sync, SYNC_SUCCEEDED);
 
-    do_check_true(generateAndUploadKeys());
+    do_check_true(generateAndUploadKeys(server));
 
     Service.login();
     Service.sync();
 
     do_check_eq(Status.sync, OVER_QUOTA);
     do_check_eq(Status.service, SYNC_FAILED_PARTIAL);
   } finally {
     Status.resetSync();
     Service.startOver();
   }
   server.stop(run_next_test);
 });
 
 add_test(function test_service_networkError() {
   _("Test: Connection refused error from Service.sync() leads to the right status code.");
-  setUp();
-  // Provoke connection refused.
-  Service.clusterURL = "http://localhost:12345/";
+  let server = sync_httpd_setup();
+  setUp(server);
+  server.stop(() => {
+    // Provoke connection refused.
+    Service.clusterURL = "http://localhost:12345/";
 
-  try {
-    do_check_eq(Status.sync, SYNC_SUCCEEDED);
+    try {
+      do_check_eq(Status.sync, SYNC_SUCCEEDED);
 
-    Service._loggedIn = true;
-    Service.sync();
+      Service._loggedIn = true;
+      Service.sync();
 
-    do_check_eq(Status.sync, LOGIN_FAILED_NETWORK_ERROR);
-    do_check_eq(Status.service, SYNC_FAILED);
-  } finally {
-    Status.resetSync();
-    Service.startOver();
-  }
-  run_next_test();
+      do_check_eq(Status.sync, LOGIN_FAILED_NETWORK_ERROR);
+      do_check_eq(Status.service, SYNC_FAILED);
+    } finally {
+      Status.resetSync();
+      Service.startOver();
+    }
+    run_next_test();
+  });
 });
 
 add_test(function test_service_offline() {
   _("Test: Wanting to sync in offline mode leads to the right status code but does not increment the ignorable error count.");
-  setUp();
-  Services.io.offline = true;
+  let server = sync_httpd_setup();
+  setUp(server);
+  server.stop(() => {
+    Services.io.offline = true;
 
-  try {
-    do_check_eq(Status.sync, SYNC_SUCCEEDED);
-
-    Service._loggedIn = true;
-    Service.sync();
+    try {
+      do_check_eq(Status.sync, SYNC_SUCCEEDED);
 
-    do_check_eq(Status.sync, LOGIN_FAILED_NETWORK_ERROR);
-    do_check_eq(Status.service, SYNC_FAILED);
-  } finally {
-    Status.resetSync();
-    Service.startOver();
-  }
-  Services.io.offline = false;
-  run_next_test();
+      Service._loggedIn = true;
+      Service.sync();
+
+      do_check_eq(Status.sync, LOGIN_FAILED_NETWORK_ERROR);
+      do_check_eq(Status.service, SYNC_FAILED);
+    } finally {
+      Status.resetSync();
+      Service.startOver();
+    }
+    Services.io.offline = false;
+    run_next_test();
+  });
 });
 
 add_test(function test_engine_networkError() {
   _("Test: Network related exceptions from engine.sync() lead to the right status code.");
-  setUp();
   let server = sync_httpd_setup();
+  setUp(server);
 
   let engine = engineManager.get("catapult");
   engine.enabled = true;
   engine.exception = Components.Exception("NS_ERROR_UNKNOWN_HOST",
                                           Cr.NS_ERROR_UNKNOWN_HOST);
 
   try {
     do_check_eq(Status.sync, SYNC_SUCCEEDED);
 
-    do_check_true(generateAndUploadKeys());
+    do_check_true(generateAndUploadKeys(server));
 
     Service.login();
     Service.sync();
 
     do_check_eq(Status.sync, LOGIN_FAILED_NETWORK_ERROR);
     do_check_eq(Status.service, SYNC_FAILED_PARTIAL);
   } finally {
     Status.resetSync();
     Service.startOver();
   }
   server.stop(run_next_test);
 });
 
 add_test(function test_resource_timeout() {
-  setUp();
   let server = sync_httpd_setup();
+  setUp(server);
 
   let engine = engineManager.get("catapult");
   engine.enabled = true;
   // Resource throws this when it encounters a timeout.
   engine.exception = Components.Exception("Aborting due to channel inactivity.",
                                           Cr.NS_ERROR_NET_TIMEOUT);
 
   try {
     do_check_eq(Status.sync, SYNC_SUCCEEDED);
 
-    do_check_true(generateAndUploadKeys());
+    do_check_true(generateAndUploadKeys(server));
 
     Service.login();
     Service.sync();
 
     do_check_eq(Status.sync, LOGIN_FAILED_NETWORK_ERROR);
     do_check_eq(Status.service, SYNC_FAILED_PARTIAL);
   } finally {
     Status.resetSync();
--- a/services/sync/tests/unit/test_history_engine.js
+++ b/services/sync/tests/unit/test_history_engine.js
@@ -12,31 +12,35 @@ Cu.import("resource://testing-common/ser
 
 Service.engineManager.clear();
 
 add_test(function test_processIncoming_mobile_history_batched() {
   _("SyncEngine._processIncoming works on history engine.");
 
   let FAKE_DOWNLOAD_LIMIT = 100;
 
-  new SyncTestingInfrastructure();
-
   Svc.Prefs.set("client.type", "mobile");
   PlacesUtils.history.removeAllPages();
   Service.engineManager.register(HistoryEngine);
 
   // A collection that logs each GET
   let collection = new ServerCollection();
   collection.get_log = [];
   collection._get = collection.get;
   collection.get = function (options) {
     this.get_log.push(options);
     return this._get(options);
   };
 
+  let server = sync_httpd_setup({
+    "/1.1/foo/storage/history": collection.handler()
+  });
+
+  new SyncTestingInfrastructure(server);
+
   // Let's create some 234 server side history records. They're all at least
   // 10 minutes old.
   let visitType = Ci.nsINavHistoryService.TRANSITION_LINK;
   for (var i = 0; i < 234; i++) {
     let id = 'record-no' + ("00" + i).slice(-3);
     let modified = Date.now()/1000 - 60*(i+10);
     let payload = encryptPayload({
       id: id,
@@ -46,20 +50,16 @@ add_test(function test_processIncoming_m
         visits: [{date: (modified - 5) * 1000000, type: visitType}],
         deleted: false});
 
     let wbo = new ServerWBO(id, payload);
     wbo.modified = modified;
     collection.insertWBO(wbo);
   }
 
-  let server = sync_httpd_setup({
-      "/1.1/foo/storage/history": collection.handler()
-  });
-
   let engine = Service.engineManager.get("history");
   let meta_global = Service.recordManager.set(engine.metaURL,
                                               new WBORecord(engine.metaURL));
   meta_global.payload.engines = {history: {version: engine.version,
                                            syncID: engine.syncID}};
 
   try {
 
--- a/services/sync/tests/unit/test_hmac_error.js
+++ b/services/sync/tests/unit/test_hmac_error.js
@@ -17,18 +17,16 @@ let hmacErrorCount = 0;
   };
 })();
 
 function shared_setup() {
   hmacErrorCount = 0;
 
   // Do not instantiate SyncTestingInfrastructure; we need real crypto.
   setBasicCredentials("foo", "foo", "aabcdeabcdeabcdeabcdeabcde");
-  Service.serverURL  = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
 
   // Make sure RotaryEngine is the only one we sync.
   Service.engineManager._engines = {};
   Service.engineManager.register(RotaryEngine);
   let engine = Service.engineManager.get("rotary");
   engine.enabled = true;
   engine.lastSync = 123; // Needs to be non-zero so that tracker is queried.
   engine._store.items = {flying: "LNER Class A3 4472",
@@ -75,16 +73,17 @@ add_test(function hmac_error_during_404(
     "/1.1/foo/info/collections": collectionsHelper.handler,
     "/1.1/foo/storage/meta/global": upd("meta", global.handler()),
     "/1.1/foo/storage/crypto/keys": upd("crypto", keys404Handler),
     "/1.1/foo/storage/clients": upd("clients", clientsColl.handler()),
     "/1.1/foo/storage/rotary": upd("rotary", rotaryColl.handler())
   };
 
   let server = sync_httpd_setup(handlers);
+  Service.serverURL = server.baseURI;
 
   try {
     _("Syncing.");
     Service.sync();
     _("Partially resetting client, as if after a restart, and forcing redownload.");
     Service.collectionKeys.clear();
     engine.lastSync = 0;        // So that we redownload records.
     key404Counter = 1;
@@ -150,16 +149,17 @@ add_test(function hmac_error_during_node
     "/1.1/foo/info/collections":    collectionsHelper.handler,
     "/1.1/foo/storage/meta/global": upd("meta", global.handler()),
     "/1.1/foo/storage/crypto/keys": upd("crypto", keysWBO.handler()),
     "/1.1/foo/storage/clients":     upd401("clients", clientsColl.handler()),
     "/1.1/foo/storage/rotary":      upd("rotary", rotaryColl.handler())
   };
 
   let server = sync_httpd_setup(handlers);
+  Service.serverURL = server.baseURI;
   _("Syncing.");
   // First hit of clients will 401. This will happen after meta/global and
   // keys -- i.e., in the middle of the sync, but before RotaryEngine.
   should401 = true;
 
   // Use observers to perform actions when our sync finishes.
   // This allows us to observe the automatic next-tick sync that occurs after
   // an abort.
--- a/services/sync/tests/unit/test_httpd_sync_server.js
+++ b/services/sync/tests/unit/test_httpd_sync_server.js
@@ -60,32 +60,31 @@ add_test(function test_url_parsing() {
   let [all, storage, collection, id] = parts;
   do_check_eq(all, "storage");
   do_check_eq(collection, undefined);
 
   run_next_test();
 });
 
 Cu.import("resource://services-common/rest.js");
-function localRequest(path) {
+function localRequest(server, path) {
   _("localRequest: " + path);
-  let url = "http://127.0.0.1:8080" + path;
+  let url = server.baseURI.substr(0, server.baseURI.length - 1) + path;
   _("url: " + url);
   return new RESTRequest(url);
 }
 
 add_test(function test_basic_http() {
   let server = new SyncServer();
   server.registerUser("john", "password");
   do_check_true(server.userExists("john"));
-  server.start(8080, function () {
+  server.start(null, function () {
     _("Started on " + server.port);
-    do_check_eq(server.port, 8080);
     Utils.nextTick(function () {
-      let req = localRequest("/1.1/john/storage/crypto/keys");
+      let req = localRequest(server, "/1.1/john/storage/crypto/keys");
       _("req is " + req);
       req.get(function (err) {
         do_check_eq(null, err);
         Utils.nextTick(function () {
           server.stop(run_next_test);
         });
       });
     });
@@ -98,51 +97,50 @@ add_test(function test_info_collections(
   });
   function responseHasCorrectHeaders(r) {
     do_check_eq(r.status, 200);
     do_check_eq(r.headers["content-type"], "application/json");
     do_check_true("x-weave-timestamp" in r.headers);
   }
 
   server.registerUser("john", "password");
-  server.start(8080, function () {
-    do_check_eq(server.port, 8080);
+  server.start(null, function () {
     Utils.nextTick(function () {
-      let req = localRequest("/1.1/john/info/collections");
+      let req = localRequest(server, "/1.1/john/info/collections");
       req.get(function (err) {
         // Initial info/collections fetch is empty.
         do_check_eq(null, err);
         responseHasCorrectHeaders(this.response);
 
         do_check_eq(this.response.body, "{}");
         Utils.nextTick(function () {
           // When we PUT something to crypto/keys, "crypto" appears in the response.
           function cb(err) {
             do_check_eq(null, err);
             responseHasCorrectHeaders(this.response);
             let putResponseBody = this.response.body;
             _("PUT response body: " + JSON.stringify(putResponseBody));
 
-            req = localRequest("/1.1/john/info/collections");
+            req = localRequest(server, "/1.1/john/info/collections");
             req.get(function (err) {
               do_check_eq(null, err);
               responseHasCorrectHeaders(this.response);
               let expectedColl = server.getCollection("john", "crypto");
               do_check_true(!!expectedColl);
               let modified = expectedColl.timestamp;
               do_check_true(modified > 0);
               do_check_eq(putResponseBody, modified);
               do_check_eq(JSON.parse(this.response.body).crypto, modified);
               Utils.nextTick(function () {
                 server.stop(run_next_test);
               });
             });
           }
           let payload = JSON.stringify({foo: "bar"});
-          localRequest("/1.1/john/storage/crypto/keys").put(payload, cb);
+          localRequest(server, "/1.1/john/storage/crypto/keys").put(payload, cb);
         });
       });
     });
   });
 });
 
 add_test(function test_storage_request() {
   let keysURL = "/1.1/john/storage/crypto/keys?foo=bar";
@@ -158,54 +156,54 @@ add_test(function test_storage_request()
   });
   let coll = server.user("john").collection("crypto");
   do_check_true(!!coll);
 
   _("We're tracking timestamps.");
   do_check_true(coll.timestamp >= creation);
 
   function retrieveWBONotExists(next) {
-    let req = localRequest(keysURL);
+    let req = localRequest(server, keysURL);
     req.get(function (err) {
       _("Body is " + this.response.body);
       _("Modified is " + this.response.newModified);
       do_check_eq(null, err);
       do_check_eq(this.response.status, 404);
       do_check_eq(this.response.body, "Not found");
       Utils.nextTick(next);
     });
   }
   function retrieveWBOExists(next) {
-    let req = localRequest(foosURL);
+    let req = localRequest(server, foosURL);
     req.get(function (err) {
       _("Body is " + this.response.body);
       _("Modified is " + this.response.newModified);
       let parsedBody = JSON.parse(this.response.body);
       do_check_eq(parsedBody.id, "foos");
       do_check_eq(parsedBody.modified, coll.wbo("foos").modified);
       do_check_eq(JSON.parse(parsedBody.payload).foo, "bar");
       Utils.nextTick(next);
     });
   }
   function deleteWBONotExists(next) {
-    let req = localRequest(keysURL);
+    let req = localRequest(server, keysURL);
     server.callback.onItemDeleted = function (username, collection, wboID) {
       do_throw("onItemDeleted should not have been called.");
     };
 
     req.delete(function (err) {
       _("Body is " + this.response.body);
       _("Modified is " + this.response.newModified);
       do_check_eq(this.response.status, 200);
       delete server.callback.onItemDeleted;
       Utils.nextTick(next);
     });
   }
   function deleteWBOExists(next) {
-    let req = localRequest(foosURL);
+    let req = localRequest(server, foosURL);
     server.callback.onItemDeleted = function (username, collection, wboID) {
       _("onItemDeleted called for " + collection + "/" + wboID);
       delete server.callback.onItemDeleted;
       do_check_eq(username, "john");
       do_check_eq(collection, "crypto");
       do_check_eq(wboID, "foos");
       Utils.nextTick(next);
     };
@@ -215,45 +213,45 @@ add_test(function test_storage_request()
       _("Modified is " + this.response.newModified);
       do_check_eq(this.response.status, 200);
     });
   }
   function deleteStorage(next) {
     _("Testing DELETE on /storage.");
     let now = server.timestamp();
     _("Timestamp: " + now);
-    let req = localRequest(storageURL);
+    let req = localRequest(server, storageURL);
     req.delete(function (err) {
       _("Body is " + this.response.body);
       _("Modified is " + this.response.newModified);
       let parsedBody = JSON.parse(this.response.body);
       do_check_true(parsedBody >= now);
       do_check_empty(server.users["john"].collections);
       Utils.nextTick(next);
     });
   }
   function getStorageFails(next) {
     _("Testing that GET on /storage fails.");
-    let req = localRequest(storageURL);
+    let req = localRequest(server, storageURL);
     req.get(function (err) {
       do_check_eq(this.response.status, 405);
       do_check_eq(this.response.headers["allow"], "DELETE");
       Utils.nextTick(next);
     });
   }
   function getMissingCollectionWBO(next) {
     _("Testing that fetching a WBO from an on-existent collection 404s.");
-    let req = localRequest(storageURL + "/foobar/baz");
+    let req = localRequest(server, storageURL + "/foobar/baz");
     req.get(function (err) {
       do_check_eq(this.response.status, 404);
       Utils.nextTick(next);
     });
   }
 
-  server.start(8080,
+  server.start(null,
     Async.chain(
       retrieveWBONotExists,
       retrieveWBOExists,
       deleteWBOExists,
       deleteWBONotExists,
       getStorageFails,
       getMissingCollectionWBO,
       deleteStorage,
@@ -265,22 +263,22 @@ add_test(function test_storage_request()
 add_test(function test_x_weave_records() {
   let server = new SyncServer();
   server.registerUser("john", "password");
 
   server.createContents("john", {
     crypto: {foos: {foo: "bar"},
              bars: {foo: "baz"}}
   });
-  server.start(8080, function () {
-    let wbo = localRequest("/1.1/john/storage/crypto/foos");
+  server.start(null, function () {
+    let wbo = localRequest(server, "/1.1/john/storage/crypto/foos");
     wbo.get(function (err) {
       // WBO fetches don't have one.
       do_check_false("x-weave-records" in this.response.headers);
-      let col = localRequest("/1.1/john/storage/crypto");
+      let col = localRequest(server, "/1.1/john/storage/crypto");
       col.get(function (err) {
         // Collection fetches do.
         do_check_eq(this.response.headers["x-weave-records"], "2");
         server.stop(run_next_test);
       });
     });
   });
 });
--- a/services/sync/tests/unit/test_interval_triggers.js
+++ b/services/sync/tests/unit/test_interval_triggers.js
@@ -30,20 +30,20 @@ function sync_httpd_setup() {
     "/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())
   });
 }
 
-function setUp() {
+function setUp(server) {
   setBasicCredentials("johndoe", "ilovejane", "abcdeabcdeabcdeabcdeabcdea");
-  Service.serverURL = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
+  Service.serverURL = server.baseURI + "/";
+  Service.clusterURL = server.baseURI + "/";
 
   generateNewKeys(Service.collectionKeys);
   let serverKeys = Service.collectionKeys.asWBO("crypto", "keys");
   serverKeys.encrypt(Service.identity.syncKeyBundle);
   return serverKeys.upload(Service.resource(Service.cryptoKeysURL));
 }
 
 function run_test() {
@@ -60,17 +60,17 @@ add_test(function test_successful_sync_a
   let syncSuccesses = 0;
   function onSyncFinish() {
     _("Sync success.");
     syncSuccesses++;
   };
   Svc.Obs.add("weave:service:sync:finish", onSyncFinish);
 
   let server = sync_httpd_setup();
-  setUp();
+  setUp(server);
 
   // Confirm defaults
   do_check_false(scheduler.idle);
   do_check_false(scheduler.numClients > 1);
   do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
   do_check_false(scheduler.hasIncomingItems);
 
   _("Test as long as numClients <= 1 our sync interval is SINGLE_USER.");
@@ -164,17 +164,17 @@ add_test(function test_unsuccessful_sync
   }
   Svc.Obs.add("weave:service:sync:error", onSyncError);
 
   _("Test unsuccessful sync calls adjustSyncInterval");
   // Force sync to fail.
   Svc.Prefs.set("firstSync", "notReady");
 
   let server = sync_httpd_setup();
-  setUp();
+  setUp(server);
 
   // Confirm defaults
   do_check_false(scheduler.idle);
   do_check_false(scheduler.numClients > 1);
   do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
   do_check_false(scheduler.hasIncomingItems);
 
   _("Test as long as numClients <= 1 our sync interval is SINGLE_USER.");
@@ -256,17 +256,17 @@ add_test(function test_unsuccessful_sync
 
   Service.startOver();
   Svc.Obs.remove("weave:service:sync:error", onSyncError);
   server.stop(run_next_test);
 });
 
 add_test(function test_back_triggers_sync() {
   let server = sync_httpd_setup();
-  setUp();
+  setUp(server);
 
   // Single device: no sync triggered.
   scheduler.idle = true;
   scheduler.observe(null, "back", Svc.Prefs.get("scheduler.idleTime"));
   do_check_false(scheduler.idle);
 
   // Multiple devices: sync is triggered.
   clientsEngine._store.create({id: "foo", cleartext: "bar"});
@@ -286,17 +286,17 @@ add_test(function test_back_triggers_syn
 
   scheduler.idle = true;
   scheduler.observe(null, "back", Svc.Prefs.get("scheduler.idleTime"));
   do_check_false(scheduler.idle);
 });
 
 add_test(function test_adjust_interval_on_sync_error() {
   let server = sync_httpd_setup();
-  setUp();
+  setUp(server);
 
   let syncFailures = 0;
   function onSyncError() {
     _("Sync error.");
     syncFailures++;
   }
   Svc.Obs.add("weave:service:sync:error", onSyncError);
 
@@ -322,17 +322,17 @@ add_test(function test_adjust_interval_o
 
 add_test(function test_bug671378_scenario() {
   // Test scenario similar to bug 671378. This bug appeared when a score
   // update occurred that wasn't large enough to trigger a sync so
   // scheduleNextSync() was called without a time interval parameter,
   // setting nextSync to a non-zero value and preventing the timer from
   // being adjusted in the next call to scheduleNextSync().
   let server = sync_httpd_setup();
-  setUp();
+  setUp(server);
 
   let syncSuccesses = 0;
   function onSyncFinish() {
     _("Sync success.");
     syncSuccesses++;
   };
   Svc.Obs.add("weave:service:sync:finish", onSyncFinish);
 
--- a/services/sync/tests/unit/test_jpakeclient.js
+++ b/services/sync/tests/unit/test_jpakeclient.js
@@ -164,36 +164,35 @@ let BaseController = {
   }
 };
 
 
 const DATA = {"msg": "eggstreamly sekrit"};
 const POLLINTERVAL = 50;
 
 function run_test() {
-  Svc.Prefs.set("jpake.serverURL", TEST_SERVER_URL);
+  server = httpd_setup({"/new_channel": server_new_channel,
+                        "/report":      server_report});
+  Svc.Prefs.set("jpake.serverURL", server.baseURI + "/");
   Svc.Prefs.set("jpake.pollInterval", POLLINTERVAL);
   Svc.Prefs.set("jpake.maxTries", 2);
   Svc.Prefs.set("jpake.firstMsgMaxTries", 5);
   Svc.Prefs.set("jpake.lastMsgMaxTries", 5);
   // Ensure clean up
   Svc.Obs.add("profile-before-change", function() {
     Svc.Prefs.resetBranch("");
   });
 
   // Ensure PSM is initialized.
   Cc["@mozilla.org/psm;1"].getService(Ci.nsISupports);
 
   // Simulate Sync setup with credentials in place. We want to make
   // sure the J-PAKE requests don't include those data.
   setBasicCredentials("johndoe", "ilovejane");
 
-  server = httpd_setup({"/new_channel": server_new_channel,
-                        "/report":      server_report});
-
   initTestLogging("Trace");
   Log4Moz.repository.getLogger("Sync.JPAKEClient").level = Log4Moz.Level.Trace;
   Log4Moz.repository.getLogger("Common.RESTRequest").level =
     Log4Moz.Level.Trace;
   run_next_test();
 }
 
 
--- a/services/sync/tests/unit/test_node_reassignment.js
+++ b/services/sync/tests/unit/test_node_reassignment.js
@@ -54,39 +54,39 @@ function handleReassign(handler, req, re
   resp.setStatusLine(req.httpVersion, 401, "Node reassignment");
   resp.setHeader("Content-Type", "application/json");
   resp.bodyOutputStream.write(reassignBody, reassignBody.length);
 }
 
 /**
  * A node assignment handler.
  */
-const newNodeBody = "http://localhost:8080/";
 function installNodeHandler(server, next) {
+  let newNodeBody = server.baseURI;
   function handleNodeRequest(req, resp) {
     _("Client made a request for a node reassignment.");
     resp.setStatusLine(req.httpVersion, 200, "OK");
     resp.setHeader("Content-Type", "text/plain");
     resp.bodyOutputStream.write(newNodeBody, newNodeBody.length);
     Utils.nextTick(next);
   }
   let nodePath = "/user/1.0/johndoe/node/weave";
   server.server.registerPathHandler(nodePath, handleNodeRequest);
   _("Registered node handler at " + nodePath);
 }
 
 function prepareServer() {
   setBasicCredentials("johndoe", "ilovejane", "abcdeabcdeabcdeabcdeabcdea");
-  Service.serverURL  = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
 
-  do_check_eq(Service.userAPIURI, "http://localhost:8080/user/1.0/");
   let server = new SyncServer();
   server.registerUser("johndoe");
   server.start();
+  Service.serverURL = server.baseURI;
+  Service.clusterURL = server.baseURI;
+  do_check_eq(Service.userAPIURI, server.baseURI + "user/1.0/");
   return server;
 }
 
 function getReassigned() {
   try {
     return Services.prefs.getBoolPref("services.sync.lastSyncReassigned");
   } catch (ex if (ex.result == Cr.NS_ERROR_UNEXPECTED)) {
     return false;
--- a/services/sync/tests/unit/test_records_wbo.js
+++ b/services/sync/tests/unit/test_records_wbo.js
@@ -46,25 +46,25 @@ function test_fetch() {
     "/record2": httpd_handler(200, "OK", JSON.stringify(record2)),
     "/coll":    httpd_handler(200, "OK", JSON.stringify(coll))
   });
   do_test_pending();
 
   try {
     _("Fetching a WBO record");
     let rec = new WBORecord("coll", "record");
-    rec.fetch(Service.resource("http://localhost:8080/record"));
+    rec.fetch(Service.resource(server.baseURI + "/record"));
     do_check_eq(rec.id, "asdf-1234-asdf-1234"); // NOT "record"!
 
     do_check_eq(rec.modified, 2454725.98283);
     do_check_eq(typeof(rec.payload), "object");
     do_check_eq(rec.payload.cheese, "roquefort");
 
     _("Fetching a WBO record using the record manager");
-    let rec2 = Service.recordManager.get("http://localhost:8080/record2");
+    let rec2 = Service.recordManager.get(server.baseURI + "/record2");
     do_check_eq(rec2.id, "record2");
     do_check_eq(rec2.modified, 2454725.98284);
     do_check_eq(typeof(rec2.payload), "object");
     do_check_eq(rec2.payload.cheese, "gruyere");
     do_check_eq(Service.recordManager.response.status, 200);
 
     // Testing collection extraction.
     _("Extracting collection.");
--- a/services/sync/tests/unit/test_resource.js
+++ b/services/sync/tests/unit/test_resource.js
@@ -171,31 +171,31 @@ function run_test() {
     "/quota-error": server_quota_error
   });
 
   Svc.Prefs.set("network.numRetries", 1); // speed up test
 
   // This apparently has to come first in order for our PAC URL to be hit.
   // Don't put any other HTTP requests earlier in the file!
   _("Testing handling of proxy auth redirection.");
-  PACSystemSettings.PACURI = "http://localhost:8080/pac1";
+  PACSystemSettings.PACURI = server.baseURI + "/pac1";
   installFakePAC();
-  let proxiedRes = new Resource("http://localhost:8080/open");
+  let proxiedRes = new Resource(server.baseURI + "/open");
   let content = proxiedRes.get();
   do_check_true(pacFetched);
   do_check_true(fetched);
   do_check_eq(content, "This path exists");
   pacFetched = fetched = false;
   uninstallFakePAC();
 
   _("Resource object members");
-  let res = new Resource("http://localhost:8080/open");
+  let res = new Resource(server.baseURI + "/open");
   do_check_true(res.uri instanceof Ci.nsIURI);
-  do_check_eq(res.uri.spec, "http://localhost:8080/open");
-  do_check_eq(res.spec, "http://localhost:8080/open");
+  do_check_eq(res.uri.spec, server.baseURI + "/open");
+  do_check_eq(res.spec, server.baseURI + "/open");
   do_check_eq(typeof res.headers, "object");
   do_check_eq(typeof res.authenticator, "object");
   // Initially res.data is null since we haven't performed a GET or
   // PUT/POST request yet.
   do_check_eq(res.data, null);
 
   _("GET a non-password-protected resource");
   content = res.get();
@@ -225,52 +225,52 @@ function run_test() {
   }
   do_check_true(didThrow);
   do_check_eq(debugMessages.length, 1);
   do_check_eq(debugMessages[0],
               "Parse fail: Response body starts: \"\"This path exists\"\".");
   logger.debug = dbg;
 
   _("Test that the BasicAuthenticator doesn't screw up header case.");
-  let res1 = new Resource("http://localhost:8080/foo");
+  let res1 = new Resource(server.baseURI + "/foo");
   res1.setHeader("Authorization", "Basic foobar");
   do_check_eq(res1.headers["authorization"], "Basic foobar");
 
   _("GET a password protected resource (test that it'll fail w/o pass, no throw)");
-  let res2 = new Resource("http://localhost:8080/protected");
+  let res2 = new Resource(server.baseURI + "/protected");
   content = res2.get();
   do_check_eq(content, "This path exists and is protected - failed");
   do_check_eq(content.status, 401);
   do_check_false(content.success);
 
   _("GET a password protected resource");
-  let res3 = new Resource("http://localhost:8080/protected");
+  let res3 = new Resource(server.baseURI + "/protected");
   let identity = new IdentityManager();
   let auth = identity.getBasicResourceAuthenticator("guest", "guest");
   res3.authenticator = auth;
   do_check_eq(res3.authenticator, auth);
   content = res3.get();
   do_check_eq(content, "This path exists and is protected");
   do_check_eq(content.status, 200);
   do_check_true(content.success);
 
   _("GET a non-existent resource (test that it'll fail, but not throw)");
-  let res4 = new Resource("http://localhost:8080/404");
+  let res4 = new Resource(server.baseURI + "/404");
   content = res4.get();
   do_check_eq(content, "File not found");
   do_check_eq(content.status, 404);
   do_check_false(content.success);
 
   // Check some headers of the 404 response
   do_check_eq(content.headers.connection, "close");
   do_check_eq(content.headers.server, "httpd.js");
   do_check_eq(content.headers["content-length"], 14);
 
   _("PUT to a resource (string)");
-  let res5 = new Resource("http://localhost:8080/upload");
+  let res5 = new Resource(server.baseURI + "/upload");
   content = res5.put(JSON.stringify(sample_data));
   do_check_eq(content, "Valid data upload via PUT");
   do_check_eq(content.status, 200);
   do_check_eq(res5.data, content);
 
   _("PUT to a resource (object)");
   content = res5.put(sample_data);
   do_check_eq(content, "Valid data upload via PUT");
@@ -313,38 +313,38 @@ function run_test() {
   _("POST without data arg (uses resource.data) (object)");
   res5.data = sample_data;
   content = res5.post();
   do_check_eq(content, "Valid data upload via POST");
   do_check_eq(content.status, 200);
   do_check_eq(res5.data, content);
 
   _("DELETE a resource");
-  let res6 = new Resource("http://localhost:8080/delete");
+  let res6 = new Resource(server.baseURI + "/delete");
   content = res6.delete();
   do_check_eq(content, "This resource has been deleted")
   do_check_eq(content.status, 200);
 
   _("JSON conversion of response body");
-  let res7 = new Resource("http://localhost:8080/json");
+  let res7 = new Resource(server.baseURI + "/json");
   content = res7.get();
   do_check_eq(content, JSON.stringify(sample_data));
   do_check_eq(content.status, 200);
   do_check_eq(JSON.stringify(content.obj), JSON.stringify(sample_data));
 
   _("X-Weave-Timestamp header updates AsyncResource.serverTime");
   // Before having received any response containing the
   // X-Weave-Timestamp header, AsyncResource.serverTime is null.
   do_check_eq(AsyncResource.serverTime, null);
-  let res8 = new Resource("http://localhost:8080/timestamp");
+  let res8 = new Resource(server.baseURI + "/timestamp");
   content = res8.get();
   do_check_eq(AsyncResource.serverTime, TIMESTAMP);
 
   _("GET: no special request headers");
-  let res9 = new Resource("http://localhost:8080/headers");
+  let res9 = new Resource(server.baseURI + "/headers");
   content = res9.get();
   do_check_eq(content, '{}');
 
   _("PUT: Content-Type defaults to text/plain");
   content = res9.put('data');
   do_check_eq(content, JSON.stringify({"content-type": "text/plain"}));
 
   _("POST: Content-Type defaults to text/plain");
@@ -382,34 +382,34 @@ function run_test() {
 
   _("X-Weave-Backoff header notifies observer");
   let backoffInterval;
   function onBackoff(subject, data) {
     backoffInterval = subject;
   }
   Observers.add("weave:service:backoff:interval", onBackoff);
 
-  let res10 = new Resource("http://localhost:8080/backoff");
+  let res10 = new Resource(server.baseURI + "/backoff");
   content = res10.get();
   do_check_eq(backoffInterval, 600);
 
 
   _("X-Weave-Quota-Remaining header notifies observer on successful requests.");
   let quotaValue;
   function onQuota(subject, data) {
     quotaValue = subject;
   }
   Observers.add("weave:service:quota:remaining", onQuota);
 
-  res10 = new Resource("http://localhost:8080/quota-error");
+  res10 = new Resource(server.baseURI + "/quota-error");
   content = res10.get();
   do_check_eq(content.status, 400);
   do_check_eq(quotaValue, undefined); // HTTP 400, so no observer notification.
 
-  res10 = new Resource("http://localhost:8080/quota-notice");
+  res10 = new Resource(server.baseURI + "/quota-notice");
   content = res10.get();
   do_check_eq(content.status, 200);
   do_check_eq(quotaValue, 1048576);
 
 
   _("Error handling in _request() preserves exception information");
   let error;
   let res11 = new Resource("http://localhost:12345/does/not/exist");
@@ -418,17 +418,17 @@ function run_test() {
   } catch(ex) {
     error = ex;
   }
   do_check_eq(error.result, Cr.NS_ERROR_CONNECTION_REFUSED);
   do_check_eq(error.message, "NS_ERROR_CONNECTION_REFUSED");
   do_check_eq(typeof error.stack, "string");
 
   _("Checking handling of errors in onProgress.");
-  let res18 = new Resource("http://localhost:8080/json");
+  let res18 = new Resource(server.baseURI + "/json");
   let onProgress = function(rec) {
     // Provoke an XPC exception without a Javascript wrapper.
     Services.io.newURI("::::::::", null, null);
   };
   res18._onProgress = onProgress;
   let oldWarn = res18._log.warn;
   let warnings = [];
   res18._log.warn = function(msg) { warnings.push(msg) };
@@ -439,20 +439,20 @@ function run_test() {
     error = ex;
   }
 
   // It throws and logs.
   do_check_eq(error.result, Cr.NS_ERROR_MALFORMED_URI);
   do_check_eq(error, "Error: NS_ERROR_MALFORMED_URI");
   do_check_eq(warnings.pop(),
               "Got exception calling onProgress handler during fetch of " +
-              "http://localhost:8080/json");
+              server.baseURI + "/json");
 
   // And this is what happens if JS throws an exception.
-  res18 = new Resource("http://localhost:8080/json");
+  res18 = new Resource(server.baseURI + "/json");
   onProgress = function(rec) {
     throw "BOO!";
   };
   res18._onProgress = onProgress;
   oldWarn = res18._log.warn;
   warnings = [];
   res18._log.warn = function(msg) { warnings.push(msg) };
   error = undefined;
@@ -462,21 +462,21 @@ function run_test() {
     error = ex;
   }
 
   // It throws and logs.
   do_check_eq(error.result, Cr.NS_ERROR_XPC_JS_THREW_STRING);
   do_check_eq(error, "Error: NS_ERROR_XPC_JS_THREW_STRING");
   do_check_eq(warnings.pop(),
               "Got exception calling onProgress handler during fetch of " +
-              "http://localhost:8080/json");
+              server.baseURI + "/json");
 
 
   _("Ensure channel timeouts are thrown appropriately.");
-  let res19 = new Resource("http://localhost:8080/json");
+  let res19 = new Resource(server.baseURI + "/json");
   res19.ABORT_TIMEOUT = 0;
   error = undefined;
   try {
     content = res19.get();
   } catch (ex) {
     error = ex;
   }
   do_check_eq(error.result, Cr.NS_ERROR_NET_TIMEOUT);
--- a/services/sync/tests/unit/test_resource_async.js
+++ b/services/sync/tests/unit/test_resource_async.js
@@ -2,19 +2,16 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 Cu.import("resource://services-common/log4moz.js");
 Cu.import("resource://services-common/observers.js");
 Cu.import("resource://services-sync/identity.js");
 Cu.import("resource://services-sync/resource.js");
 Cu.import("resource://services-sync/util.js");
 
-const RES_UPLOAD_URL = "http://localhost:8080/upload";
-const RES_HEADERS_URL = "http://localhost:8080/headers";
-
 let logger;
 
 let fetched = false;
 function server_open(metadata, response) {
   let body;
   if (metadata.method == "GET") {
     fetched = true;
     body = "This path exists";
@@ -168,19 +165,19 @@ function run_test() {
 add_test(function test_proxy_auth_redirect() {
   _("Ensure that a proxy auth redirect (which switches out our channel) " +
     "doesn't break AsyncResource.");
   let server = httpd_setup({
     "/open": server_open,
     "/pac2": server_pac
   });
 
-  PACSystemSettings.PACURI = "http://localhost:8080/pac2";
+  PACSystemSettings.PACURI = server.baseURI + "/pac2";
   installFakePAC();
-  let res = new AsyncResource("http://localhost:8080/open");
+  let res = new AsyncResource(server.baseURI + "/open");
   res.get(function (error, result) {
     do_check_true(!error);
     do_check_true(pacFetched);
     do_check_true(fetched);
     do_check_eq("This path exists", result);
     pacFetched = fetched = false;
     uninstallFakePAC();
     server.stop(run_next_test);
@@ -194,28 +191,29 @@ add_test(function test_new_channel() {
   function resourceHandler(metadata, response) {
     resourceRequested = true;
 
     let body = "Test";
     response.setHeader("Content-Type", "text/plain");
     response.bodyOutputStream.write(body, body.length);
   }
 
+  let locationURL;
   function redirectHandler(metadata, response) {
     let body = "Redirecting";
     response.setStatusLine(metadata.httpVersion, 307, "TEMPORARY REDIRECT");
-    response.setHeader("Location", "http://localhost:8080/resource");
+    response.setHeader("Location", locationURL);
     response.bodyOutputStream.write(body, body.length);
   }
 
   let server = httpd_setup({"/resource": resourceHandler,
-                            "/redirect": redirectHandler},
-                            8080);
+                            "/redirect": redirectHandler});
+  locationURL = server.baseURI + "/resource";
 
-  let request = new AsyncResource("http://localhost:8080/redirect");
+  let request = new AsyncResource(server.baseURI + "/redirect");
   request.get(function onRequest(error, content) {
     do_check_null(error);
     do_check_true(resourceRequested);
     do_check_eq(200, content.status);
     do_check_true("content-type" in content.headers);
     do_check_eq("text/plain", content.headers["content-type"]);
 
     server.stop(run_next_test);
@@ -241,32 +239,33 @@ add_test(function setup() {
     "/quota-error": server_quota_error
   });
 
   run_next_test();
 });
 
 add_test(function test_members() {
   _("Resource object members");
-  let res = new AsyncResource("http://localhost:8080/open");
+  let uri = server.baseURI + "/open";
+  let res = new AsyncResource(uri);
   do_check_true(res.uri instanceof Ci.nsIURI);
-  do_check_eq(res.uri.spec, "http://localhost:8080/open");
-  do_check_eq(res.spec, "http://localhost:8080/open");
+  do_check_eq(res.uri.spec, uri);
+  do_check_eq(res.spec, uri);
   do_check_eq(typeof res.headers, "object");
   do_check_eq(typeof res.authenticator, "object");
   // Initially res.data is null since we haven't performed a GET or
   // PUT/POST request yet.
   do_check_eq(res.data, null);
 
   run_next_test();
 });
 
 add_test(function test_get() {
   _("GET a non-password-protected resource");
-  let res = new AsyncResource("http://localhost:8080/open");
+  let res = new AsyncResource(server.baseURI + "/open");
   res.get(function (error, content) {
     do_check_eq(error, null);
     do_check_eq(content, "This path exists");
     do_check_eq(content.status, 200);
     do_check_true(content.success);
     // res.data has been updated with the result from the request
     do_check_eq(res.data, content);
 
@@ -294,55 +293,55 @@ add_test(function test_get() {
     logger.debug = dbg;
 
     run_next_test();
   });
 });
 
 add_test(function test_basicauth() {
   _("Test that the BasicAuthenticator doesn't screw up header case.");
-  let res1 = new AsyncResource("http://localhost:8080/foo");
+  let res1 = new AsyncResource(server.baseURI + "/foo");
   res1.setHeader("Authorization", "Basic foobar");
   do_check_eq(res1._headers["authorization"], "Basic foobar");
   do_check_eq(res1.headers["authorization"], "Basic foobar");
 
   run_next_test();
 });
 
 add_test(function test_get_protected_fail() {
   _("GET a password protected resource (test that it'll fail w/o pass, no throw)");
-  let res2 = new AsyncResource("http://localhost:8080/protected");
+  let res2 = new AsyncResource(server.baseURI + "/protected");
   res2.get(function (error, content) {
     do_check_eq(error, null);
     do_check_eq(content, "This path exists and is protected - failed");
     do_check_eq(content.status, 401);
     do_check_false(content.success);
     run_next_test();
   });
 });
 
 add_test(function test_get_protected_success() {
   _("GET a password protected resource");
   let identity = new IdentityManager();
   let auth = identity.getBasicResourceAuthenticator("guest", "guest");
-  let res3 = new AsyncResource("http://localhost:8080/protected");
+  let res3 = new AsyncResource(server.baseURI + "/protected");
   res3.authenticator = auth;
   do_check_eq(res3.authenticator, auth);
   res3.get(function (error, content) {
     do_check_eq(error, null);
     do_check_eq(content, "This path exists and is protected");
     do_check_eq(content.status, 200);
     do_check_true(content.success);
     run_next_test();
   });
 });
 
 add_test(function test_get_404() {
   _("GET a non-existent resource (test that it'll fail, but not throw)");
-  let res4 = new AsyncResource("http://localhost:8080/404");
+  let res4 = new AsyncResource(server.baseURI + "/404");
   res4.get(function (error, content) {
     do_check_eq(error, null);
     do_check_eq(content, "File not found");
     do_check_eq(content.status, 404);
     do_check_false(content.success);
 
     // Check some headers of the 404 response
     do_check_eq(content.headers.connection, "close");
@@ -350,271 +349,271 @@ add_test(function test_get_404() {
     do_check_eq(content.headers["content-length"], 14);
 
     run_next_test();
   });
 });
 
 add_test(function test_put_string() {
   _("PUT to a resource (string)");
-  let res_upload = new AsyncResource(RES_UPLOAD_URL);
+  let res_upload = new AsyncResource(server.baseURI + "/upload");
   res_upload.put(JSON.stringify(sample_data), function(error, content) {
     do_check_eq(error, null);
     do_check_eq(content, "Valid data upload via PUT");
     do_check_eq(content.status, 200);
     do_check_eq(res_upload.data, content);
     run_next_test();
   });
 });
 
 add_test(function test_put_object() {
   _("PUT to a resource (object)");
-  let res_upload = new AsyncResource(RES_UPLOAD_URL);
+  let res_upload = new AsyncResource(server.baseURI + "/upload");
   res_upload.put(sample_data, function (error, content) {
     do_check_eq(error, null);
     do_check_eq(content, "Valid data upload via PUT");
     do_check_eq(content.status, 200);
     do_check_eq(res_upload.data, content);
     run_next_test();
   });
 });
 
 add_test(function test_put_data_string() {
   _("PUT without data arg (uses resource.data) (string)");
-  let res_upload = new AsyncResource(RES_UPLOAD_URL);
+  let res_upload = new AsyncResource(server.baseURI + "/upload");
   res_upload.data = JSON.stringify(sample_data);
   res_upload.put(function (error, content) {
     do_check_eq(error, null);
     do_check_eq(content, "Valid data upload via PUT");
     do_check_eq(content.status, 200);
     do_check_eq(res_upload.data, content);
     run_next_test();
   });
 });
 
 add_test(function test_put_data_object() {
   _("PUT without data arg (uses resource.data) (object)");
-  let res_upload = new AsyncResource(RES_UPLOAD_URL);
+  let res_upload = new AsyncResource(server.baseURI + "/upload");
   res_upload.data = sample_data;
   res_upload.put(function (error, content) {
     do_check_eq(error, null);
     do_check_eq(content, "Valid data upload via PUT");
     do_check_eq(content.status, 200);
     do_check_eq(res_upload.data, content);
     run_next_test();
   });
 });
 
 add_test(function test_post_string() {
   _("POST to a resource (string)");
-  let res_upload = new AsyncResource(RES_UPLOAD_URL);
+  let res_upload = new AsyncResource(server.baseURI + "/upload");
   res_upload.post(JSON.stringify(sample_data), function (error, content) {
     do_check_eq(error, null);
     do_check_eq(content, "Valid data upload via POST");
     do_check_eq(content.status, 200);
     do_check_eq(res_upload.data, content);
     run_next_test();
   });
 });
 
 add_test(function test_post_object() {
   _("POST to a resource (object)");
-  let res_upload = new AsyncResource(RES_UPLOAD_URL);
+  let res_upload = new AsyncResource(server.baseURI + "/upload");
   res_upload.post(sample_data, function (error, content) {
     do_check_eq(error, null);
     do_check_eq(content, "Valid data upload via POST");
     do_check_eq(content.status, 200);
     do_check_eq(res_upload.data, content);
     run_next_test();
   });
 });
 
 add_test(function test_post_data_string() {
   _("POST without data arg (uses resource.data) (string)");
-  let res_upload = new AsyncResource(RES_UPLOAD_URL);
+  let res_upload = new AsyncResource(server.baseURI + "/upload");
   res_upload.data = JSON.stringify(sample_data);
   res_upload.post(function (error, content) {
     do_check_eq(error, null);
     do_check_eq(content, "Valid data upload via POST");
     do_check_eq(content.status, 200);
     do_check_eq(res_upload.data, content);
     run_next_test();
   });
 });
 
 add_test(function test_post_data_object() {
   _("POST without data arg (uses resource.data) (object)");
-  let res_upload = new AsyncResource(RES_UPLOAD_URL);
+  let res_upload = new AsyncResource(server.baseURI + "/upload");
   res_upload.data = sample_data;
   res_upload.post(function (error, content) {
     do_check_eq(error, null);
     do_check_eq(content, "Valid data upload via POST");
     do_check_eq(content.status, 200);
     do_check_eq(res_upload.data, content);
     run_next_test();
   });
 });
 
 add_test(function test_delete() {
   _("DELETE a resource");
-  let res6 = new AsyncResource("http://localhost:8080/delete");
+  let res6 = new AsyncResource(server.baseURI + "/delete");
   res6.delete(function (error, content) {
     do_check_eq(error, null);
     do_check_eq(content, "This resource has been deleted");
     do_check_eq(content.status, 200);
     run_next_test();
   });
 });
 
 add_test(function test_json_body() {
   _("JSON conversion of response body");
-  let res7 = new AsyncResource("http://localhost:8080/json");
+  let res7 = new AsyncResource(server.baseURI + "/json");
   res7.get(function (error, content) {
     do_check_eq(error, null);
     do_check_eq(content, JSON.stringify(sample_data));
     do_check_eq(content.status, 200);
     do_check_eq(JSON.stringify(content.obj), JSON.stringify(sample_data));
     run_next_test();
   });
 });
 
 add_test(function test_weave_timestamp() {
   _("X-Weave-Timestamp header updates AsyncResource.serverTime");
   // Before having received any response containing the
   // X-Weave-Timestamp header, AsyncResource.serverTime is null.
   do_check_eq(AsyncResource.serverTime, null);
-  let res8 = new AsyncResource("http://localhost:8080/timestamp");
+  let res8 = new AsyncResource(server.baseURI + "/timestamp");
   res8.get(function (error, content) {
     do_check_eq(error, null);
     do_check_eq(AsyncResource.serverTime, TIMESTAMP);
     run_next_test();
   });
 });
 
 add_test(function test_get_no_headers() {
   _("GET: no special request headers");
-  let res_headers = new AsyncResource(RES_HEADERS_URL);
+  let res_headers = new AsyncResource(server.baseURI + "/headers");
   res_headers.get(function (error, content) {
     do_check_eq(error, null);
     do_check_eq(content, '{}');
     run_next_test();
   });
 });
 
 add_test(function test_put_default_content_type() {
   _("PUT: Content-Type defaults to text/plain");
-  let res_headers = new AsyncResource(RES_HEADERS_URL);
+  let res_headers = new AsyncResource(server.baseURI + "/headers");
   res_headers.put('data', function (error, content) {
     do_check_eq(error, null);
     do_check_eq(content, JSON.stringify({"content-type": "text/plain"}));
     run_next_test();
   });
 });
 
 add_test(function test_post_default_content_type() {
   _("POST: Content-Type defaults to text/plain");
-  let res_headers = new AsyncResource(RES_HEADERS_URL);
+  let res_headers = new AsyncResource(server.baseURI + "/headers");
   res_headers.post('data', function (error, content) {
     do_check_eq(error, null);
     do_check_eq(content, JSON.stringify({"content-type": "text/plain"}));
     run_next_test();
   });
 });
 
 add_test(function test_setHeader() {
   _("setHeader(): setting simple header");
-  let res_headers = new AsyncResource(RES_HEADERS_URL);
+  let res_headers = new AsyncResource(server.baseURI + "/headers");
   res_headers.setHeader('X-What-Is-Weave', 'awesome');
   do_check_eq(res_headers.headers['x-what-is-weave'], 'awesome');
   res_headers.get(function (error, content) {
     do_check_eq(error, null);
     do_check_eq(content, JSON.stringify({"x-what-is-weave": "awesome"}));
     run_next_test();
   });
 });
 
 add_test(function test_setHeader_overwrite() {
   _("setHeader(): setting multiple headers, overwriting existing header");
-  let res_headers = new AsyncResource(RES_HEADERS_URL);
+  let res_headers = new AsyncResource(server.baseURI + "/headers");
   res_headers.setHeader('X-WHAT-is-Weave', 'more awesomer');
   res_headers.setHeader('X-Another-Header', 'hello world');
   do_check_eq(res_headers.headers['x-what-is-weave'], 'more awesomer');
   do_check_eq(res_headers.headers['x-another-header'], 'hello world');
   res_headers.get(function (error, content) {
     do_check_eq(error, null);
     do_check_eq(content, JSON.stringify({"x-another-header": "hello world",
                                          "x-what-is-weave": "more awesomer"}));
 
     run_next_test();
   });
 });
 
 add_test(function test_headers_object() {
   _("Setting headers object");
-  let res_headers = new AsyncResource(RES_HEADERS_URL);
+  let res_headers = new AsyncResource(server.baseURI + "/headers");
   res_headers.headers = {};
   res_headers.get(function (error, content) {
     do_check_eq(error, null);
     do_check_eq(content, "{}");
     run_next_test();
   });
 });
 
 add_test(function test_put_override_content_type() {
   _("PUT: override default Content-Type");
-  let res_headers = new AsyncResource(RES_HEADERS_URL);
+  let res_headers = new AsyncResource(server.baseURI + "/headers");
   res_headers.setHeader('Content-Type', 'application/foobar');
   do_check_eq(res_headers.headers['content-type'], 'application/foobar');
   res_headers.put('data', function (error, content) {
     do_check_eq(error, null);
     do_check_eq(content, JSON.stringify({"content-type": "application/foobar"}));
     run_next_test();
   });
 });
 
 add_test(function test_post_override_content_type() {
   _("POST: override default Content-Type");
-  let res_headers = new AsyncResource(RES_HEADERS_URL);
+  let res_headers = new AsyncResource(server.baseURI + "/headers");
   res_headers.setHeader('Content-Type', 'application/foobar');
   res_headers.post('data', function (error, content) {
     do_check_eq(error, null);
     do_check_eq(content, JSON.stringify({"content-type": "application/foobar"}));
     run_next_test();
   });
 });
 
 add_test(function test_weave_backoff() {
   _("X-Weave-Backoff header notifies observer");
   let backoffInterval;
   function onBackoff(subject, data) {
     backoffInterval = subject;
   }
   Observers.add("weave:service:backoff:interval", onBackoff);
 
-  let res10 = new AsyncResource("http://localhost:8080/backoff");
+  let res10 = new AsyncResource(server.baseURI + "/backoff");
   res10.get(function (error, content) {
     do_check_eq(error, null);
     do_check_eq(backoffInterval, 600);
     run_next_test();
   });
 });
 
 add_test(function test_quota_error() {
   _("X-Weave-Quota-Remaining header notifies observer on successful requests.");
-  let res10 = new AsyncResource("http://localhost:8080/quota-error");
+  let res10 = new AsyncResource(server.baseURI + "/quota-error");
   res10.get(function (error, content) {
     do_check_eq(error, null);
     do_check_eq(content.status, 400);
     do_check_eq(quotaValue, undefined); // HTTP 400, so no observer notification.
     run_next_test();
   });
 });
 
 add_test(function test_quota_notice() {
-  let res10 = new AsyncResource("http://localhost:8080/quota-notice");
+  let res10 = new AsyncResource(server.baseURI + "/quota-notice");
   res10.get(function (error, content) {
     do_check_eq(error, null);
     do_check_eq(content.status, 200);
     do_check_eq(quotaValue, 1048576);
     run_next_test();
   });
 });
 
@@ -626,60 +625,60 @@ add_test(function test_preserve_exceptio
     do_check_eq(error.result, Cr.NS_ERROR_CONNECTION_REFUSED);
     do_check_eq(error.message, "NS_ERROR_CONNECTION_REFUSED");
     run_next_test();
   });
 });
 
 add_test(function test_xpc_exception_handling() {
   _("Exception handling inside fetches.");
-  let res14 = new AsyncResource("http://localhost:8080/json");
+  let res14 = new AsyncResource(server.baseURI + "/json");
   res14._onProgress = function(rec) {
     // Provoke an XPC exception without a Javascript wrapper.
     Services.io.newURI("::::::::", null, null);
   };
   let warnings = [];
   res14._log.warn = function(msg) { warnings.push(msg); };
 
   res14.get(function (error, content) {
     do_check_eq(error.result, Cr.NS_ERROR_MALFORMED_URI);
     do_check_eq(error.message, "NS_ERROR_MALFORMED_URI");
     do_check_eq(content, null);
     do_check_eq(warnings.pop(),
                 "Got exception calling onProgress handler during fetch of " +
-                "http://localhost:8080/json");
+                server.baseURI + "/json");
 
     run_next_test();
   });
 });
 
 add_test(function test_js_exception_handling() {
   _("JS exception handling inside fetches.");
-  let res15 = new AsyncResource("http://localhost:8080/json");
+  let res15 = new AsyncResource(server.baseURI + "/json");
   res15._onProgress = function(rec) {
     throw "BOO!";
   };
   let warnings = [];
   res15._log.warn = function(msg) { warnings.push(msg); };
 
   res15.get(function (error, content) {
     do_check_eq(error.result, Cr.NS_ERROR_XPC_JS_THREW_STRING);
     do_check_eq(error.message, "NS_ERROR_XPC_JS_THREW_STRING");
     do_check_eq(content, null);
     do_check_eq(warnings.pop(),
                 "Got exception calling onProgress handler during fetch of " +
-                "http://localhost:8080/json");
+                server.baseURI + "/json");
 
     run_next_test();
   });
 });
 
 add_test(function test_timeout() {
   _("Ensure channel timeouts are thrown appropriately.");
-  let res19 = new AsyncResource("http://localhost:8080/json");
+  let res19 = new AsyncResource(server.baseURI + "/json");
   res19.ABORT_TIMEOUT = 0;
   res19.get(function (error, content) {
     do_check_eq(error.result, Cr.NS_ERROR_NET_TIMEOUT);
     run_next_test();
   });
 });
 
 add_test(function test_uri_construction() {
@@ -705,20 +704,20 @@ add_test(function test_not_sending_cooki
   function handler(metadata, response) {
     let body = "COOKIE!";
     response.setStatusLine(metadata.httpVersion, 200, "OK");
     response.bodyOutputStream.write(body, body.length);
     do_check_false(metadata.hasHeader("Cookie"));
   }
   let cookieSer = Cc["@mozilla.org/cookieService;1"]
                     .getService(Ci.nsICookieService);
-  let uri = CommonUtils.makeURI("http://localhost:8080");
+  let uri = CommonUtils.makeURI(server.baseURI);
   cookieSer.setCookieString(uri, null, "test=test; path=/;", null);
 
-  let res = new AsyncResource("http://localhost:8080/test");
+  let res = new AsyncResource(server.baseURI + "/test");
   res.get(function (error) {
     do_check_null(error);
     do_check_true(this.response.success);
     do_check_eq("COOKIE!", this.response.body);
     server.stop(run_next_test);
   });
 });
 
--- a/services/sync/tests/unit/test_resource_ua.js
+++ b/services/sync/tests/unit/test_resource_ua.js
@@ -2,18 +2,16 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 Cu.import("resource://services-sync/constants.js");
 Cu.import("resource://services-sync/resource.js");
 Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/util.js");
 Cu.import("resource://testing-common/services/sync/utils.js");
 
-const TEST_GET_URL = "http://localhost:8080/1.1/johndoe/storage/meta/global";
-
 // Tracking info/collections.
 let collectionsHelper = track_collections_helper();
 let collections = collectionsHelper.collections;
 
 let meta_global;
 let server;
 
 let expectedUA;
@@ -21,25 +19,27 @@ let ua;
 function uaHandler(f) {
   return function(request, response) {
     ua = request.getHeader("User-Agent");
     return f(request, response);
   };
 }
 
 function run_test() {
+  Log4Moz.repository.rootLogger.addAppender(new Log4Moz.DumpAppender());
   meta_global = new ServerWBO('global');
   server = httpd_setup({
     "/1.1/johndoe/info/collections": uaHandler(collectionsHelper.handler),
     "/1.1/johndoe/storage/meta/global": uaHandler(meta_global.handler()),
   });
 
   setBasicCredentials("johndoe", "ilovejane");
-  Service.serverURL  = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
+  Service.serverURL = server.baseURI + "/";
+  Service.clusterURL = server.baseURI + "/";
+  _("Server URL: " + server.baseURI);
 
   expectedUA = Services.appinfo.name + "/" + Services.appinfo.version +
                " FxSync/" + WEAVE_VERSION + "." +
                Services.appinfo.appBuildID;
 
   run_next_test();
 }
 
@@ -49,41 +49,41 @@ add_test(function test_fetchInfo() {
   _("User-Agent: " + ua);
   do_check_eq(ua, expectedUA + ".desktop");
   ua = "";
   run_next_test();
 });
 
 add_test(function test_desktop_post() {
   _("Testing direct Resource POST.");
-  let r = new AsyncResource(TEST_GET_URL);
+  let r = new AsyncResource(server.baseURI + "/1.1/johndoe/storage/meta/global");
   r.post("foo=bar", function (error, content) {
     _("User-Agent: " + ua);
     do_check_eq(ua, expectedUA + ".desktop");
     ua = "";
     run_next_test();
   });
 });
 
 add_test(function test_desktop_get() {
   _("Testing async.");
   Svc.Prefs.set("client.type", "desktop");
-  let r = new AsyncResource(TEST_GET_URL);
+  let r = new AsyncResource(server.baseURI + "/1.1/johndoe/storage/meta/global");
   r.get(function(error, content) {
     _("User-Agent: " + ua);
     do_check_eq(ua, expectedUA + ".desktop");
     ua = "";
     run_next_test();
   });
 });
 
 add_test(function test_mobile_get() {
   _("Testing mobile.");
   Svc.Prefs.set("client.type", "mobile");
-  let r = new AsyncResource(TEST_GET_URL);
+  let r = new AsyncResource(server.baseURI + "/1.1/johndoe/storage/meta/global");
   r.get(function (error, content) {
     _("User-Agent: " + ua);
     do_check_eq(ua, expectedUA + ".mobile");
     ua = "";
     run_next_test();
   });
 });
 
--- a/services/sync/tests/unit/test_score_triggers.js
+++ b/services/sync/tests/unit/test_score_triggers.js
@@ -38,18 +38,18 @@ function sync_httpd_setup() {
 
   let cl = new ServerCollection();
   handlers["/1.1/johndoe/storage/clients"] =
     upd("clients", cl.handler());
 
   return httpd_setup(handlers);
 }
 
-function setUp() {
-  new SyncTestingInfrastructure("johndoe", "ilovejane", "sekrit");
+function setUp(server) {
+  new SyncTestingInfrastructure(server, "johndoe", "ilovejane", "sekrit");
 }
 
 function run_test() {
   initTestLogging("Trace");
 
   Log4Moz.repository.getLogger("Sync.Service").level = Log4Moz.Level.Trace;
 
   run_next_test();
@@ -75,17 +75,17 @@ add_test(function test_tracker_score_upd
     Svc.Obs.remove("weave:engine:score:updated", onScoreUpdated);
     tracker.resetScore();
     run_next_test();
   }
 });
 
 add_test(function test_sync_triggered() {
   let server = sync_httpd_setup();
-  setUp();
+  setUp(server);
 
   Service.login();
 
   Service.scheduler.syncThreshold = MULTI_DEVICE_THRESHOLD;
   Svc.Obs.add("weave:service:sync:finish", function onSyncFinish() {
     Svc.Obs.remove("weave:service:sync:finish", onSyncFinish);
     _("Sync completed!");
     server.stop(run_next_test);
@@ -98,17 +98,17 @@ add_test(function test_sync_triggered() 
 add_test(function test_clients_engine_sync_triggered() {
   _("Ensure that client engine score changes trigger a sync.");
 
   // The clients engine is not registered like other engines. Therefore,
   // it needs special treatment throughout the code. Here, we verify the
   // global score tracker gives it that treatment. See bug 676042 for more.
 
   let server = sync_httpd_setup();
-  setUp();
+  setUp(server);
   Service.login();
 
   const TOPIC = "weave:service:sync:finish";
   Svc.Obs.add(TOPIC, function onSyncFinish() {
     Svc.Obs.remove(TOPIC, onSyncFinish);
     _("Sync due to clients engine change completed.");
     server.stop(run_next_test);
   });
@@ -116,17 +116,17 @@ add_test(function test_clients_engine_sy
   Service.scheduler.syncThreshold = MULTI_DEVICE_THRESHOLD;
   do_check_eq(Status.login, LOGIN_SUCCEEDED);
   Service.clientsEngine._tracker.score += SCORE_INCREMENT_XLARGE;
 });
 
 add_test(function test_incorrect_credentials_sync_not_triggered() {
   _("Ensure that score changes don't trigger a sync if Status.login != LOGIN_SUCCEEDED.");
   let server = sync_httpd_setup();
-  setUp();
+  setUp(server);
 
   // Ensure we don't actually try to sync.
   function onSyncStart() {
     do_throw("Should not get here!");
   }
   Svc.Obs.add("weave:service:sync:start", onSyncStart);
 
   // First wait >100ms (nsITimers can take up to that much time to fire, so
--- a/services/sync/tests/unit/test_service_changePassword.js
+++ b/services/sync/tests/unit/test_service_changePassword.js
@@ -24,31 +24,31 @@ add_test(function test_change_password()
     return function(request, response) {
       requestBody = readBytesFromInputStream(request.bodyInputStream);
       response.setStatusLine(request.httpVersion, statusCode, status);
       response.bodyOutputStream.write(body, body.length);
     };
   }
 
   try {
-    Service.serverURL = TEST_SERVER_URL;
-    Service.clusterURL = TEST_CLUSTER_URL;
+    Service.baseURI = "http://localhost:9999/";
     setBasicCredentials("johndoe", "ilovejane");
 
     _("changePassword() returns false for a network error, the password won't change.");
     let res = Service.changePassword("ILoveJane83");
     do_check_false(res);
     do_check_eq(Service.identity.basicPassword, "ilovejane");
 
     _("Let's fire up the server and actually change the password.");
     server = httpd_setup({
       "/user/1.0/johndoe/password": send(200, "OK", ""),
       "/user/1.0/janedoe/password": send(401, "Unauthorized", "Forbidden!")
     });
 
+    Service.serverURL = server.baseURI;
     res = Service.changePassword("ILoveJane83");
     do_check_true(res);
     do_check_eq(Service.identity.basicPassword, "ILoveJane83");
     do_check_eq(requestBody, "ILoveJane83");
 
     _("Make sure the password has been persisted in the login manager.");
     let logins = Services.logins.findLogins({}, PWDMGR_HOST, null,
                                             PWDMGR_PASSWORD_REALM);
--- a/services/sync/tests/unit/test_service_checkAccount.js
+++ b/services/sync/tests/unit/test_service_checkAccount.js
@@ -11,17 +11,17 @@ function run_test() {
     "/user/1.0/johndoe": httpd_handler(200, "OK", "1"),
     "/user/1.0/janedoe": httpd_handler(200, "OK", "0"),
     // john@doe.com
     "/user/1.0/7wohs32cngzuqt466q3ge7indszva4of": httpd_handler(200, "OK", "0"),
     // jane@doe.com
     "/user/1.0/vuuf3eqgloxpxmzph27f5a6ve7gzlrms": httpd_handler(200, "OK", "1")
   });
   try {
-    Service.serverURL = TEST_SERVER_URL;
+    Service.serverURL = server.baseURI;
 
     _("A 404 will be recorded as 'generic-server-error'");
     do_check_eq(Service.checkAccount("jimdoe"), "generic-server-error");
 
     _("Account that's available.");
     do_check_eq(Service.checkAccount("john@doe.com"), "available");
 
     _("Account that's not available.");
--- a/services/sync/tests/unit/test_service_cluster.js
+++ b/services/sync/tests/unit/test_service_cluster.js
@@ -14,32 +14,34 @@ function do_check_throws(func) {
   }
   do_check_true(raised);
 }
 
 add_test(function test_findCluster() {
   _("Test Service._findCluster()");
   let server;
   try {
-    Service.serverURL = TEST_SERVER_URL;
-    Service.identity.account = "johndoe";
-
     _("_findCluster() throws on network errors (e.g. connection refused).");
     do_check_throws(function() {
+      Service.serverURL = "http://dummy:9000/";
+      Service.identify.account = "johndoe";
       Service._clusterManager._findCluster();
     });
 
     server = httpd_setup({
       "/user/1.0/johndoe/node/weave": httpd_handler(200, "OK", "http://weave.user.node/"),
       "/user/1.0/jimdoe/node/weave": httpd_handler(200, "OK", "null"),
       "/user/1.0/janedoe/node/weave": httpd_handler(404, "Not Found", "Not Found"),
       "/user/1.0/juliadoe/node/weave": httpd_handler(400, "Bad Request", "Bad Request"),
       "/user/1.0/joedoe/node/weave": httpd_handler(500, "Server Error", "Server Error")
     });
 
+    Service.serverURL = server.baseURI;
+    Service.identity.account = "johndoe";
+
     _("_findCluster() returns the user's cluster node");
     let cluster = Service._clusterManager._findCluster();
     do_check_eq(cluster, "http://weave.user.node/");
 
     _("A 'null' response is converted to null.");
     Service.identity.account = "jimdoe";
     cluster = Service._clusterManager._findCluster();
     do_check_eq(cluster, null);
@@ -71,17 +73,17 @@ add_test(function test_findCluster() {
 
 add_test(function test_setCluster() {
   _("Test Service._setCluster()");
   let server = httpd_setup({
     "/user/1.0/johndoe/node/weave": httpd_handler(200, "OK", "http://weave.user.node/"),
     "/user/1.0/jimdoe/node/weave": httpd_handler(200, "OK", "null")
   });
   try {
-    Service.serverURL = TEST_SERVER_URL;
+    Service.serverURL = server.baseURI;
     Service.identity.account = "johndoe";
 
     _("Check initial state.");
     do_check_eq(Service.clusterURL, "");
 
     _("Set the cluster URL.");
     do_check_true(Service._clusterManager.setCluster());
     do_check_eq(Service.clusterURL, "http://weave.user.node/");
--- a/services/sync/tests/unit/test_service_createAccount.js
+++ b/services/sync/tests/unit/test_service_createAccount.js
@@ -27,17 +27,17 @@ function run_test() {
     // john@doe.com
     "/user/1.0/7wohs32cngzuqt466q3ge7indszva4of": send(200, "OK", "0"),
     // jane@doe.com
     "/user/1.0/vuuf3eqgloxpxmzph27f5a6ve7gzlrms": send(400, "Bad Request", "2"),
     // jim@doe.com
     "/user/1.0/vz6fhecgw5t3sgx3a4cektoiokyczkqd": send(500, "Server Error", "Server Error")
   });
   try {
-    Service.serverURL = TEST_SERVER_URL;
+    Service.serverURL = server.baseURI;
 
     _("Create an account.");
     let res = Service.createAccount("john@doe.com", "mysecretpw",
                                     "challenge", "response");
     do_check_eq(res, null);
     let payload = JSON.parse(requestBody);
     do_check_eq(payload.password, "mysecretpw");
     do_check_eq(payload.email, "john@doe.com");
--- a/services/sync/tests/unit/test_service_detect_upgrade.js
+++ b/services/sync/tests/unit/test_service_detect_upgrade.js
@@ -61,18 +61,17 @@ add_test(function v4_upgrade() {
     delete Svc.Session;
     Svc.Session = {
       getBrowserState: function () JSON.stringify(myTabs)
     };
 
     Service.status.resetSync();
 
     _("Logging in.");
-    Service.serverURL = TEST_SERVER_URL;
-    Service.clusterURL = TEST_CLUSTER_URL;
+    Service.serverURL = server.baseURI;
 
     Service.login("johndoe", "ilovejane", passphrase);
     do_check_true(Service.isLoggedIn);
     Service.verifyAndFetchSymmetricKeys();
     do_check_true(Service._remoteSetup());
 
     function test_out_of_date() {
       _("Old meta/global: " + JSON.stringify(meta_global));
@@ -97,18 +96,17 @@ add_test(function v4_upgrade() {
     _("Syncing after server has been upgraded and wiped.");
     Service.wipeServer();
     test_out_of_date();
 
     // Now's a great time to test what happens when keys get replaced.
     _("Syncing afresh...");
     Service.logout();
     Service.collectionKeys.clear();
-    Service.serverURL = TEST_SERVER_URL;
-    Service.clusterURL = TEST_CLUSTER_URL;
+    Service.serverURL = server.baseURI;
     meta_global.payload = JSON.stringify({"syncID": "foooooooooooooobbbbbbbbbbbb",
                                           "storageVersion": STORAGE_VERSION});
     collections.meta = Date.now() / 1000;
     Service.recordManager.set(Service.metaURL, meta_global);
     Service.login("johndoe", "ilovejane", passphrase);
     do_check_true(Service.isLoggedIn);
     Service.sync();
     do_check_true(Service.isLoggedIn);
@@ -234,18 +232,18 @@ add_test(function v5_upgrade() {
     delete Svc.Session;
     Svc.Session = {
       getBrowserState: function () JSON.stringify(myTabs)
     };
 
     Service.status.resetSync();
 
     setBasicCredentials("johndoe", "ilovejane", passphrase);
-    Service.serverURL = TEST_SERVER_URL;
-    Service.clusterURL = TEST_CLUSTER_URL;
+    Service.serverURL = server.baseURI + "/";
+    Service.clusterURL = server.baseURI + "/";
 
     // Test an upgrade where the contents of the server would cause us to error
     // -- keys decrypted with a different sync key, for example.
     _("Testing v4 -> v5 (or similar) upgrade.");
     function update_server_keys(syncKeyBundle, wboName, collWBO) {
       generateNewKeys(Service.collectionKeys);
       serverKeys = Service.collectionKeys.asWBO("crypto", wboName);
       serverKeys.encrypt(syncKeyBundle);
--- a/services/sync/tests/unit/test_service_getStorageInfo.js
+++ b/services/sync/tests/unit/test_service_getStorageInfo.js
@@ -7,30 +7,30 @@ Cu.import("resource://services-sync/serv
 Cu.import("resource://services-sync/util.js");
 Cu.import("resource://testing-common/services/sync/utils.js");
 
 let collections = {steam:  65.11328,
                    petrol: 82.488281,
                    diesel: 2.25488281};
 
 function run_test() {
-  setBasicCredentials("johndoe", "ilovejane");
-  Service.serverURL = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
-
   Log4Moz.repository.getLogger("Sync.Service").level = Log4Moz.Level.Trace;
   Log4Moz.repository.getLogger("Sync.StorageRequest").level = Log4Moz.Level.Trace;
   initTestLogging();
 
+  setBasicCredentials("johndoe", "ilovejane");
+
   run_next_test();
 }
 
 add_test(function test_success() {
   let handler = httpd_handler(200, "OK", JSON.stringify(collections));
   let server = httpd_setup({"/1.1/johndoe/info/collections": handler});
+  Service.serverURL = server.baseURI + "/";
+  Service.clusterURL = server.baseURI + "/";
 
   let request = Service.getStorageInfo("collections", function (error, info) {
     do_check_eq(error, null);
     do_check_true(Utils.deepEquals(info, collections));
 
     // Ensure that the request is sent off with the right bits.
     do_check_true(basic_auth_matches(handler.request,
                                      Service.identity.username,
@@ -60,27 +60,31 @@ add_test(function test_network_error() {
     do_check_eq(info, null);
     run_next_test();
   });
 });
 
 add_test(function test_http_error() {
   let handler = httpd_handler(500, "Oh noez", "Something went wrong!");
   let server = httpd_setup({"/1.1/johndoe/info/collections": handler});
+  Service.serverURL = server.baseURI + "/";
+  Service.clusterURL = server.baseURI + "/";
 
   let request = Service.getStorageInfo(INFO_COLLECTIONS, function (error, info) {
     do_check_eq(error.status, 500);
     do_check_eq(info, null);
     server.stop(run_next_test);
   });
 });
 
 add_test(function test_invalid_json() {
   let handler = httpd_handler(200, "OK", "Invalid JSON");
   let server = httpd_setup({"/1.1/johndoe/info/collections": handler});
+  Service.serverURL = server.baseURI + "/";
+  Service.clusterURL = server.baseURI + "/";
 
   let request = Service.getStorageInfo(INFO_COLLECTIONS, function (error, info) {
     do_check_eq(error.name, "SyntaxError");
     do_check_eq(error.message, "JSON.parse: unexpected character");
     do_check_eq(info, null);
     server.stop(run_next_test);
   });
 });
--- a/services/sync/tests/unit/test_service_login.js
+++ b/services/sync/tests/unit/test_service_login.js
@@ -38,38 +38,38 @@ add_test(function test_offline() {
     Services.io.offline = false;
   } finally {
     Svc.Prefs.resetBranch("");
     run_next_test();
   }
 });
 
 function setup() {
-  Service.serverURL = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
-
   let janeHelper = track_collections_helper();
   let janeU      = janeHelper.with_updated_collection;
   let janeColls  = janeHelper.collections;
   let johnHelper = track_collections_helper();
   let johnU      = johnHelper.with_updated_collection;
   let johnColls  = johnHelper.collections;
 
-  return httpd_setup({
+  let server = httpd_setup({
     "/1.1/johndoe/info/collections": login_handling(johnHelper.handler),
     "/1.1/janedoe/info/collections": login_handling(janeHelper.handler),
 
     // We need these handlers because we test login, and login
     // is where keys are generated or fetched.
     // TODO: have Jane fetch her keys, not generate them...
     "/1.1/johndoe/storage/crypto/keys": johnU("crypto", new ServerWBO("keys").handler()),
     "/1.1/johndoe/storage/meta/global": johnU("meta",   new ServerWBO("global").handler()),
     "/1.1/janedoe/storage/crypto/keys": janeU("crypto", new ServerWBO("keys").handler()),
     "/1.1/janedoe/storage/meta/global": janeU("meta",   new ServerWBO("global").handler())
   });
+
+  Service.serverURL = server.baseURI;
+  return server;
 }
 
 add_test(function test_login_logout() {
   let server = setup();
 
   try {
     _("Force the initial state.");
     Service.status.service = STATUS_OK;
--- a/services/sync/tests/unit/test_service_passwordUTF8.js
+++ b/services/sync/tests/unit/test_service_passwordUTF8.js
@@ -62,17 +62,17 @@ function run_test() {
   let server = httpd_setup({
     "/1.1/johndoe/info/collections":    login_handling(collectionsHelper.handler),
     "/1.1/johndoe/storage/meta/global": upd("meta",   new ServerWBO("global").handler()),
     "/1.1/johndoe/storage/crypto/keys": upd("crypto", new ServerWBO("keys").handler()),
     "/user/1.0/johndoe/password":       change_password
   });
 
   setBasicCredentials("johndoe", JAPANESE, "irrelevant");
-  Service.serverURL = TEST_SERVER_URL;
+  Service.serverURL = server.baseURI;
 
   try {
     _("Try to log in with the password.");
     server_password = "foobar";
     do_check_false(Service.verifyLogin());
     do_check_eq(server_password, "foobar");
 
     _("Make the server password the low byte version of our password.");
--- a/services/sync/tests/unit/test_service_startOver.js
+++ b/services/sync/tests/unit/test_service_startOver.js
@@ -68,18 +68,18 @@ add_test(function test_resetLocalData() 
 add_test(function test_removeClientData() {
   let engine = Service.engineManager.get("bla");
 
   // No cluster URL = no removal.
   do_check_false(engine.removed);
   Service.startOver();
   do_check_false(engine.removed);
 
-  Service.serverURL = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
+  Service.serverURL = "https://localhost/";
+  Service.clusterURL = Service.serverURL;
 
   do_check_false(engine.removed);
   Service.startOver();
   do_check_true(engine.removed);
 
   run_next_test();
 });
 
--- a/services/sync/tests/unit/test_service_startup.js
+++ b/services/sync/tests/unit/test_service_startup.js
@@ -8,18 +8,16 @@ Cu.import("resource://testing-common/ser
 
 Svc.Prefs.set("registerEngines", "Tab,Bookmarks,Form,History");
 Cu.import("resource://services-sync/service.js");
 
 function run_test() {
   _("When imported, Service.onStartup is called");
   initTestLogging("Trace");
 
-  new SyncTestingInfrastructure();
-
   // Test fixtures
   Service.identity.username = "johndoe";
 
   Cu.import("resource://services-sync/service.js");
 
   _("Service is enabled.");
   do_check_eq(Service.enabled, true);
 
--- a/services/sync/tests/unit/test_service_sync_401.js
+++ b/services/sync/tests/unit/test_service_sync_401.js
@@ -33,17 +33,17 @@ function run_test() {
     "/1.1/johndoe/storage/meta/global": upd("meta",   new ServerWBO("global").handler()),
     "/1.1/johndoe/info/collections":    login_handling(collectionsHelper.handler)
   });
 
   const GLOBAL_SCORE = 42;
 
   try {
     _("Set up test fixtures.");
-    new SyncTestingInfrastructure("johndoe", "ilovejane", "foo");
+    new SyncTestingInfrastructure(server, "johndoe", "ilovejane", "foo");
     Service.scheduler.globalScore = GLOBAL_SCORE;
     // Avoid daily ping
     Svc.Prefs.set("lastPing", Math.floor(Date.now() / 1000));
 
     let threw = false;
     Svc.Obs.add("weave:service:sync:error", function (subject, data) {
       threw = true;
     });
--- a/services/sync/tests/unit/test_service_sync_remoteSetup.js
+++ b/services/sync/tests/unit/test_service_sync_remoteSetup.js
@@ -60,34 +60,32 @@ function run_test() {
     "/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
   });
 
   try {
     _("Log in.");
-    Service.serverURL = TEST_SERVER_URL;
-    Service.clusterURL = TEST_CLUSTER_URL;
+    Service.serverURL = server.baseURI;
 
     _("Checking Status.sync with no credentials.");
     Service.verifyAndFetchSymmetricKeys();
     do_check_eq(Service.status.sync, CREDENTIALS_CHANGED);
     do_check_eq(Service.status.login, LOGIN_FAILED_NO_PASSPHRASE);
 
     _("Log in with an old secret phrase, is upgraded to Sync Key.");
     Service.login("johndoe", "ilovejane", "my old secret phrase!!1!");
     _("End of login");
     do_check_true(Service.isLoggedIn);
     do_check_true(Utils.isPassphrase(Service.identity.syncKey));
     let syncKey = Service.identity.syncKey;
     Service.startOver();
 
-    Service.serverURL = TEST_SERVER_URL;
-    Service.clusterURL = TEST_CLUSTER_URL;
+    Service.serverURL = server.baseURI;
     Service.login("johndoe", "ilovejane", syncKey);
     do_check_true(Service.isLoggedIn);
 
     _("Checking that remoteSetup returns true when credentials have changed.");
     Service.recordManager.get(Service.metaURL).payload.syncID = "foobar";
     do_check_true(Service._remoteSetup());
 
     _("Do an initial sync.");
--- a/services/sync/tests/unit/test_service_sync_updateEnabledEngines.js
+++ b/services/sync/tests/unit/test_service_sync_updateEnabledEngines.js
@@ -61,18 +61,18 @@ function sync_httpd_setup(handlers) {
 
   let cl = new ServerCollection();
   handlers["/1.1/johndoe/storage/clients"] =
     upd("clients", cl.handler());
 
   return httpd_setup(handlers);
 }
 
-function setUp() {
-  new SyncTestingInfrastructure("johndoe", "ilovejane",
+function setUp(server) {
+  new SyncTestingInfrastructure(server, "johndoe", "ilovejane",
                                 "abcdeabcdeabcdeabcdeabcdea");
   // 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(Service.collectionKeys);
   let serverKeys = Service.collectionKeys.asWBO("crypto", "keys");
   serverKeys.encrypt(Service.identity.syncKeyBundle);
   return serverKeys.upload(Service.resource(Service.cryptoKeysURL)).success;
 }
@@ -90,17 +90,17 @@ function run_test() {
 
 add_test(function test_newAccount() {
   _("Test: New account does not disable locally enabled engines.");
   let engine = Service.engineManager.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();
+  setUp(server);
 
   try {
     _("Engine is enabled from the beginning.");
     Service._ignorePrefObserver = true;
     engine.enabled = true;
     Service._ignorePrefObserver = false;
 
     _("Sync.");
@@ -120,17 +120,17 @@ add_test(function test_enabledLocally() 
   let engine = Service.engineManager.get("steam");
   let metaWBO = new ServerWBO("global", {syncID: Service.syncID,
                                          storageVersion: STORAGE_VERSION,
                                          engines: {}});
   let server = sync_httpd_setup({
     "/1.1/johndoe/storage/meta/global": metaWBO.handler(),
     "/1.1/johndoe/storage/steam": new ServerWBO("steam", {}).handler()
   });
-  setUp();
+  setUp(server);
 
   try {
     _("Enable engine locally.");
     engine.enabled = true;
 
     _("Sync.");
     Service.sync();
 
@@ -156,17 +156,17 @@ add_test(function test_disabledLocally()
                       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();
+  setUp(server);
 
   try {
     _("Disable engine locally.");
     Service._ignorePrefObserver = true;
     engine.enabled = true;
     Service._ignorePrefObserver = false;
     engine.enabled = false;
 
@@ -205,17 +205,17 @@ add_test(function test_disabledLocally_w
     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();
+  setUp(server);
 
   _("Disable engine locally.");
   Service._ignorePrefObserver = true;
   engine.enabled = true;
   Service._ignorePrefObserver = false;
   engine.enabled = false;
 
   Svc.Obs.add("weave:ui:sync:error", function onSyncError() {
@@ -243,17 +243,17 @@ add_test(function test_enabledRemotely()
   });
   let server = sync_httpd_setup({
     "/1.1/johndoe/storage/meta/global":
     upd("meta", metaWBO.handler()),
 
     "/1.1/johndoe/storage/steam":
     upd("steam", new ServerWBO("steam", {}).handler())
   });
-  setUp();
+  setUp(server);
 
   // We need to be very careful how we do this, so that we don't trigger a
   // fresh start!
   try {
     _("Upload some keys to avoid a fresh start.");
     let wbo = Service.collectionKeys.generateNewKeysWBO();
     wbo.encrypt(Service.identity.syncKeyBundle);
     do_check_eq(200, wbo.upload(Service.resource(Service.cryptoKeysURL)).status);
@@ -284,17 +284,17 @@ add_test(function test_disabledRemotelyT
                                          engines: {}});
   let server = sync_httpd_setup({
     "/1.1/johndoe/storage/meta/global":
     upd("meta", metaWBO.handler()),
 
     "/1.1/johndoe/storage/steam":
     upd("steam", new ServerWBO("steam", {}).handler())
   });
-  setUp();
+  setUp(server);
 
   try {
     _("Enable engine locally.");
     Service._ignorePrefObserver = true;
     engine.enabled = true;
     Service._ignorePrefObserver = false;
 
     _("Sync.");
@@ -325,17 +325,17 @@ add_test(function test_disabledRemotely(
   let engine = Service.engineManager.get("steam");
   let metaWBO = new ServerWBO("global", {syncID: Service.syncID,
                                          storageVersion: STORAGE_VERSION,
                                          engines: {}});
   let server = sync_httpd_setup({
     "/1.1/johndoe/storage/meta/global": metaWBO.handler(),
     "/1.1/johndoe/storage/steam": new ServerWBO("steam", {}).handler()
   });
-  setUp();
+  setUp(server);
 
   try {
     _("Enable engine locally.");
     Service._ignorePrefObserver = true;
     engine.enabled = true;
     Service._ignorePrefObserver = false;
 
     _("Sync.");
@@ -358,17 +358,17 @@ add_test(function test_dependentEnginesE
   let metaWBO = new ServerWBO("global", {syncID: Service.syncID,
                                          storageVersion: STORAGE_VERSION,
                                          engines: {}});
   let server = sync_httpd_setup({
     "/1.1/johndoe/storage/meta/global": metaWBO.handler(),
     "/1.1/johndoe/storage/steam": new ServerWBO("steam", {}).handler(),
     "/1.1/johndoe/storage/stirling": new ServerWBO("stirling", {}).handler()
   });
-  setUp();
+  setUp(server);
 
   try {
     _("Enable engine locally. Doing it on one is enough.");
     steamEngine.enabled = true;
 
     _("Sync.");
     Service.sync();
 
@@ -402,17 +402,17 @@ add_test(function test_dependentEnginesD
   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();
+  setUp(server);
 
   try {
     _("Disable engines locally. Doing it on one is enough.");
     Service._ignorePrefObserver = true;
     steamEngine.enabled = true;
     do_check_true(stirlingEngine.enabled);
     Service._ignorePrefObserver = false;
     steamEngine.enabled = false;
--- a/services/sync/tests/unit/test_service_verifyLogin.js
+++ b/services/sync/tests/unit/test_service_verifyLogin.js
@@ -32,27 +32,35 @@ function run_test() {
 
   // This test expects a clean slate -- no saved passphrase.
   Services.logins.removeAllLogins();
   let johnHelper = track_collections_helper();
   let johnU      = johnHelper.with_updated_collection;
   let johnColls  = johnHelper.collections;
 
   do_test_pending();
-  let server = httpd_setup({
+
+  let server;
+  function weaveHandler (request, response) {
+    response.setStatusLine(request.httpVersion, 200, "OK");
+    let body = server.baseURI + "/api/";
+    response.bodyOutputStream.write(body, body.length);
+  }
+
+  server = httpd_setup({
     "/api/1.1/johndoe/info/collections": login_handling(johnHelper.handler),
     "/api/1.1/janedoe/info/collections": service_unavailable,
 
     "/api/1.1/johndoe/storage/crypto/keys": johnU("crypto", new ServerWBO("keys").handler()),
     "/api/1.1/johndoe/storage/meta/global": johnU("meta",   new ServerWBO("global").handler()),
-    "/user/1.0/johndoe/node/weave": httpd_handler(200, "OK", "http://localhost:8080/api/")
+    "/user/1.0/johndoe/node/weave": weaveHandler,
   });
 
   try {
-    Service.serverURL = TEST_SERVER_URL;
+    Service.serverURL = server.baseURI;
 
     _("Force the initial state.");
     Service.status.service = STATUS_OK;
     do_check_eq(Service.status.service, STATUS_OK);
 
     _("Credentials won't check out because we're not configured yet.");
     Service.status.resetSync();
     do_check_false(Service.verifyLogin());
@@ -62,17 +70,17 @@ function run_test() {
     _("Try again with username and password set.");
     Service.status.resetSync();
     setBasicCredentials("johndoe", "ilovejane", null);
     do_check_false(Service.verifyLogin());
     do_check_eq(Service.status.service, CLIENT_NOT_CONFIGURED);
     do_check_eq(Service.status.login, LOGIN_FAILED_NO_PASSPHRASE);
 
     _("verifyLogin() has found out the user's cluster URL, though.");
-    do_check_eq(Service.clusterURL, "http://localhost:8080/api/");
+    do_check_eq(Service.clusterURL, server.baseURI + "/api/");
 
     _("Success if passphrase is set.");
     Service.status.resetSync();
     Service.identity.syncKey = "foo";
     do_check_true(Service.verifyLogin());
     do_check_eq(Service.status.service, STATUS_OK);
     do_check_eq(Service.status.login, LOGIN_SUCCEEDED);
 
--- a/services/sync/tests/unit/test_service_wipeClient.js
+++ b/services/sync/tests/unit/test_service_wipeClient.js
@@ -77,17 +77,17 @@ add_test(function test_startOver_clears_
 
   run_next_test();
 });
 
 add_test(function test_credentials_preserved() {
   _("Ensure that credentials are preserved if client is wiped.");
 
   // Required for wipeClient().
-  Service.clusterURL = TEST_CLUSTER_URL;
+  Service.clusterURL = "http://dummy:9000/";
   Service.identity.account = "testaccount";
   Service.identity.basicPassword = "testpassword";
   let key = Utils.generatePassphrase();
   Service.identity.syncKey = key;
   Service.identity.persistCredentials();
 
   // Simulate passwords engine wipe without all the overhead. To do this
   // properly would require extra test infrastructure.
--- a/services/sync/tests/unit/test_service_wipeServer.js
+++ b/services/sync/tests/unit/test_service_wipeServer.js
@@ -23,21 +23,21 @@ FakeCollection.prototype = {
       }
       response.setHeader("X-Weave-Timestamp", timestamp);
       response.setStatusLine(request.httpVersion, 200, "OK");
       response.bodyOutputStream.write(body, body.length);
     };
   }
 };
 
-function setUpTestFixtures() {
+function setUpTestFixtures(server) {
   let cryptoService = new FakeCryptoService();
 
-  Service.serverURL = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
+  Service.serverURL = server.baseURI + "/";
+  Service.clusterURL = server.baseURI + "/";
 
   setBasicCredentials("johndoe", null, "aabcdeabcdeabcdeabcdeabcde");
 }
 
 
 function run_test() {
   initTestLogging("Trace");
   run_next_test();
@@ -51,18 +51,18 @@ add_test(function test_wipeServer_list_s
 
   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();
-    new SyncTestingInfrastructure("johndoe", "irrelevant", "irrelevant");
+    setUpTestFixtures(server);
+    new SyncTestingInfrastructure(server, "johndoe", "irrelevant", "irrelevant");
 
     _("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);
@@ -85,18 +85,18 @@ add_test(function test_wipeServer_list_5
 
   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/diesel": diesel_coll.handler()
   });
 
   try {
-    setUpTestFixtures();
-    new SyncTestingInfrastructure("johndoe", "irrelevant", "irrelevant");
+    setUpTestFixtures(server);
+    new SyncTestingInfrastructure(server, "johndoe", "irrelevant", "irrelevant");
 
     _("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 {
@@ -131,20 +131,20 @@ add_test(function test_wipeServer_all_su
     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();
+  setUpTestFixtures(server);
 
   _("Try deletion.");
-  new SyncTestingInfrastructure("johndoe", "irrelevant", "irrelevant");
+  new SyncTestingInfrastructure(server, "johndoe", "irrelevant", "irrelevant");
   let returnedTimestamp = Service.wipeServer();
   do_check_true(deleted);
   do_check_eq(returnedTimestamp, serverTimestamp);
 
   server.stop(run_next_test);
   Svc.Prefs.resetBranch("");
 });
 
@@ -163,20 +163,20 @@ add_test(function test_wipeServer_all_40
     serverTimestamp = new_timestamp();
     response.setHeader("X-Weave-Timestamp", "" + serverTimestamp);
     response.setStatusLine(request.httpVersion, 404, "Not Found");
   }
 
   let server = httpd_setup({
     "/1.1/johndoe/storage": storageHandler
   });
-  setUpTestFixtures();
+  setUpTestFixtures(server);
 
   _("Try deletion.");
-  new SyncTestingInfrastructure("johndoe", "irrelevant", "irrelevant");
+  new SyncTestingInfrastructure(server, "johndoe", "irrelevant", "irrelevant");
   let returnedTimestamp = Service.wipeServer();
   do_check_true(deleted);
   do_check_eq(returnedTimestamp, serverTimestamp);
 
   server.stop(run_next_test);
   Svc.Prefs.resetBranch("");
 });
 
@@ -190,40 +190,44 @@ add_test(function test_wipeServer_all_50
     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();
+  setUpTestFixtures(server);
 
   _("Try deletion.");
   let error;
   try {
-    new SyncTestingInfrastructure("johndoe", "irrelevant", "irrelevant");
+    new SyncTestingInfrastructure(server, "johndoe", "irrelevant", "irrelevant");
     Service.wipeServer();
     do_throw("Should have thrown!");
   } catch (ex) {
     error = ex;
   }
   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();
+  let server = httpd_setup({});
+  setUpTestFixtures(server);
+
+  Service.serverURL = "http://localhost:4352/";
+  Service.clusterURL = "http://localhost:4352/";
 
   _("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("");
+  server.stop(run_next_test);
 });
--- a/services/sync/tests/unit/test_syncengine.js
+++ b/services/sync/tests/unit/test_syncengine.js
@@ -5,33 +5,35 @@ Cu.import("resource://services-sync/engi
 Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/util.js");
 Cu.import("resource://testing-common/services/sync/utils.js");
 
 function makeSteamEngine() {
   return new SyncEngine('Steam', Service);
 }
 
+let server;
+
 function test_url_attributes() {
   _("SyncEngine url attributes");
-  let syncTesting = new SyncTestingInfrastructure();
+  let syncTesting = new SyncTestingInfrastructure(server);
   Service.clusterURL = "https://cluster/";
   let engine = makeSteamEngine();
   try {
     do_check_eq(engine.storageURL, "https://cluster/1.1/foo/storage/");
     do_check_eq(engine.engineURL, "https://cluster/1.1/foo/storage/steam");
     do_check_eq(engine.metaURL, "https://cluster/1.1/foo/storage/meta/global");
   } finally {
     Svc.Prefs.resetBranch("");
   }
 }
 
 function test_syncID() {
   _("SyncEngine.syncID corresponds to preference");
-  let syncTesting = new SyncTestingInfrastructure();
+  let syncTesting = new SyncTestingInfrastructure(server);
   let engine = makeSteamEngine();
   try {
     // Ensure pristine environment
     do_check_eq(Svc.Prefs.get("steam.syncID"), undefined);
 
     // Performing the first get on the attribute will generate a new GUID.
     do_check_eq(engine.syncID, "fake-guid-0");
     do_check_eq(Svc.Prefs.get("steam.syncID"), "fake-guid-0");
@@ -41,17 +43,17 @@ function test_syncID() {
     do_check_eq(engine.syncID, "fake-guid-1");
   } finally {
     Svc.Prefs.resetBranch("");
   }
 }
 
 function test_lastSync() {
   _("SyncEngine.lastSync and SyncEngine.lastSyncLocal correspond to preferences");
-  let syncTesting = new SyncTestingInfrastructure();
+  let syncTesting = new SyncTestingInfrastructure(server);
   let engine = makeSteamEngine();
   try {
     // Ensure pristine environment
     do_check_eq(Svc.Prefs.get("steam.lastSync"), undefined);
     do_check_eq(engine.lastSync, 0);
     do_check_eq(Svc.Prefs.get("steam.lastSyncLocal"), undefined);
     do_check_eq(engine.lastSyncLocal, 0);
 
@@ -71,17 +73,17 @@ function test_lastSync() {
     do_check_eq(Svc.Prefs.get("steam.lastSync"), "0");
   } finally {
     Svc.Prefs.resetBranch("");
   }
 }
 
 function test_toFetch() {
   _("SyncEngine.toFetch corresponds to file on disk");
-  let syncTesting = new SyncTestingInfrastructure();
+  let syncTesting = new SyncTestingInfrastructure(server);
   const filename = "weave/toFetch/steam.json";
   let engine = makeSteamEngine();
   try {
     // Ensure pristine environment
     do_check_eq(engine.toFetch.length, 0);
 
     // Write file to disk
     let toFetch = [Utils.makeGUID(), Utils.makeGUID(), Utils.makeGUID()];
@@ -101,17 +103,17 @@ function test_toFetch() {
     do_check_eq(engine.toFetch[1], toFetch[1]);
   } finally {
     Svc.Prefs.resetBranch("");
   }
 }
 
 function test_previousFailed() {
   _("SyncEngine.previousFailed corresponds to file on disk");
-  let syncTesting = new SyncTestingInfrastructure();
+  let syncTesting = new SyncTestingInfrastructure(server);
   const filename = "weave/failed/steam.json";
   let engine = makeSteamEngine();
   try {
     // Ensure pristine environment
     do_check_eq(engine.previousFailed.length, 0);
 
     // Write file to disk
     let previousFailed = [Utils.makeGUID(), Utils.makeGUID(), Utils.makeGUID()];
@@ -131,17 +133,17 @@ function test_previousFailed() {
     do_check_eq(engine.previousFailed[1], previousFailed[1]);
   } finally {
     Svc.Prefs.resetBranch("");
   }
 }
 
 function test_resetClient() {
   _("SyncEngine.resetClient resets lastSync and toFetch");
-  let syncTesting = new SyncTestingInfrastructure();
+  let syncTesting = new SyncTestingInfrastructure(server);
   let engine = makeSteamEngine();
   try {
     // Ensure pristine environment
     do_check_eq(Svc.Prefs.get("steam.lastSync"), undefined);
     do_check_eq(Svc.Prefs.get("steam.lastSyncLocal"), undefined);
     do_check_eq(engine.toFetch.length, 0);
 
     engine.lastSync = 123.45;
@@ -156,26 +158,24 @@ function test_resetClient() {
     do_check_eq(engine.previousFailed.length, 0);
   } finally {
     Svc.Prefs.resetBranch("");
   }
 }
 
 function test_wipeServer() {
   _("SyncEngine.wipeServer deletes server data and resets the client.");
-  let syncTesting = new SyncTestingInfrastructure();
-  Service.serverURL = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
   let engine = makeSteamEngine();
 
   const PAYLOAD = 42;
   let steamCollection = new ServerWBO("steam", PAYLOAD);
   let server = httpd_setup({
     "/1.1/foo/storage/steam": steamCollection.handler()
   });
+  let syncTesting = new SyncTestingInfrastructure(server);
   do_test_pending();
 
   try {
     // Some data to reset.
     engine.lastSync = 123.45;
     engine.toFetch = [Utils.makeGUID(), Utils.makeGUID(), Utils.makeGUID()];
 
     _("Wipe server data and reset client.");
@@ -186,16 +186,19 @@ function test_wipeServer() {
 
   } finally {
     server.stop(do_test_finished);
     Svc.Prefs.resetBranch("");
   }
 }
 
 function run_test() {
+  server = httpd_setup({});
   test_url_attributes();
   test_syncID();
   test_lastSync();
   test_toFetch();
   test_previousFailed();
   test_resetClient();
   test_wipeServer();
+
+  server.stop(run_next_test);
 }
--- a/services/sync/tests/unit/test_syncengine_sync.js
+++ b/services/sync/tests/unit/test_syncengine_sync.js
@@ -17,43 +17,43 @@ function makeRotaryEngine() {
 
 function cleanAndGo(server) {
   Svc.Prefs.resetBranch("");
   Svc.Prefs.set("log.logger.engine.rotary", "Trace");
   Service.recordManager.clearCache();
   server.stop(run_next_test);
 }
 
-function configureService(username, password) {
-  Service.clusterURL = TEST_CLUSTER_URL;
+function configureService(server, username, password) {
+  Service.clusterURL = server.baseURI;
 
   Service.identity.account = username || "foo";
   Service.identity.basicPassword = password || "password";
 }
 
 function createServerAndConfigureClient() {
   let engine = new RotaryEngine(Service);
 
   let contents = {
     meta: {global: {engines: {rotary: {version: engine.version,
                                        syncID:  engine.syncID}}}},
     crypto: {},
     rotary: {}
   };
 
   const USER = "foo";
-  Service.serverURL = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
-  Service.identity.username = USER;
-
   let server = new SyncServer();
   server.registerUser(USER, "password");
   server.createContents(USER, contents);
   server.start();
 
+  Service.serverURL = server.baseURI;
+  Service.clusterURL = server.baseURI;
+  Service.identity.username = USER;
+
   return [engine, server, USER];
 }
 
 function run_test() {
   generateNewKeys(Service.collectionKeys);
   Svc.Prefs.set("log.logger.engine.rotary", "Trace");
   run_next_test();
 }
@@ -70,34 +70,32 @@ function run_test() {
  *
  * In the spirit of unit testing, these are tested individually for
  * different scenarios below.
  */
 
 add_test(function test_syncStartup_emptyOrOutdatedGlobalsResetsSync() {
   _("SyncEngine._syncStartup resets sync and wipes server data if there's no or an outdated global record");
 
-  let syncTesting = new SyncTestingInfrastructure();
-  Service.serverURL = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
-  Service.identity.username = "foo";
-
   // Some server side data that's going to be wiped
   let collection = new ServerCollection();
   collection.insert('flying',
                     encryptPayload({id: 'flying',
                                     denomination: "LNER Class A3 4472"}));
   collection.insert('scotsman',
                     encryptPayload({id: 'scotsman',
                                     denomination: "Flying Scotsman"}));
 
   let server = sync_httpd_setup({
       "/1.1/foo/storage/rotary": collection.handler()
   });
 
+  let syncTesting = new SyncTestingInfrastructure(server);
+  Service.identity.username = "foo";
+
   let engine = makeRotaryEngine();
   engine._store.items = {rekolok: "Rekonstruktionslokomotive"};
   try {
 
     // Confirm initial environment
     do_check_eq(engine._tracker.changedIDs["rekolok"], undefined);
     let metaGlobal = Service.recordManager.get(engine.metaURL);
     do_check_eq(metaGlobal.payload.engines, undefined);
@@ -124,25 +122,24 @@ add_test(function test_syncStartup_empty
   } finally {
     cleanAndGo(server);
   }
 });
 
 add_test(function test_syncStartup_serverHasNewerVersion() {
   _("SyncEngine._syncStartup ");
 
-  let syncTesting = new SyncTestingInfrastructure();
-  Service.serverURL = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
-  Service.identity.username = "foo";
   let global = new ServerWBO('global', {engines: {rotary: {version: 23456}}});
   let server = httpd_setup({
       "/1.1/foo/storage/meta/global": global.handler()
   });
 
+  let syncTesting = new SyncTestingInfrastructure(server);
+  Service.identity.username = "foo";
+
   let engine = makeRotaryEngine();
   try {
 
     // The server has a newer version of the data and our engine can
     // handle.  That should give us an exception.
     let error;
     try {
       engine._syncStartup();
@@ -155,21 +152,19 @@ add_test(function test_syncStartup_serve
     cleanAndGo(server);
   }
 });
 
 
 add_test(function test_syncStartup_syncIDMismatchResetsClient() {
   _("SyncEngine._syncStartup resets sync if syncIDs don't match");
 
-  let syncTesting = new SyncTestingInfrastructure();
-  Service.serverURL = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
+  let server = sync_httpd_setup({});
+  let syncTesting = new SyncTestingInfrastructure(server);
   Service.identity.username = "foo";
-  let server = sync_httpd_setup({});
 
   // global record with a different syncID than our engine has
   let engine = makeRotaryEngine();
   let global = new ServerWBO('global',
                              {engines: {rotary: {version: engine.version,
                                                 syncID: 'foobar'}}});
   server.registerPathHandler("/1.1/foo/storage/meta/global", global.handler());
 
@@ -193,49 +188,40 @@ add_test(function test_syncStartup_syncI
     cleanAndGo(server);
   }
 });
 
 
 add_test(function test_processIncoming_emptyServer() {
   _("SyncEngine._processIncoming working with an empty server backend");
 
-  let syncTesting = new SyncTestingInfrastructure();
-  Service.serverURL = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
-  Service.identity.username = "foo";
   let collection = new ServerCollection();
-
   let server = sync_httpd_setup({
       "/1.1/foo/storage/rotary": collection.handler()
   });
 
+  let syncTesting = new SyncTestingInfrastructure(server);
+  Service.identity.username = "foo";
+
   let engine = makeRotaryEngine();
   try {
 
     // Merely ensure that this code path is run without any errors
     engine._processIncoming();
     do_check_eq(engine.lastSync, 0);
 
   } finally {
     cleanAndGo(server);
   }
 });
 
 
 add_test(function test_processIncoming_createFromServer() {
   _("SyncEngine._processIncoming creates new records from server data");
 
-  let syncTesting = new SyncTestingInfrastructure();
-  Service.serverURL = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
-  Service.identity.username = "foo";
-
-  generateNewKeys(Service.collectionKeys);
-
   // Some server records that will be downloaded
   let collection = new ServerCollection();
   collection.insert('flying',
                     encryptPayload({id: 'flying',
                                     denomination: "LNER Class A3 4472"}));
   collection.insert('scotsman',
                     encryptPayload({id: 'scotsman',
                                     denomination: "Flying Scotsman"}));
@@ -246,16 +232,21 @@ add_test(function test_processIncoming_c
   collection.insert('../pathological', pathologicalPayload);
 
   let server = sync_httpd_setup({
       "/1.1/foo/storage/rotary": collection.handler(),
       "/1.1/foo/storage/rotary/flying": collection.wbo("flying").handler(),
       "/1.1/foo/storage/rotary/scotsman": collection.wbo("scotsman").handler()
   });
 
+  let syncTesting = new SyncTestingInfrastructure(server);
+  Service.identity.username = "foo";
+
+  generateNewKeys(Service.collectionKeys);
+
   let engine = makeRotaryEngine();
   let meta_global = Service.recordManager.set(engine.metaURL,
                                               new WBORecord(engine.metaURL));
   meta_global.payload.engines = {rotary: {version: engine.version,
                                          syncID: engine.syncID}};
 
   try {
 
@@ -282,20 +273,16 @@ add_test(function test_processIncoming_c
     cleanAndGo(server);
   }
 });
 
 
 add_test(function test_processIncoming_reconcile() {
   _("SyncEngine._processIncoming updates local records");
 
-  let syncTesting = new SyncTestingInfrastructure();
-  Service.serverURL = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
-  Service.identity.username = "foo";
   let collection = new ServerCollection();
 
   // This server record is newer than the corresponding client one,
   // so it'll update its data.
   collection.insert('newrecord',
                     encryptPayload({id: 'newrecord',
                                     denomination: "New stuff..."}));
 
@@ -330,16 +317,19 @@ add_test(function test_processIncoming_r
                     encryptPayload({id: 'nukeme',
                                     denomination: "Nuke me!",
                                     deleted: true}));
 
   let server = sync_httpd_setup({
       "/1.1/foo/storage/rotary": collection.handler()
   });
 
+  let syncTesting = new SyncTestingInfrastructure(server);
+  Service.identity.username = "foo";
+
   let engine = makeRotaryEngine();
   engine._store.items = {newerserver: "New data, but not as new as server!",
                          olderidentical: "Older but identical",
                          updateclient: "Got data?",
                          original: "Original Entry",
                          long_original: "Long Original Entry",
                          nukeme: "Nuke me!"};
   // Make this record 1 min old, thus older than the one on the server
@@ -603,21 +593,18 @@ add_test(function test_processIncoming_r
   let payload = JSON.parse(JSON.parse(wbo.payload).ciphertext);
   do_check_eq("incoming", payload.denomination);
   cleanAndGo(server);
 });
 
 add_test(function test_processIncoming_mobile_batchSize() {
   _("SyncEngine._processIncoming doesn't fetch everything at once on mobile clients");
 
-  let syncTesting = new SyncTestingInfrastructure();
-  Service.serverURL = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
+  Svc.Prefs.set("client.type", "mobile");
   Service.identity.username = "foo";
-  Svc.Prefs.set("client.type", "mobile");
 
   // A collection that logs each GET
   let collection = new ServerCollection();
   collection.get_log = [];
   collection._get = collection.get;
   collection.get = function (options) {
     this.get_log.push(options);
     return this._get(options);
@@ -632,16 +619,18 @@ add_test(function test_processIncoming_m
     wbo.modified = Date.now()/1000 - 60*(i+10);
     collection.insertWBO(wbo);
   }
 
   let server = sync_httpd_setup({
       "/1.1/foo/storage/rotary": collection.handler()
   });
 
+  let syncTesting = new SyncTestingInfrastructure(server);
+
   let engine = makeRotaryEngine();
   let meta_global = Service.recordManager.set(engine.metaURL,
                                               new WBORecord(engine.metaURL));
   meta_global.payload.engines = {rotary: {version: engine.version,
                                          syncID: engine.syncID}};
 
   try {
 
@@ -674,19 +663,16 @@ add_test(function test_processIncoming_m
   } finally {
     cleanAndGo(server);
   }
 });
 
 
 add_test(function test_processIncoming_store_toFetch() {
   _("If processIncoming fails in the middle of a batch on mobile, state is saved in toFetch and lastSync.");
-  let syncTesting = new SyncTestingInfrastructure();
-  Service.serverURL = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
   Service.identity.username = "foo";
   Svc.Prefs.set("client.type", "mobile");
 
   // A collection that throws at the fourth get.
   let collection = new ServerCollection();
   collection._get_calls = 0;
   collection._get = collection.get;
   collection.get = function() {
@@ -704,24 +690,26 @@ add_test(function test_processIncoming_s
     let wbo = new ServerWBO(id, payload);
     wbo.modified = Date.now()/1000 + 60 * (i - MOBILE_BATCH_SIZE * 3);
     collection.insertWBO(wbo);
   }
 
   let engine = makeRotaryEngine();
   engine.enabled = true;
 
+  let server = sync_httpd_setup({
+      "/1.1/foo/storage/rotary": collection.handler()
+  });
+
+  let syncTesting = new SyncTestingInfrastructure(server);
+
   let meta_global = Service.recordManager.set(engine.metaURL,
                                               new WBORecord(engine.metaURL));
   meta_global.payload.engines = {rotary: {version: engine.version,
                                          syncID: engine.syncID}};
-  let server = sync_httpd_setup({
-      "/1.1/foo/storage/rotary": collection.handler()
-  });
-
   try {
 
     // Confirm initial environment
     do_check_eq(engine.lastSync, 0);
     do_check_empty(engine._store.items);
 
     let error;
     try {
@@ -743,19 +731,16 @@ add_test(function test_processIncoming_s
   } finally {
     cleanAndGo(server);
   }
 });
 
 
 add_test(function test_processIncoming_resume_toFetch() {
   _("toFetch and previousFailed items left over from previous syncs are fetched on the next sync, along with new items.");
-  let syncTesting = new SyncTestingInfrastructure();
-  Service.serverURL = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
   Service.identity.username = "foo";
 
   const LASTSYNC = Date.now() / 1000;
 
   // Server records that will be downloaded
   let collection = new ServerCollection();
   collection.insert('flying',
                     encryptPayload({id: 'flying',
@@ -779,24 +764,26 @@ add_test(function test_processIncoming_r
   collection._wbos.rekolok.modified = LASTSYNC + 10;
 
   // Time travel 10 seconds into the future but still download the above WBOs.
   let engine = makeRotaryEngine();
   engine.lastSync = LASTSYNC;
   engine.toFetch = ["flying", "scotsman"];
   engine.previousFailed = ["failed0", "failed1", "failed2"];
 
+  let server = sync_httpd_setup({
+      "/1.1/foo/storage/rotary": collection.handler()
+  });
+
+  let syncTesting = new SyncTestingInfrastructure(server);
+
   let meta_global = Service.recordManager.set(engine.metaURL,
                                               new WBORecord(engine.metaURL));
   meta_global.payload.engines = {rotary: {version: engine.version,
                                          syncID: engine.syncID}};
-  let server = sync_httpd_setup({
-      "/1.1/foo/storage/rotary": collection.handler()
-  });
-
   try {
 
     // Confirm initial environment
     do_check_eq(engine._store.items.flying, undefined);
     do_check_eq(engine._store.items.scotsman, undefined);
     do_check_eq(engine._store.items.rekolok, undefined);
 
     engine._syncStartup();
@@ -813,19 +800,16 @@ add_test(function test_processIncoming_r
   } finally {
     cleanAndGo(server);
   }
 });
 
 
 add_test(function test_processIncoming_applyIncomingBatchSize_smaller() {
   _("Ensure that a number of incoming items less than applyIncomingBatchSize is still applied.");
-  let syncTesting = new SyncTestingInfrastructure();
-  Service.serverURL = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
   Service.identity.username = "foo";
 
   // Engine that doesn't like the first and last record it's given.
   const APPLY_BATCH_SIZE = 10;
   let engine = makeRotaryEngine();
   engine.applyIncomingBatchSize = APPLY_BATCH_SIZE;
   engine._store._applyIncomingBatch = engine._store.applyIncomingBatch;
   engine._store.applyIncomingBatch = function (records) {
@@ -838,24 +822,26 @@ add_test(function test_processIncoming_a
   // Let's create less than a batch worth of server side records.
   let collection = new ServerCollection();
   for (let i = 0; i < APPLY_BATCH_SIZE - 1; i++) {
     let id = 'record-no-' + i;
     let payload = encryptPayload({id: id, denomination: "Record No. " + id});
     collection.insert(id, payload);
   }
 
+  let server = sync_httpd_setup({
+      "/1.1/foo/storage/rotary": collection.handler()
+  });
+
+  let syncTesting = new SyncTestingInfrastructure(server);
+
   let meta_global = Service.recordManager.set(engine.metaURL,
                                               new WBORecord(engine.metaURL));
   meta_global.payload.engines = {rotary: {version: engine.version,
                                          syncID: engine.syncID}};
-  let server = sync_httpd_setup({
-      "/1.1/foo/storage/rotary": collection.handler()
-  });
-
   try {
 
     // Confirm initial environment
     do_check_empty(engine._store.items);
 
     engine._syncStartup();
     engine._processIncoming();
 
@@ -869,18 +855,16 @@ add_test(function test_processIncoming_a
   } finally {
     cleanAndGo(server);
   }
 });
 
 
 add_test(function test_processIncoming_applyIncomingBatchSize_multiple() {
   _("Ensure that incoming items are applied according to applyIncomingBatchSize.");
-  let syncTesting = new SyncTestingInfrastructure();
-  Service.clusterURL = TEST_CLUSTER_URL;
   Service.identity.username = "foo";
 
   const APPLY_BATCH_SIZE = 10;
 
   // Engine that applies records in batches.
   let engine = makeRotaryEngine();
   engine.applyIncomingBatchSize = APPLY_BATCH_SIZE;
   let batchCalls = 0;
@@ -894,24 +878,26 @@ add_test(function test_processIncoming_a
   // Let's create three batches worth of server side records.
   let collection = new ServerCollection();
   for (let i = 0; i < APPLY_BATCH_SIZE * 3; i++) {
     let id = 'record-no-' + i;
     let payload = encryptPayload({id: id, denomination: "Record No. " + id});
     collection.insert(id, payload);
   }
 
+  let server = sync_httpd_setup({
+      "/1.1/foo/storage/rotary": collection.handler()
+  });
+
+  let syncTesting = new SyncTestingInfrastructure(server);
+
   let meta_global = Service.recordManager.set(engine.metaURL,
                                               new WBORecord(engine.metaURL));
   meta_global.payload.engines = {rotary: {version: engine.version,
                                          syncID: engine.syncID}};
-  let server = sync_httpd_setup({
-      "/1.1/foo/storage/rotary": collection.handler()
-  });
-
   try {
 
     // Confirm initial environment
     do_check_empty(engine._store.items);
 
     engine._syncStartup();
     engine._processIncoming();
 
@@ -922,19 +908,16 @@ add_test(function test_processIncoming_a
   } finally {
     cleanAndGo(server);
   }
 });
 
 
 add_test(function test_processIncoming_notify_count() {
   _("Ensure that failed records are reported only once.");
-  let syncTesting = new SyncTestingInfrastructure();
-  Service.serverURL = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
   Service.identity.username = "foo";
 
   const APPLY_BATCH_SIZE = 5;
   const NUMBER_OF_RECORDS = 15;
 
   // Engine that fails the first record.
   let engine = makeRotaryEngine();
   engine.applyIncomingBatchSize = APPLY_BATCH_SIZE;
@@ -947,24 +930,26 @@ add_test(function test_processIncoming_n
   // Create a batch of server side records.
   let collection = new ServerCollection();
   for (var i = 0; i < NUMBER_OF_RECORDS; i++) {
     let id = 'record-no-' + i;
     let payload = encryptPayload({id: id, denomination: "Record No. " + id});
     collection.insert(id, payload);
   }
 
+  let server = sync_httpd_setup({
+      "/1.1/foo/storage/rotary": collection.handler()
+  });
+
+  let syncTesting = new SyncTestingInfrastructure(server);
+
   let meta_global = Service.recordManager.set(engine.metaURL,
                                               new WBORecord(engine.metaURL));
   meta_global.payload.engines = {rotary: {version: engine.version,
                                          syncID: engine.syncID}};
-  let server = sync_httpd_setup({
-      "/1.1/foo/storage/rotary": collection.handler()
-  });
-
   try {
     // Confirm initial environment.
     do_check_eq(engine.lastSync, 0);
     do_check_eq(engine.toFetch.length, 0);
     do_check_eq(engine.previousFailed.length, 0);
     do_check_empty(engine._store.items);
 
     let called = 0;
@@ -1012,19 +997,16 @@ add_test(function test_processIncoming_n
   } finally {
     cleanAndGo(server);
   }
 });
 
 
 add_test(function test_processIncoming_previousFailed() {
   _("Ensure that failed records are retried.");
-  let syncTesting = new SyncTestingInfrastructure();
-  Service.serverURL = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
   Service.identity.username = "foo";
   Svc.Prefs.set("client.type", "mobile");
 
   const APPLY_BATCH_SIZE = 4;
   const NUMBER_OF_RECORDS = 14;
 
   // Engine that fails the first 2 records.
   let engine = makeRotaryEngine();
@@ -1038,24 +1020,26 @@ add_test(function test_processIncoming_p
   // Create a batch of server side records.
   let collection = new ServerCollection();
   for (var i = 0; i < NUMBER_OF_RECORDS; i++) {
     let id = 'record-no-' + i;
     let payload = encryptPayload({id: id, denomination: "Record No. " + i});
     collection.insert(id, payload);
   }
 
+  let server = sync_httpd_setup({
+      "/1.1/foo/storage/rotary": collection.handler()
+  });
+
+  let syncTesting = new SyncTestingInfrastructure(server);
+
   let meta_global = Service.recordManager.set(engine.metaURL,
                                               new WBORecord(engine.metaURL));
   meta_global.payload.engines = {rotary: {version: engine.version,
                                          syncID: engine.syncID}};
-  let server = sync_httpd_setup({
-      "/1.1/foo/storage/rotary": collection.handler()
-  });
-
   try {
     // Confirm initial environment.
     do_check_eq(engine.lastSync, 0);
     do_check_eq(engine.toFetch.length, 0);
     do_check_eq(engine.previousFailed.length, 0);
     do_check_empty(engine._store.items);
 
     // Initial failed items in previousFailed to be reset.
@@ -1099,19 +1083,16 @@ add_test(function test_processIncoming_p
   } finally {
     cleanAndGo(server);
   }
 });
 
 
 add_test(function test_processIncoming_failed_records() {
   _("Ensure that failed records from _reconcile and applyIncomingBatch are refetched.");
-  let syncTesting = new SyncTestingInfrastructure();
-  Service.serverURL = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
   Service.identity.username = "foo";
 
   // Let's create three and a bit batches worth of server side records.
   let collection = new ServerCollection();
   const NUMBER_OF_RECORDS = MOBILE_BATCH_SIZE * 3 + 5;
   for (let i = 0; i < NUMBER_OF_RECORDS; i++) {
     let id = 'record-no-' + i;
     let payload = encryptPayload({id: id, denomination: "Record No. " + id});
@@ -1144,36 +1125,38 @@ add_test(function test_processIncoming_f
   engine._store._applyIncoming = engine._store.applyIncoming;
   engine._store.applyIncoming = function (record) {
     if (BOGUS_RECORDS.indexOf(record.id) % 2 == 1) {
       throw "I don't like this record! Baaaaaah!";
     }
     return this._applyIncoming.apply(this, arguments);
   };
 
-  let meta_global = Service.recordManager.set(engine.metaURL,
-                                              new WBORecord(engine.metaURL));
-  meta_global.payload.engines = {rotary: {version: engine.version,
-                                         syncID: engine.syncID}};
-
   // Keep track of requests made of a collection.
   let count = 0;
   let uris  = [];
   function recording_handler(collection) {
     let h = collection.handler();
     return function(req, res) {
       ++count;
       uris.push(req.path + "?" + req.queryString);
       return h(req, res);
     };
   }
   let server = sync_httpd_setup({
       "/1.1/foo/storage/rotary": recording_handler(collection)
   });
 
+  let syncTesting = new SyncTestingInfrastructure(server);
+
+  let meta_global = Service.recordManager.set(engine.metaURL,
+                                              new WBORecord(engine.metaURL));
+  meta_global.payload.engines = {rotary: {version: engine.version,
+                                         syncID: engine.syncID}};
+
   try {
 
     // Confirm initial environment
     do_check_eq(engine.lastSync, 0);
     do_check_eq(engine.toFetch.length, 0);
     do_check_eq(engine.previousFailed.length, 0);
     do_check_empty(engine._store.items);
 
@@ -1235,19 +1218,16 @@ add_test(function test_processIncoming_f
     cleanAndGo(server);
   }
 });
 
 
 add_test(function test_processIncoming_decrypt_failed() {
   _("Ensure that records failing to decrypt are either replaced or refetched.");
 
-  let syncTesting = new SyncTestingInfrastructure();
-  Service.serverURL = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
   Service.identity.username = "foo";
 
   // Some good and some bogus records. One doesn't contain valid JSON,
   // the other will throw during decrypt.
   let collection = new ServerCollection();
   collection._wbos.flying = new ServerWBO(
       'flying', encryptPayload({id: 'flying',
                                 denomination: "LNER Class A3 4472"}));
@@ -1269,24 +1249,26 @@ add_test(function test_processIncoming_d
   };
 
   // Some broken records also exist locally.
   let engine = makeRotaryEngine();
   engine.enabled = true;
   engine._store.items = {nojson: "Valid JSON",
                          nodecrypt: "Valid ciphertext"};
 
+  let server = sync_httpd_setup({
+      "/1.1/foo/storage/rotary": collection.handler()
+  });
+
+  let syncTesting = new SyncTestingInfrastructure(server);
+
   let meta_global = Service.recordManager.set(engine.metaURL,
                                               new WBORecord(engine.metaURL));
   meta_global.payload.engines = {rotary: {version: engine.version,
                                          syncID: engine.syncID}};
-  let server = sync_httpd_setup({
-      "/1.1/foo/storage/rotary": collection.handler()
-  });
-
   try {
 
     // Confirm initial state
     do_check_eq(engine.toFetch.length, 0);
     do_check_eq(engine.previousFailed.length, 0);
 
     let observerSubject;
     let observerData;
@@ -1314,29 +1296,28 @@ add_test(function test_processIncoming_d
     cleanAndGo(server);
   }
 });
 
 
 add_test(function test_uploadOutgoing_toEmptyServer() {
   _("SyncEngine._uploadOutgoing uploads new records to server");
 
-  let syncTesting = new SyncTestingInfrastructure();
-  Service.serverURL = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
   Service.identity.username = "foo";
   let collection = new ServerCollection();
   collection._wbos.flying = new ServerWBO('flying');
   collection._wbos.scotsman = new ServerWBO('scotsman');
 
   let server = sync_httpd_setup({
       "/1.1/foo/storage/rotary": collection.handler(),
       "/1.1/foo/storage/rotary/flying": collection.wbo("flying").handler(),
       "/1.1/foo/storage/rotary/scotsman": collection.wbo("scotsman").handler()
   });
+
+  let syncTesting = new SyncTestingInfrastructure(server);
   generateNewKeys(Service.collectionKeys);
 
   let engine = makeRotaryEngine();
   engine.lastSync = 123; // needs to be non-zero so that tracker is queried
   engine._store.items = {flying: "LNER Class A3 4472",
                          scotsman: "Flying Scotsman"};
   // Mark one of these records as changed
   engine._tracker.addChangedID('scotsman', 0);
@@ -1374,29 +1355,28 @@ add_test(function test_uploadOutgoing_to
     cleanAndGo(server);
   }
 });
 
 
 add_test(function test_uploadOutgoing_failed() {
   _("SyncEngine._uploadOutgoing doesn't clear the tracker of objects that failed to upload.");
 
-  let syncTesting = new SyncTestingInfrastructure();
-  Service.serverURL = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
   Service.identity.username = "foo";
   let collection = new ServerCollection();
   // We only define the "flying" WBO on the server, not the "scotsman"
   // and "peppercorn" ones.
   collection._wbos.flying = new ServerWBO('flying');
 
   let server = sync_httpd_setup({
       "/1.1/foo/storage/rotary": collection.handler()
   });
 
+  let syncTesting = new SyncTestingInfrastructure(server);
+
   let engine = makeRotaryEngine();
   engine.lastSync = 123; // needs to be non-zero so that tracker is queried
   engine._store.items = {flying: "LNER Class A3 4472",
                          scotsman: "Flying Scotsman",
                          peppercorn: "Peppercorn Class"};
   // Mark these records as changed
   const FLYING_CHANGED = 12345;
   const SCOTSMAN_CHANGED = 23456;
@@ -1438,19 +1418,16 @@ add_test(function test_uploadOutgoing_fa
     cleanAndGo(server);
   }
 });
 
 
 add_test(function test_uploadOutgoing_MAX_UPLOAD_RECORDS() {
   _("SyncEngine._uploadOutgoing uploads in batches of MAX_UPLOAD_RECORDS");
 
-  let syncTesting = new SyncTestingInfrastructure();
-  Service.serverURL = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
   Service.identity.username = "foo";
   let collection = new ServerCollection();
 
   // Let's count how many times the client posts to the server
   var noOfUploads = 0;
   collection.post = (function(orig) {
     return function() {
       noOfUploads++;
@@ -1471,16 +1448,18 @@ add_test(function test_uploadOutgoing_MA
                                               new WBORecord(engine.metaURL));
   meta_global.payload.engines = {rotary: {version: engine.version,
                                          syncID: engine.syncID}};
 
   let server = sync_httpd_setup({
       "/1.1/foo/storage/rotary": collection.handler()
   });
 
+  let syncTesting = new SyncTestingInfrastructure(server);
+
   try {
 
     // Confirm initial environment.
     do_check_eq(noOfUploads, 0);
 
     engine._syncStartup();
     engine._uploadOutgoing();
 
@@ -1496,49 +1475,49 @@ add_test(function test_uploadOutgoing_MA
     cleanAndGo(server);
   }
 });
 
 
 add_test(function test_syncFinish_noDelete() {
   _("SyncEngine._syncFinish resets tracker's score");
 
-  let syncTesting = new SyncTestingInfrastructure();
+  let server = httpd_setup({});
+
+  let syncTesting = new SyncTestingInfrastructure(server);
   let engine = makeRotaryEngine();
   engine._delete = {}; // Nothing to delete
   engine._tracker.score = 100;
 
   // _syncFinish() will reset the engine's score.
   engine._syncFinish();
   do_check_eq(engine.score, 0);
-  run_next_test();
+  server.stop(run_next_test);
 });
 
 
 add_test(function test_syncFinish_deleteByIds() {
   _("SyncEngine._syncFinish deletes server records slated for deletion (list of record IDs).");
 
-  let syncTesting = new SyncTestingInfrastructure();
-  Service.serverURL = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
   Service.identity.username = "foo";
   let collection = new ServerCollection();
   collection._wbos.flying = new ServerWBO(
       'flying', encryptPayload({id: 'flying',
                                 denomination: "LNER Class A3 4472"}));
   collection._wbos.scotsman = new ServerWBO(
       'scotsman', encryptPayload({id: 'scotsman',
                                   denomination: "Flying Scotsman"}));
   collection._wbos.rekolok = new ServerWBO(
       'rekolok', encryptPayload({id: 'rekolok',
                                 denomination: "Rekonstruktionslokomotive"}));
 
   let server = httpd_setup({
       "/1.1/foo/storage/rotary": collection.handler()
   });
+  let syncTesting = new SyncTestingInfrastructure(server);
 
   let engine = makeRotaryEngine();
   try {
     engine._delete = {ids: ['flying', 'rekolok']};
     engine._syncFinish();
 
     // The 'flying' and 'rekolok' records were deleted while the
     // 'scotsman' one wasn't.
@@ -1553,19 +1532,16 @@ add_test(function test_syncFinish_delete
     cleanAndGo(server);
   }
 });
 
 
 add_test(function test_syncFinish_deleteLotsInBatches() {
   _("SyncEngine._syncFinish deletes server records in batches of 100 (list of record IDs).");
 
-  let syncTesting = new SyncTestingInfrastructure();
-  Service.serverURL = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
   Service.identity.username = "foo";
   let collection = new ServerCollection();
 
   // Let's count how many times the client does a DELETE request to the server
   var noOfUploads = 0;
   collection.delete = (function(orig) {
     return function() {
       noOfUploads++;
@@ -1582,16 +1558,18 @@ add_test(function test_syncFinish_delete
     wbo.modified = now / 1000 - 60 * (i + 110);
     collection.insertWBO(wbo);
   }
 
   let server = httpd_setup({
       "/1.1/foo/storage/rotary": collection.handler()
   });
 
+  let syncTesting = new SyncTestingInfrastructure(server);
+
   let engine = makeRotaryEngine();
   try {
 
     // Confirm initial environment
     do_check_eq(noOfUploads, 0);
 
     // Declare what we want to have deleted: all records no. 100 and
     // up and all records that are less than 200 mins old (which are
@@ -1625,25 +1603,23 @@ add_test(function test_syncFinish_delete
     cleanAndGo(server);
   }
 });
 
 
 add_test(function test_sync_partialUpload() {
   _("SyncEngine.sync() keeps changedIDs that couldn't be uploaded.");
 
-  let syncTesting = new SyncTestingInfrastructure();
-  Service.serverURL = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
   Service.identity.username = "foo";
 
   let collection = new ServerCollection();
   let server = sync_httpd_setup({
       "/1.1/foo/storage/rotary": collection.handler()
   });
+  let syncTesting = new SyncTestingInfrastructure(server);
   generateNewKeys(Service.collectionKeys);
 
   let engine = makeRotaryEngine();
   engine.lastSync = 123; // needs to be non-zero so that tracker is queried
   engine.lastSyncLocal = 456;
 
   // Let the third upload fail completely
   var noOfUploads = 0;
@@ -1700,97 +1676,93 @@ add_test(function test_sync_partialUploa
 
   } finally {
     cleanAndGo(server);
   }
 });
 
 add_test(function test_canDecrypt_noCryptoKeys() {
   _("SyncEngine.canDecrypt returns false if the engine fails to decrypt items on the server, e.g. due to a missing crypto key collection.");
-  let syncTesting = new SyncTestingInfrastructure();
-  Service.serverURL = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
   Service.identity.username = "foo";
 
   // Wipe collection keys so we can test the desired scenario.
   Service.collectionKeys.clear();
 
   let collection = new ServerCollection();
   collection._wbos.flying = new ServerWBO(
       'flying', encryptPayload({id: 'flying',
                                 denomination: "LNER Class A3 4472"}));
 
   let server = sync_httpd_setup({
       "/1.1/foo/storage/rotary": collection.handler()
   });
 
+  let syncTesting = new SyncTestingInfrastructure(server);
   let engine = makeRotaryEngine();
   try {
 
     do_check_false(engine.canDecrypt());
 
   } finally {
     cleanAndGo(server);
   }
 });
 
 add_test(function test_canDecrypt_true() {
   _("SyncEngine.canDecrypt returns true if the engine can decrypt the items on the server.");
-  let syncTesting = new SyncTestingInfrastructure();
-  Service.serverURL = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
   Service.identity.username = "foo";
 
   generateNewKeys(Service.collectionKeys);
 
   let collection = new ServerCollection();
   collection._wbos.flying = new ServerWBO(
       'flying', encryptPayload({id: 'flying',
                                 denomination: "LNER Class A3 4472"}));
 
   let server = sync_httpd_setup({
       "/1.1/foo/storage/rotary": collection.handler()
   });
 
+  let syncTesting = new SyncTestingInfrastructure(server);
   let engine = makeRotaryEngine();
   try {
 
     do_check_true(engine.canDecrypt());
 
   } finally {
     cleanAndGo(server);
   }
 
 });
 
 add_test(function test_syncapplied_observer() {
-  let syncTesting = new SyncTestingInfrastructure();
-  Service.serverURL = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
   Service.identity.username = "foo";
 
   const NUMBER_OF_RECORDS = 10;
 
   let engine = makeRotaryEngine();
 
   // Create a batch of server side records.
   let collection = new ServerCollection();
   for (var i = 0; i < NUMBER_OF_RECORDS; i++) {
     let id = 'record-no-' + i;
     let payload = encryptPayload({id: id, denomination: "Record No. " + id});
     collection.insert(id, payload);
   }
 
+  let server = httpd_setup({
+    "/1.1/foo/storage/rotary": collection.handler()
+  });
+
+  let syncTesting = new SyncTestingInfrastructure(server);
+
   let meta_global = Service.recordManager.set(engine.metaURL,
                                               new WBORecord(engine.metaURL));
   meta_global.payload.engines = {rotary: {version: engine.version,
                                          syncID: engine.syncID}};
-  let server = httpd_setup({
-    "/1.1/foo/storage/rotary": collection.handler()
-  });
 
   let numApplyCalls = 0;
   let engine_name;
   let count;
   function onApplied(subject, data) {
     numApplyCalls++;
     engine_name = data;
     count = subject;
--- a/services/sync/tests/unit/test_syncscheduler.js
+++ b/services/sync/tests/unit/test_syncscheduler.js
@@ -47,19 +47,19 @@ function sync_httpd_setup() {
     "/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()),
     "/user/1.0/johndoe/node/weave": httpd_handler(200, "OK", "null")
   });
 }
 
-function setUp() {
+function setUp(server) {
   setBasicCredentials("johndoe", "ilovejane", "abcdeabcdeabcdeabcdeabcdea");
-  Service.clusterURL = TEST_CLUSTER_URL;
+  Service.clusterURL = server.baseURI + "/";
 
   generateNewKeys(Service.collectionKeys);
   let serverKeys = Service.collectionKeys.asWBO("crypto", "keys");
   serverKeys.encrypt(Service.identity.syncKeyBundle);
   return serverKeys.upload(Service.resource(Service.cryptoKeysURL)).success;
 }
 
 function cleanUpAndGo(server) {
@@ -191,17 +191,17 @@ add_test(function test_masterpassword_lo
 
   let oldVerifyLogin = Service.verifyLogin;
   Service.verifyLogin = function () {
     Status.login = MASTER_PASSWORD_LOCKED;
     return false;
   };
 
   let server = sync_httpd_setup();
-  setUp();
+  setUp(server);
 
   Service.sync();
 
   do_check_true(loginFailed);
   do_check_eq(Status.login, MASTER_PASSWORD_LOCKED);
   do_check_true(rescheduleInterval);
 
   Service.verifyLogin = oldVerifyLogin;
@@ -234,17 +234,17 @@ add_test(function test_calculateBackoff(
 
 add_test(function test_scheduleNextSync_nowOrPast() {
   Svc.Obs.add("weave:service:sync:finish", function onSyncFinish() {
     Svc.Obs.remove("weave:service:sync:finish", onSyncFinish);
     cleanUpAndGo(server);
   });
 
   let server = sync_httpd_setup();
-  setUp();
+  setUp(server);
 
   // We're late for a sync...
   scheduler.scheduleNextSync(-1);
 });
 
 add_test(function test_scheduleNextSync_future_noBackoff() {
   _("scheduleNextSync() uses the current syncInterval if no interval is provided.");
   // Test backoffInterval is 0 as expected.
@@ -341,17 +341,17 @@ add_test(function test_scheduleNextSync_
   do_check_true(scheduler.nextSync <= Date.now() + Status.backoffInterval);
   do_check_eq(scheduler.syncTimer.delay, Status.backoffInterval);
 
   cleanUpAndGo();
 });
 
 add_test(function test_handleSyncError() {
   let server = sync_httpd_setup();
-  setUp();
+  setUp(server);
 
   // Force sync to fail.
   Svc.Prefs.set("firstSync", "notReady");
 
   _("Ensure expected initial environment.");
   do_check_eq(scheduler._syncErrors, 0);
   do_check_false(Status.enforceBackoff);
   do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
@@ -399,17 +399,17 @@ add_test(function test_handleSyncError()
   do_check_true(Status.enforceBackoff);
   scheduler.syncTimer.clear();
 
   cleanUpAndGo(server);
 });
 
 add_test(function test_client_sync_finish_updateClientMode() {
   let server = sync_httpd_setup();
-  setUp();
+  setUp(server);
 
   // Confirm defaults.
   do_check_eq(scheduler.syncThreshold, SINGLE_USER_THRESHOLD);
   do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
   do_check_false(scheduler.idle);
 
   // Trigger a change in interval & threshold by adding a client.
   clientsEngine._store.create({id: "foo", cleartext: "bar"});
@@ -440,17 +440,17 @@ add_test(function test_autoconnect_nextS
   // nextSync will be 0 by default, so it's way in the past.
 
   Svc.Obs.add("weave:service:sync:finish", function onSyncFinish() {
     Svc.Obs.remove("weave:service:sync:finish", onSyncFinish);
     cleanUpAndGo(server);
   });
 
   let server = sync_httpd_setup();
-  setUp();
+  setUp(server);
 
   scheduler.delayedAutoConnect(0);
 });
 
 add_test(function test_autoconnect_nextSync_future() {
   let previousSync = Date.now() + scheduler.syncInterval / 2;
   scheduler.nextSync = previousSync;
   // nextSync rounds to the nearest second.
@@ -472,17 +472,17 @@ add_test(function test_autoconnect_nextS
   });
 
   setBasicCredentials("johndoe", "ilovejane", "abcdeabcdeabcdeabcdeabcdea");
   scheduler.delayedAutoConnect(0);
 });
 
 add_test(function test_autoconnect_mp_locked() {
   let server = sync_httpd_setup();
-  setUp();
+  setUp(server);
 
   // Pretend user did not unlock master password.
   let origLocked = Utils.mpLocked;
   Utils.mpLocked = function() true;
 
   let origGetter = Service.identity.__lookupGetter__("syncKey");
   let origSetter = Service.identity.__lookupSetter__("syncKey");
   delete Service.identity.syncKey;
@@ -507,17 +507,17 @@ add_test(function test_autoconnect_mp_lo
     });
   });
 
   scheduler.delayedAutoConnect(0);
 });
 
 add_test(function test_no_autoconnect_during_wizard() {
   let server = sync_httpd_setup();
-  setUp();
+  setUp(server);
 
   // Simulate the Sync setup wizard.
   Svc.Prefs.set("firstSync", "notReady");
 
   // Ensure we don't actually try to sync (or log in for that matter).
   function onLoginStart() {
     do_throw("Should not get here!");
   }
@@ -556,17 +556,17 @@ add_test(function test_autoconnectDelay_
   Svc.Obs.add("weave:service:sync:finish", function onSyncFinish() {
     Svc.Obs.remove("weave:service:sync:finish", onSyncFinish);
     cleanUpAndGo(server);
   });
 
   Svc.Prefs.set("autoconnectDelay", 1);
 
   let server = sync_httpd_setup();
-  setUp();
+  setUp(server);
 
   Svc.Obs.notify("weave:service:ready");
 
   // autoconnectDelay pref is multiplied by 1000.
   do_check_eq(scheduler._autoTimer.delay, 1000);
   do_check_eq(Status.service, STATUS_OK);
 });
 
@@ -665,19 +665,19 @@ add_test(function test_back_debouncing()
     cleanUpAndGo();
   }, IDLE_OBSERVER_BACK_DELAY * 1.5, {}, "timer");
 });
 
 add_test(function test_no_sync_node() {
   // Test when Status.sync == NO_SYNC_NODE_FOUND
   // it is not overwritten on sync:finish
   let server = sync_httpd_setup();
-  setUp();
+  setUp(server);
 
-  Service.serverURL = TEST_SERVER_URL;
+  Service.serverURL = server.baseURI + "/";
 
   Service.sync();
   do_check_eq(Status.sync, NO_SYNC_NODE_FOUND);
   do_check_eq(scheduler.syncTimer.delay, NO_SYNC_NODE_INTERVAL);
 
   cleanUpAndGo(server);
 });
 
@@ -687,17 +687,17 @@ add_test(function test_sync_failed_parti
   let server = sync_httpd_setup();
 
   let engine = Service.engineManager.get("catapult");
   engine.enabled = true;
   engine.exception = {status: 500};
 
   do_check_eq(Status.sync, SYNC_SUCCEEDED);
 
-  do_check_true(setUp());
+  do_check_true(setUp(server));
 
   Service.sync();
 
   do_check_eq(Status.service, SYNC_FAILED_PARTIAL);
 
   let maxInterval = scheduler._syncErrors * (2 * MINIMUM_BACKOFF_INTERVAL);
   do_check_eq(Status.backoffInterval, 0);
   do_check_true(Status.enforceBackoff);
@@ -717,17 +717,17 @@ add_test(function test_sync_failed_parti
   engine.enabled = true;
   engine.exception = {status: 400};
 
   // Have multiple devices for an active interval.
   clientsEngine._store.create({id: "foo", cleartext: "bar"});
 
   do_check_eq(Status.sync, SYNC_SUCCEEDED);
 
-  do_check_true(setUp());
+  do_check_true(setUp(server));
 
   Service.sync();
 
   do_check_eq(Status.service, SYNC_FAILED_PARTIAL);
   do_check_eq(scheduler.syncInterval, scheduler.activeInterval);
 
   do_check_eq(Status.backoffInterval, 0);
   do_check_false(Status.enforceBackoff);
@@ -735,17 +735,17 @@ add_test(function test_sync_failed_parti
   do_check_true(scheduler.nextSync <= (Date.now() + scheduler.activeInterval));
   do_check_true(scheduler.syncTimer.delay <= scheduler.activeInterval);
 
   cleanUpAndGo(server);
 });
 
 add_test(function test_sync_X_Weave_Backoff() {
   let server = sync_httpd_setup();
-  setUp();
+  setUp(server);
 
   // Use an odd value on purpose so that it doesn't happen to coincide with one
   // of the sync intervals.
   const BACKOFF = 7337;
 
   // Extend info/collections so that we can put it into server maintenance mode.
   const INFO_COLLECTIONS = "/1.1/johndoe/info/collections";
   let infoColl = server._handler._overridePaths[INFO_COLLECTIONS];
@@ -790,17 +790,17 @@ add_test(function test_sync_X_Weave_Back
   do_check_true(scheduler.nextSync >= Date.now() + minimumExpectedDelay);
   do_check_true(scheduler.syncTimer.delay >= minimumExpectedDelay);
 
   cleanUpAndGo(server);
 });
 
 add_test(function test_sync_503_Retry_After() {
   let server = sync_httpd_setup();
-  setUp();
+  setUp(server);
 
   // Use an odd value on purpose so that it doesn't happen to coincide with one
   // of the sync intervals.
   const BACKOFF = 7337;
 
   // Extend info/collections so that we can put it into server maintenance mode.
   const INFO_COLLECTIONS = "/1.1/johndoe/info/collections";
   let infoColl = server._handler._overridePaths[INFO_COLLECTIONS];
@@ -850,18 +850,18 @@ add_test(function test_sync_503_Retry_Af
   do_check_true(scheduler.syncTimer.delay >= minimumExpectedDelay);
 
   cleanUpAndGo(server);
 });
 
 add_test(function test_loginError_recoverable_reschedules() {
   _("Verify that a recoverable login error schedules a new sync.");
   setBasicCredentials("johndoe", "ilovejane", "abcdeabcdeabcdeabcdeabcdea");
-  Service.serverURL = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
+  Service.serverURL = "http://localhost:1234/";
+  Service.clusterURL = Service.serverURL;
   Service.persistLogin();
   Status.resetSync(); // reset Status.login
 
   Svc.Obs.add("weave:service:login:error", function onLoginError() {
     Svc.Obs.remove("weave:service:login:error", onLoginError);
     Utils.nextTick(function aLittleBitAfterLoginError() {
       do_check_eq(Status.login, LOGIN_FAILED_NETWORK_ERROR);
 
@@ -892,25 +892,26 @@ add_test(function test_loginError_recove
   do_check_eq(Status.login, LOGIN_SUCCEEDED);
 
   scheduler.scheduleNextSync(0);
 });
 
 add_test(function test_loginError_fatal_clearsTriggers() {
   _("Verify that a fatal login error clears sync triggers.");
   setBasicCredentials("johndoe", "ilovejane", "abcdeabcdeabcdeabcdeabcdea");
-  Service.serverURL = TEST_SERVER_URL;
-  Service.clusterURL = TEST_CLUSTER_URL;
-  Service.persistLogin();
-  Status.resetSync(); // reset Status.login
 
   let server = httpd_setup({
     "/1.1/johndoe/info/collections": httpd_handler(401, "Unauthorized")
   });
 
+  Service.serverURL = server.baseURI + "/";
+  Service.clusterURL = Service.serverURL;
+  Service.persistLogin();
+  Status.resetSync(); // reset Status.login
+
   Svc.Obs.add("weave:service:login:error", function onLoginError() {
     Svc.Obs.remove("weave:service:login:error", onLoginError);
     Utils.nextTick(function aLittleBitAfterLoginError() {
       do_check_eq(Status.login, LOGIN_FAILED_LOGIN_REJECTED);
 
       do_check_eq(scheduler.nextSync, 0);
       do_check_eq(scheduler.syncTimer, null);
 
--- a/services/sync/tests/unit/test_syncstoragerequest.js
+++ b/services/sync/tests/unit/test_syncstoragerequest.js
@@ -3,34 +3,32 @@
 
 Cu.import("resource://services-common/log4moz.js");
 Cu.import("resource://services-sync/constants.js");
 Cu.import("resource://services-sync/rest.js");
 Cu.import("resource://services-sync/service.js");
 Cu.import("resource://services-sync/util.js");
 Cu.import("resource://testing-common/services/sync/utils.js");
 
-const STORAGE_REQUEST_RESOURCE_URL = TEST_SERVER_URL + "resource";
-
 function run_test() {
   Log4Moz.repository.getLogger("Sync.RESTRequest").level = Log4Moz.Level.Trace;
   initTestLogging();
 
   run_next_test();
 }
 
 add_test(function test_user_agent_desktop() {
   let handler = httpd_handler(200, "OK");
   let server = httpd_setup({"/resource": handler});
 
   let expectedUA = Services.appinfo.name + "/" + Services.appinfo.version +
                    " FxSync/" + WEAVE_VERSION + "." +
                    Services.appinfo.appBuildID + ".desktop";
 
-  let request = new SyncStorageRequest(STORAGE_REQUEST_RESOURCE_URL);
+  let request = new SyncStorageRequest(server.baseURI + "/resource");
   request.onComplete = function onComplete(error) {
     do_check_eq(error, null);
     do_check_eq(this.response.status, 200);
     do_check_eq(handler.request.getHeader("User-Agent"), expectedUA);
     server.stop(run_next_test);
   };
   do_check_eq(request.get(), request);
 });
@@ -39,33 +37,33 @@ add_test(function test_user_agent_mobile
   let handler = httpd_handler(200, "OK");
   let server = httpd_setup({"/resource": handler});
 
   Svc.Prefs.set("client.type", "mobile");
   let expectedUA = Services.appinfo.name + "/" + Services.appinfo.version +
                    " FxSync/" + WEAVE_VERSION + "." +
                    Services.appinfo.appBuildID + ".mobile";
 
-  let request = new SyncStorageRequest(STORAGE_REQUEST_RESOURCE_URL);
+  let request = new SyncStorageRequest(server.baseURI + "/resource");
   request.get(function (error) {
     do_check_eq(error, null);
     do_check_eq(this.response.status, 200);
     do_check_eq(handler.request.getHeader("User-Agent"), expectedUA);
     Svc.Prefs.resetBranch("");
     server.stop(run_next_test);
   });
 });
 
 add_test(function test_auth() {
   let handler = httpd_handler(200, "OK");
   let server = httpd_setup({"/resource": handler});
 
   setBasicCredentials("johndoe", "ilovejane", "XXXXXXXXX");
 
-  let request = Service.getStorageRequest(STORAGE_REQUEST_RESOURCE_URL);
+  let request = Service.getStorageRequest(server.baseURI + "/resource");
   request.get(function (error) {
     do_check_eq(error, null);
     do_check_eq(this.response.status, 200);
     do_check_true(basic_auth_matches(handler.request, "johndoe", "ilovejane"));
 
     Svc.Prefs.reset("");
 
     server.stop(run_next_test);
@@ -79,17 +77,17 @@ add_test(function test_weave_timestamp()
   const TIMESTAMP = 1274380461;
   function handler(request, response) {
     response.setHeader("X-Weave-Timestamp", "" + TIMESTAMP, false);
     response.setStatusLine(request.httpVersion, 200, "OK");
   }
   let server = httpd_setup({"/resource": handler});
 
   do_check_eq(SyncStorageRequest.serverTime, undefined);
-  let request = new SyncStorageRequest(STORAGE_REQUEST_RESOURCE_URL);
+  let request = new SyncStorageRequest(server.baseURI + "/resource");
   request.get(function (error) {
     do_check_eq(error, null);
     do_check_eq(this.response.status, 200);
     do_check_eq(SyncStorageRequest.serverTime, TIMESTAMP);
     delete SyncStorageRequest.serverTime;
     server.stop(run_next_test);
   });
 });
@@ -105,17 +103,17 @@ add_test(function test_weave_backoff() {
   let server = httpd_setup({"/resource": handler});
 
   let backoffInterval;
   Svc.Obs.add("weave:service:backoff:interval", function onBackoff(subject) {
     Svc.Obs.remove("weave:service:backoff:interval", onBackoff);
     backoffInterval = subject;
   });
 
-  let request = new SyncStorageRequest(STORAGE_REQUEST_RESOURCE_URL);
+  let request = new SyncStorageRequest(server.baseURI + "/resource");
   request.get(function (error) {
     do_check_eq(error, null);
     do_check_eq(this.response.status, 200);
     do_check_eq(backoffInterval, 600);
     server.stop(run_next_test);
   });
 });
 
@@ -130,17 +128,17 @@ add_test(function test_weave_quota_notic
   let server = httpd_setup({"/resource": handler});
 
   let quotaValue;
   Svc.Obs.add("weave:service:quota:remaining", function onQuota(subject) {
     Svc.Obs.remove("weave:service:quota:remaining", onQuota);
     quotaValue = subject;
   });
 
-  let request = new SyncStorageRequest(STORAGE_REQUEST_RESOURCE_URL);
+  let request = new SyncStorageRequest(server.baseURI + "/resource");
   request.get(function (error) {
     do_check_eq(error, null);
     do_check_eq(this.response.status, 200);
     do_check_eq(quotaValue, 1048576);
     server.stop(run_next_test);
   });
 });
 
@@ -155,17 +153,17 @@ add_test(function test_weave_quota_error
   let server = httpd_setup({"/resource": handler});
 
   let quotaValue;
   function onQuota(subject) {
     quotaValue = subject;
   }
   Svc.Obs.add("weave:service:quota:remaining", onQuota);
 
-  let request = new SyncStorageRequest(STORAGE_REQUEST_RESOURCE_URL);
+  let request = new SyncStorageRequest(server.baseURI + "/resource");
   request.get(function (error) {
     do_check_eq(error, null);
     do_check_eq(this.response.status, 400);
     do_check_eq(quotaValue, undefined);
     Svc.Obs.remove("weave:service:quota:remaining", onQuota);
     server.stop(run_next_test);
   });
 });
@@ -174,17 +172,17 @@ add_test(function test_abort() {
   function handler(request, response) {
     response.setHeader("X-Weave-Timestamp", "" + TIMESTAMP, false);
     response.setHeader("X-Weave-Quota-Remaining", '1048576', false);
     response.setHeader("X-Weave-Backoff", '600', false);
     response.setStatusLine(request.httpVersion, 200, "OK");
   }
   let server = httpd_setup({"/resource": handler});
 
-  let request = new SyncStorageRequest(STORAGE_REQUEST_RESOURCE_URL);
+  let request = new SyncStorageRequest(server.baseURI + "/resource");
 
   // Aborting a request that hasn't been sent yet is pointless and will throw.
   do_check_throws(function () {
     request.abort();
   });
 
   function throwy() {
     do_throw("Shouldn't have gotten here!");
--- a/toolkit/content/widgets/tree.xml
+++ b/toolkit/content/widgets/tree.xml
@@ -38,17 +38,17 @@
       <children includes="treecols"/>
       <xul:stack class="tree-stack" flex="1">
         <xul:treerows class="tree-rows" flex="1" xbl:inherits="hidevscroll">
           <children/>
         </xul:treerows>
         <xul:textbox anonid="input" class="tree-input" left="0" top="0" hidden="true"/>
       </xul:stack>
       <xul:hbox xbl:inherits="collapsed=hidehscroll">
-        <xul:scrollbar orient="horizontal" flex="1" increment="16"/>
+        <xul:scrollbar orient="horizontal" flex="1" increment="16" style="position:relative; z-index:2147483647;"/>
         <xul:scrollcorner xbl:inherits="collapsed=hidevscroll"/>
       </xul:hbox>
     </content>
     
     <implementation implements="nsIDOMXULTreeElement, nsIDOMXULMultiSelectControlElement, nsIAccessibleProvider">
 
       <!-- ///////////////// nsIDOMXULTreeElement ///////////////// -->
 
@@ -960,17 +960,17 @@
     </implementation>
   </binding>
 
   <binding id="treerows" extends="chrome://global/content/bindings/tree.xml#tree-base">
     <content>
       <xul:hbox flex="1" class="tree-bodybox">
         <children/>
       </xul:hbox>
-      <xul:scrollbar height="0" minwidth="0" minheight="0" orient="vertical" xbl:inherits="collapsed=hidevscroll"/>
+      <xul:scrollbar height="0" minwidth="0" minheight="0" orient="vertical" xbl:inherits="collapsed=hidevscroll" style="position:relative; z-index:2147483647;"/>
     </content>
     <handlers>
       <handler event="underflow">
         <![CDATA[
           // Scrollport event orientation
           // 0: vertical
           // 1: horizontal
           // 2: both (not used)
--- a/toolkit/themes/osx/global/nativescrollbars.css
+++ b/toolkit/themes/osx/global/nativescrollbars.css
@@ -13,21 +13,16 @@ scrollbar {
 }
 
 html|select[size]:not([size="0"]):not([size="1"]) > scrollbar,
 html|select[multiple] > scrollbar {
   -moz-appearance: scrollbar-small;
 }
 
 @media all and (-moz-overlay-scrollbars) {
-  scrollbar {
-    position: relative;
-    z-index: 2147483647;
-  }
-
   scrollbar:not([active="true"]),
   scrollbar[disabled="true"] {
     visibility: hidden;
   }
 }
 
 /* ..... track ..... */