Bug 836437 - Part 1 of 3 - Unify DownloadLegacy tests in preparation for resuming support. r=enn
authorPaolo Amadini <paolo.mozmail@amadzone.org>
Fri, 26 Jul 2013 15:30:40 +0200
changeset 152388 8c3ee4235ec1e5cbb311fb52feb23c95b7003a7e
parent 152387 6ce49253650628609d7f4f3cc03b03942784012a
child 152389 8da2f00eb92ea5dc7f8b0e2f312153f6c03fd607
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)
reviewersenn
bugs836437
milestone25.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 836437 - Part 1 of 3 - Unify DownloadLegacy tests in preparation for resuming support. r=enn
toolkit/components/jsdownloads/test/unit/common_test_Download.js
toolkit/components/jsdownloads/test/unit/head.js
toolkit/components/jsdownloads/test/unit/test_DownloadCore.js
toolkit/components/jsdownloads/test/unit/test_DownloadLegacy.js
toolkit/components/jsdownloads/test/unit/test_DownloadList.js
toolkit/components/jsdownloads/test/unit/test_DownloadStore.js
copy from toolkit/components/jsdownloads/test/unit/test_DownloadCore.js
copy to toolkit/components/jsdownloads/test/unit/common_test_Download.js
--- a/toolkit/components/jsdownloads/test/unit/test_DownloadCore.js
+++ b/toolkit/components/jsdownloads/test/unit/common_test_Download.js
@@ -1,53 +1,121 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
- * Tests the objects defined in the "DownloadCore" module.
+ * This script is loaded by "test_DownloadCore.js" and "test_DownloadLegacy.js"
+ * with different values of the gUseLegacySaver variable, to apply tests to both
+ * the "copy" and "legacy" saver implementations.
  */
 
 "use strict";
 
 ////////////////////////////////////////////////////////////////////////////////
+//// Globals
+
+/**
+ * Creates and starts a new download, using either DownloadCopySaver or
+ * DownloadLegacySaver based on the current test run.
+ *
+ * @return {Promise}
+ * @resolves The newly created Download object.  The download may be in progress
+ *           or already finished.  The promiseDownloadStopped function can be
+ *           used to wait for completion.
+ * @rejects JavaScript exception.
+ */
+function promiseStartDownload(aSourceUrl) {
+  if (gUseLegacySaver) {
+    return promiseStartLegacyDownload(aSourceUrl);
+  }
+
+  return promiseNewDownload(aSourceUrl).then(download => {
+    download.start();
+    return download;
+  });
+}
+
+/**
+ * Waits for a download to finish, in case it has not finished already.
+ *
+ * @param aDownload
+ *        The Download object to wait upon.
+ *
+ * @return {Promise}
+ * @resolves When the download has finished successfully.
+ * @rejects JavaScript exception if the download failed.
+ */
+function promiseDownloadStopped(aDownload) {
+  if (!aDownload.stopped) {
+    // The download is in progress, wait for the current attempt to finish and
+    // report any errors that may occur.
+    return aDownload.start();
+  }
+
+  if (aDownload.succeeded) {
+    return Promise.resolve();
+  }
+
+  // The download failed or was canceled.
+  return Promise.reject(aDownload.error || new Error("Download canceled."));
+}
+
+////////////////////////////////////////////////////////////////////////////////
 //// Tests
 
 /**
- * Executes a download, started by constructing the simplest Download object.
+ * Executes a download and checks its basic properties after construction.
+ * The download is started by constructing the simplest Download object with
+ * the "copy" saver, or using the legacy nsITransfer interface.
  */
-add_task(function test_download_construction()
+add_task(function test_basic()
 {
-  let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
+  let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
+
+  let download;
+  if (!gUseLegacySaver) {
+    // When testing DownloadCopySaver, we have control over the download, thus
+    // we can check its basic properties before it starts.
+    download = yield Downloads.createDownload({
+      source: { url: httpUrl("source.txt") },
+      target: { path: targetFile.path },
+      saver: { type: "copy" },
+    });
 
-  let download = yield Downloads.createDownload({
-    source: { url: httpUrl("source.txt") },
-    target: { path: targetPath },
-    saver: { type: "copy" },
-  });
+    do_check_eq(download.source.url, httpUrl("source.txt"));
+    do_check_eq(download.target.path, targetFile.path);
 
-  // Checks the generated DownloadSource and DownloadTarget properties.
-  do_check_eq(download.source.url, httpUrl("source.txt"));
-  do_check_eq(download.target.path, targetPath);
+    yield download.start();
+  } else {
+    // When testing DownloadLegacySaver, the download is already started when it
+    // is created, thus we must check its basic properties while in progress.
+    download = yield promiseStartLegacyDownload(null,
+                                                { targetFile: targetFile });
+
+    do_check_eq(download.source.url, httpUrl("source.txt"));
+    do_check_eq(download.target.path, targetFile.path);
+
+    yield promiseDownloadStopped(download);
+  }
+
+  // Check additional properties on the finished download.
   do_check_true(download.source.referrer === null);
 
-  // Starts the download and waits for completion.
-  yield download.start();
-
-  yield promiseVerifyContents(targetPath, TEST_DATA_SHORT);
+  yield promiseVerifyContents(download.target.path, TEST_DATA_SHORT);
 });
 
 /**
  * Checks the referrer for downloads.
  */
-add_task(function test_download_referrer()
+add_task(function test_referrer()
 {
-  let sourcePath = "/test_download_referrer.txt";
-  let sourceUrl = httpUrl("test_download_referrer.txt");
+  let sourcePath = "/test_referrer.txt";
+  let sourceUrl = httpUrl("test_referrer.txt");
   let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
 
   function cleanup() {
     gHttpServer.registerPathHandler(sourcePath, null);
   }
 
   do_register_cleanup(cleanup);
 
@@ -82,168 +150,204 @@ add_task(function test_download_referrer
   yield download.start();
 
   cleanup();
 });
 
 /**
  * Checks initial and final state and progress for a successful download.
  */
-add_task(function test_download_initial_final_state()
+add_task(function test_initial_final_state()
 {
-  let download = yield promiseSimpleDownload();
+  let download;
+  if (!gUseLegacySaver) {
+    // When testing DownloadCopySaver, we have control over the download, thus
+    // we can check its state before it starts.
+    download = yield promiseNewDownload();
 
-  do_check_true(download.stopped);
-  do_check_false(download.succeeded);
-  do_check_false(download.canceled);
-  do_check_true(download.error === null);
-  do_check_eq(download.progress, 0);
-  do_check_true(download.startTime === null);
+    do_check_true(download.stopped);
+    do_check_false(download.succeeded);
+    do_check_false(download.canceled);
+    do_check_true(download.error === null);
+    do_check_eq(download.progress, 0);
+    do_check_true(download.startTime === null);
 
-  // Starts the download and waits for completion.
-  yield download.start();
+    yield download.start();
+  } else {
+    // When testing DownloadLegacySaver, the download is already started when it
+    // is created, thus we cannot check its initial state.
+    download = yield promiseStartLegacyDownload();
+    yield promiseDownloadStopped(download);
+  }
 
   do_check_true(download.stopped);
   do_check_true(download.succeeded);
   do_check_false(download.canceled);
   do_check_true(download.error === null);
   do_check_eq(download.progress, 100);
   do_check_true(isValidDate(download.startTime));
 });
 
 /**
  * Checks the notification of the final download state.
  */
-add_task(function test_download_final_state_notified()
+add_task(function test_final_state_notified()
 {
-  let download = yield promiseSimpleDownload();
+  let deferResponse = deferNextResponse();
+
+  let download = yield promiseStartDownload(httpUrl("interruptible.txt"));
 
   let onchangeNotified = false;
   let lastNotifiedStopped;
   let lastNotifiedProgress;
   download.onchange = function () {
     onchangeNotified = true;
     lastNotifiedStopped = download.stopped;
     lastNotifiedProgress = download.progress;
   };
 
-  // Starts the download and waits for completion.
-  yield download.start();
+  // Allow the download to complete.
+  let promiseAttempt = download.start();
+  deferResponse.resolve();
+  yield promiseAttempt;
 
   // The view should have been notified before the download completes.
   do_check_true(onchangeNotified);
   do_check_true(lastNotifiedStopped);
   do_check_eq(lastNotifiedProgress, 100);
 });
 
 /**
  * Checks intermediate progress for a successful download.
  */
-add_task(function test_download_intermediate_progress()
+add_task(function test_intermediate_progress()
 {
   let deferResponse = deferNextResponse();
 
-  let download = yield promiseSimpleDownload(httpUrl("interruptible.txt"));
+  let download = yield promiseStartDownload(httpUrl("interruptible.txt"));
 
-  download.onchange = function () {
+  let onchange = function () {
     if (download.progress == 50) {
       do_check_true(download.hasProgress);
       do_check_eq(download.currentBytes, TEST_DATA_SHORT.length);
       do_check_eq(download.totalBytes, TEST_DATA_SHORT.length * 2);
 
       // Continue after the first chunk of data is fully received.
       deferResponse.resolve();
     }
   };
 
-  // Starts the download and waits for completion.
-  yield download.start();
+  // Register for the notification, but also call the function directly in case
+  // the download already reached the expected progress.
+  download.onchange = onchange;
+  onchange();
+
+  yield promiseDownloadStopped(download);
 
   do_check_true(download.stopped);
   do_check_eq(download.progress, 100);
 
   yield promiseVerifyContents(download.target.path,
                               TEST_DATA_SHORT + TEST_DATA_SHORT);
 });
 
 /**
  * Downloads a file with a "Content-Length" of 0 and checks the progress.
  */
-add_task(function test_download_empty_progress()
+add_task(function test_empty_progress()
 {
-  let download = yield promiseSimpleDownload(httpUrl("empty.txt"));
-
-  yield download.start();
+  let download = yield promiseStartDownload(httpUrl("empty.txt"));
+  yield promiseDownloadStopped(download);
 
   do_check_true(download.stopped);
   do_check_true(download.hasProgress);
   do_check_eq(download.progress, 100);
   do_check_eq(download.currentBytes, 0);
   do_check_eq(download.totalBytes, 0);
 
   do_check_eq((yield OS.File.stat(download.target.path)).size, 0);
 });
 
 /**
  * Downloads an empty file with no "Content-Length" and checks the progress.
  */
-add_task(function test_download_empty_noprogress()
+add_task(function test_empty_noprogress()
 {
   let deferResponse = deferNextResponse();
   let promiseEmptyRequestReceived = promiseNextRequestReceived();
 
-  let download = yield promiseSimpleDownload(httpUrl("empty-noprogress.txt"));
+  let download;
+  if (!gUseLegacySaver) {
+    // When testing DownloadCopySaver, we have control over the download, thus
+    // we can hook its onchange callback that will be notified when the
+    // download starts.
+    download = yield promiseNewDownload(httpUrl("empty-noprogress.txt"));
 
-  download.onchange = function () {
-    if (!download.stopped) {
-      do_check_false(download.hasProgress);
-      do_check_eq(download.currentBytes, 0);
-      do_check_eq(download.totalBytes, 0);
-    }
-  };
+    download.onchange = function () {
+      if (!download.stopped) {
+        do_check_false(download.hasProgress);
+        do_check_eq(download.currentBytes, 0);
+        do_check_eq(download.totalBytes, 0);
+      }
+    };
 
-  // Start the download, while waiting for the request to be received.
-  let promiseAttempt = download.start();
+    download.start();
+  } else {
+    // When testing DownloadLegacySaver, the download is already started when it
+    // is created, and it may have already made all needed property change
+    // notifications, thus there is no point in checking the onchange callback.
+    download = yield promiseStartLegacyDownload(
+                                       httpUrl("empty-noprogress.txt"));
+  }
 
   // Wait for the request to be received by the HTTP server, but don't allow the
   // request to finish yet.  Before checking the download state, wait for the
   // events to be processed by the client.
   yield promiseEmptyRequestReceived;
   yield promiseExecuteSoon();
 
   // Check that this download has no progress report.
   do_check_false(download.stopped);
   do_check_false(download.hasProgress);
   do_check_eq(download.currentBytes, 0);
   do_check_eq(download.totalBytes, 0);
 
-  // Now allow the response to finish, and wait for the download to complete.
+  // Now allow the response to finish.
   deferResponse.resolve();
-  yield promiseAttempt;
+  yield promiseDownloadStopped(download);
 
   // Verify the state of the completed download.
   do_check_true(download.stopped);
   do_check_false(download.hasProgress);
   do_check_eq(download.progress, 100);
   do_check_eq(download.currentBytes, 0);
   do_check_eq(download.totalBytes, 0);
 
   do_check_eq((yield OS.File.stat(download.target.path)).size, 0);
 });
 
 /**
  * Calls the "start" method two times before the download is finished.
  */
-add_task(function test_download_start_twice()
+add_task(function test_start_twice()
 {
-  let download = yield promiseSimpleDownload(httpUrl("interruptible.txt"));
-
   // Ensure that the download cannot complete before start is called twice.
   let deferResponse = deferNextResponse();
 
+  let download;
+  if (!gUseLegacySaver) {
+    // When testing DownloadCopySaver, we have control over the download, thus
+    // we can start the download later during the test.
+    download = yield promiseNewDownload(httpUrl("interruptible.txt"));
+  } else {
+    // When testing DownloadLegacySaver, the download is already started when it
+    // is created.  Effectively, we are starting the download three times.
+    download = yield promiseStartLegacyDownload(httpUrl("interruptible.txt"));
+  }
+
   // Call the start method two times.
   let promiseAttempt1 = download.start();
   let promiseAttempt2 = download.start();
 
   // Allow the download to finish.
   deferResponse.resolve();
 
   // Both promises should now be resolved.
@@ -257,73 +361,99 @@ add_task(function test_download_start_tw
 
   yield promiseVerifyContents(download.target.path,
                               TEST_DATA_SHORT + TEST_DATA_SHORT);
 });
 
 /**
  * Cancels a download and verifies that its state is reported correctly.
  */
-add_task(function test_download_cancel_midway()
+add_task(function test_cancel_midway()
 {
-  let download = yield promiseSimpleDownload(httpUrl("interruptible.txt"));
+  let deferResponse = deferNextResponse();
 
-  let deferResponse = deferNextResponse();
+  // In this test case, we execute different checks that are only possible with
+  // DownloadCopySaver or DownloadLegacySaver respectively.
+  let download;
+  let options = {};
+  if (!gUseLegacySaver) {
+    download = yield promiseNewDownload(httpUrl("interruptible.txt"));
+  } else {
+    download = yield promiseStartLegacyDownload(httpUrl("interruptible.txt"),
+                                                options);
+  }
+
   try {
     // Cancel the download after receiving the first part of the response.
     let deferCancel = Promise.defer();
-    download.onchange = function () {
+    let onchange = function () {
       if (!download.stopped && !download.canceled && download.progress == 50) {
         deferCancel.resolve(download.cancel());
 
         // The state change happens immediately after calling "cancel", but
         // temporary files or part files may still exist at this point.
         do_check_true(download.canceled);
       }
     };
 
-    let promiseAttempt = download.start();
+    // Register for the notification, but also call the function directly in
+    // case the download already reached the expected progress.  This may happen
+    // when using DownloadLegacySaver.
+    download.onchange = onchange;
+    onchange();
+
+    let promiseAttempt;
+    if (!gUseLegacySaver) {
+      promiseAttempt = download.start();
+    }
 
     // Wait on the promise returned by the "cancel" method to ensure that the
     // cancellation process finished and temporary files were removed.
     yield deferCancel.promise;
 
+    if (gUseLegacySaver) {
+      // The nsIWebBrowserPersist instance should have been canceled now.
+      do_check_eq(options.outPersist.result, Cr.NS_ERROR_ABORT);
+    }
+
     do_check_true(download.stopped);
     do_check_true(download.canceled);
     do_check_true(download.error === null);
 
     do_check_false(yield OS.File.exists(download.target.path));
 
     // Progress properties are not reset by canceling.
     do_check_eq(download.progress, 50);
     do_check_eq(download.totalBytes, TEST_DATA_SHORT.length * 2);
     do_check_eq(download.currentBytes, TEST_DATA_SHORT.length);
 
-    // The promise returned by "start" should have been rejected meanwhile.
-    try {
-      yield promiseAttempt;
-      do_throw("The download should have been canceled.");
-    } catch (ex if ex instanceof Downloads.Error) {
-      do_check_false(ex.becauseSourceFailed);
-      do_check_false(ex.becauseTargetFailed);
+    if (!gUseLegacySaver) {
+      // The promise returned by "start" should have been rejected meanwhile.
+      try {
+        yield promiseAttempt;
+        do_throw("The download should have been canceled.");
+      } catch (ex if ex instanceof Downloads.Error) {
+        do_check_false(ex.becauseSourceFailed);
+        do_check_false(ex.becauseTargetFailed);
+      }
     }
   } finally {
     deferResponse.resolve();
   }
 });
 
 /**
  * Cancels a download right after starting it.
  */
-add_task(function test_download_cancel_immediately()
+add_task(function test_cancel_immediately()
 {
   // Ensure that the download cannot complete before cancel is called.
   let deferResponse = deferNextResponse();
   try {
-    let download = yield promiseSimpleDownload(httpUrl("interruptible.txt"));
+    let download = yield promiseStartDownload(httpUrl("interruptible.txt"));
 
     let promiseAttempt = download.start();
     do_check_false(download.stopped);
 
     let promiseCancel = download.cancel();
     do_check_true(download.canceled);
 
     // At this point, we don't know whether the download has already stopped or
@@ -356,19 +486,24 @@ add_task(function test_download_cancel_i
   for (let i = 0; i < 5; i++) {
     yield promiseExecuteSoon();
   }
 });
 
 /**
  * Cancels and restarts a download sequentially.
  */
-add_task(function test_download_cancel_midway_restart()
+add_task(function test_cancel_midway_restart()
 {
-  let download = yield promiseSimpleDownload(httpUrl("interruptible.txt"));
+  // TODO: Enable all the restart tests for DownloadLegacySaver.
+  if (gUseLegacySaver) {
+    return;
+  }
+
+  let download = yield promiseNewDownload(httpUrl("interruptible.txt"));
 
   // The first time, cancel the download midway.
   let deferResponse = deferNextResponse();
   try {
     let deferCancel = Promise.defer();
     download.onchange = function () {
       if (!download.stopped && !download.canceled && download.progress == 50) {
         deferCancel.resolve(download.cancel());
@@ -407,19 +542,24 @@ add_task(function test_download_cancel_m
 
   yield promiseVerifyContents(download.target.path,
                               TEST_DATA_SHORT + TEST_DATA_SHORT);
 });
 
 /**
  * Cancels a download right after starting it, then restarts it immediately.
  */
-add_task(function test_download_cancel_immediately_restart_immediately()
+add_task(function test_cancel_immediately_restart_immediately()
 {
-  let download = yield promiseSimpleDownload(httpUrl("interruptible.txt"));
+  // TODO: Enable all the restart tests for DownloadLegacySaver.
+  if (gUseLegacySaver) {
+    return;
+  }
+
+  let download = yield promiseNewDownload(httpUrl("interruptible.txt"));
 
   // Ensure that the download cannot complete before cancel is called.
   let deferResponse = deferNextResponse();
 
   let promiseAttempt = download.start();
   do_check_false(download.stopped);
 
   download.cancel();
@@ -467,19 +607,24 @@ add_task(function test_download_cancel_i
 
   yield promiseVerifyContents(download.target.path,
                               TEST_DATA_SHORT + TEST_DATA_SHORT);
 });
 
 /**
  * Cancels a download midway, then restarts it immediately.
  */
-add_task(function test_download_cancel_midway_restart_immediately()
+add_task(function test_cancel_midway_restart_immediately()
 {
-  let download = yield promiseSimpleDownload(httpUrl("interruptible.txt"));
+  // TODO: Enable all the restart tests for DownloadLegacySaver.
+  if (gUseLegacySaver) {
+    return;
+  }
+
+  let download = yield promiseNewDownload(httpUrl("interruptible.txt"));
 
   // The first time, cancel the download midway.
   let deferResponse = deferNextResponse();
 
   let deferMidway = Promise.defer();
   download.onchange = function () {
     if (!download.stopped && !download.canceled && download.progress == 50) {
       do_check_eq(download.progress, 50);
@@ -525,44 +670,42 @@ add_task(function test_download_cancel_m
 
   yield promiseVerifyContents(download.target.path,
                               TEST_DATA_SHORT + TEST_DATA_SHORT);
 });
 
 /**
  * Calls the "cancel" method on a successful download.
  */
-add_task(function test_download_cancel_successful()
+add_task(function test_cancel_successful()
 {
-  let download = yield promiseSimpleDownload();
-
-  // Starts the download and waits for completion.
-  yield download.start();
+  let download = yield promiseStartDownload();
+  yield promiseDownloadStopped(download);
 
   // The cancel method should succeed with no effect.
   yield download.cancel();
 
   do_check_true(download.stopped);
   do_check_true(download.succeeded);
   do_check_false(download.canceled);
   do_check_true(download.error === null);
 
   yield promiseVerifyContents(download.target.path, TEST_DATA_SHORT);
 });
 
 /**
  * Calls the "cancel" method two times in a row.
  */
-add_task(function test_download_cancel_twice()
+add_task(function test_cancel_twice()
 {
-  let download = yield promiseSimpleDownload(httpUrl("interruptible.txt"));
-
   // Ensure that the download cannot complete before cancel is called.
   let deferResponse = deferNextResponse();
   try {
+    let download = yield promiseStartDownload(httpUrl("interruptible.txt"));
+
     let promiseAttempt = download.start();
     do_check_false(download.stopped);
 
     let promiseCancel1 = download.cancel();
     do_check_true(download.canceled);
     let promiseCancel2 = download.cancel();
 
     try {
@@ -586,19 +729,24 @@ add_task(function test_download_cancel_t
   } finally {
     deferResponse.resolve();
   }
 });
 
 /**
  * Checks that whenSucceeded returns a promise that is resolved after a restart.
  */
-add_task(function test_download_whenSucceeded()
+add_task(function test_whenSucceeded_after_restart()
 {
-  let download = yield promiseSimpleDownload(httpUrl("interruptible.txt"));
+  // TODO: Enable all the restart tests for DownloadLegacySaver.
+  if (gUseLegacySaver) {
+    return;
+  }
+
+  let download = yield promiseNewDownload(httpUrl("interruptible.txt"));
 
   // Ensure that the download cannot complete before cancel is called.
   let deferResponse = deferNextResponse();
 
   // Get a reference before the first download attempt.
   let promiseSucceeded = download.whenSucceeded();
 
   // Cancel the first download attempt.
@@ -620,63 +768,90 @@ add_task(function test_download_whenSucc
 
   yield promiseVerifyContents(download.target.path,
                               TEST_DATA_SHORT + TEST_DATA_SHORT);
 });
 
 /**
  * Ensures download error details are reported on network failures.
  */
-add_task(function test_download_error_source()
+add_task(function test_error_source()
 {
   let serverSocket = startFakeServer();
   try {
     let sourceUrl = "http://localhost:" + serverSocket.port + "/source.txt";
 
-    let download = yield promiseSimpleDownload(sourceUrl);
+    let download;
+    try {
+      if (!gUseLegacySaver) {
+        // When testing DownloadCopySaver, we want to check that the promise
+        // returned by the "start" method is rejected.
+        download = yield promiseNewDownload(sourceUrl);
+
+        do_check_true(download.error === null);
 
-    do_check_true(download.error === null);
-
-    try {
-      yield download.start();
+        yield download.start();
+      } else {
+        // When testing DownloadLegacySaver, we cannot be sure whether we are
+        // testing the promise returned by the "start" method or we are testing
+        // the "error" property checked by promiseDownloadStopped.  This happens
+        // because we don't have control over when the download is started.
+        download = yield promiseStartLegacyDownload(sourceUrl);
+        yield promiseDownloadStopped(download);
+      }
       do_throw("The download should have failed.");
     } catch (ex if ex instanceof Downloads.Error && ex.becauseSourceFailed) {
       // A specific error object is thrown when reading from the source fails.
     }
 
+    // Check the properties now that the download stopped.
     do_check_true(download.stopped);
     do_check_false(download.canceled);
     do_check_true(download.error !== null);
     do_check_true(download.error.becauseSourceFailed);
     do_check_false(download.error.becauseTargetFailed);
   } finally {
     serverSocket.close();
   }
 });
 
 /**
  * Ensures download error details are reported on local writing failures.
  */
-add_task(function test_download_error_target()
+add_task(function test_error_target()
 {
-  let download = yield promiseSimpleDownload();
-
-  do_check_true(download.error === null);
-
   // Create a file without write access permissions before downloading.
-  let targetFile = new FileUtils.File(download.target.path);
+  let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
   targetFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0);
   try {
+    let download;
     try {
-      yield download.start();
+      if (!gUseLegacySaver) {
+        // When testing DownloadCopySaver, we want to check that the promise
+        // returned by the "start" method is rejected.
+        download = yield Downloads.createDownload({
+          source: httpUrl("source.txt"),
+          target: targetFile,
+        });
+        yield download.start();
+      } else {
+        // When testing DownloadLegacySaver, we cannot be sure whether we are
+        // testing the promise returned by the "start" method or we are testing
+        // the "error" property checked by promiseDownloadStopped.  This happens
+        // because we don't have control over when the download is started.
+        download = yield promiseStartLegacyDownload(null,
+                                                    { targetFile: targetFile });
+        yield promiseDownloadStopped(download);
+      }
       do_throw("The download should have failed.");
     } catch (ex if ex instanceof Downloads.Error && ex.becauseTargetFailed) {
       // A specific error object is thrown when writing to the target fails.
     }
 
+    // Check the properties now that the download stopped.
     do_check_true(download.stopped);
     do_check_false(download.canceled);
     do_check_true(download.error !== null);
     do_check_true(download.error.becauseTargetFailed);
     do_check_false(download.error.becauseSourceFailed);
   } finally {
     // Restore the default permissions to allow deleting the file on Windows.
     if (targetFile.exists()) {
@@ -684,19 +859,24 @@ add_task(function test_download_error_ta
       targetFile.remove(false);
     }
   }
 });
 
 /**
  * Restarts a failed download.
  */
-add_task(function test_download_error_restart()
+add_task(function test_error_restart()
 {
-  let download = yield promiseSimpleDownload();
+  // TODO: Enable all the restart tests for DownloadLegacySaver.
+  if (gUseLegacySaver) {
+    return;
+  }
+
+  let download = yield promiseNewDownload();
 
   do_check_true(download.error === null);
 
   // Create a file without write access permissions before downloading.
   let targetFile = new FileUtils.File(download.target.path);
   targetFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0);
 
   try {
@@ -727,20 +907,20 @@ add_task(function test_download_error_re
   do_check_eq(download.progress, 100);
 
   yield promiseVerifyContents(download.target.path, TEST_DATA_SHORT);
 });
 
 /**
  * Executes download in both public and private modes.
  */
-add_task(function test_download_public_and_private()
+add_task(function test_public_and_private()
 {
-  let sourcePath = "/test_download_public_and_private.txt";
-  let sourceUrl = httpUrl("test_download_public_and_private.txt");
+  let sourcePath = "/test_public_and_private.txt";
+  let sourceUrl = httpUrl("test_public_and_private.txt");
   let testCount = 0;
 
   // Apply pref to allow all cookies.
   Services.prefs.setIntPref("network.cookie.cookieBehavior", 0);
 
   function cleanup() {
     Services.prefs.clearUserPref("network.cookie.cookieBehavior");
     Services.cookies.removeAll();
@@ -765,31 +945,43 @@ add_task(function test_download_public_a
       // No cookies should exist for first private download.
       do_check_false(aRequest.hasHeader("Cookie"));
     }
   });
 
   let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
   yield Downloads.simpleDownload(sourceUrl, targetFile);
   yield Downloads.simpleDownload(sourceUrl, targetFile);
-  let download = yield Downloads.createDownload({
-    source: { url: sourceUrl, isPrivate: true },
-    target: targetFile,
-  });
-  yield download.start();
+
+  if (!gUseLegacySaver) {
+    let download = yield Downloads.createDownload({
+      source: { url: sourceUrl, isPrivate: true },
+      target: targetFile,
+    });
+    yield download.start();
+  } else {
+    let download = yield promiseStartLegacyDownload(sourceUrl,
+                                                    { isPrivate: true });
+    yield promiseDownloadStopped(download);
+  }
 
   cleanup();
 });
 
 /**
  * Checks the startTime gets updated even after a restart.
  */
-add_task(function test_download_cancel_immediately_restart_and_check_startTime()
+add_task(function test_cancel_immediately_restart_and_check_startTime()
 {
-  let download = yield promiseSimpleDownload();
+  // TODO: Enable all the restart tests for DownloadLegacySaver.
+  if (gUseLegacySaver) {
+    return;
+  }
+
+  let download = yield promiseNewDownload();
 
   download.start();
   let startTime = download.startTime;
   do_check_true(isValidDate(download.startTime));
 
   yield download.cancel();
   do_check_eq(download.startTime.getTime(), startTime.getTime());
 
@@ -798,20 +990,20 @@ add_task(function test_download_cancel_i
 
   yield download.start();
   do_check_true(download.startTime.getTime() > startTime.getTime());
 });
 
 /**
  * Executes download with content-encoding.
  */
-add_task(function test_download_with_content_encoding()
+add_task(function test_with_content_encoding()
 {
-  let sourcePath = "/test_download_with_content_encoding.txt";
-  let sourceUrl = httpUrl("test_download_with_content_encoding.txt");
+  let sourcePath = "/test_with_content_encoding.txt";
+  let sourceUrl = httpUrl("test_with_content_encoding.txt");
 
   function cleanup() {
     gHttpServer.registerPathHandler(sourcePath, null);
   }
   do_register_cleanup(cleanup);
 
   gHttpServer.registerPathHandler(sourcePath, function (aRequest, aResponse) {
     aResponse.setHeader("Content-Type", "text/plain", false);
@@ -819,35 +1011,37 @@ add_task(function test_download_with_con
     aResponse.setHeader("Content-Length",
                         "" + TEST_DATA_SHORT_GZIP_ENCODED.length, false);
 
     let bos =  new BinaryOutputStream(aResponse.bodyOutputStream);
     bos.writeByteArray(TEST_DATA_SHORT_GZIP_ENCODED,
                        TEST_DATA_SHORT_GZIP_ENCODED.length);
   });
 
-  let download = yield Downloads.createDownload({
-    source: sourceUrl,
-    target: getTempFile(TEST_TARGET_FILE_NAME),
-  });
-  yield download.start();
+  let download = yield promiseStartDownload(sourceUrl);
+  yield promiseDownloadStopped(download);
 
   do_check_eq(download.progress, 100);
   do_check_eq(download.totalBytes, TEST_DATA_SHORT_GZIP_ENCODED.length);
 
   // Ensure the content matches the decoded test data.
   yield promiseVerifyContents(download.target.path, TEST_DATA_SHORT);
 });
 
 /**
  * Cancels and restarts a download sequentially with content-encoding.
  */
-add_task(function test_download_cancel_midway_restart_with_content_encoding()
+add_task(function test_cancel_midway_restart_with_content_encoding()
 {
-  let download = yield promiseSimpleDownload(httpUrl("interruptible_gzip.txt"));
+  // TODO: Enable all the restart tests for DownloadLegacySaver.
+  if (gUseLegacySaver) {
+    return;
+  }
+
+  let download = yield promiseNewDownload(httpUrl("interruptible_gzip.txt"));
 
   // The first time, cancel the download midway.
   let deferResponse = deferNextResponse();
   try {
     let deferCancel = Promise.defer();
     download.onchange = function () {
       if (!download.stopped && !download.canceled &&
           download.currentBytes == TEST_DATA_SHORT_GZIP_ENCODED_FIRST.length) {
@@ -870,27 +1064,42 @@ add_task(function test_download_cancel_m
   do_check_eq(download.totalBytes, TEST_DATA_SHORT_GZIP_ENCODED.length);
 
   yield promiseVerifyContents(download.target.path, TEST_DATA_SHORT);
 });
 
 /**
  * Download with parental controls enabled.
  */
-add_task(function test_download_blocked_parental_controls()
+add_task(function test_blocked_parental_controls()
 {
   function cleanup() {
     DownloadIntegration.shouldBlockInTest = false;
   }
   do_register_cleanup(cleanup);
   DownloadIntegration.shouldBlockInTest = true;
 
-  let download = yield promiseSimpleDownload();
-
+  let download;
   try {
-    yield download.start();
+    if (!gUseLegacySaver) {
+      // When testing DownloadCopySaver, we want to check that the promise
+      // returned by the "start" method is rejected.
+      download = yield promiseNewDownload();
+      yield download.start();
+    } else {
+      // When testing DownloadLegacySaver, we cannot be sure whether we are
+      // testing the promise returned by the "start" method or we are testing
+      // the "error" property checked by promiseDownloadStopped.  This happens
+      // because we don't have control over when the download is started.
+      download = yield promiseStartLegacyDownload();
+      yield promiseDownloadStopped(download);
+    }
     do_throw("The download should have blocked.");
   } catch (ex if ex instanceof Downloads.Error && ex.becauseBlocked) {
     do_check_true(ex.becauseBlockedByParentalControls);
   }
+
+  // Now that the download stopped, the target file should not exist.
+  do_check_false(yield OS.File.exists(download.target.path));
+
   cleanup();
 });
 
--- a/toolkit/components/jsdownloads/test/unit/head.js
+++ b/toolkit/components/jsdownloads/test/unit/head.js
@@ -167,24 +167,104 @@ function promiseTimeout(aTime)
  * @param aSourceUrl
  *        String containing the URI for the download source, or null to use
  *        httpUrl("source.txt").
  *
  * @return {Promise}
  * @resolves The newly created Download object.
  * @rejects JavaScript exception.
  */
-function promiseSimpleDownload(aSourceUrl) {
+function promiseNewDownload(aSourceUrl) {
   return Downloads.createDownload({
     source: aSourceUrl || httpUrl("source.txt"),
     target: getTempFile(TEST_TARGET_FILE_NAME),
   });
 }
 
 /**
+ * Starts a new download using the nsIWebBrowserPersist interface, and controls
+ * it using the legacy nsITransfer interface.
+ *
+ * @param aSourceUrl
+ *        String containing the URI for the download source, or null to use
+ *        httpUrl("source.txt").
+ * @param aOptions
+ *        An optional object used to control the behavior of this function.
+ *        You may pass an object with a subset of the following fields:
+ *        {
+ *          isPrivate: Boolean indicating whether the download originated from a
+ *                     private window.
+ *          targetFile: nsIFile for the target, or null to use a temporary file.
+ *          outPersist: Receives a reference to the created nsIWebBrowserPersist
+ *                      instance.
+ *        }
+ *
+ * @return {Promise}
+ * @resolves The Download object created as a consequence of controlling the
+ *           download through the legacy nsITransfer interface.
+ * @rejects Never.  The current test fails in case of exceptions.
+ */
+function promiseStartLegacyDownload(aSourceUrl, aOptions) {
+  let sourceURI = NetUtil.newURI(aSourceUrl || httpUrl("source.txt"));
+  let targetFile = (aOptions && aOptions.targetFile)
+                   || getTempFile(TEST_TARGET_FILE_NAME);
+
+  let persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
+                  .createInstance(Ci.nsIWebBrowserPersist);
+  if (aOptions) {
+    aOptions.outPersist = persist;
+  }
+
+  // Apply decoding if required by the "Content-Encoding" header.
+  persist.persistFlags &= ~Ci.nsIWebBrowserPersist.PERSIST_FLAGS_NO_CONVERSION;
+
+  // We must create the nsITransfer implementation using its class ID because
+  // the "@mozilla.org/transfer;1" contract is currently implemented in
+  // "toolkit/components/downloads".  When the other folder is not included in
+  // builds anymore (bug 851471), we'll be able to use the contract ID.
+  let transfer =
+      Components.classesByID["{1b4c85df-cbdd-4bb6-b04e-613caece083c}"]
+                .createInstance(Ci.nsITransfer);
+
+  let deferred = Promise.defer();
+
+  let isPrivate = aOptions && aOptions.isPrivate;
+  let promise = isPrivate ? Downloads.getPrivateDownloadList()
+                          : Downloads.getPublicDownloadList();
+  promise.then(function (aList) {
+    // Temporarily register a view that will get notified when the download we
+    // are controlling becomes visible in the list of downloads.
+    aList.addView({
+      onDownloadAdded: function (aDownload) {
+        aList.removeView(this);
+
+        // Remove the download to keep the list empty for the next test.  This
+        // also allows the caller to register the "onchange" event directly.
+        aList.remove(aDownload);
+
+        // When the download object is ready, make it available to the caller.
+        deferred.resolve(aDownload);
+      },
+    });
+
+    // Initialize the components so they reference each other.  This will cause
+    // the Download object to be created and added to the public downloads.
+    transfer.init(sourceURI, NetUtil.newURI(targetFile), null, null, null, null,
+                  persist, isPrivate);
+    persist.progressListener = transfer;
+
+    // Start the actual download process.
+    persist.savePrivacyAwareURI(sourceURI, null, null, null, null, targetFile,
+                                isPrivate);
+  }.bind(this)).then(null, do_report_unexpected_exception);
+
+  return deferred.promise;
+}
+
+/**
  * Returns a new public DownloadList object.
  *
  * @return {Promise}
  * @resolves The newly created DownloadList object.
  * @rejects JavaScript exception.
  */
 function promiseNewDownloadList() {
   // Force the creation of a new public download list.
--- a/toolkit/components/jsdownloads/test/unit/test_DownloadCore.js
+++ b/toolkit/components/jsdownloads/test/unit/test_DownloadCore.js
@@ -1,896 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
- * Tests the objects defined in the "DownloadCore" module.
+ * Tests the main download interfaces using DownloadCopySaver.
  */
 
 "use strict";
 
 ////////////////////////////////////////////////////////////////////////////////
-//// Tests
-
-/**
- * Executes a download, started by constructing the simplest Download object.
- */
-add_task(function test_download_construction()
-{
-  let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
-
-  let download = yield Downloads.createDownload({
-    source: { url: httpUrl("source.txt") },
-    target: { path: targetPath },
-    saver: { type: "copy" },
-  });
-
-  // Checks the generated DownloadSource and DownloadTarget properties.
-  do_check_eq(download.source.url, httpUrl("source.txt"));
-  do_check_eq(download.target.path, targetPath);
-  do_check_true(download.source.referrer === null);
-
-  // Starts the download and waits for completion.
-  yield download.start();
-
-  yield promiseVerifyContents(targetPath, TEST_DATA_SHORT);
-});
-
-/**
- * Checks the referrer for downloads.
- */
-add_task(function test_download_referrer()
-{
-  let sourcePath = "/test_download_referrer.txt";
-  let sourceUrl = httpUrl("test_download_referrer.txt");
-  let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
-
-  function cleanup() {
-    gHttpServer.registerPathHandler(sourcePath, null);
-  }
-
-  do_register_cleanup(cleanup);
-
-  gHttpServer.registerPathHandler(sourcePath, function (aRequest, aResponse) {
-    aResponse.setHeader("Content-Type", "text/plain", false);
-
-    do_check_true(aRequest.hasHeader("Referer"));
-    do_check_eq(aRequest.getHeader("Referer"), TEST_REFERRER_URL);
-  });
-  let download = yield Downloads.createDownload({
-    source: { url: sourceUrl, referrer: TEST_REFERRER_URL },
-    target: targetPath,
-  });
-  do_check_eq(download.source.referrer, TEST_REFERRER_URL);
-  yield download.start();
-
-  download = yield Downloads.createDownload({
-    source: { url: sourceUrl, referrer: TEST_REFERRER_URL,
-              isPrivate: true },
-    target: targetPath,
-  });
-  do_check_eq(download.source.referrer, TEST_REFERRER_URL);
-  yield download.start();
-
-  // Test the download still works for non-HTTP channel with referrer.
-  sourceUrl = "data:text/html,<html><body></body></html>";
-  download = yield Downloads.createDownload({
-    source: { url: sourceUrl, referrer: TEST_REFERRER_URL },
-    target: targetPath,
-  });
-  do_check_eq(download.source.referrer, TEST_REFERRER_URL);
-  yield download.start();
-
-  cleanup();
-});
-
-/**
- * Checks initial and final state and progress for a successful download.
- */
-add_task(function test_download_initial_final_state()
-{
-  let download = yield promiseSimpleDownload();
-
-  do_check_true(download.stopped);
-  do_check_false(download.succeeded);
-  do_check_false(download.canceled);
-  do_check_true(download.error === null);
-  do_check_eq(download.progress, 0);
-  do_check_true(download.startTime === null);
-
-  // Starts the download and waits for completion.
-  yield download.start();
-
-  do_check_true(download.stopped);
-  do_check_true(download.succeeded);
-  do_check_false(download.canceled);
-  do_check_true(download.error === null);
-  do_check_eq(download.progress, 100);
-  do_check_true(isValidDate(download.startTime));
-});
-
-/**
- * Checks the notification of the final download state.
- */
-add_task(function test_download_final_state_notified()
-{
-  let download = yield promiseSimpleDownload();
-
-  let onchangeNotified = false;
-  let lastNotifiedStopped;
-  let lastNotifiedProgress;
-  download.onchange = function () {
-    onchangeNotified = true;
-    lastNotifiedStopped = download.stopped;
-    lastNotifiedProgress = download.progress;
-  };
-
-  // Starts the download and waits for completion.
-  yield download.start();
-
-  // The view should have been notified before the download completes.
-  do_check_true(onchangeNotified);
-  do_check_true(lastNotifiedStopped);
-  do_check_eq(lastNotifiedProgress, 100);
-});
-
-/**
- * Checks intermediate progress for a successful download.
- */
-add_task(function test_download_intermediate_progress()
-{
-  let deferResponse = deferNextResponse();
-
-  let download = yield promiseSimpleDownload(httpUrl("interruptible.txt"));
-
-  download.onchange = function () {
-    if (download.progress == 50) {
-      do_check_true(download.hasProgress);
-      do_check_eq(download.currentBytes, TEST_DATA_SHORT.length);
-      do_check_eq(download.totalBytes, TEST_DATA_SHORT.length * 2);
-
-      // Continue after the first chunk of data is fully received.
-      deferResponse.resolve();
-    }
-  };
-
-  // Starts the download and waits for completion.
-  yield download.start();
-
-  do_check_true(download.stopped);
-  do_check_eq(download.progress, 100);
-
-  yield promiseVerifyContents(download.target.path,
-                              TEST_DATA_SHORT + TEST_DATA_SHORT);
-});
-
-/**
- * Downloads a file with a "Content-Length" of 0 and checks the progress.
- */
-add_task(function test_download_empty_progress()
-{
-  let download = yield promiseSimpleDownload(httpUrl("empty.txt"));
-
-  yield download.start();
-
-  do_check_true(download.stopped);
-  do_check_true(download.hasProgress);
-  do_check_eq(download.progress, 100);
-  do_check_eq(download.currentBytes, 0);
-  do_check_eq(download.totalBytes, 0);
-
-  do_check_eq((yield OS.File.stat(download.target.path)).size, 0);
-});
-
-/**
- * Downloads an empty file with no "Content-Length" and checks the progress.
- */
-add_task(function test_download_empty_noprogress()
-{
-  let deferResponse = deferNextResponse();
-  let promiseEmptyRequestReceived = promiseNextRequestReceived();
-
-  let download = yield promiseSimpleDownload(httpUrl("empty-noprogress.txt"));
-
-  download.onchange = function () {
-    if (!download.stopped) {
-      do_check_false(download.hasProgress);
-      do_check_eq(download.currentBytes, 0);
-      do_check_eq(download.totalBytes, 0);
-    }
-  };
-
-  // Start the download, while waiting for the request to be received.
-  let promiseAttempt = download.start();
-
-  // Wait for the request to be received by the HTTP server, but don't allow the
-  // request to finish yet.  Before checking the download state, wait for the
-  // events to be processed by the client.
-  yield promiseEmptyRequestReceived;
-  yield promiseExecuteSoon();
-
-  // Check that this download has no progress report.
-  do_check_false(download.stopped);
-  do_check_false(download.hasProgress);
-  do_check_eq(download.currentBytes, 0);
-  do_check_eq(download.totalBytes, 0);
-
-  // Now allow the response to finish, and wait for the download to complete.
-  deferResponse.resolve();
-  yield promiseAttempt;
-
-  // Verify the state of the completed download.
-  do_check_true(download.stopped);
-  do_check_false(download.hasProgress);
-  do_check_eq(download.progress, 100);
-  do_check_eq(download.currentBytes, 0);
-  do_check_eq(download.totalBytes, 0);
-
-  do_check_eq((yield OS.File.stat(download.target.path)).size, 0);
-});
-
-/**
- * Calls the "start" method two times before the download is finished.
- */
-add_task(function test_download_start_twice()
-{
-  let download = yield promiseSimpleDownload(httpUrl("interruptible.txt"));
-
-  // Ensure that the download cannot complete before start is called twice.
-  let deferResponse = deferNextResponse();
-
-  // Call the start method two times.
-  let promiseAttempt1 = download.start();
-  let promiseAttempt2 = download.start();
-
-  // Allow the download to finish.
-  deferResponse.resolve();
-
-  // Both promises should now be resolved.
-  yield promiseAttempt1;
-  yield promiseAttempt2;
-
-  do_check_true(download.stopped);
-  do_check_true(download.succeeded);
-  do_check_false(download.canceled);
-  do_check_true(download.error === null);
-
-  yield promiseVerifyContents(download.target.path,
-                              TEST_DATA_SHORT + TEST_DATA_SHORT);
-});
-
-/**
- * Cancels a download and verifies that its state is reported correctly.
- */
-add_task(function test_download_cancel_midway()
-{
-  let download = yield promiseSimpleDownload(httpUrl("interruptible.txt"));
-
-  let deferResponse = deferNextResponse();
-  try {
-    // Cancel the download after receiving the first part of the response.
-    let deferCancel = Promise.defer();
-    download.onchange = function () {
-      if (!download.stopped && !download.canceled && download.progress == 50) {
-        deferCancel.resolve(download.cancel());
-
-        // The state change happens immediately after calling "cancel", but
-        // temporary files or part files may still exist at this point.
-        do_check_true(download.canceled);
-      }
-    };
-
-    let promiseAttempt = download.start();
-
-    // Wait on the promise returned by the "cancel" method to ensure that the
-    // cancellation process finished and temporary files were removed.
-    yield deferCancel.promise;
-
-    do_check_true(download.stopped);
-    do_check_true(download.canceled);
-    do_check_true(download.error === null);
-
-    do_check_false(yield OS.File.exists(download.target.path));
-
-    // Progress properties are not reset by canceling.
-    do_check_eq(download.progress, 50);
-    do_check_eq(download.totalBytes, TEST_DATA_SHORT.length * 2);
-    do_check_eq(download.currentBytes, TEST_DATA_SHORT.length);
-
-    // The promise returned by "start" should have been rejected meanwhile.
-    try {
-      yield promiseAttempt;
-      do_throw("The download should have been canceled.");
-    } catch (ex if ex instanceof Downloads.Error) {
-      do_check_false(ex.becauseSourceFailed);
-      do_check_false(ex.becauseTargetFailed);
-    }
-  } finally {
-    deferResponse.resolve();
-  }
-});
-
-/**
- * Cancels a download right after starting it.
- */
-add_task(function test_download_cancel_immediately()
-{
-  // Ensure that the download cannot complete before cancel is called.
-  let deferResponse = deferNextResponse();
-  try {
-    let download = yield promiseSimpleDownload(httpUrl("interruptible.txt"));
-
-    let promiseAttempt = download.start();
-    do_check_false(download.stopped);
-
-    let promiseCancel = download.cancel();
-    do_check_true(download.canceled);
-
-    // At this point, we don't know whether the download has already stopped or
-    // is still waiting for cancellation.  We can wait on the promise returned
-    // by the "start" method to know for sure.
-    try {
-      yield promiseAttempt;
-      do_throw("The download should have been canceled.");
-    } catch (ex if ex instanceof Downloads.Error) {
-      do_check_false(ex.becauseSourceFailed);
-      do_check_false(ex.becauseTargetFailed);
-    }
-
-    do_check_true(download.stopped);
-    do_check_true(download.canceled);
-    do_check_true(download.error === null);
-
-    do_check_false(yield OS.File.exists(download.target.path));
-
-    // Check that the promise returned by the "cancel" method has been resolved.
-    yield promiseCancel;
-  } finally {
-    deferResponse.resolve();
-  }
-
-  // Even if we canceled the download immediately, the HTTP request might have
-  // been made, and the internal HTTP handler might be waiting to process it.
-  // Thus, we process any pending events now, to avoid that the request is
-  // processed during the tests that follow, interfering with them.
-  for (let i = 0; i < 5; i++) {
-    yield promiseExecuteSoon();
-  }
-});
-
-/**
- * Cancels and restarts a download sequentially.
- */
-add_task(function test_download_cancel_midway_restart()
-{
-  let download = yield promiseSimpleDownload(httpUrl("interruptible.txt"));
-
-  // The first time, cancel the download midway.
-  let deferResponse = deferNextResponse();
-  try {
-    let deferCancel = Promise.defer();
-    download.onchange = function () {
-      if (!download.stopped && !download.canceled && download.progress == 50) {
-        deferCancel.resolve(download.cancel());
-      }
-    };
-    download.start();
-    yield deferCancel.promise;
-  } finally {
-    deferResponse.resolve();
-  }
-
-  do_check_true(download.stopped);
-
-  // The second time, we'll provide the entire interruptible response.
-  download.onchange = null;
-  let promiseAttempt = download.start();
-
-  // Download state should have already been reset.
-  do_check_false(download.stopped);
-  do_check_false(download.canceled);
-  do_check_true(download.error === null);
-
-  // For the following test, we rely on the network layer reporting its progress
-  // asynchronously.  Otherwise, there is nothing stopping the restarted
-  // download from reaching the same progress as the first request already.
-  do_check_eq(download.progress, 0);
-  do_check_eq(download.totalBytes, 0);
-  do_check_eq(download.currentBytes, 0);
-
-  yield promiseAttempt;
-
-  do_check_true(download.stopped);
-  do_check_true(download.succeeded);
-  do_check_false(download.canceled);
-  do_check_true(download.error === null);
-
-  yield promiseVerifyContents(download.target.path,
-                              TEST_DATA_SHORT + TEST_DATA_SHORT);
-});
-
-/**
- * Cancels a download right after starting it, then restarts it immediately.
- */
-add_task(function test_download_cancel_immediately_restart_immediately()
-{
-  let download = yield promiseSimpleDownload(httpUrl("interruptible.txt"));
-
-  // Ensure that the download cannot complete before cancel is called.
-  let deferResponse = deferNextResponse();
-
-  let promiseAttempt = download.start();
-  do_check_false(download.stopped);
-
-  download.cancel();
-  do_check_true(download.canceled);
-
-  let promiseRestarted = download.start();
-  do_check_false(download.stopped);
-  do_check_false(download.canceled);
-  do_check_true(download.error === null);
-
-  // For the following test, we rely on the network layer reporting its progress
-  // asynchronously.  Otherwise, there is nothing stopping the restarted
-  // download from reaching the same progress as the first request already.
-  do_check_eq(download.hasProgress, false);
-  do_check_eq(download.progress, 0);
-  do_check_eq(download.totalBytes, 0);
-  do_check_eq(download.currentBytes, 0);
-
-  // Even if we canceled the download immediately, the HTTP request might have
-  // been made, and the internal HTTP handler might be waiting to process it.
-  // Thus, we process any pending events now, to avoid that the request is
-  // processed during the tests that follow, interfering with them.
-  for (let i = 0; i < 5; i++) {
-    yield promiseExecuteSoon();
-  }
-
-  // Ensure the next request is now allowed to complete, regardless of whether
-  // the canceled request was received by the server or not.
-  deferResponse.resolve();
+//// Execution of common tests
 
-  try {
-    yield promiseAttempt;
-    do_throw("The download should have been canceled.");
-  } catch (ex if ex instanceof Downloads.Error) {
-    do_check_false(ex.becauseSourceFailed);
-    do_check_false(ex.becauseTargetFailed);
-  }
-
-  yield promiseRestarted;
-
-  do_check_true(download.stopped);
-  do_check_true(download.succeeded);
-  do_check_false(download.canceled);
-  do_check_true(download.error === null);
-
-  yield promiseVerifyContents(download.target.path,
-                              TEST_DATA_SHORT + TEST_DATA_SHORT);
-});
-
-/**
- * Cancels a download midway, then restarts it immediately.
- */
-add_task(function test_download_cancel_midway_restart_immediately()
-{
-  let download = yield promiseSimpleDownload(httpUrl("interruptible.txt"));
-
-  // The first time, cancel the download midway.
-  let deferResponse = deferNextResponse();
-
-  let deferMidway = Promise.defer();
-  download.onchange = function () {
-    if (!download.stopped && !download.canceled && download.progress == 50) {
-      do_check_eq(download.progress, 50);
-      deferMidway.resolve();
-    }
-  };
-  let promiseAttempt = download.start();
-  yield deferMidway.promise;
-
-  download.cancel();
-  do_check_true(download.canceled);
-
-  let promiseRestarted = download.start();
-  do_check_false(download.stopped);
-  do_check_false(download.canceled);
-  do_check_true(download.error === null);
-
-  // For the following test, we rely on the network layer reporting its progress
-  // asynchronously.  Otherwise, there is nothing stopping the restarted
-  // download from reaching the same progress as the first request already.
-  do_check_eq(download.hasProgress, false);
-  do_check_eq(download.progress, 0);
-  do_check_eq(download.totalBytes, 0);
-  do_check_eq(download.currentBytes, 0);
-
-  deferResponse.resolve();
-
-  // The second request is allowed to complete.
-  try {
-    yield promiseAttempt;
-    do_throw("The download should have been canceled.");
-  } catch (ex if ex instanceof Downloads.Error) {
-    do_check_false(ex.becauseSourceFailed);
-    do_check_false(ex.becauseTargetFailed);
-  }
-
-  yield promiseRestarted;
-
-  do_check_true(download.stopped);
-  do_check_true(download.succeeded);
-  do_check_false(download.canceled);
-  do_check_true(download.error === null);
-
-  yield promiseVerifyContents(download.target.path,
-                              TEST_DATA_SHORT + TEST_DATA_SHORT);
-});
-
-/**
- * Calls the "cancel" method on a successful download.
- */
-add_task(function test_download_cancel_successful()
-{
-  let download = yield promiseSimpleDownload();
-
-  // Starts the download and waits for completion.
-  yield download.start();
-
-  // The cancel method should succeed with no effect.
-  yield download.cancel();
-
-  do_check_true(download.stopped);
-  do_check_true(download.succeeded);
-  do_check_false(download.canceled);
-  do_check_true(download.error === null);
-
-  yield promiseVerifyContents(download.target.path, TEST_DATA_SHORT);
-});
-
-/**
- * Calls the "cancel" method two times in a row.
- */
-add_task(function test_download_cancel_twice()
-{
-  let download = yield promiseSimpleDownload(httpUrl("interruptible.txt"));
-
-  // Ensure that the download cannot complete before cancel is called.
-  let deferResponse = deferNextResponse();
-  try {
-    let promiseAttempt = download.start();
-    do_check_false(download.stopped);
-
-    let promiseCancel1 = download.cancel();
-    do_check_true(download.canceled);
-    let promiseCancel2 = download.cancel();
-
-    try {
-      yield promiseAttempt;
-      do_throw("The download should have been canceled.");
-    } catch (ex if ex instanceof Downloads.Error) {
-      do_check_false(ex.becauseSourceFailed);
-      do_check_false(ex.becauseTargetFailed);
-    }
-
-    // Both promises should now be resolved.
-    yield promiseCancel1;
-    yield promiseCancel2;
-
-    do_check_true(download.stopped);
-    do_check_false(download.succeeded);
-    do_check_true(download.canceled);
-    do_check_true(download.error === null);
-
-    do_check_false(yield OS.File.exists(download.target.path));
-  } finally {
-    deferResponse.resolve();
-  }
-});
-
-/**
- * Checks that whenSucceeded returns a promise that is resolved after a restart.
- */
-add_task(function test_download_whenSucceeded()
-{
-  let download = yield promiseSimpleDownload(httpUrl("interruptible.txt"));
-
-  // Ensure that the download cannot complete before cancel is called.
-  let deferResponse = deferNextResponse();
-
-  // Get a reference before the first download attempt.
-  let promiseSucceeded = download.whenSucceeded();
-
-  // Cancel the first download attempt.
-  download.start();
-  yield download.cancel();
-
-  deferResponse.resolve();
-
-  // The second request is allowed to complete.
-  download.start();
-
-  // Wait for the download to finish by waiting on the whenSucceeded promise.
-  yield promiseSucceeded;
-
-  do_check_true(download.stopped);
-  do_check_true(download.succeeded);
-  do_check_false(download.canceled);
-  do_check_true(download.error === null);
-
-  yield promiseVerifyContents(download.target.path,
-                              TEST_DATA_SHORT + TEST_DATA_SHORT);
-});
-
-/**
- * Ensures download error details are reported on network failures.
- */
-add_task(function test_download_error_source()
-{
-  let serverSocket = startFakeServer();
-  try {
-    let sourceUrl = "http://localhost:" + serverSocket.port + "/source.txt";
-
-    let download = yield promiseSimpleDownload(sourceUrl);
-
-    do_check_true(download.error === null);
-
-    try {
-      yield download.start();
-      do_throw("The download should have failed.");
-    } catch (ex if ex instanceof Downloads.Error && ex.becauseSourceFailed) {
-      // A specific error object is thrown when reading from the source fails.
-    }
-
-    do_check_true(download.stopped);
-    do_check_false(download.canceled);
-    do_check_true(download.error !== null);
-    do_check_true(download.error.becauseSourceFailed);
-    do_check_false(download.error.becauseTargetFailed);
-  } finally {
-    serverSocket.close();
-  }
-});
-
-/**
- * Ensures download error details are reported on local writing failures.
- */
-add_task(function test_download_error_target()
-{
-  let download = yield promiseSimpleDownload();
-
-  do_check_true(download.error === null);
-
-  // Create a file without write access permissions before downloading.
-  let targetFile = new FileUtils.File(download.target.path);
-  targetFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0);
-  try {
-    try {
-      yield download.start();
-      do_throw("The download should have failed.");
-    } catch (ex if ex instanceof Downloads.Error && ex.becauseTargetFailed) {
-      // A specific error object is thrown when writing to the target fails.
-    }
+let gUseLegacySaver = false;
 
-    do_check_true(download.stopped);
-    do_check_false(download.canceled);
-    do_check_true(download.error !== null);
-    do_check_true(download.error.becauseTargetFailed);
-    do_check_false(download.error.becauseSourceFailed);
-  } finally {
-    // Restore the default permissions to allow deleting the file on Windows.
-    if (targetFile.exists()) {
-      targetFile.permissions = FileUtils.PERMS_FILE;
-      targetFile.remove(false);
-    }
-  }
-});
-
-/**
- * Restarts a failed download.
- */
-add_task(function test_download_error_restart()
-{
-  let download = yield promiseSimpleDownload();
-
-  do_check_true(download.error === null);
-
-  // Create a file without write access permissions before downloading.
-  let targetFile = new FileUtils.File(download.target.path);
-  targetFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0);
-
-  try {
-    yield download.start();
-    do_throw("The download should have failed.");
-  } catch (ex if ex instanceof Downloads.Error && ex.becauseTargetFailed) {
-    // A specific error object is thrown when writing to the target fails.
-  } finally {
-    // Restore the default permissions to allow deleting the file on Windows.
-    if (targetFile.exists()) {
-      targetFile.permissions = FileUtils.PERMS_FILE;
-
-      // Also for Windows, rename the file before deleting.  This makes the
-      // current file name available immediately for a new file, while deleting
-      // in place prevents creation of a file with the same name for some time.
-      targetFile.moveTo(null, targetFile.leafName + ".delete.tmp");
-      targetFile.remove(false);
-    }
-  }
-
-  // Restart the download and wait for completion.
-  yield download.start();
-
-  do_check_true(download.stopped);
-  do_check_true(download.succeeded);
-  do_check_false(download.canceled);
-  do_check_true(download.error === null);
-  do_check_eq(download.progress, 100);
-
-  yield promiseVerifyContents(download.target.path, TEST_DATA_SHORT);
-});
-
-/**
- * Executes download in both public and private modes.
- */
-add_task(function test_download_public_and_private()
-{
-  let sourcePath = "/test_download_public_and_private.txt";
-  let sourceUrl = httpUrl("test_download_public_and_private.txt");
-  let testCount = 0;
-
-  // Apply pref to allow all cookies.
-  Services.prefs.setIntPref("network.cookie.cookieBehavior", 0);
-
-  function cleanup() {
-    Services.prefs.clearUserPref("network.cookie.cookieBehavior");
-    Services.cookies.removeAll();
-    gHttpServer.registerPathHandler(sourcePath, null);
-  }
-  do_register_cleanup(cleanup);
-
-  gHttpServer.registerPathHandler(sourcePath, function (aRequest, aResponse) {
-    aResponse.setHeader("Content-Type", "text/plain", false);
-
-    if (testCount == 0) {
-      // No cookies should exist for first public download.
-      do_check_false(aRequest.hasHeader("Cookie"));
-      aResponse.setHeader("Set-Cookie", "foobar=1", false);
-      testCount++;
-    } else if (testCount == 1) {
-      // The cookie should exists for second public download.
-      do_check_true(aRequest.hasHeader("Cookie"));
-      do_check_eq(aRequest.getHeader("Cookie"), "foobar=1");
-      testCount++;
-    } else if (testCount == 2)  {
-      // No cookies should exist for first private download.
-      do_check_false(aRequest.hasHeader("Cookie"));
-    }
-  });
-
-  let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
-  yield Downloads.simpleDownload(sourceUrl, targetFile);
-  yield Downloads.simpleDownload(sourceUrl, targetFile);
-  let download = yield Downloads.createDownload({
-    source: { url: sourceUrl, isPrivate: true },
-    target: targetFile,
-  });
-  yield download.start();
-
-  cleanup();
-});
-
-/**
- * Checks the startTime gets updated even after a restart.
- */
-add_task(function test_download_cancel_immediately_restart_and_check_startTime()
-{
-  let download = yield promiseSimpleDownload();
-
-  download.start();
-  let startTime = download.startTime;
-  do_check_true(isValidDate(download.startTime));
-
-  yield download.cancel();
-  do_check_eq(download.startTime.getTime(), startTime.getTime());
-
-  // Wait for a timeout.
-  yield promiseTimeout(10);
-
-  yield download.start();
-  do_check_true(download.startTime.getTime() > startTime.getTime());
-});
-
-/**
- * Executes download with content-encoding.
- */
-add_task(function test_download_with_content_encoding()
-{
-  let sourcePath = "/test_download_with_content_encoding.txt";
-  let sourceUrl = httpUrl("test_download_with_content_encoding.txt");
-
-  function cleanup() {
-    gHttpServer.registerPathHandler(sourcePath, null);
-  }
-  do_register_cleanup(cleanup);
-
-  gHttpServer.registerPathHandler(sourcePath, function (aRequest, aResponse) {
-    aResponse.setHeader("Content-Type", "text/plain", false);
-    aResponse.setHeader("Content-Encoding", "gzip", false);
-    aResponse.setHeader("Content-Length",
-                        "" + TEST_DATA_SHORT_GZIP_ENCODED.length, false);
-
-    let bos =  new BinaryOutputStream(aResponse.bodyOutputStream);
-    bos.writeByteArray(TEST_DATA_SHORT_GZIP_ENCODED,
-                       TEST_DATA_SHORT_GZIP_ENCODED.length);
-  });
-
-  let download = yield Downloads.createDownload({
-    source: sourceUrl,
-    target: getTempFile(TEST_TARGET_FILE_NAME),
-  });
-  yield download.start();
-
-  do_check_eq(download.progress, 100);
-  do_check_eq(download.totalBytes, TEST_DATA_SHORT_GZIP_ENCODED.length);
-
-  // Ensure the content matches the decoded test data.
-  yield promiseVerifyContents(download.target.path, TEST_DATA_SHORT);
-});
-
-/**
- * Cancels and restarts a download sequentially with content-encoding.
- */
-add_task(function test_download_cancel_midway_restart_with_content_encoding()
-{
-  let download = yield promiseSimpleDownload(httpUrl("interruptible_gzip.txt"));
-
-  // The first time, cancel the download midway.
-  let deferResponse = deferNextResponse();
-  try {
-    let deferCancel = Promise.defer();
-    download.onchange = function () {
-      if (!download.stopped && !download.canceled &&
-          download.currentBytes == TEST_DATA_SHORT_GZIP_ENCODED_FIRST.length) {
-        deferCancel.resolve(download.cancel());
-      }
-    };
-    download.start();
-    yield deferCancel.promise;
-  } finally {
-    deferResponse.resolve();
-  }
-
-  do_check_true(download.stopped);
-
-  // The second time, we'll provide the entire interruptible response.
-  download.onchange = null;
-  yield download.start()
-
-  do_check_eq(download.progress, 100);
-  do_check_eq(download.totalBytes, TEST_DATA_SHORT_GZIP_ENCODED.length);
-
-  yield promiseVerifyContents(download.target.path, TEST_DATA_SHORT);
-});
-
-/**
- * Download with parental controls enabled.
- */
-add_task(function test_download_blocked_parental_controls()
-{
-  function cleanup() {
-    DownloadIntegration.shouldBlockInTest = false;
-  }
-  do_register_cleanup(cleanup);
-  DownloadIntegration.shouldBlockInTest = true;
-
-  let download = yield promiseSimpleDownload();
-
-  try {
-    yield download.start();
-    do_throw("The download should have blocked.");
-  } catch (ex if ex instanceof Downloads.Error && ex.becauseBlocked) {
-    do_check_true(ex.becauseBlockedByParentalControls);
-  }
-  cleanup();
-});
-
+let scriptFile = do_get_file("common_test_Download.js");
+Services.scriptloader.loadSubScript(NetUtil.newURI(scriptFile).spec);
--- a/toolkit/components/jsdownloads/test/unit/test_DownloadLegacy.js
+++ b/toolkit/components/jsdownloads/test/unit/test_DownloadLegacy.js
@@ -5,380 +5,14 @@
 
 /**
  * Tests the integration with legacy interfaces for downloads.
  */
 
 "use strict";
 
 ////////////////////////////////////////////////////////////////////////////////
-//// Globals
-
-/**
- * Starts a new download using the nsIWebBrowserPersist interface, and controls
- * it using the legacy nsITransfer interface.
- *
- * @param aSourceUrl
- *        String containing the URI for the download source, or null to use
- *        httpUrl("source.txt").
- * @param isPrivate
- *        Optional boolean indicates whether the download originated from a
- *        private window.
- * @param aOutPersist
- *        Optional object that receives a reference to the created
- *        nsIWebBrowserPersist instance in the "value" property.
- *
- * @return {Promise}
- * @resolves The Download object created as a consequence of controlling the
- *           download through the legacy nsITransfer interface.
- * @rejects Never.  The current test fails in case of exceptions.
- */
-function promiseStartLegacyDownload(aSourceUrl, aIsPrivate, aOutPersist) {
-  let sourceURI = NetUtil.newURI(aSourceUrl || httpUrl("source.txt"));
-  let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
-
-  let persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
-                  .createInstance(Ci.nsIWebBrowserPersist);
-
-  // We must create the nsITransfer implementation using its class ID because
-  // the "@mozilla.org/transfer;1" contract is currently implemented in
-  // "toolkit/components/downloads".  When the other folder is not included in
-  // builds anymore (bug 851471), we'll be able to use the contract ID.
-  let transfer =
-      Components.classesByID["{1b4c85df-cbdd-4bb6-b04e-613caece083c}"]
-                .createInstance(Ci.nsITransfer);
-
-  if (aOutPersist) {
-    aOutPersist.value = persist;
-  }
-
-  let deferred = Promise.defer();
-  let promise = aIsPrivate ? Downloads.getPrivateDownloadList() :
-                Downloads.getPublicDownloadList();
-  promise.then(function (aList) {
-    // Temporarily register a view that will get notified when the download we
-    // are controlling becomes visible in the list of public downloads.
-    aList.addView({
-      onDownloadAdded: function (aDownload) {
-        aList.removeView(this);
-
-        // Remove the download to keep the list empty for the next test.  This
-        // also allows the caller to register the "onchange" event directly.
-        aList.remove(aDownload);
-
-        // When the download object is ready, make it available to the caller.
-        deferred.resolve(aDownload);
-      },
-    });
-
-    // Initialize the components so they reference each other.  This will cause
-    // the Download object to be created and added to the public downloads.
-    transfer.init(sourceURI, NetUtil.newURI(targetFile), null, null, null, null,
-                  persist, aIsPrivate);
-    persist.progressListener = transfer;
-
-    // Start the actual download process.
-    persist.savePrivacyAwareURI(sourceURI, null, null, null, null, targetFile, aIsPrivate);
-  }.bind(this)).then(null, do_report_unexpected_exception);
-
-  return deferred.promise;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//// Tests
-
-/**
- * Executes a download controlled by the legacy nsITransfer interface.
- */
-add_task(function test_basic()
-{
-  let tempDirectory = FileUtils.getDir("TmpD", []);
-
-  let download = yield promiseStartLegacyDownload();
-
-  // Checks the generated DownloadSource and DownloadTarget properties.
-  do_check_eq(download.source.url, httpUrl("source.txt"));
-  do_check_true(new FileUtils.File(download.target.path).parent
-                                                        .equals(tempDirectory));
-
-  // The download is already started, wait for completion and report any errors.
-  if (!download.stopped) {
-    yield download.start();
-  }
-
-  yield promiseVerifyContents(download.target.path, TEST_DATA_SHORT);
-});
-
-/**
- * Checks final state and progress for a successful download.
- */
-add_task(function test_final_state()
-{
-  let download = yield promiseStartLegacyDownload();
-
-  // The download is already started, wait for completion and report any errors.
-  if (!download.stopped) {
-    yield download.start();
-  }
-
-  do_check_true(download.stopped);
-  do_check_true(download.succeeded);
-  do_check_false(download.canceled);
-  do_check_true(download.error === null);
-  do_check_eq(download.progress, 100);
-});
-
-/**
- * Checks intermediate progress for a successful download.
- */
-add_task(function test_intermediate_progress()
-{
-  let deferResponse = deferNextResponse();
-
-  let download = yield promiseStartLegacyDownload(httpUrl("interruptible.txt"));
-
-  let onchange = function () {
-    if (download.progress == 50) {
-      do_check_true(download.hasProgress);
-      do_check_eq(download.currentBytes, TEST_DATA_SHORT.length);
-      do_check_eq(download.totalBytes, TEST_DATA_SHORT.length * 2);
-
-      // Continue after the first chunk of data is fully received.
-      deferResponse.resolve();
-    }
-  };
-
-  // Register for the notification, but also call the function directly in case
-  // the download already reached the expected progress.
-  download.onchange = onchange;
-  onchange();
-
-  // The download is already started, wait for completion and report any errors.
-  if (!download.stopped) {
-    yield download.start();
-  }
-
-  do_check_true(download.stopped);
-  do_check_eq(download.progress, 100);
-
-  yield promiseVerifyContents(download.target.path,
-                              TEST_DATA_SHORT + TEST_DATA_SHORT);
-});
-
-/**
- * Downloads a file with a "Content-Length" of 0 and checks the progress.
- */
-add_task(function test_empty_progress()
-{
-  let download = yield promiseStartLegacyDownload(httpUrl("empty.txt"));
-
-  // The download is already started, wait for completion and report any errors.
-  if (!download.stopped) {
-    yield download.start();
-  }
-
-  do_check_true(download.stopped);
-  do_check_true(download.hasProgress);
-  do_check_eq(download.progress, 100);
-  do_check_eq(download.currentBytes, 0);
-  do_check_eq(download.totalBytes, 0);
-
-  do_check_eq((yield OS.File.stat(download.target.path)).size, 0);
-});
-
-/**
- * Downloads an empty file with no "Content-Length" and checks the progress.
- */
-add_task(function test_empty_noprogress()
-{
-  let deferResponse = deferNextResponse();
-  let promiseEmptyRequestReceived = promiseNextRequestReceived();
-
-  let download = yield promiseStartLegacyDownload(
-                                         httpUrl("empty-noprogress.txt"));
+//// Execution of common tests
 
-  // Wait for the request to be received by the HTTP server, but don't allow the
-  // request to finish yet.  Before checking the download state, wait for the
-  // events to be processed by the client.
-  yield promiseEmptyRequestReceived;
-  yield promiseExecuteSoon();
-
-  // Check that this download has no progress report.
-  do_check_false(download.stopped);
-  do_check_false(download.hasProgress);
-  do_check_eq(download.currentBytes, 0);
-  do_check_eq(download.totalBytes, 0);
-
-  // Now allow the response to finish, and wait for the download to complete,
-  // while reporting any errors that may occur.
-  deferResponse.resolve();
-  if (!download.stopped) {
-    yield download.start();
-  }
-
-  // Verify the state of the completed download.
-  do_check_true(download.stopped);
-  do_check_false(download.hasProgress);
-  do_check_eq(download.progress, 100);
-  do_check_eq(download.currentBytes, 0);
-  do_check_eq(download.totalBytes, 0);
-
-  do_check_eq((yield OS.File.stat(download.target.path)).size, 0);
-});
-
-/**
- * Cancels a download and verifies that its state is reported correctly.
- */
-add_task(function test_cancel_midway()
-{
-  let deferResponse = deferNextResponse();
-  let outPersist = {};
-  let download = yield promiseStartLegacyDownload(httpUrl("interruptible.txt"),
-                                                  false, outPersist);
-
-  try {
-    // Cancel the download after receiving the first part of the response.
-    let deferCancel = Promise.defer();
-    let onchange = function () {
-      if (!download.stopped && !download.canceled && download.progress == 50) {
-        deferCancel.resolve(download.cancel());
-
-        // The state change happens immediately after calling "cancel", but
-        // temporary files or part files may still exist at this point.
-        do_check_true(download.canceled);
-      }
-    };
-
-    // Register for the notification, but also call the function directly in
-    // case the download already reached the expected progress.
-    download.onchange = onchange;
-    onchange();
-
-    // Wait on the promise returned by the "cancel" method to ensure that the
-    // cancellation process finished and temporary files were removed.
-    yield deferCancel.promise;
-
-    // The nsIWebBrowserPersist instance should have been canceled now.
-    do_check_eq(outPersist.value.result, Cr.NS_ERROR_ABORT);
-
-    do_check_true(download.stopped);
-    do_check_true(download.canceled);
-    do_check_true(download.error === null);
-
-    do_check_false(yield OS.File.exists(download.target.path));
-
-    // Progress properties are not reset by canceling.
-    do_check_eq(download.progress, 50);
-    do_check_eq(download.totalBytes, TEST_DATA_SHORT.length * 2);
-    do_check_eq(download.currentBytes, TEST_DATA_SHORT.length);
-  } finally {
-    deferResponse.resolve();
-  }
-});
-
-/**
- * Ensures download error details are reported for legacy downloads.
- */
-add_task(function test_error()
-{
-  let serverSocket = startFakeServer();
-  try {
-    let sourceUrl = "http://localhost:" + serverSocket.port + "/source.txt";
-
-    let download = yield promiseStartLegacyDownload(sourceUrl);
+let gUseLegacySaver = true;
 
-    // We must check the download properties instead of calling the "start"
-    // method because the download has been started and may already be stopped.
-    let deferStopped = Promise.defer();
-    let onchange = function () {
-      if (download.stopped) {
-        deferStopped.resolve();
-      }
-    };
-    download.onchange = onchange;
-    onchange();
-    yield deferStopped.promise;
-
-    // Check the properties now that the download stopped.
-    do_check_false(download.canceled);
-    do_check_true(download.error !== null);
-    do_check_true(download.error.becauseSourceFailed);
-    do_check_false(download.error.becauseTargetFailed);
-  } finally {
-    serverSocket.close();
-  }
-});
-
-/**
- * Executes download in both public and private modes.
- */
-add_task(function test_download_public_and_private()
-{
-  let sourcePath = "/test_download_public_and_private.txt";
-  let sourceUrl = httpUrl("test_download_public_and_private.txt");
-  let testCount = 0;
-
-  // Apply pref to allow all cookies.
-  Services.prefs.setIntPref("network.cookie.cookieBehavior", 0);
-
-  function cleanup() {
-    Services.prefs.clearUserPref("network.cookie.cookieBehavior");
-    Services.cookies.removeAll();
-    gHttpServer.registerPathHandler(sourcePath, null);
-  }
-
-  do_register_cleanup(cleanup);
-
-  gHttpServer.registerPathHandler(sourcePath, function (aRequest, aResponse) {
-    aResponse.setHeader("Content-Type", "text/plain", false);
-
-    if (testCount == 0) {
-      // No cookies should exist for first public download.
-      do_check_false(aRequest.hasHeader("Cookie"));
-      aResponse.setHeader("Set-Cookie", "foobar=1", false);
-      testCount++;
-    } else if (testCount == 1) {
-      // The cookie should exists for second public download.
-      do_check_true(aRequest.hasHeader("Cookie"));
-      do_check_eq(aRequest.getHeader("Cookie"), "foobar=1");
-      testCount++;
-    } else if (testCount == 2)  {
-      // No cookies should exist for first private download.
-      do_check_false(aRequest.hasHeader("Cookie"));
-    }
-  });
-
-  let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
-  yield Downloads.simpleDownload(sourceUrl, targetFile);
-  yield Downloads.simpleDownload(sourceUrl, targetFile);
-  let download = yield promiseStartLegacyDownload(sourceUrl, true);
-  // The download is already started, wait for completion and report any errors.
-  if (!download.stopped) {
-    yield download.start();
-  }
-
-  cleanup();
-});
-
-/**
- * Download with parental controls enabled.
- */
-add_task(function test_download_blocked_parental_controls()
-{
-  function cleanup() {
-    DownloadIntegration.shouldBlockInTest = false;
-  }
-  do_register_cleanup(cleanup);
-  DownloadIntegration.shouldBlockInTest = true;
-
-  let download = yield promiseStartLegacyDownload();
-
-  try {
-    yield download.start();
-    do_throw("The download should have blocked.");
-  } catch (ex if ex instanceof Downloads.Error && ex.becauseBlocked) {
-    do_check_true(ex.becauseBlockedByParentalControls);
-  }
-
-  do_check_false(yield OS.File.exists(download.target.path));
-
-  cleanup();
-});
+let scriptFile = do_get_file("common_test_Download.js");
+Services.scriptloader.loadSubScript(NetUtil.newURI(scriptFile).spec);
--- a/toolkit/components/jsdownloads/test/unit/test_DownloadList.js
+++ b/toolkit/components/jsdownloads/test/unit/test_DownloadList.js
@@ -29,24 +29,24 @@ add_task(function test_construction()
 
 /**
  * Checks the methods to add and retrieve items from the list.
  */
 add_task(function test_add_getAll()
 {
   let list = yield promiseNewDownloadList();
 
-  let downloadOne = yield promiseSimpleDownload();
+  let downloadOne = yield promiseNewDownload();
   list.add(downloadOne);
 
   let itemsOne = yield list.getAll();
   do_check_eq(itemsOne.length, 1);
   do_check_eq(itemsOne[0], downloadOne);
 
-  let downloadTwo = yield promiseSimpleDownload();
+  let downloadTwo = yield promiseNewDownload();
   list.add(downloadTwo);
 
   let itemsTwo = yield list.getAll();
   do_check_eq(itemsTwo.length, 2);
   do_check_eq(itemsTwo[0], downloadOne);
   do_check_eq(itemsTwo[1], downloadTwo);
 
   // The first snapshot should not have been modified.
@@ -55,39 +55,39 @@ add_task(function test_add_getAll()
 
 /**
  * Checks the method to remove items from the list.
  */
 add_task(function test_remove()
 {
   let list = yield promiseNewDownloadList();
 
-  list.add(yield promiseSimpleDownload());
-  list.add(yield promiseSimpleDownload());
+  list.add(yield promiseNewDownload());
+  list.add(yield promiseNewDownload());
 
   let items = yield list.getAll();
   list.remove(items[0]);
 
   // Removing an item that was never added should not raise an error.
-  list.remove(yield promiseSimpleDownload());
+  list.remove(yield promiseNewDownload());
 
   items = yield list.getAll();
   do_check_eq(items.length, 1);
 });
 
 /**
  * Checks that views receive the download add and remove notifications, and that
  * adding and removing views works as expected.
  */
 add_task(function test_notifications_add_remove()
 {
   let list = yield promiseNewDownloadList();
 
-  let downloadOne = yield promiseSimpleDownload();
-  let downloadTwo = yield promiseSimpleDownload();
+  let downloadOne = yield promiseNewDownload();
+  let downloadTwo = yield promiseNewDownload();
   list.add(downloadOne);
   list.add(downloadTwo);
 
   // Check that we receive add notifications for existing elements.
   let addNotifications = 0;
   let viewOne = {
     onDownloadAdded: function (aDownload) {
       // The first download to be notified should be the first that was added.
@@ -98,17 +98,17 @@ add_task(function test_notifications_add
       }
       addNotifications++;
     },
   };
   list.addView(viewOne);
   do_check_eq(addNotifications, 2);
 
   // Check that we receive add notifications for new elements.
-  list.add(yield promiseSimpleDownload());
+  list.add(yield promiseNewDownload());
   do_check_eq(addNotifications, 3);
 
   // Check that we receive remove notifications.
   let removeNotifications = 0;
   let viewTwo = {
     onDownloadRemoved: function (aDownload) {
       do_check_eq(aDownload, downloadOne);
       removeNotifications++;
@@ -120,29 +120,29 @@ add_task(function test_notifications_add
 
   // We should not receive remove notifications after the view is removed.
   list.removeView(viewTwo);
   list.remove(downloadTwo);
   do_check_eq(removeNotifications, 1);
 
   // We should not receive add notifications after the view is removed.
   list.removeView(viewOne);
-  list.add(yield promiseSimpleDownload());
+  list.add(yield promiseNewDownload());
   do_check_eq(addNotifications, 3);
 });
 
 /**
  * Checks that views receive the download change notifications.
  */
 add_task(function test_notifications_change()
 {
   let list = yield promiseNewDownloadList();
 
-  let downloadOne = yield promiseSimpleDownload();
-  let downloadTwo = yield promiseSimpleDownload();
+  let downloadOne = yield promiseNewDownload();
+  let downloadTwo = yield promiseNewDownload();
   list.add(downloadOne);
   list.add(downloadTwo);
 
   // Check that we receive change notifications.
   let receivedOnDownloadChanged = false;
   list.addView({
     onDownloadChanged: function (aDownload) {
       do_check_eq(aDownload, downloadOne);
@@ -172,18 +172,18 @@ add_task(function test_history_expiratio
   // Set max pages to 0 to make the download expire.
   Services.prefs.setIntPref("places.history.expiration.max_pages", 0);
 
   // Add expirable visit for downloads.
   yield promiseAddDownloadToHistory();
   yield promiseAddDownloadToHistory(httpUrl("interruptible.txt"));
 
   let list = yield promiseNewDownloadList();
-  let downloadOne = yield promiseSimpleDownload();
-  let downloadTwo = yield promiseSimpleDownload(httpUrl("interruptible.txt"));
+  let downloadOne = yield promiseNewDownload();
+  let downloadTwo = yield promiseNewDownload(httpUrl("interruptible.txt"));
   list.add(downloadOne);
   list.add(downloadTwo);
 
   let deferred = Promise.defer();
   let removeNotifications = 0;
   let downloadView = {
     onDownloadRemoved: function (aDownload) {
       if (++removeNotifications == 2) {
@@ -216,18 +216,18 @@ add_task(function test_history_expiratio
  */
 add_task(function test_history_clear()
 {
   // Add expirable visit for downloads.
   yield promiseAddDownloadToHistory();
   yield promiseAddDownloadToHistory();
 
   let list = yield promiseNewDownloadList();
-  let downloadOne = yield promiseSimpleDownload();
-  let downloadTwo = yield promiseSimpleDownload();
+  let downloadOne = yield promiseNewDownload();
+  let downloadTwo = yield promiseNewDownload();
   list.add(downloadOne);
   list.add(downloadTwo);
 
   let deferred = Promise.defer();
   let removeNotifications = 0;
   let downloadView = {
     onDownloadRemoved: function (aDownload) {
       if (++removeNotifications == 2) {
--- a/toolkit/components/jsdownloads/test/unit/test_DownloadStore.js
+++ b/toolkit/components/jsdownloads/test/unit/test_DownloadStore.js
@@ -44,17 +44,17 @@ function promiseNewListAndStore(aStorePa
  * Saves downloads to a file, then reloads them.
  */
 add_task(function test_save_reload()
 {
   let [listForSave, storeForSave] = yield promiseNewListAndStore();
   let [listForLoad, storeForLoad] = yield promiseNewListAndStore(
                                                  storeForSave.path);
 
-  listForSave.add(yield promiseSimpleDownload(httpUrl("source.txt")));
+  listForSave.add(yield promiseNewDownload(httpUrl("source.txt")));
   listForSave.add(yield Downloads.createDownload({
     source: { url: httpUrl("empty.txt"),
               referrer: TEST_REFERRER_URL },
     target: getTempFile(TEST_TARGET_FILE_NAME),
   }));
 
   yield storeForSave.save();
   yield storeForLoad.load();