summaryrefslogtreecommitdiffstats
path: root/toolkit/components/jsdownloads
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/jsdownloads')
-rw-r--r--toolkit/components/jsdownloads/moz.build11
-rw-r--r--toolkit/components/jsdownloads/src/DownloadIntegration.jsm28
-rw-r--r--toolkit/components/jsdownloads/src/DownloadPlatform.cpp16
-rw-r--r--toolkit/components/jsdownloads/test/browser/.eslintrc.js7
-rw-r--r--toolkit/components/jsdownloads/test/browser/browser.ini7
-rw-r--r--toolkit/components/jsdownloads/test/browser/browser_DownloadPDFSaver.js97
-rw-r--r--toolkit/components/jsdownloads/test/browser/head.js87
-rw-r--r--toolkit/components/jsdownloads/test/browser/testFile.html9
-rw-r--r--toolkit/components/jsdownloads/test/data/.eslintrc.js7
-rw-r--r--toolkit/components/jsdownloads/test/data/empty.txt0
-rw-r--r--toolkit/components/jsdownloads/test/data/source.txt1
-rw-r--r--toolkit/components/jsdownloads/test/unit/.eslintrc.js7
-rw-r--r--toolkit/components/jsdownloads/test/unit/common_test_Download.js2432
-rw-r--r--toolkit/components/jsdownloads/test/unit/head.js843
-rw-r--r--toolkit/components/jsdownloads/test/unit/test_DownloadCore.js87
-rw-r--r--toolkit/components/jsdownloads/test/unit/test_DownloadImport.js701
-rw-r--r--toolkit/components/jsdownloads/test/unit/test_DownloadIntegration.js432
-rw-r--r--toolkit/components/jsdownloads/test/unit/test_DownloadLegacy.js17
-rw-r--r--toolkit/components/jsdownloads/test/unit/test_DownloadList.js564
-rw-r--r--toolkit/components/jsdownloads/test/unit/test_DownloadStore.js315
-rw-r--r--toolkit/components/jsdownloads/test/unit/test_Downloads.js194
-rw-r--r--toolkit/components/jsdownloads/test/unit/test_PrivateTemp.js24
-rw-r--r--toolkit/components/jsdownloads/test/unit/xpcshell.ini19
23 files changed, 5 insertions, 5900 deletions
diff --git a/toolkit/components/jsdownloads/moz.build b/toolkit/components/jsdownloads/moz.build
index 62f08b160..56566bc97 100644
--- a/toolkit/components/jsdownloads/moz.build
+++ b/toolkit/components/jsdownloads/moz.build
@@ -4,15 +4,4 @@
# 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/.
-with Files('*'):
- BUG_COMPONENT = ('Toolkit', 'Download Manager')
-
DIRS += ['public', 'src']
-
-XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
-BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini']
-
-TEST_HARNESS_FILES.xpcshell.toolkit.components.jsdownloads.test.data += [
- 'test/data/empty.txt',
- 'test/data/source.txt',
-]
diff --git a/toolkit/components/jsdownloads/src/DownloadIntegration.jsm b/toolkit/components/jsdownloads/src/DownloadIntegration.jsm
index 995cc0669..7656128d2 100644
--- a/toolkit/components/jsdownloads/src/DownloadIntegration.jsm
+++ b/toolkit/components/jsdownloads/src/DownloadIntegration.jsm
@@ -70,10 +70,6 @@ XPCOMUtils.defineLazyServiceGetter(this, "gMIMEService",
XPCOMUtils.defineLazyServiceGetter(this, "gExternalProtocolService",
"@mozilla.org/uriloader/external-protocol-service;1",
"nsIExternalProtocolService");
-#ifdef MOZ_WIDGET_ANDROID
-XPCOMUtils.defineLazyModuleGetter(this, "RuntimePermissions",
- "resource://gre/modules/RuntimePermissions.jsm");
-#endif
XPCOMUtils.defineLazyGetter(this, "gParentalControlsService", function() {
if ("@mozilla.org/parental-controls-service;1" in Cc) {
@@ -299,14 +295,10 @@ this.DownloadIntegration = {
aDownload.hasBlockedData) {
return true;
}
-#if defined(MOZ_WIDGET_ANDROID)
- // On Android we store all history.
- return true;
-#else
+
// On Desktop, stopped downloads for which we don't need to track the
// presence of a ".part" file are only retained in the browser history.
return false;
-#endif
},
/**
@@ -332,16 +324,8 @@ this.DownloadIntegration = {
} else {
directoryPath = this._getDirectory("DfltDwnld");
}
+
#elifdef XP_UNIX
-#ifdef MOZ_WIDGET_ANDROID
- // Android doesn't have a $HOME directory, and by default we only have
- // write access to /data/data/org.mozilla.{$APP} and /sdcard
- directoryPath = gEnvironment.get("DOWNLOADS_DIRECTORY");
- if (!directoryPath) {
- throw new Components.Exception("DOWNLOADS_DIRECTORY is not set.",
- Cr.NS_ERROR_FILE_UNRECOGNIZED_PATH);
- }
-#else
// For Linux, use XDG download dir, with a fallback to Home/Downloads
// if the XDG user dirs are disabled.
try {
@@ -349,7 +333,6 @@ this.DownloadIntegration = {
} catch(e) {
directoryPath = yield this._createDownloadsDirectory("Home");
}
-#endif
#else
directoryPath = yield this._createDownloadsDirectory("Home");
#endif
@@ -403,8 +386,6 @@ this.DownloadIntegration = {
let directoryPath = null;
#ifdef XP_MACOSX
directoryPath = yield this.getPreferredDownloadsDirectory();
-#elifdef MOZ_WIDGET_ANDROID
- directoryPath = yield this.getSystemDownloadsDirectory();
#else
directoryPath = this._getDirectory("TmpD");
#endif
@@ -443,12 +424,7 @@ this.DownloadIntegration = {
* @resolves The boolean indicates to block downloads or not.
*/
shouldBlockForRuntimePermissions() {
-#ifdef MOZ_WIDGET_ANDROID
- return RuntimePermissions.waitForPermissions(RuntimePermissions.WRITE_EXTERNAL_STORAGE)
- .then(permissionGranted => !permissionGranted);
-#else
return Promise.resolve(false);
-#endif
},
/**
diff --git a/toolkit/components/jsdownloads/src/DownloadPlatform.cpp b/toolkit/components/jsdownloads/src/DownloadPlatform.cpp
index d91124ee6..66ad2b8fa 100644
--- a/toolkit/components/jsdownloads/src/DownloadPlatform.cpp
+++ b/toolkit/components/jsdownloads/src/DownloadPlatform.cpp
@@ -30,10 +30,6 @@
#include "../../../../xpcom/io/CocoaFileUtils.h"
#endif
-#ifdef MOZ_WIDGET_ANDROID
-#include "FennecJNIWrappers.h"
-#endif
-
#ifdef MOZ_WIDGET_GTK
#include <gtk/gtk.h>
#endif
@@ -101,21 +97,15 @@ CFURLRef CreateCFURLFromNSIURI(nsIURI *aURI) {
nsresult DownloadPlatform::DownloadDone(nsIURI* aSource, nsIURI* aReferrer, nsIFile* aTarget,
const nsACString& aContentType, bool aIsPrivate)
{
-#if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_ANDROID) \
- || defined(MOZ_WIDGET_GTK)
+#if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK)
nsAutoString path;
if (aTarget && NS_SUCCEEDED(aTarget->GetPath(path))) {
-#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_ANDROID)
+#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
// On Windows and Gtk, add the download to the system's "recent documents"
// list, with a pref to disable.
{
bool addToRecentDocs = Preferences::GetBool(PREF_BDM_ADDTORECENTDOCS);
-#ifdef MOZ_WIDGET_ANDROID
- if (jni::IsFennec() && addToRecentDocs) {
- java::DownloadsIntegration::ScanMedia(path, aContentType);
- }
-#else
if (addToRecentDocs && !aIsPrivate) {
#ifdef XP_WIN
::SHAddToRecentDocs(SHARD_PATHW, path.get());
@@ -130,7 +120,7 @@ nsresult DownloadPlatform::DownloadDone(nsIURI* aSource, nsIURI* aReferrer, nsIF
}
#endif
}
-#endif
+
#ifdef MOZ_ENABLE_GIO
// Use GIO to store the source URI for later display in the file manager.
GFile* gio_file = g_file_new_for_path(NS_ConvertUTF16toUTF8(path).get());
diff --git a/toolkit/components/jsdownloads/test/browser/.eslintrc.js b/toolkit/components/jsdownloads/test/browser/.eslintrc.js
deleted file mode 100644
index 7c8021192..000000000
--- a/toolkit/components/jsdownloads/test/browser/.eslintrc.js
+++ /dev/null
@@ -1,7 +0,0 @@
-"use strict";
-
-module.exports = {
- "extends": [
- "../../../../../testing/mochitest/browser.eslintrc.js"
- ]
-};
diff --git a/toolkit/components/jsdownloads/test/browser/browser.ini b/toolkit/components/jsdownloads/test/browser/browser.ini
deleted file mode 100644
index 131fc4ec8..000000000
--- a/toolkit/components/jsdownloads/test/browser/browser.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[DEFAULT]
-support-files =
- head.js
- testFile.html
-
-[browser_DownloadPDFSaver.js]
-skip-if = os != "win"
diff --git a/toolkit/components/jsdownloads/test/browser/browser_DownloadPDFSaver.js b/toolkit/components/jsdownloads/test/browser/browser_DownloadPDFSaver.js
deleted file mode 100644
index 80ed9665a..000000000
--- a/toolkit/components/jsdownloads/test/browser/browser_DownloadPDFSaver.js
+++ /dev/null
@@ -1,97 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 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 PDF download saver, and tests using a window as a
- * source for the copy download saver.
- */
-
-"use strict";
-
-/**
- * Helper function to make sure a window reference exists on the download source.
- */
-function* test_download_windowRef(aTab, aDownload) {
- ok(aDownload.source.windowRef, "Download source had a window reference");
- ok(aDownload.source.windowRef instanceof Ci.xpcIJSWeakReference, "Download window reference is a weak ref");
- is(aDownload.source.windowRef.get(), aTab.linkedBrowser.contentWindow, "Download window exists during test");
-}
-
-/**
- * Helper function to check the state of a completed download.
- */
-function* test_download_state_complete(aTab, aDownload, aPrivate, aCanceled) {
- ok(aDownload.source, "Download has a source");
- is(aDownload.source.url, aTab.linkedBrowser.contentWindow.location, "Download source has correct url");
- is(aDownload.source.isPrivate, aPrivate, "Download source has correct private state");
- ok(aDownload.stopped, "Download is stopped");
- is(aCanceled, aDownload.canceled, "Download has correct canceled state");
- is(!aCanceled, aDownload.succeeded, "Download has correct succeeded state");
- is(aDownload.error, null, "Download error is not defined");
-}
-
-function* test_createDownload_common(aPrivate, aType) {
- let win = yield BrowserTestUtils.openNewBrowserWindow({ private : aPrivate});
-
- let tab = yield BrowserTestUtils.openNewForegroundTab(win.gBrowser, getRootDirectory(gTestPath) + "testFile.html");
- let download = yield Downloads.createDownload({
- source: tab.linkedBrowser.contentWindow,
- target: { path: getTempFile(TEST_TARGET_FILE_NAME_PDF).path },
- saver: { type: aType }
- });
-
- yield test_download_windowRef(tab, download);
- yield download.start();
-
- yield test_download_state_complete(tab, download, aPrivate, false);
- if (aType == "pdf") {
- let signature = yield OS.File.read(download.target.path,
- { bytes: 4, encoding: "us-ascii" });
- is(signature, "%PDF", "File exists and signature matches");
- } else {
- ok((yield OS.File.exists(download.target.path)), "File exists");
- }
-
- win.gBrowser.removeTab(tab);
- win.close()
-}
-
-add_task(function* test_createDownload_pdf_private() {
- yield test_createDownload_common(true, "pdf");
-});
-add_task(function* test_createDownload_pdf_not_private() {
- yield test_createDownload_common(false, "pdf");
-});
-
-// Even for the copy saver, using a window should produce valid results
-add_task(function* test_createDownload_copy_private() {
- yield test_createDownload_common(true, "copy");
-});
-add_task(function* test_createDownload_copy_not_private() {
- yield test_createDownload_common(false, "copy");
-});
-
-add_task(function* test_cancel_pdf_download() {
- let tab = gBrowser.addTab(getRootDirectory(gTestPath) + "testFile.html");
- yield promiseBrowserLoaded(tab.linkedBrowser);
-
- let download = yield Downloads.createDownload({
- source: tab.linkedBrowser.contentWindow,
- target: { path: getTempFile(TEST_TARGET_FILE_NAME_PDF).path },
- saver: "pdf",
- });
-
- yield test_download_windowRef(tab, download);
- download.start().catch(() => {});
-
- // Immediately cancel the download to test that it is erased correctly.
- yield download.cancel();
- yield test_download_state_complete(tab, download, false, true);
-
- let exists = yield OS.File.exists(download.target.path)
- ok(!exists, "Target file does not exist");
-
- gBrowser.removeTab(tab);
-});
diff --git a/toolkit/components/jsdownloads/test/browser/head.js b/toolkit/components/jsdownloads/test/browser/head.js
deleted file mode 100644
index 769aaacb3..000000000
--- a/toolkit/components/jsdownloads/test/browser/head.js
+++ /dev/null
@@ -1,87 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 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/ */
-
-/**
- * Provides infrastructure for automated download components tests.
- */
-
-"use strict";
-
-// Globals
-
-var Cc = Components.classes;
-var Ci = Components.interfaces;
-var Cu = Components.utils;
-var Cr = Components.results;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "DownloadPaths",
- "resource://gre/modules/DownloadPaths.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
- "resource://gre/modules/Downloads.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
- "resource://gre/modules/FileUtils.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "Services",
- "resource://gre/modules/Services.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "HttpServer",
- "resource://testing-common/httpd.js");
-XPCOMUtils.defineLazyModuleGetter(this, "OS",
- "resource://gre/modules/osfile.jsm");
-
-const TEST_TARGET_FILE_NAME_PDF = "test-download.pdf";
-
-// Support functions
-
-// While the previous test file should have deleted all the temporary files it
-// used, on Windows these might still be pending deletion on the physical file
-// system. Thus, start from a new base number every time, to make a collision
-// with a file that is still pending deletion highly unlikely.
-var gFileCounter = Math.floor(Math.random() * 1000000);
-
-/**
- * Returns a reference to a temporary file, that is guaranteed not to exist, and
- * to have never been created before.
- *
- * @param aLeafName
- * Suggested leaf name for the file to be created.
- *
- * @return nsIFile pointing to a non-existent file in a temporary directory.
- *
- * @note It is not enough to delete the file if it exists, or to delete the file
- * after calling nsIFile.createUnique, because on Windows the delete
- * operation in the file system may still be pending, preventing a new
- * file with the same name to be created.
- */
-function getTempFile(aLeafName)
-{
- // Prepend a serial number to the extension in the suggested leaf name.
- let [base, ext] = DownloadPaths.splitBaseNameAndExtension(aLeafName);
- let leafName = base + "-" + gFileCounter + ext;
- gFileCounter++;
-
- // Get a file reference under the temporary directory for this test file.
- let file = FileUtils.getFile("TmpD", [leafName]);
- ok(!file.exists(), "Temp file does not exist");
-
- registerCleanupFunction(function () {
- if (file.exists()) {
- file.remove(false);
- }
- });
-
- return file;
-}
-
-function promiseBrowserLoaded(browser) {
- return new Promise(resolve => {
- browser.addEventListener("load", function onLoad(event) {
- if (event.target == browser.contentDocument) {
- browser.removeEventListener("load", onLoad, true);
- resolve();
- }
- }, true);
- });
-}
diff --git a/toolkit/components/jsdownloads/test/browser/testFile.html b/toolkit/components/jsdownloads/test/browser/testFile.html
deleted file mode 100644
index ee413514b..000000000
--- a/toolkit/components/jsdownloads/test/browser/testFile.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <title>Test Save as PDF</title>
- </head>
- <body>
- <p>Save me as a PDF!</p>
- </body>
-</html>
diff --git a/toolkit/components/jsdownloads/test/data/.eslintrc.js b/toolkit/components/jsdownloads/test/data/.eslintrc.js
deleted file mode 100644
index d35787cd2..000000000
--- a/toolkit/components/jsdownloads/test/data/.eslintrc.js
+++ /dev/null
@@ -1,7 +0,0 @@
-"use strict";
-
-module.exports = {
- "extends": [
- "../../../../../testing/xpcshell/xpcshell.eslintrc.js"
- ]
-};
diff --git a/toolkit/components/jsdownloads/test/data/empty.txt b/toolkit/components/jsdownloads/test/data/empty.txt
deleted file mode 100644
index e69de29bb..000000000
--- a/toolkit/components/jsdownloads/test/data/empty.txt
+++ /dev/null
diff --git a/toolkit/components/jsdownloads/test/data/source.txt b/toolkit/components/jsdownloads/test/data/source.txt
deleted file mode 100644
index 2156cb8c0..000000000
--- a/toolkit/components/jsdownloads/test/data/source.txt
+++ /dev/null
@@ -1 +0,0 @@
-This test string is downloaded. \ No newline at end of file
diff --git a/toolkit/components/jsdownloads/test/unit/.eslintrc.js b/toolkit/components/jsdownloads/test/unit/.eslintrc.js
deleted file mode 100644
index d35787cd2..000000000
--- a/toolkit/components/jsdownloads/test/unit/.eslintrc.js
+++ /dev/null
@@ -1,7 +0,0 @@
-"use strict";
-
-module.exports = {
- "extends": [
- "../../../../../testing/xpcshell/xpcshell.eslintrc.js"
- ]
-};
diff --git a/toolkit/components/jsdownloads/test/unit/common_test_Download.js b/toolkit/components/jsdownloads/test/unit/common_test_Download.js
deleted file mode 100644
index 42d4c5682..000000000
--- a/toolkit/components/jsdownloads/test/unit/common_test_Download.js
+++ /dev/null
@@ -1,2432 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 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/ */
-
-/**
- * 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
-
-const kDeleteTempFileOnExit = "browser.helperApps.deleteTempFileOnExit";
-
-/**
- * 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().catch(() => {});
- return download;
- });
-}
-
-/**
- * Creates and starts a new download, configured to keep partial data, and
- * returns only when the first part of "interruptible_resumable.txt" has been
- * saved to disk. You must call "continueResponses" to allow the interruptible
- * request to continue.
- *
- * This function uses either DownloadCopySaver or DownloadLegacySaver based on
- * the current test run.
- *
- * @return {Promise}
- * @resolves The newly created Download object, still in progress.
- * @rejects JavaScript exception.
- */
-function promiseStartDownload_tryToKeepPartialData() {
- return Task.spawn(function* () {
- mustInterruptResponses();
-
- // Start a new download and configure it to keep partially downloaded data.
- let download;
- if (!gUseLegacySaver) {
- let targetFilePath = getTempFile(TEST_TARGET_FILE_NAME).path;
- download = yield Downloads.createDownload({
- source: httpUrl("interruptible_resumable.txt"),
- target: { path: targetFilePath,
- partFilePath: targetFilePath + ".part" },
- });
- download.tryToKeepPartialData = true;
- download.start().catch(() => {});
- } else {
- // Start a download using nsIExternalHelperAppService, that is configured
- // to keep partially downloaded data by default.
- download = yield promiseStartExternalHelperAppServiceDownload();
- }
-
- yield promiseDownloadMidway(download);
- yield promisePartFileReady(download);
-
- return download;
- });
-}
-
-/**
- * This function should be called after the progress notification for a download
- * is received, and waits for the worker thread of BackgroundFileSaver to
- * receive the data to be written to the ".part" file on disk.
- *
- * @return {Promise}
- * @resolves When the ".part" file has been written to disk.
- * @rejects JavaScript exception.
- */
-function promisePartFileReady(aDownload) {
- return Task.spawn(function* () {
- // We don't have control over the file output code in BackgroundFileSaver.
- // After we receive the download progress notification, we may only check
- // that the ".part" file has been created, while its size cannot be
- // determined because the file is currently open.
- try {
- do {
- yield promiseTimeout(50);
- } while (!(yield OS.File.exists(aDownload.target.partFilePath)));
- } catch (ex) {
- if (!(ex instanceof OS.File.Error)) {
- throw ex;
- }
- // This indicates that the file has been created and cannot be accessed.
- // The specific error might vary with the platform.
- do_print("Expected exception while checking existence: " + ex.toString());
- // Wait some more time to allow the write to complete.
- yield promiseTimeout(100);
- }
- });
-}
-
-/**
- * Checks that the actual data written to disk matches the expected data as well
- * as the properties of the given DownloadTarget object.
- *
- * @param downloadTarget
- * The DownloadTarget object whose details have to be verified.
- * @param expectedContents
- * String containing the octets that are expected in the file.
- *
- * @return {Promise}
- * @resolves When the properties have been verified.
- * @rejects JavaScript exception.
- */
-var promiseVerifyTarget = Task.async(function* (downloadTarget,
- expectedContents) {
- yield promiseVerifyContents(downloadTarget.path, expectedContents);
- do_check_true(downloadTarget.exists);
- do_check_eq(downloadTarget.size, expectedContents.length);
-});
-
-/**
- * Waits for an attempt to launch a file, and returns the nsIMIMEInfo used for
- * the launch, or null if the file was launched with the default handler.
- */
-function waitForFileLaunched() {
- return new Promise(resolve => {
- let waitFn = base => ({
- launchFile(file, mimeInfo) {
- Integration.downloads.unregister(waitFn);
- if (!mimeInfo ||
- mimeInfo.preferredAction == Ci.nsIMIMEInfo.useSystemDefault) {
- resolve(null);
- } else {
- resolve(mimeInfo);
- }
- return Promise.resolve();
- },
- });
- Integration.downloads.register(waitFn);
- });
-}
-
-/**
- * Waits for an attempt to show the directory where a file is located, and
- * returns the path of the file.
- */
-function waitForDirectoryShown() {
- return new Promise(resolve => {
- let waitFn = base => ({
- showContainingDirectory(path) {
- Integration.downloads.unregister(waitFn);
- resolve(path);
- return Promise.resolve();
- },
- });
- Integration.downloads.register(waitFn);
- });
-}
-
-// Tests
-
-/**
- * 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_basic()
-{
- 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" },
- });
-
- do_check_eq(download.source.url, httpUrl("source.txt"));
- do_check_eq(download.target.path, targetFile.path);
-
- 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);
-
- yield promiseVerifyTarget(download.target, TEST_DATA_SHORT);
-});
-
-/**
- * Executes a download with the tryToKeepPartialData property set, and ensures
- * that the file is saved correctly. When testing DownloadLegacySaver, the
- * download is executed using the nsIExternalHelperAppService component.
- */
-add_task(function* test_basic_tryToKeepPartialData()
-{
- let download = yield promiseStartDownload_tryToKeepPartialData();
- continueResponses();
- yield promiseDownloadStopped(download);
-
- // The target file should now have been created, and the ".part" file deleted.
- yield promiseVerifyTarget(download.target, TEST_DATA_SHORT + TEST_DATA_SHORT);
- do_check_false(yield OS.File.exists(download.target.partFilePath));
- do_check_eq(32, download.saver.getSha256Hash().length);
-});
-
-/**
- * Tests the permissions of the final target file once the download finished.
- */
-add_task(function* test_unix_permissions()
-{
- // This test is only executed on some Desktop systems.
- if (Services.appinfo.OS != "Darwin" && Services.appinfo.OS != "Linux" &&
- Services.appinfo.OS != "WINNT") {
- do_print("Skipping test.");
- return;
- }
-
- let launcherPath = getTempFile("app-launcher").path;
-
- for (let autoDelete of [false, true]) {
- for (let isPrivate of [false, true]) {
- for (let launchWhenSucceeded of [false, true]) {
- do_print("Checking " + JSON.stringify({ autoDelete,
- isPrivate,
- launchWhenSucceeded }));
-
- Services.prefs.setBoolPref(kDeleteTempFileOnExit, autoDelete);
-
- let download;
- if (!gUseLegacySaver) {
- download = yield Downloads.createDownload({
- source: { url: httpUrl("source.txt"), isPrivate },
- target: getTempFile(TEST_TARGET_FILE_NAME).path,
- launchWhenSucceeded,
- launcherPath,
- });
- yield download.start();
- } else {
- download = yield promiseStartLegacyDownload(httpUrl("source.txt"), {
- isPrivate,
- launchWhenSucceeded,
- launcherPath: launchWhenSucceeded && launcherPath,
- });
- yield promiseDownloadStopped(download);
- }
-
- let isTemporary = launchWhenSucceeded && (autoDelete || isPrivate);
- let stat = yield OS.File.stat(download.target.path);
- if (Services.appinfo.OS == "WINNT") {
- // On Windows
- // Temporary downloads should be read-only
- do_check_eq(stat.winAttributes.readOnly, isTemporary ? true : false);
- } else {
- // On Linux, Mac
- // Temporary downloads should be read-only and not accessible to other
- // users, while permanently downloaded files should be readable and
- // writable as specified by the system umask.
- do_check_eq(stat.unixMode,
- isTemporary ? 0o400 : (0o666 & ~OS.Constants.Sys.umask));
- }
- }
- }
- }
-
- // Clean up the changes to the preference.
- Services.prefs.clearUserPref(kDeleteTempFileOnExit);
-});
-
-/**
- * Checks the referrer for downloads.
- */
-add_task(function* test_referrer()
-{
- 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);
-
- 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 the adjustChannel callback for downloads.
- */
-add_task(function* test_adjustChannel()
-{
- const sourcePath = "/test_post.txt";
- const sourceUrl = httpUrl("test_post.txt");
- const targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
- const customHeader = { name: "X-Answer", value: "42" };
- const postData = "Don't Panic";
-
- function cleanup() {
- gHttpServer.registerPathHandler(sourcePath, null);
- }
- do_register_cleanup(cleanup);
-
- gHttpServer.registerPathHandler(sourcePath, aRequest => {
- do_check_eq(aRequest.method, "POST");
-
- do_check_true(aRequest.hasHeader(customHeader.name));
- do_check_eq(aRequest.getHeader(customHeader.name), customHeader.value);
-
- const stream = aRequest.bodyInputStream;
- const body = NetUtil.readInputStreamToString(stream, stream.available());
- do_check_eq(body, postData);
- });
-
- function adjustChannel(channel) {
- channel.QueryInterface(Ci.nsIHttpChannel);
- channel.setRequestHeader(customHeader.name, customHeader.value, false);
-
- const stream = Cc["@mozilla.org/io/string-input-stream;1"]
- .createInstance(Ci.nsIStringInputStream);
- stream.setData(postData, postData.length);
-
- channel.QueryInterface(Ci.nsIUploadChannel2);
- channel.explicitSetUploadStream(stream, null, -1, "POST", false);
-
- return Promise.resolve();
- }
-
- const download = yield Downloads.createDownload({
- source: { url: sourceUrl, adjustChannel },
- target: targetPath,
- });
- do_check_eq(download.source.adjustChannel, adjustChannel);
- do_check_eq(download.toSerializable(), null);
- yield download.start();
-
- cleanup();
-});
-
-/**
- * Checks initial and final state and progress for a successful download.
- */
-add_task(function* test_initial_final_state()
-{
- 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_false(download.target.exists);
- do_check_eq(download.target.size, 0);
-
- 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));
- do_check_true(download.target.exists);
- do_check_eq(download.target.size, TEST_DATA_SHORT.length);
-});
-
-/**
- * Checks the notification of the final download state.
- */
-add_task(function* test_final_state_notified()
-{
- mustInterruptResponses();
-
- 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;
- };
-
- // Allow the download to complete.
- let promiseAttempt = download.start();
- continueResponses();
- 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_intermediate_progress()
-{
- mustInterruptResponses();
-
- let download = yield promiseStartDownload(httpUrl("interruptible.txt"));
-
- yield promiseDownloadMidway(download);
-
- do_check_true(download.hasProgress);
- do_check_eq(download.currentBytes, TEST_DATA_SHORT.length);
- do_check_eq(download.totalBytes, TEST_DATA_SHORT.length * 2);
-
- // The final file size should not be computed for in-progress downloads.
- do_check_false(download.target.exists);
- do_check_eq(download.target.size, 0);
-
- // Continue after the first chunk of data is fully received.
- continueResponses();
- yield promiseDownloadStopped(download);
-
- do_check_true(download.stopped);
- do_check_eq(download.progress, 100);
-
- yield promiseVerifyTarget(download.target, 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 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);
-
- // We should have received the content type even for an empty file.
- do_check_eq(download.contentType, "text/plain");
-
- do_check_eq((yield OS.File.stat(download.target.path)).size, 0);
- do_check_true(download.target.exists);
- do_check_eq(download.target.size, 0);
-});
-
-/**
- * Downloads a file with a "Content-Length" of 0 with the tryToKeepPartialData
- * property set, and ensures that the file is saved correctly.
- */
-add_task(function* test_empty_progress_tryToKeepPartialData()
-{
- // Start a new download and configure it to keep partially downloaded data.
- let download;
- if (!gUseLegacySaver) {
- let targetFilePath = getTempFile(TEST_TARGET_FILE_NAME).path;
- download = yield Downloads.createDownload({
- source: httpUrl("empty.txt"),
- target: { path: targetFilePath,
- partFilePath: targetFilePath + ".part" },
- });
- download.tryToKeepPartialData = true;
- download.start().catch(() => {});
- } else {
- // Start a download using nsIExternalHelperAppService, that is configured
- // to keep partially downloaded data by default.
- download = yield promiseStartExternalHelperAppServiceDownload(
- httpUrl("empty.txt"));
- }
- yield promiseDownloadStopped(download);
-
- // The target file should now have been created, and the ".part" file deleted.
- do_check_eq((yield OS.File.stat(download.target.path)).size, 0);
- do_check_true(download.target.exists);
- do_check_eq(download.target.size, 0);
-
- do_check_false(yield OS.File.exists(download.target.partFilePath));
- do_check_eq(32, download.saver.getSha256Hash().length);
-});
-
-/**
- * Downloads an empty file with no "Content-Length" and checks the progress.
- */
-add_task(function* test_empty_noprogress()
-{
- let sourcePath = "/test_empty_noprogress.txt";
- let sourceUrl = httpUrl("test_empty_noprogress.txt");
- let deferRequestReceived = Promise.defer();
-
- // Register an interruptible handler that notifies us when the request occurs.
- function cleanup() {
- gHttpServer.registerPathHandler(sourcePath, null);
- }
- do_register_cleanup(cleanup);
-
- registerInterruptibleHandler(sourcePath,
- function firstPart(aRequest, aResponse) {
- aResponse.setHeader("Content-Type", "text/plain", false);
- deferRequestReceived.resolve();
- }, function secondPart(aRequest, aResponse) { });
-
- // Start the download, without allowing the request to finish.
- mustInterruptResponses();
- 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(sourceUrl);
-
- download.onchange = function () {
- if (!download.stopped) {
- do_check_false(download.hasProgress);
- do_check_eq(download.currentBytes, 0);
- do_check_eq(download.totalBytes, 0);
- }
- };
-
- download.start().catch(() => {});
- } 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(sourceUrl);
- }
-
- // 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 deferRequestReceived.promise;
- 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.
- continueResponses();
- yield promiseDownloadStopped(download);
-
- // We should have received the content type even if no progress is reported.
- do_check_eq(download.contentType, "text/plain");
-
- // 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_true(download.target.exists);
- do_check_eq(download.target.size, 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_start_twice()
-{
- mustInterruptResponses();
-
- 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.
- continueResponses();
-
- // 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 promiseVerifyTarget(download.target, TEST_DATA_SHORT + TEST_DATA_SHORT);
-});
-
-/**
- * Cancels a download and verifies that its state is reported correctly.
- */
-add_task(function* test_cancel_midway()
-{
- mustInterruptResponses();
-
- // 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);
- }
-
- // 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) {
- // Cancel the download immediately during the notification.
- 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. 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(download.target.exists);
- do_check_eq(download.target.size, 0);
-
- 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);
-
- 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)) {
- throw ex;
- }
- do_check_false(ex.becauseSourceFailed);
- do_check_false(ex.becauseTargetFailed);
- }
- }
-});
-
-/**
- * Cancels a download while keeping partially downloaded data, and verifies that
- * both the target file and the ".part" file are deleted.
- */
-add_task(function* test_cancel_midway_tryToKeepPartialData()
-{
- let download = yield promiseStartDownload_tryToKeepPartialData();
-
- do_check_true(yield OS.File.exists(download.target.path));
- do_check_true(yield OS.File.exists(download.target.partFilePath));
-
- yield download.cancel();
- yield download.removePartialData();
-
- 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));
- do_check_false(yield OS.File.exists(download.target.partFilePath));
-});
-
-/**
- * Cancels a download right after starting it.
- */
-add_task(function* test_cancel_immediately()
-{
- mustInterruptResponses();
-
- 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
- // 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)) {
- throw ex;
- }
- 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;
-});
-
-/**
- * Cancels and restarts a download sequentially.
- */
-add_task(function* test_cancel_midway_restart()
-{
- mustInterruptResponses();
-
- let download = yield promiseStartDownload(httpUrl("interruptible.txt"));
-
- // The first time, cancel the download midway.
- yield promiseDownloadMidway(download);
- yield download.cancel();
-
- do_check_true(download.stopped);
-
- // The second time, we'll provide the entire interruptible response.
- continueResponses();
- 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 promiseVerifyTarget(download.target, TEST_DATA_SHORT + TEST_DATA_SHORT);
-});
-
-/**
- * Cancels a download and restarts it from where it stopped.
- */
-add_task(function* test_cancel_midway_restart_tryToKeepPartialData()
-{
- let download = yield promiseStartDownload_tryToKeepPartialData();
- yield download.cancel();
-
- do_check_true(download.stopped);
- do_check_true(download.hasPartialData);
-
- // The target file should not exist, but we should have kept the partial data.
- do_check_false(yield OS.File.exists(download.target.path));
- yield promiseVerifyContents(download.target.partFilePath, TEST_DATA_SHORT);
- do_check_false(download.target.exists);
- do_check_eq(download.target.size, 0);
-
- // Verify that the server sent the response from the start.
- do_check_eq(gMostRecentFirstBytePos, 0);
-
- // The second time, we'll request and obtain the second part of the response,
- // but we still stop when half of the remaining progress is reached.
- let deferMidway = Promise.defer();
- download.onchange = function () {
- if (!download.stopped && !download.canceled &&
- download.currentBytes == Math.floor(TEST_DATA_SHORT.length * 3 / 2)) {
- download.onchange = null;
- deferMidway.resolve();
- }
- };
-
- mustInterruptResponses();
- let promiseAttempt = download.start();
-
- // Continue when the number of bytes we received is correct, then check that
- // progress is at about 75 percent. The exact figure may vary because of
- // rounding issues, since the total number of bytes in the response might not
- // be a multiple of four.
- yield deferMidway.promise;
- do_check_true(download.progress > 72 && download.progress < 78);
-
- // Now we allow the download to finish.
- continueResponses();
- yield promiseAttempt;
-
- // Check that the server now sent the second part only.
- do_check_eq(gMostRecentFirstBytePos, TEST_DATA_SHORT.length);
-
- // The target file should now have been created, and the ".part" file deleted.
- yield promiseVerifyTarget(download.target, TEST_DATA_SHORT + TEST_DATA_SHORT);
- do_check_false(yield OS.File.exists(download.target.partFilePath));
-});
-
-/**
- * Cancels a download while keeping partially downloaded data, then removes the
- * data and restarts the download from the beginning.
- */
-add_task(function* test_cancel_midway_restart_removePartialData()
-{
- let download = yield promiseStartDownload_tryToKeepPartialData();
- yield download.cancel();
-
- do_check_true(download.hasPartialData);
- yield promiseVerifyContents(download.target.partFilePath, TEST_DATA_SHORT);
- do_check_false(download.target.exists);
- do_check_eq(download.target.size, 0);
-
- yield download.removePartialData();
-
- do_check_false(download.hasPartialData);
- do_check_false(yield OS.File.exists(download.target.partFilePath));
- do_check_false(download.target.exists);
- do_check_eq(download.target.size, 0);
-
- // The second time, we'll request and obtain the entire response again.
- continueResponses();
- yield download.start();
-
- // Verify that the server sent the response from the start.
- do_check_eq(gMostRecentFirstBytePos, 0);
-
- // The target file should now have been created, and the ".part" file deleted.
- yield promiseVerifyTarget(download.target, TEST_DATA_SHORT + TEST_DATA_SHORT);
- do_check_false(yield OS.File.exists(download.target.partFilePath));
-});
-
-/**
- * Cancels a download while keeping partially downloaded data, then removes the
- * data and restarts the download from the beginning without keeping the partial
- * data anymore.
- */
-add_task(function* test_cancel_midway_restart_tryToKeepPartialData_false()
-{
- let download = yield promiseStartDownload_tryToKeepPartialData();
- yield download.cancel();
-
- download.tryToKeepPartialData = false;
-
- // The above property change does not affect existing partial data.
- do_check_true(download.hasPartialData);
- yield promiseVerifyContents(download.target.partFilePath, TEST_DATA_SHORT);
-
- yield download.removePartialData();
- do_check_false(yield OS.File.exists(download.target.partFilePath));
-
- // Restart the download from the beginning.
- mustInterruptResponses();
- download.start().catch(() => {});
-
- yield promiseDownloadMidway(download);
- yield promisePartFileReady(download);
-
- // While the download is in progress, we should still have a ".part" file.
- do_check_false(download.hasPartialData);
- do_check_true(yield OS.File.exists(download.target.partFilePath));
-
- // On Unix, verify that the file with the partially downloaded data is not
- // accessible by other users on the system.
- if (Services.appinfo.OS == "Darwin" || Services.appinfo.OS == "Linux") {
- do_check_eq((yield OS.File.stat(download.target.partFilePath)).unixMode,
- 0o600);
- }
-
- yield download.cancel();
-
- // The ".part" file should be deleted now that the download is canceled.
- do_check_false(download.hasPartialData);
- do_check_false(yield OS.File.exists(download.target.partFilePath));
-
- // The third time, we'll request and obtain the entire response again.
- continueResponses();
- yield download.start();
-
- // Verify that the server sent the response from the start.
- do_check_eq(gMostRecentFirstBytePos, 0);
-
- // The target file should now have been created, and the ".part" file deleted.
- yield promiseVerifyTarget(download.target, TEST_DATA_SHORT + TEST_DATA_SHORT);
- do_check_false(yield OS.File.exists(download.target.partFilePath));
-});
-
-/**
- * Cancels a download right after starting it, then restarts it immediately.
- */
-add_task(function* test_cancel_immediately_restart_immediately()
-{
- mustInterruptResponses();
-
- let download = yield promiseStartDownload(httpUrl("interruptible.txt"));
- 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);
-
- // Ensure the next request is now allowed to complete, regardless of whether
- // the canceled request was received by the server or not.
- continueResponses();
- try {
- yield promiseAttempt;
- // If we get here, it means that the first attempt actually succeeded. In
- // fact, this could be a valid outcome, because the cancellation request may
- // not have been processed in time before the download finished.
- do_print("The download should have been canceled.");
- } catch (ex) {
- if (!(ex instanceof Downloads.Error)) {
- throw ex;
- }
- 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 promiseVerifyTarget(download.target, TEST_DATA_SHORT + TEST_DATA_SHORT);
-});
-
-/**
- * Cancels a download midway, then restarts it immediately.
- */
-add_task(function* test_cancel_midway_restart_immediately()
-{
- mustInterruptResponses();
-
- let download = yield promiseStartDownload(httpUrl("interruptible.txt"));
- let promiseAttempt = download.start();
-
- // The first time, cancel the download midway.
- yield promiseDownloadMidway(download);
- 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);
-
- // The second request is allowed to complete.
- continueResponses();
- try {
- yield promiseAttempt;
- do_throw("The download should have been canceled.");
- } catch (ex) {
- if (!(ex instanceof Downloads.Error)) {
- throw ex;
- }
- 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 promiseVerifyTarget(download.target, TEST_DATA_SHORT + TEST_DATA_SHORT);
-});
-
-/**
- * Calls the "cancel" method on a successful download.
- */
-add_task(function* test_cancel_successful()
-{
- 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 promiseVerifyTarget(download.target, TEST_DATA_SHORT);
-});
-
-/**
- * Calls the "cancel" method two times in a row.
- */
-add_task(function* test_cancel_twice()
-{
- mustInterruptResponses();
-
- 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 {
- yield promiseAttempt;
- do_throw("The download should have been canceled.");
- } catch (ex) {
- if (!(ex instanceof Downloads.Error)) {
- throw ex;
- }
- 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));
-});
-
-/**
- * Checks the "refresh" method for succeeded downloads.
- */
-add_task(function* test_refresh_succeeded()
-{
- let download = yield promiseStartDownload();
- yield promiseDownloadStopped(download);
-
- // The DownloadTarget properties should be the same after calling "refresh".
- yield download.refresh();
- yield promiseVerifyTarget(download.target, TEST_DATA_SHORT);
-
- // If the file is removed, only the "exists" property should change, and the
- // "size" property should keep its previous value.
- yield OS.File.move(download.target.path, download.target.path + ".old");
- yield download.refresh();
- do_check_false(download.target.exists);
- do_check_eq(download.target.size, TEST_DATA_SHORT.length);
-
- // The DownloadTarget properties should be restored when the file is put back.
- yield OS.File.move(download.target.path + ".old", download.target.path);
- yield download.refresh();
- yield promiseVerifyTarget(download.target, TEST_DATA_SHORT);
-});
-
-/**
- * Checks that a download cannot be restarted after the "finalize" method.
- */
-add_task(function* test_finalize()
-{
- mustInterruptResponses();
-
- let download = yield promiseStartDownload(httpUrl("interruptible.txt"));
-
- let promiseFinalized = download.finalize();
-
- try {
- yield download.start();
- do_throw("It should not be possible to restart after finalization.");
- } catch (ex) { }
-
- yield promiseFinalized;
-
- 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));
-});
-
-/**
- * Checks that the "finalize" method can remove partially downloaded data.
- */
-add_task(function* test_finalize_tryToKeepPartialData()
-{
- // Check finalization without removing partial data.
- let download = yield promiseStartDownload_tryToKeepPartialData();
- yield download.finalize();
-
- do_check_true(download.hasPartialData);
- do_check_true(yield OS.File.exists(download.target.partFilePath));
-
- // Clean up.
- yield download.removePartialData();
-
- // Check finalization while removing partial data.
- download = yield promiseStartDownload_tryToKeepPartialData();
- yield download.finalize(true);
-
- do_check_false(download.hasPartialData);
- do_check_false(yield OS.File.exists(download.target.partFilePath));
-});
-
-/**
- * Checks that whenSucceeded returns a promise that is resolved after a restart.
- */
-add_task(function* test_whenSucceeded_after_restart()
-{
- mustInterruptResponses();
-
- let promiseSucceeded;
-
- let download;
- if (!gUseLegacySaver) {
- // When testing DownloadCopySaver, we have control over the download, thus
- // we can verify getting a reference before the first download attempt.
- download = yield promiseNewDownload(httpUrl("interruptible.txt"));
- promiseSucceeded = download.whenSucceeded();
- download.start().catch(() => {});
- } else {
- // When testing DownloadLegacySaver, the download is already started when it
- // is created, thus we cannot get the reference before the first attempt.
- download = yield promiseStartLegacyDownload(httpUrl("interruptible.txt"));
- promiseSucceeded = download.whenSucceeded();
- }
-
- // Cancel the first download attempt.
- yield download.cancel();
-
- // The second request is allowed to complete.
- continueResponses();
- download.start().catch(() => {});
-
- // 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 promiseVerifyTarget(download.target, TEST_DATA_SHORT + TEST_DATA_SHORT);
-});
-
-/**
- * Ensures download error details are reported on network failures.
- */
-add_task(function* test_error_source()
-{
- let serverSocket = startFakeServer();
- try {
- let sourceUrl = "http://localhost:" + serverSocket.port + "/source.txt";
-
- 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);
-
- 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) {
- throw ex;
- }
- // 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);
-
- do_check_false(yield OS.File.exists(download.target.path));
- do_check_false(download.target.exists);
- do_check_eq(download.target.size, 0);
- } finally {
- serverSocket.close();
- }
-});
-
-/**
- * Ensures a download error is reported when receiving less bytes than what was
- * specified in the Content-Length header.
- */
-add_task(function* test_error_source_partial()
-{
- let sourceUrl = httpUrl("shorter-than-content-length-http-1-1.txt");
-
- let enforcePref = Services.prefs.getBoolPref("network.http.enforce-framing.http1");
- Services.prefs.setBoolPref("network.http.enforce-framing.http1", true);
-
- function cleanup() {
- Services.prefs.setBoolPref("network.http.enforce-framing.http1", enforcePref);
- }
- do_register_cleanup(cleanup);
-
- 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);
-
- 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) {
- throw ex;
- }
- // 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);
- do_check_eq(download.error.result, Cr.NS_ERROR_NET_PARTIAL_TRANSFER);
-
- do_check_false(yield OS.File.exists(download.target.path));
- do_check_false(download.target.exists);
- do_check_eq(download.target.size, 0);
-});
-
-/**
- * Ensures download error details are reported on local writing failures.
- */
-add_task(function* test_error_target()
-{
- // Create a file without write access permissions before downloading.
- let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
- targetFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0);
- try {
- let download;
- try {
- 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) {
- throw ex;
- }
- // 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()) {
- targetFile.permissions = FileUtils.PERMS_FILE;
- targetFile.remove(false);
- }
- }
-});
-
-/**
- * Restarts a failed download.
- */
-add_task(function* test_error_restart()
-{
- let download;
-
- // Create a file without write access permissions before downloading.
- let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
- targetFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0);
- try {
- // Use DownloadCopySaver or DownloadLegacySaver based on the test run,
- // specifying the target file we created.
- if (!gUseLegacySaver) {
- download = yield Downloads.createDownload({
- source: httpUrl("source.txt"),
- target: targetFile,
- });
- download.start().catch(() => {});
- } else {
- 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) {
- throw ex;
- }
- // 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 promiseVerifyTarget(download.target, TEST_DATA_SHORT);
-});
-
-/**
- * Executes download in both public and private modes.
- */
-add_task(function* test_public_and_private()
-{
- 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();
- 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.fetch(sourceUrl, targetFile);
- yield Downloads.fetch(sourceUrl, targetFile);
-
- 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_cancel_immediately_restart_and_check_startTime()
-{
- let download = yield promiseStartDownload();
-
- 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_with_content_encoding()
-{
- 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);
- 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 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 promiseVerifyTarget(download.target, TEST_DATA_SHORT);
-
- cleanup();
-});
-
-/**
- * Checks that the file is not decoded if the extension matches the encoding.
- */
-add_task(function* test_with_content_encoding_ignore_extension()
-{
- let sourcePath = "/test_with_content_encoding_ignore_extension.gz";
- let sourceUrl = httpUrl("test_with_content_encoding_ignore_extension.gz");
-
- 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 promiseStartDownload(sourceUrl);
- yield promiseDownloadStopped(download);
-
- do_check_eq(download.progress, 100);
- do_check_eq(download.totalBytes, TEST_DATA_SHORT_GZIP_ENCODED.length);
- do_check_eq(download.target.size, TEST_DATA_SHORT_GZIP_ENCODED.length);
-
- // Ensure the content matches the encoded test data. We convert the data to a
- // string before executing the content check.
- yield promiseVerifyTarget(download.target,
- String.fromCharCode.apply(String, TEST_DATA_SHORT_GZIP_ENCODED));
-
- cleanup();
-});
-
-/**
- * Cancels and restarts a download sequentially with content-encoding.
- */
-add_task(function* test_cancel_midway_restart_with_content_encoding()
-{
- mustInterruptResponses();
-
- let download = yield promiseStartDownload(httpUrl("interruptible_gzip.txt"));
-
- // The first time, cancel the download midway.
- let deferCancel = Promise.defer();
- let onchange = function () {
- if (!download.stopped && !download.canceled &&
- download.currentBytes == TEST_DATA_SHORT_GZIP_ENCODED_FIRST.length) {
- deferCancel.resolve(download.cancel());
- }
- };
-
- // Register for the notification, but also call the function directly in
- // case the download already reached the expected progress.
- download.onchange = onchange;
- onchange();
-
- yield deferCancel.promise;
-
- do_check_true(download.stopped);
-
- // The second time, we'll provide the entire interruptible response.
- continueResponses();
- download.onchange = null;
- yield download.start();
-
- do_check_eq(download.progress, 100);
- do_check_eq(download.totalBytes, TEST_DATA_SHORT_GZIP_ENCODED.length);
-
- yield promiseVerifyTarget(download.target, TEST_DATA_SHORT);
-});
-
-/**
- * Download with parental controls enabled.
- */
-add_task(function* test_blocked_parental_controls()
-{
- let blockFn = base => ({
- shouldBlockForParentalControls: () => Promise.resolve(true),
- });
-
- Integration.downloads.register(blockFn);
- function cleanup() {
- Integration.downloads.unregister(blockFn);
- }
- do_register_cleanup(cleanup);
-
- 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();
- 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) {
- throw ex;
- }
- do_check_true(ex.becauseBlockedByParentalControls);
- do_check_true(download.error.becauseBlockedByParentalControls);
- }
-
- // Now that the download stopped, the target file should not exist.
- do_check_false(yield OS.File.exists(download.target.path));
-
- cleanup();
-});
-
-/**
- * Test a download that will be blocked by Windows parental controls by
- * resulting in an HTTP status code of 450.
- */
-add_task(function* test_blocked_parental_controls_httpstatus450()
-{
- let download;
- try {
- if (!gUseLegacySaver) {
- download = yield promiseNewDownload(httpUrl("parentalblocked.zip"));
- yield download.start();
- }
- else {
- download = yield promiseStartLegacyDownload(httpUrl("parentalblocked.zip"));
- yield promiseDownloadStopped(download);
- }
- do_throw("The download should have blocked.");
- } catch (ex) {
- if (!(ex instanceof Downloads.Error) || !ex.becauseBlocked) {
- throw ex;
- }
- do_check_true(ex.becauseBlockedByParentalControls);
- do_check_true(download.error.becauseBlockedByParentalControls);
- do_check_true(download.stopped);
- }
-
- do_check_false(yield OS.File.exists(download.target.path));
-});
-
-/**
- * Download with runtime permissions
- */
-add_task(function* test_blocked_runtime_permissions()
-{
- let blockFn = base => ({
- shouldBlockForRuntimePermissions: () => Promise.resolve(true),
- });
-
- Integration.downloads.register(blockFn);
- function cleanup() {
- Integration.downloads.unregister(blockFn);
- }
- do_register_cleanup(cleanup);
-
- 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();
- 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) {
- throw ex;
- }
- do_check_true(ex.becauseBlockedByRuntimePermissions);
- do_check_true(download.error.becauseBlockedByRuntimePermissions);
- }
-
- // Now that the download stopped, the target file should not exist.
- do_check_false(yield OS.File.exists(download.target.path));
-
- cleanup();
-});
-
-/**
- * Check that DownloadCopySaver can always retrieve the hash.
- * DownloadLegacySaver can only retrieve the hash when
- * nsIExternalHelperAppService is invoked.
- */
-add_task(function* test_getSha256Hash()
-{
- if (!gUseLegacySaver) {
- let download = yield promiseStartDownload(httpUrl("source.txt"));
- yield promiseDownloadStopped(download);
- do_check_true(download.stopped);
- do_check_eq(32, download.saver.getSha256Hash().length);
- }
-});
-
-/**
- * Create a download which will be reputation blocked.
- *
- * @param options
- * {
- * keepPartialData: bool,
- * keepBlockedData: bool,
- * }
- * @return {Promise}
- * @resolves The reputation blocked download.
- * @rejects JavaScript exception.
- */
-var promiseBlockedDownload = Task.async(function* (options) {
- let blockFn = base => ({
- shouldBlockForReputationCheck: () => Promise.resolve({
- shouldBlock: true,
- verdict: Downloads.Error.BLOCK_VERDICT_UNCOMMON,
- }),
- shouldKeepBlockedData: () => Promise.resolve(options.keepBlockedData),
- });
-
- Integration.downloads.register(blockFn);
- function cleanup() {
- Integration.downloads.unregister(blockFn);
- }
- do_register_cleanup(cleanup);
-
- let download;
-
- try {
- if (options.keepPartialData) {
- download = yield promiseStartDownload_tryToKeepPartialData();
- continueResponses();
- } else if (gUseLegacySaver) {
- download = yield promiseStartLegacyDownload();
- } else {
- download = yield promiseNewDownload();
- yield download.start();
- do_throw("The download should have blocked.");
- }
-
- yield promiseDownloadStopped(download);
- do_throw("The download should have blocked.");
- } catch (ex) {
- if (!(ex instanceof Downloads.Error) || !ex.becauseBlocked) {
- throw ex;
- }
- do_check_true(ex.becauseBlockedByReputationCheck);
- do_check_eq(ex.reputationCheckVerdict,
- Downloads.Error.BLOCK_VERDICT_UNCOMMON);
- do_check_true(download.error.becauseBlockedByReputationCheck);
- do_check_eq(download.error.reputationCheckVerdict,
- Downloads.Error.BLOCK_VERDICT_UNCOMMON);
- }
-
- do_check_true(download.stopped);
- do_check_false(download.succeeded);
- do_check_false(yield OS.File.exists(download.target.path));
-
- cleanup();
- return download;
-});
-
-/**
- * Checks that application reputation blocks the download and the target file
- * does not exist.
- */
-add_task(function* test_blocked_applicationReputation()
-{
- let download = yield promiseBlockedDownload({
- keepPartialData: false,
- keepBlockedData: false,
- });
-
- // Now that the download is blocked, the target file should not exist.
- do_check_false(yield OS.File.exists(download.target.path));
- do_check_false(download.target.exists);
- do_check_eq(download.target.size, 0);
-
- // There should also be no blocked data in this case
- do_check_false(download.hasBlockedData);
-});
-
-/**
- * Checks that if a download restarts while processing an application reputation
- * request, the status is handled correctly.
- */
-add_task(function* test_blocked_applicationReputation_race()
-{
- let isFirstShouldBlockCall = true;
-
- let blockFn = base => ({
- shouldBlockForReputationCheck(download) {
- if (isFirstShouldBlockCall) {
- isFirstShouldBlockCall = false;
-
- // 2. Cancel and restart the download before the first attempt has a
- // chance to finish.
- download.cancel();
- download.removePartialData();
- download.start();
-
- // 3. Allow the first attempt to finish with a blocked response.
- return Promise.resolve({
- shouldBlock: true,
- verdict: Downloads.Error.BLOCK_VERDICT_UNCOMMON,
- });
- }
-
- // 4/5. Don't block the download the second time. The race condition would
- // occur with the first attempt regardless of whether the second one
- // is blocked, but not blocking here makes the test simpler.
- return Promise.resolve({
- shouldBlock: false,
- verdict: "",
- });
- },
- shouldKeepBlockedData: () => Promise.resolve(true),
- });
-
- Integration.downloads.register(blockFn);
- function cleanup() {
- Integration.downloads.unregister(blockFn);
- }
- do_register_cleanup(cleanup);
-
- let download;
-
- try {
- // 1. Start the download and get a reference to the promise asociated with
- // the first attempt, before allowing the response to continue.
- download = yield promiseStartDownload_tryToKeepPartialData();
- let firstAttempt = promiseDownloadStopped(download);
- continueResponses();
-
- // 4/5. Wait for the first attempt to be completed. The result of this
- // should appear as a cancellation.
- yield firstAttempt;
-
- do_throw("The first attempt should have been canceled.");
- } catch (ex) {
- // The "becauseBlocked" property should be false.
- if (!(ex instanceof Downloads.Error) || ex.becauseBlocked) {
- throw ex;
- }
- }
-
- // 6. Wait for the second attempt to be completed.
- yield promiseDownloadStopped(download);
-
- // 7. At this point, "hasBlockedData" should be false.
- do_check_false(download.hasBlockedData);
-
- cleanup();
-});
-
-/**
- * Checks that application reputation blocks the download but maintains the
- * blocked data, which will be deleted when the block is confirmed.
- */
-add_task(function* test_blocked_applicationReputation_confirmBlock()
-{
- let download = yield promiseBlockedDownload({
- keepPartialData: true,
- keepBlockedData: true,
- });
-
- do_check_true(download.hasBlockedData);
- do_check_true(yield OS.File.exists(download.target.partFilePath));
-
- yield download.confirmBlock();
-
- // After confirming the block the download should be in a failed state and
- // have no downloaded data left on disk.
- do_check_true(download.stopped);
- do_check_false(download.succeeded);
- do_check_false(download.hasBlockedData);
- do_check_false(yield OS.File.exists(download.target.partFilePath));
- do_check_false(yield OS.File.exists(download.target.path));
- do_check_false(download.target.exists);
- do_check_eq(download.target.size, 0);
-});
-
-/**
- * Checks that application reputation blocks the download but maintains the
- * blocked data, which will be used to complete the download when unblocking.
- */
-add_task(function* test_blocked_applicationReputation_unblock()
-{
- let download = yield promiseBlockedDownload({
- keepPartialData: true,
- keepBlockedData: true,
- });
-
- do_check_true(download.hasBlockedData);
- do_check_true(yield OS.File.exists(download.target.partFilePath));
-
- yield download.unblock();
-
- // After unblocking the download should have succeeded and be
- // present at the final path.
- do_check_true(download.stopped);
- do_check_true(download.succeeded);
- do_check_false(download.hasBlockedData);
- do_check_false(yield OS.File.exists(download.target.partFilePath));
- yield promiseVerifyTarget(download.target, TEST_DATA_SHORT + TEST_DATA_SHORT);
-
- // The only indication the download was previously blocked is the
- // existence of the error, so we make sure it's still set.
- do_check_true(download.error instanceof Downloads.Error);
- do_check_true(download.error.becauseBlocked);
- do_check_true(download.error.becauseBlockedByReputationCheck);
-});
-
-/**
- * Check that calling cancel on a blocked download will not cause errors
- */
-add_task(function* test_blocked_applicationReputation_cancel()
-{
- let download = yield promiseBlockedDownload({
- keepPartialData: true,
- keepBlockedData: true,
- });
-
- // This call should succeed on a blocked download.
- yield download.cancel();
-
- // Calling cancel should not have changed the current state, the download
- // should still be blocked.
- do_check_true(download.error.becauseBlockedByReputationCheck);
- do_check_true(download.stopped);
- do_check_false(download.succeeded);
- do_check_true(download.hasBlockedData);
-});
-
-/**
- * Checks that unblock and confirmBlock cannot race on a blocked download
- */
-add_task(function* test_blocked_applicationReputation_decisionRace()
-{
- let download = yield promiseBlockedDownload({
- keepPartialData: true,
- keepBlockedData: true,
- });
-
- let unblockPromise = download.unblock();
- let confirmBlockPromise = download.confirmBlock();
-
- yield confirmBlockPromise.then(() => {
- do_throw("confirmBlock should have failed.");
- }, () => {});
-
- yield unblockPromise;
-
- // After unblocking the download should have succeeded and be
- // present at the final path.
- do_check_true(download.stopped);
- do_check_true(download.succeeded);
- do_check_false(download.hasBlockedData);
- do_check_false(yield OS.File.exists(download.target.partFilePath));
- do_check_true(yield OS.File.exists(download.target.path));
-
- download = yield promiseBlockedDownload({
- keepPartialData: true,
- keepBlockedData: true,
- });
-
- confirmBlockPromise = download.confirmBlock();
- unblockPromise = download.unblock();
-
- yield unblockPromise.then(() => {
- do_throw("unblock should have failed.");
- }, () => {});
-
- yield confirmBlockPromise;
-
- // After confirming the block the download should be in a failed state and
- // have no downloaded data left on disk.
- do_check_true(download.stopped);
- do_check_false(download.succeeded);
- do_check_false(download.hasBlockedData);
- do_check_false(yield OS.File.exists(download.target.partFilePath));
- do_check_false(yield OS.File.exists(download.target.path));
- do_check_false(download.target.exists);
- do_check_eq(download.target.size, 0);
-});
-
-/**
- * Checks that unblocking a blocked download fails if the blocked data has been
- * removed.
- */
-add_task(function* test_blocked_applicationReputation_unblock()
-{
- let download = yield promiseBlockedDownload({
- keepPartialData: true,
- keepBlockedData: true,
- });
-
- do_check_true(download.hasBlockedData);
- do_check_true(yield OS.File.exists(download.target.partFilePath));
-
- // Remove the blocked data without telling the download.
- yield OS.File.remove(download.target.partFilePath);
-
- let unblockPromise = download.unblock();
- yield unblockPromise.then(() => {
- do_throw("unblock should have failed.");
- }, () => {});
-
- // Even though unblocking failed the download state should have been updated
- // to reflect the lack of blocked data.
- do_check_false(download.hasBlockedData);
- do_check_true(download.stopped);
- do_check_false(download.succeeded);
- do_check_false(download.target.exists);
- do_check_eq(download.target.size, 0);
-});
-
-/**
- * download.showContainingDirectory() action
- */
-add_task(function* test_showContainingDirectory() {
- let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
-
- let download = yield Downloads.createDownload({
- source: { url: httpUrl("source.txt") },
- target: ""
- });
-
- let promiseDirectoryShown = waitForDirectoryShown();
- yield download.showContainingDirectory();
- let path = yield promiseDirectoryShown;
- try {
- new FileUtils.File(path);
- do_throw("Should have failed because of an invalid path.");
- } catch (ex) {
- if (!(ex instanceof Components.Exception)) {
- throw ex;
- }
- // Invalid paths on Windows are reported with NS_ERROR_FAILURE,
- // but with NS_ERROR_FILE_UNRECOGNIZED_PATH on Mac/Linux
- let validResult = ex.result == Cr.NS_ERROR_FILE_UNRECOGNIZED_PATH ||
- ex.result == Cr.NS_ERROR_FAILURE;
- do_check_true(validResult);
- }
-
- download = yield Downloads.createDownload({
- source: { url: httpUrl("source.txt") },
- target: targetPath
- });
-
- promiseDirectoryShown = waitForDirectoryShown();
- download.showContainingDirectory();
- yield promiseDirectoryShown;
-});
-
-/**
- * download.launch() action
- */
-add_task(function* test_launch() {
- let customLauncher = getTempFile("app-launcher");
-
- // Test both with and without setting a custom application.
- for (let launcherPath of [null, customLauncher.path]) {
- let download;
- if (!gUseLegacySaver) {
- // When testing DownloadCopySaver, we have control over the download, thus
- // we can test that file is not launched if download.succeeded is not set.
- download = yield Downloads.createDownload({
- source: httpUrl("source.txt"),
- target: getTempFile(TEST_TARGET_FILE_NAME).path,
- launcherPath: launcherPath,
- launchWhenSucceeded: true
- });
-
- try {
- yield download.launch();
- do_throw("Can't launch download file as it has not completed yet");
- } catch (ex) {
- do_check_eq(ex.message,
- "launch can only be called if the download succeeded");
- }
-
- yield download.start();
- } else {
- // When testing DownloadLegacySaver, the download is already started when
- // it is created, thus we don't test calling "launch" before starting.
- download = yield promiseStartLegacyDownload(
- httpUrl("source.txt"),
- { launcherPath: launcherPath,
- launchWhenSucceeded: true });
- yield promiseDownloadStopped(download);
- }
-
- do_check_true(download.launchWhenSucceeded);
-
- let promiseFileLaunched = waitForFileLaunched();
- download.launch();
- let result = yield promiseFileLaunched;
-
- // Verify that the results match the test case.
- if (!launcherPath) {
- // This indicates that the default handler has been chosen.
- do_check_true(result === null);
- } else {
- // Check the nsIMIMEInfo instance that would have been used for launching.
- do_check_eq(result.preferredAction, Ci.nsIMIMEInfo.useHelperApp);
- do_check_true(result.preferredApplicationHandler
- .QueryInterface(Ci.nsILocalHandlerApp)
- .executable.equals(customLauncher));
- }
- }
-});
-
-/**
- * Test passing an invalid path as the launcherPath property.
- */
-add_task(function* test_launcherPath_invalid() {
- let download = yield Downloads.createDownload({
- source: { url: httpUrl("source.txt") },
- target: { path: getTempFile(TEST_TARGET_FILE_NAME).path },
- launcherPath: " "
- });
-
- let promiseDownloadLaunched = new Promise(resolve => {
- let waitFn = base => ({
- __proto__: base,
- launchDownload() {
- Integration.downloads.unregister(waitFn);
- let superPromise = super.launchDownload(...arguments);
- resolve(superPromise);
- return superPromise;
- },
- });
- Integration.downloads.register(waitFn);
- });
-
- yield download.start();
- try {
- download.launch();
- yield promiseDownloadLaunched;
- do_throw("Can't launch file with invalid custom launcher")
- } catch (ex) {
- if (!(ex instanceof Components.Exception)) {
- throw ex;
- }
- // Invalid paths on Windows are reported with NS_ERROR_FAILURE,
- // but with NS_ERROR_FILE_UNRECOGNIZED_PATH on Mac/Linux
- let validResult = ex.result == Cr.NS_ERROR_FILE_UNRECOGNIZED_PATH ||
- ex.result == Cr.NS_ERROR_FAILURE;
- do_check_true(validResult);
- }
-});
-
-/**
- * Tests that download.launch() is automatically called after
- * the download finishes if download.launchWhenSucceeded = true
- */
-add_task(function* test_launchWhenSucceeded() {
- let customLauncher = getTempFile("app-launcher");
-
- // Test both with and without setting a custom application.
- for (let launcherPath of [null, customLauncher.path]) {
- let promiseFileLaunched = waitForFileLaunched();
-
- if (!gUseLegacySaver) {
- let download = yield Downloads.createDownload({
- source: httpUrl("source.txt"),
- target: getTempFile(TEST_TARGET_FILE_NAME).path,
- launchWhenSucceeded: true,
- launcherPath: launcherPath,
- });
- yield download.start();
- } else {
- let download = yield promiseStartLegacyDownload(
- httpUrl("source.txt"),
- { launcherPath: launcherPath,
- launchWhenSucceeded: true });
- yield promiseDownloadStopped(download);
- }
-
- let result = yield promiseFileLaunched;
-
- // Verify that the results match the test case.
- if (!launcherPath) {
- // This indicates that the default handler has been chosen.
- do_check_true(result === null);
- } else {
- // Check the nsIMIMEInfo instance that would have been used for launching.
- do_check_eq(result.preferredAction, Ci.nsIMIMEInfo.useHelperApp);
- do_check_true(result.preferredApplicationHandler
- .QueryInterface(Ci.nsILocalHandlerApp)
- .executable.equals(customLauncher));
- }
- }
-});
-
-/**
- * Tests that the proper content type is set for a normal download.
- */
-add_task(function* test_contentType() {
- let download = yield promiseStartDownload(httpUrl("source.txt"));
- yield promiseDownloadStopped(download);
-
- do_check_eq("text/plain", download.contentType);
-});
-
-/**
- * Tests that the serialization/deserialization of the startTime Date
- * object works correctly.
- */
-add_task(function* test_toSerializable_startTime()
-{
- let download1 = yield promiseStartDownload(httpUrl("source.txt"));
- yield promiseDownloadStopped(download1);
-
- let serializable = download1.toSerializable();
- let reserialized = JSON.parse(JSON.stringify(serializable));
-
- let download2 = yield Downloads.createDownload(reserialized);
-
- do_check_eq(download1.startTime.constructor.name, "Date");
- do_check_eq(download2.startTime.constructor.name, "Date");
- do_check_eq(download1.startTime.toJSON(), download2.startTime.toJSON());
-});
-
-/**
- * Checks that downloads are added to browsing history when they start.
- */
-add_task(function* test_history()
-{
- mustInterruptResponses();
-
- // We will wait for the visit to be notified during the download.
- yield PlacesTestUtils.clearHistory();
- let promiseVisit = promiseWaitForVisit(httpUrl("interruptible.txt"));
-
- // Start a download that is not allowed to finish yet.
- let download = yield promiseStartDownload(httpUrl("interruptible.txt"));
-
- // The history notifications should be received before the download completes.
- let [time, transitionType] = yield promiseVisit;
- do_check_eq(time, download.startTime.getTime() * 1000);
- do_check_eq(transitionType, Ci.nsINavHistoryService.TRANSITION_DOWNLOAD);
-
- // Restart and complete the download after clearing history.
- yield PlacesTestUtils.clearHistory();
- download.cancel();
- continueResponses();
- yield download.start();
-
- // The restart should not have added a new history visit.
- do_check_false(yield promiseIsURIVisited(httpUrl("interruptible.txt")));
-});
-
-/**
- * Checks that downloads started by nsIHelperAppService are added to the
- * browsing history when they start.
- */
-add_task(function* test_history_tryToKeepPartialData()
-{
- // We will wait for the visit to be notified during the download.
- yield PlacesTestUtils.clearHistory();
- let promiseVisit =
- promiseWaitForVisit(httpUrl("interruptible_resumable.txt"));
-
- // Start a download that is not allowed to finish yet.
- let beforeStartTimeMs = Date.now();
- let download = yield promiseStartDownload_tryToKeepPartialData();
-
- // The history notifications should be received before the download completes.
- let [time, transitionType] = yield promiseVisit;
- do_check_eq(transitionType, Ci.nsINavHistoryService.TRANSITION_DOWNLOAD);
-
- // The time set by nsIHelperAppService may be different than the start time in
- // the download object, thus we only check that it is a meaningful time. Note
- // that we subtract one second from the earliest time to account for rounding.
- do_check_true(time >= beforeStartTimeMs * 1000 - 1000000);
-
- // Complete the download before finishing the test.
- continueResponses();
- yield promiseDownloadStopped(download);
-});
-
-/**
- * Tests that the temp download files are removed on exit and exiting private
- * mode after they have been launched.
- */
-add_task(function* test_launchWhenSucceeded_deleteTempFileOnExit() {
- let customLauncherPath = getTempFile("app-launcher").path;
- let autoDeleteTargetPathOne = getTempFile(TEST_TARGET_FILE_NAME).path;
- let autoDeleteTargetPathTwo = getTempFile(TEST_TARGET_FILE_NAME).path;
- let noAutoDeleteTargetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
-
- let autoDeleteDownloadOne = yield Downloads.createDownload({
- source: { url: httpUrl("source.txt"), isPrivate: true },
- target: autoDeleteTargetPathOne,
- launchWhenSucceeded: true,
- launcherPath: customLauncherPath,
- });
- yield autoDeleteDownloadOne.start();
-
- Services.prefs.setBoolPref(kDeleteTempFileOnExit, true);
- let autoDeleteDownloadTwo = yield Downloads.createDownload({
- source: httpUrl("source.txt"),
- target: autoDeleteTargetPathTwo,
- launchWhenSucceeded: true,
- launcherPath: customLauncherPath,
- });
- yield autoDeleteDownloadTwo.start();
-
- Services.prefs.setBoolPref(kDeleteTempFileOnExit, false);
- let noAutoDeleteDownload = yield Downloads.createDownload({
- source: httpUrl("source.txt"),
- target: noAutoDeleteTargetPath,
- launchWhenSucceeded: true,
- launcherPath: customLauncherPath,
- });
- yield noAutoDeleteDownload.start();
-
- Services.prefs.clearUserPref(kDeleteTempFileOnExit);
-
- do_check_true(yield OS.File.exists(autoDeleteTargetPathOne));
- do_check_true(yield OS.File.exists(autoDeleteTargetPathTwo));
- do_check_true(yield OS.File.exists(noAutoDeleteTargetPath));
-
- // Simulate leaving private browsing mode
- Services.obs.notifyObservers(null, "last-pb-context-exited", null);
- do_check_false(yield OS.File.exists(autoDeleteTargetPathOne));
-
- // Simulate browser shutdown
- let expire = Cc["@mozilla.org/uriloader/external-helper-app-service;1"]
- .getService(Ci.nsIObserver);
- expire.observe(null, "profile-before-change", null);
- do_check_false(yield OS.File.exists(autoDeleteTargetPathTwo));
- do_check_true(yield OS.File.exists(noAutoDeleteTargetPath));
-});
diff --git a/toolkit/components/jsdownloads/test/unit/head.js b/toolkit/components/jsdownloads/test/unit/head.js
deleted file mode 100644
index f322244c4..000000000
--- a/toolkit/components/jsdownloads/test/unit/head.js
+++ /dev/null
@@ -1,843 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 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/ */
-
-/**
- * Provides infrastructure for automated download components tests.
- */
-
-"use strict";
-
-// Globals
-
-var Cc = Components.classes;
-var Ci = Components.interfaces;
-var Cu = Components.utils;
-var Cr = Components.results;
-
-Cu.import("resource://gre/modules/Integration.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "DownloadPaths",
- "resource://gre/modules/DownloadPaths.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
- "resource://gre/modules/Downloads.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
- "resource://gre/modules/FileUtils.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "HttpServer",
- "resource://testing-common/httpd.js");
-XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
- "resource://gre/modules/NetUtil.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "PlacesTestUtils",
- "resource://testing-common/PlacesTestUtils.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
- "resource://gre/modules/PlacesUtils.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "Promise",
- "resource://gre/modules/Promise.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "Services",
- "resource://gre/modules/Services.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "Task",
- "resource://gre/modules/Task.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "OS",
- "resource://gre/modules/osfile.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "MockRegistrar",
- "resource://testing-common/MockRegistrar.jsm");
-
-XPCOMUtils.defineLazyServiceGetter(this, "gExternalHelperAppService",
- "@mozilla.org/uriloader/external-helper-app-service;1",
- Ci.nsIExternalHelperAppService);
-
-Integration.downloads.defineModuleGetter(this, "DownloadIntegration",
- "resource://gre/modules/DownloadIntegration.jsm");
-
-const ServerSocket = Components.Constructor(
- "@mozilla.org/network/server-socket;1",
- "nsIServerSocket",
- "init");
-const BinaryOutputStream = Components.Constructor(
- "@mozilla.org/binaryoutputstream;1",
- "nsIBinaryOutputStream",
- "setOutputStream")
-
-XPCOMUtils.defineLazyServiceGetter(this, "gMIMEService",
- "@mozilla.org/mime;1",
- "nsIMIMEService");
-
-const TEST_TARGET_FILE_NAME = "test-download.txt";
-const TEST_STORE_FILE_NAME = "test-downloads.json";
-
-const TEST_REFERRER_URL = "http://www.example.com/referrer.html";
-
-const TEST_DATA_SHORT = "This test string is downloaded.";
-// Generate using gzipCompressString in TelemetryController.jsm.
-const TEST_DATA_SHORT_GZIP_ENCODED_FIRST = [
- 31, 139, 8, 0, 0, 0, 0, 0, 0, 3, 11, 201, 200, 44, 86, 40, 73, 45, 46, 81, 40, 46, 41, 202, 204
-];
-const TEST_DATA_SHORT_GZIP_ENCODED_SECOND = [
- 75, 87, 0, 114, 83, 242, 203, 243, 114, 242, 19, 83, 82, 83, 244, 0, 151, 222, 109, 43, 31, 0, 0, 0
-];
-const TEST_DATA_SHORT_GZIP_ENCODED =
- TEST_DATA_SHORT_GZIP_ENCODED_FIRST.concat(TEST_DATA_SHORT_GZIP_ENCODED_SECOND);
-
-/**
- * All the tests are implemented with add_task, this starts them automatically.
- */
-function run_test()
-{
- do_get_profile();
- run_next_test();
-}
-
-// Support functions
-
-/**
- * HttpServer object initialized before tests start.
- */
-var gHttpServer;
-
-/**
- * Given a file name, returns a string containing an URI that points to the file
- * on the currently running instance of the test HTTP server.
- */
-function httpUrl(aFileName) {
- return "http://localhost:" + gHttpServer.identity.primaryPort + "/" +
- aFileName;
-}
-
-// While the previous test file should have deleted all the temporary files it
-// used, on Windows these might still be pending deletion on the physical file
-// system. Thus, start from a new base number every time, to make a collision
-// with a file that is still pending deletion highly unlikely.
-var gFileCounter = Math.floor(Math.random() * 1000000);
-
-/**
- * Returns a reference to a temporary file, that is guaranteed not to exist, and
- * to have never been created before.
- *
- * @param aLeafName
- * Suggested leaf name for the file to be created.
- *
- * @return nsIFile pointing to a non-existent file in a temporary directory.
- *
- * @note It is not enough to delete the file if it exists, or to delete the file
- * after calling nsIFile.createUnique, because on Windows the delete
- * operation in the file system may still be pending, preventing a new
- * file with the same name to be created.
- */
-function getTempFile(aLeafName)
-{
- // Prepend a serial number to the extension in the suggested leaf name.
- let [base, ext] = DownloadPaths.splitBaseNameAndExtension(aLeafName);
- let leafName = base + "-" + gFileCounter + ext;
- gFileCounter++;
-
- // Get a file reference under the temporary directory for this test file.
- let file = FileUtils.getFile("TmpD", [leafName]);
- do_check_false(file.exists());
-
- do_register_cleanup(function () {
- try {
- file.remove(false)
- } catch (e) {
- if (!(e instanceof Components.Exception &&
- (e.result == Cr.NS_ERROR_FILE_ACCESS_DENIED ||
- e.result == Cr.NS_ERROR_FILE_TARGET_DOES_NOT_EXIST ||
- e.result == Cr.NS_ERROR_FILE_NOT_FOUND))) {
- throw e;
- }
- // On Windows, we may get an access denied error if the file existed before,
- // and was recently deleted.
- // Don't bother checking file.exists() as that may also cause an access
- // denied error.
- }
- });
-
- return file;
-}
-
-/**
- * Waits for pending events to be processed.
- *
- * @return {Promise}
- * @resolves When pending events have been processed.
- * @rejects Never.
- */
-function promiseExecuteSoon()
-{
- let deferred = Promise.defer();
- do_execute_soon(deferred.resolve);
- return deferred.promise;
-}
-
-/**
- * Waits for a pending events to be processed after a timeout.
- *
- * @return {Promise}
- * @resolves When pending events have been processed.
- * @rejects Never.
- */
-function promiseTimeout(aTime)
-{
- let deferred = Promise.defer();
- do_timeout(aTime, deferred.resolve);
- return deferred.promise;
-}
-
-/**
- * Waits for a new history visit to be notified for the specified URI.
- *
- * @param aUrl
- * String containing the URI that will be visited.
- *
- * @return {Promise}
- * @resolves Array [aTime, aTransitionType] from nsINavHistoryObserver.onVisit.
- * @rejects Never.
- */
-function promiseWaitForVisit(aUrl)
-{
- let deferred = Promise.defer();
-
- let uri = NetUtil.newURI(aUrl);
-
- PlacesUtils.history.addObserver({
- QueryInterface: XPCOMUtils.generateQI([Ci.nsINavHistoryObserver]),
- onBeginUpdateBatch: function () {},
- onEndUpdateBatch: function () {},
- onVisit: function (aURI, aVisitID, aTime, aSessionID, aReferringID,
- aTransitionType, aGUID, aHidden) {
- if (aURI.equals(uri)) {
- PlacesUtils.history.removeObserver(this);
- deferred.resolve([aTime, aTransitionType]);
- }
- },
- onTitleChanged: function () {},
- onDeleteURI: function () {},
- onClearHistory: function () {},
- onPageChanged: function () {},
- onDeleteVisits: function () {},
- }, false);
-
- return deferred.promise;
-}
-
-/**
- * Check browsing history to see whether the given URI has been visited.
- *
- * @param aUrl
- * String containing the URI that will be visited.
- *
- * @return {Promise}
- * @resolves Boolean indicating whether the URI has been visited.
- * @rejects JavaScript exception.
- */
-function promiseIsURIVisited(aUrl) {
- let deferred = Promise.defer();
-
- PlacesUtils.asyncHistory.isURIVisited(NetUtil.newURI(aUrl),
- function (aURI, aIsVisited) {
- deferred.resolve(aIsVisited);
- });
-
- return deferred.promise;
-}
-
-/**
- * Creates a new Download object, setting a temporary file as the target.
- *
- * @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 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.
- * launchWhenSucceeded: Boolean indicating whether the target should
- * be launched when it has completed successfully.
- * launcherPath: String containing the path of the custom executable to
- * use to launch the target of the download.
- * }
- *
- * @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;
- }
-
- let fileExtension = null, mimeInfo = null;
- let match = sourceURI.path.match(/\.([^.\/]+)$/);
- if (match) {
- fileExtension = match[1];
- }
-
- if (fileExtension) {
- try {
- mimeInfo = gMIMEService.getFromTypeAndExtension(null, fileExtension);
- mimeInfo.preferredAction = Ci.nsIMIMEInfo.saveToDisk;
- } catch (ex) { }
- }
-
- if (aOptions && aOptions.launcherPath) {
- do_check_true(mimeInfo != null);
-
- let localHandlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"]
- .createInstance(Ci.nsILocalHandlerApp);
- localHandlerApp.executable = new FileUtils.File(aOptions.launcherPath);
-
- mimeInfo.preferredApplicationHandler = localHandlerApp;
- mimeInfo.preferredAction = Ci.nsIMIMEInfo.useHelperApp;
- }
-
- if (aOptions && aOptions.launchWhenSucceeded) {
- do_check_true(mimeInfo != null);
-
- mimeInfo.preferredAction = Ci.nsIMIMEInfo.useHelperApp;
- }
-
- // Apply decoding if required by the "Content-Encoding" header.
- persist.persistFlags &= ~Ci.nsIWebBrowserPersist.PERSIST_FLAGS_NO_CONVERSION;
- persist.persistFlags |=
- Ci.nsIWebBrowserPersist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION;
-
- let transfer = Cc["@mozilla.org/transfer;1"].createInstance(Ci.nsITransfer);
-
- let deferred = Promise.defer();
-
- Downloads.getList(Downloads.ALL).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).then(null, do_report_unexpected_exception);
-
- // Remove the download to keep the list empty for the next test. This
- // also allows the caller to register the "onchange" event directly.
- let promise = aList.remove(aDownload);
-
- // When the download object is ready, make it available to the caller.
- promise.then(() => deferred.resolve(aDownload),
- do_report_unexpected_exception);
- },
- }).then(null, do_report_unexpected_exception);
-
- let isPrivate = aOptions && aOptions.isPrivate;
-
- // 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, mimeInfo, null,
- null, persist, isPrivate);
- persist.progressListener = transfer;
-
- // Start the actual download process.
- persist.savePrivacyAwareURI(sourceURI, null, null, 0, null, null, targetFile,
- isPrivate);
- }.bind(this)).then(null, do_report_unexpected_exception);
-
- return deferred.promise;
-}
-
-/**
- * Starts a new download using the nsIHelperAppService interface, and controls
- * it using the legacy nsITransfer interface. The source of the download will
- * be "interruptible_resumable.txt" and partially downloaded data will be kept.
- *
- * @param aSourceUrl
- * String containing the URI for the download source, or null to use
- * httpUrl("interruptible_resumable.txt").
- *
- * @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 promiseStartExternalHelperAppServiceDownload(aSourceUrl) {
- let sourceURI = NetUtil.newURI(aSourceUrl ||
- httpUrl("interruptible_resumable.txt"));
-
- let deferred = Promise.defer();
-
- Downloads.getList(Downloads.PUBLIC).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).then(null, do_report_unexpected_exception);
-
- // Remove the download to keep the list empty for the next test. This
- // also allows the caller to register the "onchange" event directly.
- let promise = aList.remove(aDownload);
-
- // When the download object is ready, make it available to the caller.
- promise.then(() => deferred.resolve(aDownload),
- do_report_unexpected_exception);
- },
- }).then(null, do_report_unexpected_exception);
-
- let channel = NetUtil.newChannel({
- uri: sourceURI,
- loadUsingSystemPrincipal: true
- });
-
- // Start the actual download process.
- channel.asyncOpen2({
- contentListener: null,
-
- onStartRequest: function (aRequest, aContext)
- {
- let requestChannel = aRequest.QueryInterface(Ci.nsIChannel);
- this.contentListener = gExternalHelperAppService.doContent(
- requestChannel.contentType, aRequest, null, true);
- this.contentListener.onStartRequest(aRequest, aContext);
- },
-
- onStopRequest: function (aRequest, aContext, aStatusCode)
- {
- this.contentListener.onStopRequest(aRequest, aContext, aStatusCode);
- },
-
- onDataAvailable: function (aRequest, aContext, aInputStream, aOffset,
- aCount)
- {
- this.contentListener.onDataAvailable(aRequest, aContext, aInputStream,
- aOffset, aCount);
- },
- });
- }.bind(this)).then(null, do_report_unexpected_exception);
-
- return deferred.promise;
-}
-
-/**
- * Waits for a download to reach half of its progress, in case it has not
- * reached the expected progress already.
- *
- * @param aDownload
- * The Download object to wait upon.
- *
- * @return {Promise}
- * @resolves When the download has reached half of its progress.
- * @rejects Never.
- */
-function promiseDownloadMidway(aDownload) {
- let deferred = Promise.defer();
-
- // Wait for the download to reach half of its progress.
- let onchange = function () {
- if (!aDownload.stopped && !aDownload.canceled && aDownload.progress == 50) {
- aDownload.onchange = null;
- deferred.resolve();
- }
- };
-
- // Register for the notification, but also call the function directly in
- // case the download already reached the expected progress.
- aDownload.onchange = onchange;
- onchange();
-
- return deferred.promise;
-}
-
-/**
- * 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."));
-}
-
-/**
- * Returns a new public or private DownloadList object.
- *
- * @param aIsPrivate
- * True for the private list, false or undefined for the public list.
- *
- * @return {Promise}
- * @resolves The newly created DownloadList object.
- * @rejects JavaScript exception.
- */
-function promiseNewList(aIsPrivate)
-{
- // We need to clear all the internal state for the list and summary objects,
- // since all the objects are interdependent internally.
- Downloads._promiseListsInitialized = null;
- Downloads._lists = {};
- Downloads._summaries = {};
-
- return Downloads.getList(aIsPrivate ? Downloads.PRIVATE : Downloads.PUBLIC);
-}
-
-/**
- * Ensures that the given file contents are equal to the given string.
- *
- * @param aPath
- * String containing the path of the file whose contents should be
- * verified.
- * @param aExpectedContents
- * String containing the octets that are expected in the file.
- *
- * @return {Promise}
- * @resolves When the operation completes.
- * @rejects Never.
- */
-function promiseVerifyContents(aPath, aExpectedContents)
-{
- return Task.spawn(function* () {
- let file = new FileUtils.File(aPath);
-
- if (!(yield OS.File.exists(aPath))) {
- do_throw("File does not exist: " + aPath);
- }
-
- if ((yield OS.File.stat(aPath)).size == 0) {
- do_throw("File is empty: " + aPath);
- }
-
- let deferred = Promise.defer();
- NetUtil.asyncFetch(
- { uri: NetUtil.newURI(file), loadUsingSystemPrincipal: true },
- function(aInputStream, aStatus) {
- do_check_true(Components.isSuccessCode(aStatus));
- let contents = NetUtil.readInputStreamToString(aInputStream,
- aInputStream.available());
- if (contents.length > TEST_DATA_SHORT.length * 2 ||
- /[^\x20-\x7E]/.test(contents)) {
- // Do not print the entire content string to the test log.
- do_check_eq(contents.length, aExpectedContents.length);
- do_check_true(contents == aExpectedContents);
- } else {
- // Print the string if it is short and made of printable characters.
- do_check_eq(contents, aExpectedContents);
- }
- deferred.resolve();
- });
-
- yield deferred.promise;
- });
-}
-
-/**
- * Starts a socket listener that closes each incoming connection.
- *
- * @returns nsIServerSocket that listens for connections. Call its "close"
- * method to stop listening and free the server port.
- */
-function startFakeServer()
-{
- let serverSocket = new ServerSocket(-1, true, -1);
- serverSocket.asyncListen({
- onSocketAccepted: function (aServ, aTransport) {
- aTransport.close(Cr.NS_BINDING_ABORTED);
- },
- onStopListening: function () { },
- });
- return serverSocket;
-}
-
-/**
- * This is an internal reference that should not be used directly by tests.
- */
-var _gDeferResponses = Promise.defer();
-
-/**
- * Ensures that all the interruptible requests started after this function is
- * called won't complete until the continueResponses function is called.
- *
- * Normally, the internal HTTP server returns all the available data as soon as
- * a request is received. In order for some requests to be served one part at a
- * time, special interruptible handlers are registered on the HTTP server. This
- * allows testing events or actions that need to happen in the middle of a
- * download.
- *
- * For example, the handler accessible at the httpUri("interruptible.txt")
- * address returns the TEST_DATA_SHORT text, then it may block until the
- * continueResponses method is called. At this point, the handler sends the
- * TEST_DATA_SHORT text again to complete the response.
- *
- * If an interruptible request is started before the function is called, it may
- * or may not be blocked depending on the actual sequence of events.
- */
-function mustInterruptResponses()
-{
- // If there are pending blocked requests, allow them to complete. This is
- // done to prevent requests from being blocked forever, but should not affect
- // the test logic, since previously started requests should not be monitored
- // on the client side anymore.
- _gDeferResponses.resolve();
-
- do_print("Interruptible responses will be blocked midway.");
- _gDeferResponses = Promise.defer();
-}
-
-/**
- * Allows all the current and future interruptible requests to complete.
- */
-function continueResponses()
-{
- do_print("Interruptible responses are now allowed to continue.");
- _gDeferResponses.resolve();
-}
-
-/**
- * Registers an interruptible response handler.
- *
- * @param aPath
- * Path passed to nsIHttpServer.registerPathHandler.
- * @param aFirstPartFn
- * This function is called when the response is received, with the
- * aRequest and aResponse arguments of the server.
- * @param aSecondPartFn
- * This function is called with the aRequest and aResponse arguments of
- * the server, when the continueResponses function is called.
- */
-function registerInterruptibleHandler(aPath, aFirstPartFn, aSecondPartFn)
-{
- gHttpServer.registerPathHandler(aPath, function (aRequest, aResponse) {
- do_print("Interruptible request started.");
-
- // Process the first part of the response.
- aResponse.processAsync();
- aFirstPartFn(aRequest, aResponse);
-
- // Wait on the current deferred object, then finish the request.
- _gDeferResponses.promise.then(function RIH_onSuccess() {
- aSecondPartFn(aRequest, aResponse);
- aResponse.finish();
- do_print("Interruptible request finished.");
- }).then(null, Cu.reportError);
- });
-}
-
-/**
- * Ensure the given date object is valid.
- *
- * @param aDate
- * The date object to be checked. This value can be null.
- */
-function isValidDate(aDate) {
- return aDate && aDate.getTime && !isNaN(aDate.getTime());
-}
-
-/**
- * Position of the first byte served by the "interruptible_resumable.txt"
- * handler during the most recent response.
- */
-var gMostRecentFirstBytePos;
-
-// Initialization functions common to all tests
-
-add_task(function test_common_initialize()
-{
- // Start the HTTP server.
- gHttpServer = new HttpServer();
- gHttpServer.registerDirectory("/", do_get_file("../data"));
- gHttpServer.start(-1);
- do_register_cleanup(() => {
- return new Promise(resolve => {
- // Ensure all the pending HTTP requests have a chance to finish.
- continueResponses();
- // Stop the HTTP server, calling resolve when it's done.
- gHttpServer.stop(resolve);
- });
- });
-
- // Cache locks might prevent concurrent requests to the same resource, and
- // this may block tests that use the interruptible handlers.
- Services.prefs.setBoolPref("browser.cache.disk.enable", false);
- Services.prefs.setBoolPref("browser.cache.memory.enable", false);
- do_register_cleanup(function () {
- Services.prefs.clearUserPref("browser.cache.disk.enable");
- Services.prefs.clearUserPref("browser.cache.memory.enable");
- });
-
- registerInterruptibleHandler("/interruptible.txt",
- function firstPart(aRequest, aResponse) {
- aResponse.setHeader("Content-Type", "text/plain", false);
- aResponse.setHeader("Content-Length", "" + (TEST_DATA_SHORT.length * 2),
- false);
- aResponse.write(TEST_DATA_SHORT);
- }, function secondPart(aRequest, aResponse) {
- aResponse.write(TEST_DATA_SHORT);
- });
-
- registerInterruptibleHandler("/interruptible_resumable.txt",
- function firstPart(aRequest, aResponse) {
- aResponse.setHeader("Content-Type", "text/plain", false);
-
- // Determine if only part of the data should be sent.
- let data = TEST_DATA_SHORT + TEST_DATA_SHORT;
- if (aRequest.hasHeader("Range")) {
- var matches = aRequest.getHeader("Range")
- .match(/^\s*bytes=(\d+)?-(\d+)?\s*$/);
- var firstBytePos = (matches[1] === undefined) ? 0 : matches[1];
- var lastBytePos = (matches[2] === undefined) ? data.length - 1
- : matches[2];
- if (firstBytePos >= data.length) {
- aResponse.setStatusLine(aRequest.httpVersion, 416,
- "Requested Range Not Satisfiable");
- aResponse.setHeader("Content-Range", "*/" + data.length, false);
- aResponse.finish();
- return;
- }
-
- aResponse.setStatusLine(aRequest.httpVersion, 206, "Partial Content");
- aResponse.setHeader("Content-Range", firstBytePos + "-" +
- lastBytePos + "/" +
- data.length, false);
-
- data = data.substring(firstBytePos, lastBytePos + 1);
-
- gMostRecentFirstBytePos = firstBytePos;
- } else {
- gMostRecentFirstBytePos = 0;
- }
-
- aResponse.setHeader("Content-Length", "" + data.length, false);
-
- aResponse.write(data.substring(0, data.length / 2));
-
- // Store the second part of the data on the response object, so that it
- // can be used by the secondPart function.
- aResponse.secondPartData = data.substring(data.length / 2);
- }, function secondPart(aRequest, aResponse) {
- aResponse.write(aResponse.secondPartData);
- });
-
- registerInterruptibleHandler("/interruptible_gzip.txt",
- function firstPart(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);
-
- let bos = new BinaryOutputStream(aResponse.bodyOutputStream);
- bos.writeByteArray(TEST_DATA_SHORT_GZIP_ENCODED_FIRST,
- TEST_DATA_SHORT_GZIP_ENCODED_FIRST.length);
- }, function secondPart(aRequest, aResponse) {
- let bos = new BinaryOutputStream(aResponse.bodyOutputStream);
- bos.writeByteArray(TEST_DATA_SHORT_GZIP_ENCODED_SECOND,
- TEST_DATA_SHORT_GZIP_ENCODED_SECOND.length);
- });
-
- gHttpServer.registerPathHandler("/shorter-than-content-length-http-1-1.txt",
- function (aRequest, aResponse) {
- aResponse.processAsync();
- aResponse.setStatusLine("1.1", 200, "OK");
- aResponse.setHeader("Content-Type", "text/plain", false);
- aResponse.setHeader("Content-Length", "" + (TEST_DATA_SHORT.length * 2),
- false);
- aResponse.write(TEST_DATA_SHORT);
- aResponse.finish();
- });
-
- // This URL will emulate being blocked by Windows Parental controls
- gHttpServer.registerPathHandler("/parentalblocked.zip",
- function (aRequest, aResponse) {
- aResponse.setStatusLine(aRequest.httpVersion, 450,
- "Blocked by Windows Parental Controls");
- });
-
- // During unit tests, most of the functions that require profile access or
- // operating system features will be disabled. Individual tests may override
- // them again to check for specific behaviors.
- Integration.downloads.register(base => ({
- __proto__: base,
- loadPublicDownloadListFromStore: () => Promise.resolve(),
- shouldKeepBlockedData: () => Promise.resolve(false),
- shouldBlockForParentalControls: () => Promise.resolve(false),
- shouldBlockForRuntimePermissions: () => Promise.resolve(false),
- shouldBlockForReputationCheck: () => Promise.resolve({
- shouldBlock: false,
- verdict: "",
- }),
- confirmLaunchExecutable: () => Promise.resolve(),
- launchFile: () => Promise.resolve(),
- showContainingDirectory: () => Promise.resolve(),
- // This flag allows re-enabling the default observers during their tests.
- allowObservers: false,
- addListObservers() {
- return this.allowObservers ? super.addListObservers(...arguments)
- : Promise.resolve();
- },
- // This flag allows re-enabling the download directory logic for its tests.
- _allowDirectories: false,
- set allowDirectories(value) {
- this._allowDirectories = value;
- // We have to invalidate the previously computed directory path.
- this._downloadsDirectory = null;
- },
- _getDirectory(name) {
- return super._getDirectory(this._allowDirectories ? name : "TmpD");
- },
- }));
-
- // Make sure that downloads started using nsIExternalHelperAppService are
- // saved to disk without asking for a destination interactively.
- let mock = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIHelperAppLauncherDialog]),
- promptForSaveToFileAsync(aLauncher,
- aWindowContext,
- aDefaultFileName,
- aSuggestedFileExtension,
- aForcePrompt) {
- // The dialog should create the empty placeholder file.
- let file = getTempFile(TEST_TARGET_FILE_NAME);
- file.create(Ci.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE);
- aLauncher.saveDestinationAvailable(file);
- },
- };
-
- let cid = MockRegistrar.register("@mozilla.org/helperapplauncherdialog;1", mock);
- do_register_cleanup(() => {
- MockRegistrar.unregister(cid);
- });
-});
diff --git a/toolkit/components/jsdownloads/test/unit/test_DownloadCore.js b/toolkit/components/jsdownloads/test/unit/test_DownloadCore.js
deleted file mode 100644
index 6e32c63d3..000000000
--- a/toolkit/components/jsdownloads/test/unit/test_DownloadCore.js
+++ /dev/null
@@ -1,87 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 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 main download interfaces using DownloadCopySaver.
- */
-
-"use strict";
-
-XPCOMUtils.defineLazyModuleGetter(this, "DownloadError",
- "resource://gre/modules/DownloadCore.jsm");
-
-// Execution of common tests
-
-var gUseLegacySaver = false;
-
-var scriptFile = do_get_file("common_test_Download.js");
-Services.scriptloader.loadSubScript(NetUtil.newURI(scriptFile).spec);
-
-// Tests
-
-/**
- * Tests the DownloadError object.
- */
-add_task(function test_DownloadError()
-{
- let error = new DownloadError({ result: Cr.NS_ERROR_NOT_RESUMABLE,
- message: "Not resumable."});
- do_check_eq(error.result, Cr.NS_ERROR_NOT_RESUMABLE);
- do_check_eq(error.message, "Not resumable.");
- do_check_false(error.becauseSourceFailed);
- do_check_false(error.becauseTargetFailed);
- do_check_false(error.becauseBlocked);
- do_check_false(error.becauseBlockedByParentalControls);
-
- error = new DownloadError({ message: "Unknown error."});
- do_check_eq(error.result, Cr.NS_ERROR_FAILURE);
- do_check_eq(error.message, "Unknown error.");
-
- error = new DownloadError({ result: Cr.NS_ERROR_NOT_RESUMABLE });
- do_check_eq(error.result, Cr.NS_ERROR_NOT_RESUMABLE);
- do_check_true(error.message.indexOf("Exception") > 0);
-
- // becauseSourceFailed will be set, but not the unknown property.
- error = new DownloadError({ message: "Unknown error.",
- becauseSourceFailed: true,
- becauseUnknown: true });
- do_check_true(error.becauseSourceFailed);
- do_check_false("becauseUnknown" in error);
-
- error = new DownloadError({ result: Cr.NS_ERROR_MALFORMED_URI,
- inferCause: true });
- do_check_eq(error.result, Cr.NS_ERROR_MALFORMED_URI);
- do_check_true(error.becauseSourceFailed);
- do_check_false(error.becauseTargetFailed);
- do_check_false(error.becauseBlocked);
- do_check_false(error.becauseBlockedByParentalControls);
-
- // This test does not set inferCause, so becauseSourceFailed will not be set.
- error = new DownloadError({ result: Cr.NS_ERROR_MALFORMED_URI });
- do_check_eq(error.result, Cr.NS_ERROR_MALFORMED_URI);
- do_check_false(error.becauseSourceFailed);
-
- error = new DownloadError({ result: Cr.NS_ERROR_FILE_INVALID_PATH,
- inferCause: true });
- do_check_eq(error.result, Cr.NS_ERROR_FILE_INVALID_PATH);
- do_check_false(error.becauseSourceFailed);
- do_check_true(error.becauseTargetFailed);
- do_check_false(error.becauseBlocked);
- do_check_false(error.becauseBlockedByParentalControls);
-
- error = new DownloadError({ becauseBlocked: true });
- do_check_eq(error.message, "Download blocked.");
- do_check_false(error.becauseSourceFailed);
- do_check_false(error.becauseTargetFailed);
- do_check_true(error.becauseBlocked);
- do_check_false(error.becauseBlockedByParentalControls);
-
- error = new DownloadError({ becauseBlockedByParentalControls: true });
- do_check_eq(error.message, "Download blocked.");
- do_check_false(error.becauseSourceFailed);
- do_check_false(error.becauseTargetFailed);
- do_check_true(error.becauseBlocked);
- do_check_true(error.becauseBlockedByParentalControls);
-});
diff --git a/toolkit/components/jsdownloads/test/unit/test_DownloadImport.js b/toolkit/components/jsdownloads/test/unit/test_DownloadImport.js
deleted file mode 100644
index 388870f00..000000000
--- a/toolkit/components/jsdownloads/test/unit/test_DownloadImport.js
+++ /dev/null
@@ -1,701 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/**
- * Tests the DownloadImport object.
- */
-
-"use strict";
-
-// Globals
-
-XPCOMUtils.defineLazyModuleGetter(this, "Sqlite",
- "resource://gre/modules/Sqlite.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "DownloadImport",
- "resource://gre/modules/DownloadImport.jsm");
-
-// Importable states
-const DOWNLOAD_NOTSTARTED = -1;
-const DOWNLOAD_DOWNLOADING = 0;
-const DOWNLOAD_PAUSED = 4;
-const DOWNLOAD_QUEUED = 5;
-
-// Non importable states
-const DOWNLOAD_FAILED = 2;
-const DOWNLOAD_CANCELED = 3;
-const DOWNLOAD_BLOCKED_PARENTAL = 6;
-const DOWNLOAD_SCANNING = 7;
-const DOWNLOAD_DIRTY = 8;
-const DOWNLOAD_BLOCKED_POLICY = 9;
-
-// The TEST_DATA_TAINTED const is a version of TEST_DATA_SHORT in which the
-// beginning of the data was changed (with the TEST_DATA_REPLACEMENT value).
-// We use this to test that the entityID is properly imported and the download
-// can be resumed from where it was paused.
-// For simplification purposes, the test requires that TEST_DATA_SHORT and
-// TEST_DATA_TAINTED have the same length.
-const TEST_DATA_REPLACEMENT = "-changed- ";
-const TEST_DATA_TAINTED = TEST_DATA_REPLACEMENT +
- TEST_DATA_SHORT.substr(TEST_DATA_REPLACEMENT.length);
-const TEST_DATA_LENGTH = TEST_DATA_SHORT.length;
-
-// The length of the partial file that we'll write to disk as an existing
-// ongoing download.
-const TEST_DATA_PARTIAL_LENGTH = TEST_DATA_REPLACEMENT.length;
-
-// The value of the "maxBytes" column stored in the DB about the downloads.
-// It's intentionally different than TEST_DATA_LENGTH to test that each value
-// is seen when expected.
-const MAXBYTES_IN_DB = TEST_DATA_LENGTH - 10;
-
-var gDownloadsRowToImport;
-var gDownloadsRowNonImportable;
-
-/**
- * Creates a database with an empty moz_downloads table and leaves an
- * open connection to it.
- *
- * @param aPath
- * String containing the path of the database file to be created.
- * @param aSchemaVersion
- * Number with the version of the database schema to set.
- *
- * @return {Promise}
- * @resolves The open connection to the database.
- * @rejects If an error occurred during the database creation.
- */
-function promiseEmptyDatabaseConnection({aPath, aSchemaVersion}) {
- return Task.spawn(function* () {
- let connection = yield Sqlite.openConnection({ path: aPath });
-
- yield connection.execute("CREATE TABLE moz_downloads ("
- + "id INTEGER PRIMARY KEY,"
- + "name TEXT,"
- + "source TEXT,"
- + "target TEXT,"
- + "tempPath TEXT,"
- + "startTime INTEGER,"
- + "endTime INTEGER,"
- + "state INTEGER,"
- + "referrer TEXT,"
- + "entityID TEXT,"
- + "currBytes INTEGER NOT NULL DEFAULT 0,"
- + "maxBytes INTEGER NOT NULL DEFAULT -1,"
- + "mimeType TEXT,"
- + "preferredApplication TEXT,"
- + "preferredAction INTEGER NOT NULL DEFAULT 0,"
- + "autoResume INTEGER NOT NULL DEFAULT 0,"
- + "guid TEXT)");
-
- yield connection.setSchemaVersion(aSchemaVersion);
-
- return connection;
- });
-}
-
-/**
- * Inserts a new entry in the database with the given columns' values.
- *
- * @param aConnection
- * The database connection.
- * @param aDownloadRow
- * An object representing the values for each column of the row
- * being inserted.
- *
- * @return {Promise}
- * @resolves When the operation completes.
- * @rejects If there's an error inserting the row.
- */
-function promiseInsertRow(aConnection, aDownloadRow) {
- // We can't use the aDownloadRow obj directly in the execute statement
- // because the obj bind code in Sqlite.jsm doesn't allow objects
- // with extra properties beyond those being binded. So we might as well
- // use an array as it is simpler.
- let values = [
- aDownloadRow.source, aDownloadRow.target, aDownloadRow.tempPath,
- aDownloadRow.startTime.getTime() * 1000, aDownloadRow.state,
- aDownloadRow.referrer, aDownloadRow.entityID, aDownloadRow.maxBytes,
- aDownloadRow.mimeType, aDownloadRow.preferredApplication,
- aDownloadRow.preferredAction, aDownloadRow.autoResume
- ];
-
- return aConnection.execute("INSERT INTO moz_downloads ("
- + "name, source, target, tempPath, startTime,"
- + "endTime, state, referrer, entityID, currBytes,"
- + "maxBytes, mimeType, preferredApplication,"
- + "preferredAction, autoResume, guid)"
- + "VALUES ("
- + "'', ?, ?, ?, ?, " // name,
- + "0, ?, ?, ?, 0, " // endTime, currBytes
- + " ?, ?, ?, " //
- + " ?, ?, '')", // and guid are not imported
- values);
-}
-
-/**
- * Retrieves the number of rows in the moz_downloads table of the
- * database.
- *
- * @param aConnection
- * The database connection.
- *
- * @return {Promise}
- * @resolves With the number of rows.
- * @rejects Never.
- */
-function promiseTableCount(aConnection) {
- return aConnection.execute("SELECT COUNT(*) FROM moz_downloads")
- .then(res => res[0].getResultByName("COUNT(*)"))
- .then(null, Cu.reportError);
-}
-
-/**
- * Briefly opens a network channel to a given URL to retrieve
- * the entityID of this url, as generated by the network code.
- *
- * @param aUrl
- * The URL to retrieve the entityID.
- *
- * @return {Promise}
- * @resolves The EntityID of the given URL.
- * @rejects When there's a problem accessing the URL.
- */
-function promiseEntityID(aUrl) {
- let deferred = Promise.defer();
- let entityID = "";
- let channel = NetUtil.newChannel({
- uri: NetUtil.newURI(aUrl),
- loadUsingSystemPrincipal: true
- });
-
- channel.asyncOpen2({
- onStartRequest: function (aRequest) {
- if (aRequest instanceof Ci.nsIResumableChannel) {
- entityID = aRequest.entityID;
- }
- aRequest.cancel(Cr.NS_BINDING_ABORTED);
- },
-
- onStopRequest: function (aRequest, aContext, aStatusCode) {
- if (aStatusCode == Cr.NS_BINDING_ABORTED) {
- deferred.resolve(entityID);
- } else {
- deferred.reject("Unexpected status code received");
- }
- },
-
- onDataAvailable: function () {}
- });
-
- return deferred.promise;
-}
-
-/**
- * Gets a file path to a temporary writeable download target, in the
- * correct format as expected to be stored in the downloads database,
- * which is file:///absolute/path/to/file
- *
- * @param aLeafName
- * A hint leaf name for the file.
- *
- * @return String The path to the download target.
- */
-function getDownloadTarget(aLeafName) {
- return NetUtil.newURI(getTempFile(aLeafName)).spec;
-}
-
-/**
- * Generates a temporary partial file to use as an in-progress
- * download. The file is written to disk with a part of the total expected
- * download content pre-written.
- *
- * @param aLeafName
- * A hint leaf name for the file.
- * @param aTainted
- * A boolean value. When true, the partial content of the file
- * will be different from the expected content of the original source
- * file. See the declaration of TEST_DATA_TAINTED for more information.
- *
- * @return {Promise}
- * @resolves When the operation completes, and returns a string with the path
- * to the generated file.
- * @rejects If there's an error writing the file.
- */
-function getPartialFile(aLeafName, aTainted = false) {
- let tempDownload = getTempFile(aLeafName);
- let partialContent = aTainted
- ? TEST_DATA_TAINTED.substr(0, TEST_DATA_PARTIAL_LENGTH)
- : TEST_DATA_SHORT.substr(0, TEST_DATA_PARTIAL_LENGTH);
-
- return OS.File.writeAtomic(tempDownload.path, partialContent,
- { tmpPath: tempDownload.path + ".tmp",
- flush: true })
- .then(() => tempDownload.path);
-}
-
-/**
- * Generates a Date object to be used as the startTime for the download rows
- * in the DB. A date that is obviously different from the current time is
- * generated to make sure this stored data and a `new Date()` can't collide.
- *
- * @param aOffset
- * A offset from the base generated date is used to differentiate each
- * row in the database.
- *
- * @return A Date object.
- */
-function getStartTime(aOffset) {
- return new Date(1000000 + (aOffset * 10000));
-}
-
-/**
- * Performs various checks on an imported Download object to make sure
- * all properties are properly set as expected from the import procedure.
- *
- * @param aDownload
- * The Download object to be checked.
- * @param aDownloadRow
- * An object that represents a row from the original database table,
- * with extra properties describing expected values that are not
- * explictly part of the database.
- *
- * @return {Promise}
- * @resolves When the operation completes
- * @rejects Never
- */
-function checkDownload(aDownload, aDownloadRow) {
- return Task.spawn(function*() {
- do_check_eq(aDownload.source.url, aDownloadRow.source);
- do_check_eq(aDownload.source.referrer, aDownloadRow.referrer);
-
- do_check_eq(aDownload.target.path,
- NetUtil.newURI(aDownloadRow.target)
- .QueryInterface(Ci.nsIFileURL).file.path);
-
- do_check_eq(aDownload.target.partFilePath, aDownloadRow.tempPath);
-
- if (aDownloadRow.expectedResume) {
- do_check_true(!aDownload.stopped || aDownload.succeeded);
- yield promiseDownloadStopped(aDownload);
-
- do_check_true(aDownload.succeeded);
- do_check_eq(aDownload.progress, 100);
- // If the download has resumed, a new startTime will be set.
- // By calling toJSON we're also testing that startTime is a Date object.
- do_check_neq(aDownload.startTime.toJSON(),
- aDownloadRow.startTime.toJSON());
- } else {
- do_check_false(aDownload.succeeded);
- do_check_eq(aDownload.startTime.toJSON(),
- aDownloadRow.startTime.toJSON());
- }
-
- do_check_eq(aDownload.stopped, true);
-
- let serializedSaver = aDownload.saver.toSerializable();
- if (typeof(serializedSaver) == "object") {
- do_check_eq(serializedSaver.type, "copy");
- } else {
- do_check_eq(serializedSaver, "copy");
- }
-
- if (aDownloadRow.entityID) {
- do_check_eq(aDownload.saver.entityID, aDownloadRow.entityID);
- }
-
- do_check_eq(aDownload.currentBytes, aDownloadRow.expectedCurrentBytes);
- do_check_eq(aDownload.totalBytes, aDownloadRow.expectedTotalBytes);
-
- if (aDownloadRow.expectedContent) {
- let fileToCheck = aDownloadRow.expectedResume
- ? aDownload.target.path
- : aDownload.target.partFilePath;
- yield promiseVerifyContents(fileToCheck, aDownloadRow.expectedContent);
- }
-
- do_check_eq(aDownload.contentType, aDownloadRow.expectedContentType);
- do_check_eq(aDownload.launcherPath, aDownloadRow.preferredApplication);
-
- do_check_eq(aDownload.launchWhenSucceeded,
- aDownloadRow.preferredAction != Ci.nsIMIMEInfo.saveToDisk);
- });
-}
-
-// Preparation tasks
-
-/**
- * Prepares the list of downloads to be added to the database that should
- * be imported by the import procedure.
- */
-add_task(function* prepareDownloadsToImport() {
-
- let sourceUrl = httpUrl("source.txt");
- let sourceEntityId = yield promiseEntityID(sourceUrl);
-
- gDownloadsRowToImport = [
- // Paused download with autoResume and a partial file. By
- // setting the correct entityID the download can resume from
- // where it stopped, and to test that this works properly we
- // intentionally set different data in the beginning of the
- // partial file to make sure it was not replaced.
- {
- source: sourceUrl,
- target: getDownloadTarget("inprogress1.txt"),
- tempPath: yield getPartialFile("inprogress1.txt.part", true),
- startTime: getStartTime(1),
- state: DOWNLOAD_PAUSED,
- referrer: httpUrl("referrer1"),
- entityID: sourceEntityId,
- maxBytes: MAXBYTES_IN_DB,
- mimeType: "mimeType1",
- preferredAction: Ci.nsIMIMEInfo.saveToDisk,
- preferredApplication: "prerredApplication1",
- autoResume: 1,
-
- // Even though the information stored in the DB said
- // maxBytes was MAXBYTES_IN_DB, the download turned out to be
- // a different length. Here we make sure the totalBytes property
- // was correctly set with the actual value. The same consideration
- // applies to the contentType.
- expectedCurrentBytes: TEST_DATA_LENGTH,
- expectedTotalBytes: TEST_DATA_LENGTH,
- expectedResume: true,
- expectedContentType: "text/plain",
- expectedContent: TEST_DATA_TAINTED,
- },
-
- // Paused download with autoResume and a partial file,
- // but missing entityID. This means that the download will
- // start from beginning, and the entire original content of the
- // source file should replace the different data that was stored
- // in the partial file.
- {
- source: sourceUrl,
- target: getDownloadTarget("inprogress2.txt"),
- tempPath: yield getPartialFile("inprogress2.txt.part", true),
- startTime: getStartTime(2),
- state: DOWNLOAD_PAUSED,
- referrer: httpUrl("referrer2"),
- entityID: "",
- maxBytes: MAXBYTES_IN_DB,
- mimeType: "mimeType2",
- preferredAction: Ci.nsIMIMEInfo.saveToDisk,
- preferredApplication: "prerredApplication2",
- autoResume: 1,
-
- expectedCurrentBytes: TEST_DATA_LENGTH,
- expectedTotalBytes: TEST_DATA_LENGTH,
- expectedResume: true,
- expectedContentType: "text/plain",
- expectedContent: TEST_DATA_SHORT
- },
-
- // Paused download with no autoResume and a partial file.
- {
- source: sourceUrl,
- target: getDownloadTarget("inprogress3.txt"),
- tempPath: yield getPartialFile("inprogress3.txt.part"),
- startTime: getStartTime(3),
- state: DOWNLOAD_PAUSED,
- referrer: httpUrl("referrer3"),
- entityID: "",
- maxBytes: MAXBYTES_IN_DB,
- mimeType: "mimeType3",
- preferredAction: Ci.nsIMIMEInfo.saveToDisk,
- preferredApplication: "prerredApplication3",
- autoResume: 0,
-
- // Since this download has not been resumed, the actual data
- // about its total size and content type is not known.
- // Therefore, we're going by the information imported from the DB.
- expectedCurrentBytes: TEST_DATA_PARTIAL_LENGTH,
- expectedTotalBytes: MAXBYTES_IN_DB,
- expectedResume: false,
- expectedContentType: "mimeType3",
- expectedContent: TEST_DATA_SHORT.substr(0, TEST_DATA_PARTIAL_LENGTH),
- },
-
- // Paused download with autoResume and no partial file.
- {
- source: sourceUrl,
- target: getDownloadTarget("inprogress4.txt"),
- tempPath: "",
- startTime: getStartTime(4),
- state: DOWNLOAD_PAUSED,
- referrer: httpUrl("referrer4"),
- entityID: "",
- maxBytes: MAXBYTES_IN_DB,
- mimeType: "text/plain",
- preferredAction: Ci.nsIMIMEInfo.useHelperApp,
- preferredApplication: "prerredApplication4",
- autoResume: 1,
-
- expectedCurrentBytes: TEST_DATA_LENGTH,
- expectedTotalBytes: TEST_DATA_LENGTH,
- expectedResume: true,
- expectedContentType: "text/plain",
- expectedContent: TEST_DATA_SHORT
- },
-
- // Paused download with no autoResume and no partial file.
- {
- source: sourceUrl,
- target: getDownloadTarget("inprogress5.txt"),
- tempPath: "",
- startTime: getStartTime(5),
- state: DOWNLOAD_PAUSED,
- referrer: httpUrl("referrer4"),
- entityID: "",
- maxBytes: MAXBYTES_IN_DB,
- mimeType: "text/plain",
- preferredAction: Ci.nsIMIMEInfo.useSystemDefault,
- preferredApplication: "prerredApplication5",
- autoResume: 0,
-
- expectedCurrentBytes: 0,
- expectedTotalBytes: MAXBYTES_IN_DB,
- expectedResume: false,
- expectedContentType: "text/plain",
- },
-
- // Queued download with no autoResume and no partial file.
- // Even though autoResume=0, queued downloads always autoResume.
- {
- source: sourceUrl,
- target: getDownloadTarget("inprogress6.txt"),
- tempPath: "",
- startTime: getStartTime(6),
- state: DOWNLOAD_QUEUED,
- referrer: httpUrl("referrer6"),
- entityID: "",
- maxBytes: MAXBYTES_IN_DB,
- mimeType: "text/plain",
- preferredAction: Ci.nsIMIMEInfo.useHelperApp,
- preferredApplication: "prerredApplication6",
- autoResume: 0,
-
- expectedCurrentBytes: TEST_DATA_LENGTH,
- expectedTotalBytes: TEST_DATA_LENGTH,
- expectedResume: true,
- expectedContentType: "text/plain",
- expectedContent: TEST_DATA_SHORT
- },
-
- // Notstarted download with no autoResume and no partial file.
- // Even though autoResume=0, notstarted downloads always autoResume.
- {
- source: sourceUrl,
- target: getDownloadTarget("inprogress7.txt"),
- tempPath: "",
- startTime: getStartTime(7),
- state: DOWNLOAD_NOTSTARTED,
- referrer: httpUrl("referrer7"),
- entityID: "",
- maxBytes: MAXBYTES_IN_DB,
- mimeType: "text/plain",
- preferredAction: Ci.nsIMIMEInfo.useHelperApp,
- preferredApplication: "prerredApplication7",
- autoResume: 0,
-
- expectedCurrentBytes: TEST_DATA_LENGTH,
- expectedTotalBytes: TEST_DATA_LENGTH,
- expectedResume: true,
- expectedContentType: "text/plain",
- expectedContent: TEST_DATA_SHORT
- },
-
- // Downloading download with no autoResume and a partial file.
- // Even though autoResume=0, downloading downloads always autoResume.
- {
- source: sourceUrl,
- target: getDownloadTarget("inprogress8.txt"),
- tempPath: yield getPartialFile("inprogress8.txt.part", true),
- startTime: getStartTime(8),
- state: DOWNLOAD_DOWNLOADING,
- referrer: httpUrl("referrer8"),
- entityID: sourceEntityId,
- maxBytes: MAXBYTES_IN_DB,
- mimeType: "text/plain",
- preferredAction: Ci.nsIMIMEInfo.saveToDisk,
- preferredApplication: "prerredApplication8",
- autoResume: 0,
-
- expectedCurrentBytes: TEST_DATA_LENGTH,
- expectedTotalBytes: TEST_DATA_LENGTH,
- expectedResume: true,
- expectedContentType: "text/plain",
- expectedContent: TEST_DATA_TAINTED
- },
- ];
-});
-
-/**
- * Prepares the list of downloads to be added to the database that should
- * *not* be imported by the import procedure.
- */
-add_task(function* prepareNonImportableDownloads()
-{
- gDownloadsRowNonImportable = [
- // Download with no source (should never happen in normal circumstances).
- {
- source: "",
- target: "nonimportable1.txt",
- tempPath: "",
- startTime: getStartTime(1),
- state: DOWNLOAD_PAUSED,
- referrer: "",
- entityID: "",
- maxBytes: MAXBYTES_IN_DB,
- mimeType: "mimeType1",
- preferredAction: Ci.nsIMIMEInfo.saveToDisk,
- preferredApplication: "prerredApplication1",
- autoResume: 1
- },
-
- // state = DOWNLOAD_FAILED
- {
- source: httpUrl("source.txt"),
- target: "nonimportable2.txt",
- tempPath: "",
- startTime: getStartTime(2),
- state: DOWNLOAD_FAILED,
- referrer: "",
- entityID: "",
- maxBytes: MAXBYTES_IN_DB,
- mimeType: "mimeType2",
- preferredAction: Ci.nsIMIMEInfo.saveToDisk,
- preferredApplication: "prerredApplication2",
- autoResume: 1
- },
-
- // state = DOWNLOAD_CANCELED
- {
- source: httpUrl("source.txt"),
- target: "nonimportable3.txt",
- tempPath: "",
- startTime: getStartTime(3),
- state: DOWNLOAD_CANCELED,
- referrer: "",
- entityID: "",
- maxBytes: MAXBYTES_IN_DB,
- mimeType: "mimeType3",
- preferredAction: Ci.nsIMIMEInfo.saveToDisk,
- preferredApplication: "prerredApplication3",
- autoResume: 1
- },
-
- // state = DOWNLOAD_BLOCKED_PARENTAL
- {
- source: httpUrl("source.txt"),
- target: "nonimportable4.txt",
- tempPath: "",
- startTime: getStartTime(4),
- state: DOWNLOAD_BLOCKED_PARENTAL,
- referrer: "",
- entityID: "",
- maxBytes: MAXBYTES_IN_DB,
- mimeType: "mimeType4",
- preferredAction: Ci.nsIMIMEInfo.saveToDisk,
- preferredApplication: "prerredApplication4",
- autoResume: 1
- },
-
- // state = DOWNLOAD_SCANNING
- {
- source: httpUrl("source.txt"),
- target: "nonimportable5.txt",
- tempPath: "",
- startTime: getStartTime(5),
- state: DOWNLOAD_SCANNING,
- referrer: "",
- entityID: "",
- maxBytes: MAXBYTES_IN_DB,
- mimeType: "mimeType5",
- preferredAction: Ci.nsIMIMEInfo.saveToDisk,
- preferredApplication: "prerredApplication5",
- autoResume: 1
- },
-
- // state = DOWNLOAD_DIRTY
- {
- source: httpUrl("source.txt"),
- target: "nonimportable6.txt",
- tempPath: "",
- startTime: getStartTime(6),
- state: DOWNLOAD_DIRTY,
- referrer: "",
- entityID: "",
- maxBytes: MAXBYTES_IN_DB,
- mimeType: "mimeType6",
- preferredAction: Ci.nsIMIMEInfo.saveToDisk,
- preferredApplication: "prerredApplication6",
- autoResume: 1
- },
-
- // state = DOWNLOAD_BLOCKED_POLICY
- {
- source: httpUrl("source.txt"),
- target: "nonimportable7.txt",
- tempPath: "",
- startTime: getStartTime(7),
- state: DOWNLOAD_BLOCKED_POLICY,
- referrer: "",
- entityID: "",
- maxBytes: MAXBYTES_IN_DB,
- mimeType: "mimeType7",
- preferredAction: Ci.nsIMIMEInfo.saveToDisk,
- preferredApplication: "prerredApplication7",
- autoResume: 1
- },
- ];
-});
-
-// Test
-
-/**
- * Creates a temporary Sqlite database with download data and perform an
- * import of that data to the new Downloads API to verify that the import
- * worked correctly.
- */
-add_task(function* test_downloadImport()
-{
- let connection = null;
- let downloadsSqlite = getTempFile("downloads.sqlite").path;
-
- try {
- // Set up the database.
- connection = yield promiseEmptyDatabaseConnection({
- aPath: downloadsSqlite,
- aSchemaVersion: 9
- });
-
- // Insert both the importable and non-importable
- // downloads together.
- for (let downloadRow of gDownloadsRowToImport) {
- yield promiseInsertRow(connection, downloadRow);
- }
-
- for (let downloadRow of gDownloadsRowNonImportable) {
- yield promiseInsertRow(connection, downloadRow);
- }
-
- // Check that every item was inserted.
- do_check_eq((yield promiseTableCount(connection)),
- gDownloadsRowToImport.length +
- gDownloadsRowNonImportable.length);
- } finally {
- // Close the connection so that DownloadImport can open it.
- yield connection.close();
- }
-
- // Import items.
- let list = yield promiseNewList(false);
- yield new DownloadImport(list, downloadsSqlite).import();
- let items = yield list.getAll();
-
- do_check_eq(items.length, gDownloadsRowToImport.length);
-
- for (let i = 0; i < gDownloadsRowToImport.length; i++) {
- yield checkDownload(items[i], gDownloadsRowToImport[i]);
- }
-})
diff --git a/toolkit/components/jsdownloads/test/unit/test_DownloadIntegration.js b/toolkit/components/jsdownloads/test/unit/test_DownloadIntegration.js
deleted file mode 100644
index 31dd7c7a4..000000000
--- a/toolkit/components/jsdownloads/test/unit/test_DownloadIntegration.js
+++ /dev/null
@@ -1,432 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/**
- * Tests the DownloadIntegration object.
- */
-
-"use strict";
-
-// Globals
-
-/**
- * Notifies the prompt observers and verify the expected downloads count.
- *
- * @param aIsPrivate
- * Flag to know is test private observers.
- * @param aExpectedCount
- * the expected downloads count for quit and offline observers.
- * @param aExpectedPBCount
- * the expected downloads count for private browsing observer.
- */
-function notifyPromptObservers(aIsPrivate, aExpectedCount, aExpectedPBCount) {
- let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].
- createInstance(Ci.nsISupportsPRBool);
-
- // Notify quit application requested observer.
- DownloadIntegration._testPromptDownloads = -1;
- Services.obs.notifyObservers(cancelQuit, "quit-application-requested", null);
- do_check_eq(DownloadIntegration._testPromptDownloads, aExpectedCount);
-
- // Notify offline requested observer.
- DownloadIntegration._testPromptDownloads = -1;
- Services.obs.notifyObservers(cancelQuit, "offline-requested", null);
- do_check_eq(DownloadIntegration._testPromptDownloads, aExpectedCount);
-
- if (aIsPrivate) {
- // Notify last private browsing requested observer.
- DownloadIntegration._testPromptDownloads = -1;
- Services.obs.notifyObservers(cancelQuit, "last-pb-context-exiting", null);
- do_check_eq(DownloadIntegration._testPromptDownloads, aExpectedPBCount);
- }
-
- delete DownloadIntegration._testPromptDownloads;
-}
-
-// Tests
-
-/**
- * Allows re-enabling the real download directory logic during one test.
- */
-function allowDirectoriesInTest() {
- DownloadIntegration.allowDirectories = true;
- function cleanup() {
- DownloadIntegration.allowDirectories = false;
- }
- do_register_cleanup(cleanup);
- return cleanup;
-}
-
-XPCOMUtils.defineLazyGetter(this, "gStringBundle", function() {
- return Services.strings.
- createBundle("chrome://mozapps/locale/downloads/downloads.properties");
-});
-
-/**
- * Tests that getSystemDownloadsDirectory returns an existing directory or
- * creates a new directory depending on the platform. Instead of the real
- * directory, this test is executed in the temporary directory so we can safely
- * delete the created folder to check whether it is created again.
- */
-add_task(function* test_getSystemDownloadsDirectory_exists_or_creates()
-{
- let tempDir = Services.dirsvc.get("TmpD", Ci.nsIFile);
- let downloadDir;
-
- // OSX / Linux / Windows but not XP/2k
- if (Services.appinfo.OS == "Darwin" ||
- Services.appinfo.OS == "Linux" ||
- (Services.appinfo.OS == "WINNT" &&
- parseFloat(Services.sysinfo.getProperty("version")) >= 6)) {
- downloadDir = yield DownloadIntegration.getSystemDownloadsDirectory();
- do_check_eq(downloadDir, tempDir.path);
- do_check_true(yield OS.File.exists(downloadDir));
-
- let info = yield OS.File.stat(downloadDir);
- do_check_true(info.isDir);
- } else {
- let targetPath = OS.Path.join(tempDir.path,
- gStringBundle.GetStringFromName("downloadsFolder"));
- try {
- yield OS.File.removeEmptyDir(targetPath);
- } catch (e) {}
- downloadDir = yield DownloadIntegration.getSystemDownloadsDirectory();
- do_check_eq(downloadDir, targetPath);
- do_check_true(yield OS.File.exists(downloadDir));
-
- let info = yield OS.File.stat(downloadDir);
- do_check_true(info.isDir);
- yield OS.File.removeEmptyDir(targetPath);
- }
-});
-
-/**
- * Tests that the real directory returned by getSystemDownloadsDirectory is not
- * the one that is used during unit tests. Since this is the actual downloads
- * directory of the operating system, we don't try to delete it afterwards.
- */
-add_task(function* test_getSystemDownloadsDirectory_real()
-{
- let fakeDownloadDir = yield DownloadIntegration.getSystemDownloadsDirectory();
-
- let cleanup = allowDirectoriesInTest();
- let realDownloadDir = yield DownloadIntegration.getSystemDownloadsDirectory();
- cleanup();
-
- do_check_neq(fakeDownloadDir, realDownloadDir);
-});
-
-/**
- * Tests that the getPreferredDownloadsDirectory returns a valid download
- * directory string path.
- */
-add_task(function* test_getPreferredDownloadsDirectory()
-{
- let cleanupDirectories = allowDirectoriesInTest();
-
- let folderListPrefName = "browser.download.folderList";
- let dirPrefName = "browser.download.dir";
- function cleanupPrefs() {
- Services.prefs.clearUserPref(folderListPrefName);
- Services.prefs.clearUserPref(dirPrefName);
- }
- do_register_cleanup(cleanupPrefs);
-
- // Should return the system downloads directory.
- Services.prefs.setIntPref(folderListPrefName, 1);
- let systemDir = yield DownloadIntegration.getSystemDownloadsDirectory();
- let downloadDir = yield DownloadIntegration.getPreferredDownloadsDirectory();
- do_check_neq(downloadDir, "");
- do_check_eq(downloadDir, systemDir);
-
- // Should return the desktop directory.
- Services.prefs.setIntPref(folderListPrefName, 0);
- downloadDir = yield DownloadIntegration.getPreferredDownloadsDirectory();
- do_check_neq(downloadDir, "");
- do_check_eq(downloadDir, Services.dirsvc.get("Desk", Ci.nsIFile).path);
-
- // Should return the system downloads directory because the dir preference
- // is not set.
- Services.prefs.setIntPref(folderListPrefName, 2);
- downloadDir = yield DownloadIntegration.getPreferredDownloadsDirectory();
- do_check_neq(downloadDir, "");
- do_check_eq(downloadDir, systemDir);
-
- // Should return the directory which is listed in the dir preference.
- let time = (new Date()).getTime();
- let tempDir = Services.dirsvc.get("TmpD", Ci.nsIFile);
- tempDir.append(time);
- Services.prefs.setComplexValue("browser.download.dir", Ci.nsIFile, tempDir);
- downloadDir = yield DownloadIntegration.getPreferredDownloadsDirectory();
- do_check_neq(downloadDir, "");
- do_check_eq(downloadDir, tempDir.path);
- do_check_true(yield OS.File.exists(downloadDir));
- yield OS.File.removeEmptyDir(tempDir.path);
-
- // Should return the system downloads directory beacause the path is invalid
- // in the dir preference.
- tempDir = Services.dirsvc.get("TmpD", Ci.nsIFile);
- tempDir.append("dir_not_exist");
- tempDir.append(time);
- Services.prefs.setComplexValue("browser.download.dir", Ci.nsIFile, tempDir);
- downloadDir = yield DownloadIntegration.getPreferredDownloadsDirectory();
- do_check_eq(downloadDir, systemDir);
-
- // Should return the system downloads directory because the folderList
- // preference is invalid
- Services.prefs.setIntPref(folderListPrefName, 999);
- downloadDir = yield DownloadIntegration.getPreferredDownloadsDirectory();
- do_check_eq(downloadDir, systemDir);
-
- cleanupPrefs();
- cleanupDirectories();
-});
-
-/**
- * Tests that the getTemporaryDownloadsDirectory returns a valid download
- * directory string path.
- */
-add_task(function* test_getTemporaryDownloadsDirectory()
-{
- let cleanup = allowDirectoriesInTest();
-
- let downloadDir = yield DownloadIntegration.getTemporaryDownloadsDirectory();
- do_check_neq(downloadDir, "");
-
- if ("nsILocalFileMac" in Ci) {
- let preferredDownloadDir = yield DownloadIntegration.getPreferredDownloadsDirectory();
- do_check_eq(downloadDir, preferredDownloadDir);
- } else {
- let tempDir = Services.dirsvc.get("TmpD", Ci.nsIFile);
- do_check_eq(downloadDir, tempDir.path);
- }
-
- cleanup();
-});
-
-// Tests DownloadObserver
-
-/**
- * Re-enables the default observers for the following tests.
- *
- * This takes effect the first time a DownloadList object is created, and lasts
- * until this test file has completed.
- */
-add_task(function* test_observers_setup()
-{
- DownloadIntegration.allowObservers = true;
- do_register_cleanup(function () {
- DownloadIntegration.allowObservers = false;
- });
-});
-
-/**
- * Tests notifications prompts when observers are notified if there are public
- * and private active downloads.
- */
-add_task(function* test_notifications()
-{
- for (let isPrivate of [false, true]) {
- mustInterruptResponses();
-
- let list = yield promiseNewList(isPrivate);
- let download1 = yield promiseNewDownload(httpUrl("interruptible.txt"));
- let download2 = yield promiseNewDownload(httpUrl("interruptible.txt"));
- let download3 = yield promiseNewDownload(httpUrl("interruptible.txt"));
- let promiseAttempt1 = download1.start();
- let promiseAttempt2 = download2.start();
- download3.start().catch(() => {});
-
- // Add downloads to list.
- yield list.add(download1);
- yield list.add(download2);
- yield list.add(download3);
- // Cancel third download
- yield download3.cancel();
-
- notifyPromptObservers(isPrivate, 2, 2);
-
- // Allow the downloads to complete.
- continueResponses();
- yield promiseAttempt1;
- yield promiseAttempt2;
-
- // Clean up.
- yield list.remove(download1);
- yield list.remove(download2);
- yield list.remove(download3);
- }
-});
-
-/**
- * Tests that notifications prompts observers are not notified if there are no
- * public or private active downloads.
- */
-add_task(function* test_no_notifications()
-{
- for (let isPrivate of [false, true]) {
- let list = yield promiseNewList(isPrivate);
- let download1 = yield promiseNewDownload(httpUrl("interruptible.txt"));
- let download2 = yield promiseNewDownload(httpUrl("interruptible.txt"));
- download1.start().catch(() => {});
- download2.start().catch(() => {});
-
- // Add downloads to list.
- yield list.add(download1);
- yield list.add(download2);
-
- yield download1.cancel();
- yield download2.cancel();
-
- notifyPromptObservers(isPrivate, 0, 0);
-
- // Clean up.
- yield list.remove(download1);
- yield list.remove(download2);
- }
-});
-
-/**
- * Tests notifications prompts when observers are notified if there are public
- * and private active downloads at the same time.
- */
-add_task(function* test_mix_notifications()
-{
- mustInterruptResponses();
-
- let publicList = yield promiseNewList();
- let privateList = yield Downloads.getList(Downloads.PRIVATE);
- let download1 = yield promiseNewDownload(httpUrl("interruptible.txt"));
- let download2 = yield promiseNewDownload(httpUrl("interruptible.txt"));
- let promiseAttempt1 = download1.start();
- let promiseAttempt2 = download2.start();
-
- // Add downloads to lists.
- yield publicList.add(download1);
- yield privateList.add(download2);
-
- notifyPromptObservers(true, 2, 1);
-
- // Allow the downloads to complete.
- continueResponses();
- yield promiseAttempt1;
- yield promiseAttempt2;
-
- // Clean up.
- yield publicList.remove(download1);
- yield privateList.remove(download2);
-});
-
-/**
- * Tests suspending and resuming as well as going offline and then online again.
- * The downloads should stop when suspending and start again when resuming.
- */
-add_task(function* test_suspend_resume()
-{
- // The default wake delay is 10 seconds, so set the wake delay to be much
- // faster for these tests.
- Services.prefs.setIntPref("browser.download.manager.resumeOnWakeDelay", 5);
-
- let addDownload = function(list)
- {
- return Task.spawn(function* () {
- let download = yield promiseNewDownload(httpUrl("interruptible.txt"));
- download.start().catch(() => {});
- list.add(download);
- return download;
- });
- }
-
- let publicList = yield promiseNewList();
- let privateList = yield promiseNewList(true);
-
- let download1 = yield addDownload(publicList);
- let download2 = yield addDownload(publicList);
- let download3 = yield addDownload(privateList);
- let download4 = yield addDownload(privateList);
- let download5 = yield addDownload(publicList);
-
- // First, check that the downloads are all canceled when going to sleep.
- Services.obs.notifyObservers(null, "sleep_notification", null);
- do_check_true(download1.canceled);
- do_check_true(download2.canceled);
- do_check_true(download3.canceled);
- do_check_true(download4.canceled);
- do_check_true(download5.canceled);
-
- // Remove a download. It should not be started again.
- publicList.remove(download5);
- do_check_true(download5.canceled);
-
- // When waking up again, the downloads start again after the wake delay. To be
- // more robust, don't check after a delay but instead just wait for the
- // downloads to finish.
- Services.obs.notifyObservers(null, "wake_notification", null);
- yield download1.whenSucceeded();
- yield download2.whenSucceeded();
- yield download3.whenSucceeded();
- yield download4.whenSucceeded();
-
- // Downloads should no longer be canceled. However, as download5 was removed
- // from the public list, it will not be restarted.
- do_check_false(download1.canceled);
- do_check_true(download5.canceled);
-
- // Create four new downloads and check for going offline and then online again.
-
- download1 = yield addDownload(publicList);
- download2 = yield addDownload(publicList);
- download3 = yield addDownload(privateList);
- download4 = yield addDownload(privateList);
-
- // Going offline should cancel the downloads.
- Services.obs.notifyObservers(null, "network:offline-about-to-go-offline", null);
- do_check_true(download1.canceled);
- do_check_true(download2.canceled);
- do_check_true(download3.canceled);
- do_check_true(download4.canceled);
-
- // Going back online should start the downloads again.
- Services.obs.notifyObservers(null, "network:offline-status-changed", "online");
- yield download1.whenSucceeded();
- yield download2.whenSucceeded();
- yield download3.whenSucceeded();
- yield download4.whenSucceeded();
-
- Services.prefs.clearUserPref("browser.download.manager.resumeOnWakeDelay");
-});
-
-/**
- * Tests both the downloads list and the in-progress downloads are clear when
- * private browsing observer is notified.
- */
-add_task(function* test_exit_private_browsing()
-{
- mustInterruptResponses();
-
- let privateList = yield promiseNewList(true);
- let download1 = yield promiseNewDownload(httpUrl("source.txt"));
- let download2 = yield promiseNewDownload(httpUrl("interruptible.txt"));
- let promiseAttempt1 = download1.start();
- download2.start();
-
- // Add downloads to list.
- yield privateList.add(download1);
- yield privateList.add(download2);
-
- // Complete the download.
- yield promiseAttempt1;
-
- do_check_eq((yield privateList.getAll()).length, 2);
-
- // Simulate exiting the private browsing.
- yield new Promise(resolve => {
- DownloadIntegration._testResolveClearPrivateList = resolve;
- Services.obs.notifyObservers(null, "last-pb-context-exited", null);
- });
- delete DownloadIntegration._testResolveClearPrivateList;
-
- do_check_eq((yield privateList.getAll()).length, 0);
-
- continueResponses();
-});
diff --git a/toolkit/components/jsdownloads/test/unit/test_DownloadLegacy.js b/toolkit/components/jsdownloads/test/unit/test_DownloadLegacy.js
deleted file mode 100644
index dc6c18623..000000000
--- a/toolkit/components/jsdownloads/test/unit/test_DownloadLegacy.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 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 integration with legacy interfaces for downloads.
- */
-
-"use strict";
-
-// Execution of common tests
-
-var gUseLegacySaver = true;
-
-var scriptFile = do_get_file("common_test_Download.js");
-Services.scriptloader.loadSubScript(NetUtil.newURI(scriptFile).spec);
diff --git a/toolkit/components/jsdownloads/test/unit/test_DownloadList.js b/toolkit/components/jsdownloads/test/unit/test_DownloadList.js
deleted file mode 100644
index 71e880741..000000000
--- a/toolkit/components/jsdownloads/test/unit/test_DownloadList.js
+++ /dev/null
@@ -1,564 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 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 DownloadList object.
- */
-
-"use strict";
-
-// Globals
-
-/**
- * Returns a PRTime in the past usable to add expirable visits.
- *
- * @note Expiration ignores any visit added in the last 7 days, but it's
- * better be safe against DST issues, by going back one day more.
- */
-function getExpirablePRTime()
-{
- let dateObj = new Date();
- // Normalize to midnight
- dateObj.setHours(0);
- dateObj.setMinutes(0);
- dateObj.setSeconds(0);
- dateObj.setMilliseconds(0);
- dateObj = new Date(dateObj.getTime() - 8 * 86400000);
- return dateObj.getTime() * 1000;
-}
-
-/**
- * Adds an expirable history visit for a download.
- *
- * @param aSourceUrl
- * String containing the URI for the download source, or null to use
- * httpUrl("source.txt").
- *
- * @return {Promise}
- * @rejects JavaScript exception.
- */
-function promiseExpirableDownloadVisit(aSourceUrl)
-{
- let deferred = Promise.defer();
- PlacesUtils.asyncHistory.updatePlaces(
- {
- uri: NetUtil.newURI(aSourceUrl || httpUrl("source.txt")),
- visits: [{
- transitionType: Ci.nsINavHistoryService.TRANSITION_DOWNLOAD,
- visitDate: getExpirablePRTime(),
- }]
- },
- {
- handleError: function handleError(aResultCode, aPlaceInfo) {
- let ex = new Components.Exception("Unexpected error in adding visits.",
- aResultCode);
- deferred.reject(ex);
- },
- handleResult: function () {},
- handleCompletion: function handleCompletion() {
- deferred.resolve();
- }
- });
- return deferred.promise;
-}
-
-// Tests
-
-/**
- * Checks the testing mechanism used to build different download lists.
- */
-add_task(function* test_construction()
-{
- let downloadListOne = yield promiseNewList();
- let downloadListTwo = yield promiseNewList();
- let privateDownloadListOne = yield promiseNewList(true);
- let privateDownloadListTwo = yield promiseNewList(true);
-
- do_check_neq(downloadListOne, downloadListTwo);
- do_check_neq(privateDownloadListOne, privateDownloadListTwo);
- do_check_neq(downloadListOne, privateDownloadListOne);
-});
-
-/**
- * Checks the methods to add and retrieve items from the list.
- */
-add_task(function* test_add_getAll()
-{
- let list = yield promiseNewList();
-
- let downloadOne = yield promiseNewDownload();
- yield list.add(downloadOne);
-
- let itemsOne = yield list.getAll();
- do_check_eq(itemsOne.length, 1);
- do_check_eq(itemsOne[0], downloadOne);
-
- let downloadTwo = yield promiseNewDownload();
- yield 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.
- do_check_eq(itemsOne.length, 1);
-});
-
-/**
- * Checks the method to remove items from the list.
- */
-add_task(function* test_remove()
-{
- let list = yield promiseNewList();
-
- yield list.add(yield promiseNewDownload());
- yield list.add(yield promiseNewDownload());
-
- let items = yield list.getAll();
- yield list.remove(items[0]);
-
- // Removing an item that was never added should not raise an error.
- yield list.remove(yield promiseNewDownload());
-
- items = yield list.getAll();
- do_check_eq(items.length, 1);
-});
-
-/**
- * Tests that the "add", "remove", and "getAll" methods on the global
- * DownloadCombinedList object combine the contents of the global DownloadList
- * objects for public and private downloads.
- */
-add_task(function* test_DownloadCombinedList_add_remove_getAll()
-{
- let publicList = yield promiseNewList();
- let privateList = yield Downloads.getList(Downloads.PRIVATE);
- let combinedList = yield Downloads.getList(Downloads.ALL);
-
- let publicDownload = yield promiseNewDownload();
- let privateDownload = yield Downloads.createDownload({
- source: { url: httpUrl("source.txt"), isPrivate: true },
- target: getTempFile(TEST_TARGET_FILE_NAME).path,
- });
-
- yield publicList.add(publicDownload);
- yield privateList.add(privateDownload);
-
- do_check_eq((yield combinedList.getAll()).length, 2);
-
- yield combinedList.remove(publicDownload);
- yield combinedList.remove(privateDownload);
-
- do_check_eq((yield combinedList.getAll()).length, 0);
-
- yield combinedList.add(publicDownload);
- yield combinedList.add(privateDownload);
-
- do_check_eq((yield publicList.getAll()).length, 1);
- do_check_eq((yield privateList.getAll()).length, 1);
- do_check_eq((yield combinedList.getAll()).length, 2);
-
- yield publicList.remove(publicDownload);
- yield privateList.remove(privateDownload);
-
- do_check_eq((yield combinedList.getAll()).length, 0);
-});
-
-/**
- * Checks that views receive the download add and remove notifications, and that
- * adding and removing views works as expected, both for a normal and a combined
- * list.
- */
-add_task(function* test_notifications_add_remove()
-{
- for (let isCombined of [false, true]) {
- // Force creating a new list for both the public and combined cases.
- let list = yield promiseNewList();
- if (isCombined) {
- list = yield Downloads.getList(Downloads.ALL);
- }
-
- let downloadOne = yield promiseNewDownload();
- let downloadTwo = yield Downloads.createDownload({
- source: { url: httpUrl("source.txt"), isPrivate: true },
- target: getTempFile(TEST_TARGET_FILE_NAME).path,
- });
- yield list.add(downloadOne);
- yield 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.
- if (addNotifications == 0) {
- do_check_eq(aDownload, downloadOne);
- } else if (addNotifications == 1) {
- do_check_eq(aDownload, downloadTwo);
- }
- addNotifications++;
- },
- };
- yield list.addView(viewOne);
- do_check_eq(addNotifications, 2);
-
- // Check that we receive add notifications for new elements.
- yield 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++;
- },
- };
- yield list.addView(viewTwo);
- yield list.remove(downloadOne);
- do_check_eq(removeNotifications, 1);
-
- // We should not receive remove notifications after the view is removed.
- yield list.removeView(viewTwo);
- yield list.remove(downloadTwo);
- do_check_eq(removeNotifications, 1);
-
- // We should not receive add notifications after the view is removed.
- yield list.removeView(viewOne);
- yield list.add(yield promiseNewDownload());
- do_check_eq(addNotifications, 3);
- }
-});
-
-/**
- * Checks that views receive the download change notifications, both for a
- * normal and a combined list.
- */
-add_task(function* test_notifications_change()
-{
- for (let isCombined of [false, true]) {
- // Force creating a new list for both the public and combined cases.
- let list = yield promiseNewList();
- if (isCombined) {
- list = yield Downloads.getList(Downloads.ALL);
- }
-
- let downloadOne = yield promiseNewDownload();
- let downloadTwo = yield Downloads.createDownload({
- source: { url: httpUrl("source.txt"), isPrivate: true },
- target: getTempFile(TEST_TARGET_FILE_NAME).path,
- });
- yield list.add(downloadOne);
- yield list.add(downloadTwo);
-
- // Check that we receive change notifications.
- let receivedOnDownloadChanged = false;
- yield list.addView({
- onDownloadChanged: function (aDownload) {
- do_check_eq(aDownload, downloadOne);
- receivedOnDownloadChanged = true;
- },
- });
- yield downloadOne.start();
- do_check_true(receivedOnDownloadChanged);
-
- // We should not receive change notifications after a download is removed.
- receivedOnDownloadChanged = false;
- yield list.remove(downloadTwo);
- yield downloadTwo.start();
- do_check_false(receivedOnDownloadChanged);
- }
-});
-
-/**
- * Checks that the reference to "this" is correct in the view callbacks.
- */
-add_task(function* test_notifications_this()
-{
- let list = yield promiseNewList();
-
- // Check that we receive change notifications.
- let receivedOnDownloadAdded = false;
- let receivedOnDownloadChanged = false;
- let receivedOnDownloadRemoved = false;
- let view = {
- onDownloadAdded: function () {
- do_check_eq(this, view);
- receivedOnDownloadAdded = true;
- },
- onDownloadChanged: function () {
- // Only do this check once.
- if (!receivedOnDownloadChanged) {
- do_check_eq(this, view);
- receivedOnDownloadChanged = true;
- }
- },
- onDownloadRemoved: function () {
- do_check_eq(this, view);
- receivedOnDownloadRemoved = true;
- },
- };
- yield list.addView(view);
-
- let download = yield promiseNewDownload();
- yield list.add(download);
- yield download.start();
- yield list.remove(download);
-
- // Verify that we executed the checks.
- do_check_true(receivedOnDownloadAdded);
- do_check_true(receivedOnDownloadChanged);
- do_check_true(receivedOnDownloadRemoved);
-});
-
-/**
- * Checks that download is removed on history expiration.
- */
-add_task(function* test_history_expiration()
-{
- mustInterruptResponses();
-
- function cleanup() {
- Services.prefs.clearUserPref("places.history.expiration.max_pages");
- }
- do_register_cleanup(cleanup);
-
- // Set max pages to 0 to make the download expire.
- Services.prefs.setIntPref("places.history.expiration.max_pages", 0);
-
- let list = yield promiseNewList();
- let downloadOne = yield promiseNewDownload();
- let downloadTwo = yield promiseNewDownload(httpUrl("interruptible.txt"));
-
- let deferred = Promise.defer();
- let removeNotifications = 0;
- let downloadView = {
- onDownloadRemoved: function (aDownload) {
- if (++removeNotifications == 2) {
- deferred.resolve();
- }
- },
- };
- yield list.addView(downloadView);
-
- // Work with one finished download and one canceled download.
- yield downloadOne.start();
- downloadTwo.start().catch(() => {});
- yield downloadTwo.cancel();
-
- // We must replace the visits added while executing the downloads with visits
- // that are older than 7 days, otherwise they will not be expired.
- yield PlacesTestUtils.clearHistory();
- yield promiseExpirableDownloadVisit();
- yield promiseExpirableDownloadVisit(httpUrl("interruptible.txt"));
-
- // After clearing history, we can add the downloads to be removed to the list.
- yield list.add(downloadOne);
- yield list.add(downloadTwo);
-
- // Force a history expiration.
- Cc["@mozilla.org/places/expiration;1"]
- .getService(Ci.nsIObserver).observe(null, "places-debug-start-expiration", -1);
-
- // Wait for both downloads to be removed.
- yield deferred.promise;
-
- cleanup();
-});
-
-/**
- * Checks all downloads are removed after clearing history.
- */
-add_task(function* test_history_clear()
-{
- let list = yield promiseNewList();
- let downloadOne = yield promiseNewDownload();
- let downloadTwo = yield promiseNewDownload();
- yield list.add(downloadOne);
- yield list.add(downloadTwo);
-
- let deferred = Promise.defer();
- let removeNotifications = 0;
- let downloadView = {
- onDownloadRemoved: function (aDownload) {
- if (++removeNotifications == 2) {
- deferred.resolve();
- }
- },
- };
- yield list.addView(downloadView);
-
- yield downloadOne.start();
- yield downloadTwo.start();
-
- yield PlacesTestUtils.clearHistory();
-
- // Wait for the removal notifications that may still be pending.
- yield deferred.promise;
-});
-
-/**
- * Tests the removeFinished method to ensure that it only removes
- * finished downloads.
- */
-add_task(function* test_removeFinished()
-{
- let list = yield promiseNewList();
- let downloadOne = yield promiseNewDownload();
- let downloadTwo = yield promiseNewDownload();
- let downloadThree = yield promiseNewDownload();
- let downloadFour = yield promiseNewDownload();
- yield list.add(downloadOne);
- yield list.add(downloadTwo);
- yield list.add(downloadThree);
- yield list.add(downloadFour);
-
- let deferred = Promise.defer();
- let removeNotifications = 0;
- let downloadView = {
- onDownloadRemoved: function (aDownload) {
- do_check_true(aDownload == downloadOne ||
- aDownload == downloadTwo ||
- aDownload == downloadThree);
- do_check_true(removeNotifications < 3);
- if (++removeNotifications == 3) {
- deferred.resolve();
- }
- },
- };
- yield list.addView(downloadView);
-
- // Start three of the downloads, but don't start downloadTwo, then set
- // downloadFour to have partial data. All downloads except downloadFour
- // should be removed.
- yield downloadOne.start();
- yield downloadThree.start();
- yield downloadFour.start();
- downloadFour.hasPartialData = true;
-
- list.removeFinished();
- yield deferred.promise;
-
- let downloads = yield list.getAll()
- do_check_eq(downloads.length, 1);
-});
-
-/**
- * Tests the global DownloadSummary objects for the public, private, and
- * combined download lists.
- */
-add_task(function* test_DownloadSummary()
-{
- mustInterruptResponses();
-
- let publicList = yield promiseNewList();
- let privateList = yield Downloads.getList(Downloads.PRIVATE);
-
- let publicSummary = yield Downloads.getSummary(Downloads.PUBLIC);
- let privateSummary = yield Downloads.getSummary(Downloads.PRIVATE);
- let combinedSummary = yield Downloads.getSummary(Downloads.ALL);
-
- // Add a public download that has succeeded.
- let succeededPublicDownload = yield promiseNewDownload();
- yield succeededPublicDownload.start();
- yield publicList.add(succeededPublicDownload);
-
- // Add a public download that has been canceled midway.
- let canceledPublicDownload =
- yield promiseNewDownload(httpUrl("interruptible.txt"));
- canceledPublicDownload.start().catch(() => {});
- yield promiseDownloadMidway(canceledPublicDownload);
- yield canceledPublicDownload.cancel();
- yield publicList.add(canceledPublicDownload);
-
- // Add a public download that is in progress.
- let inProgressPublicDownload =
- yield promiseNewDownload(httpUrl("interruptible.txt"));
- inProgressPublicDownload.start().catch(() => {});
- yield promiseDownloadMidway(inProgressPublicDownload);
- yield publicList.add(inProgressPublicDownload);
-
- // Add a private download that is in progress.
- let inProgressPrivateDownload = yield Downloads.createDownload({
- source: { url: httpUrl("interruptible.txt"), isPrivate: true },
- target: getTempFile(TEST_TARGET_FILE_NAME).path,
- });
- inProgressPrivateDownload.start().catch(() => {});
- yield promiseDownloadMidway(inProgressPrivateDownload);
- yield privateList.add(inProgressPrivateDownload);
-
- // Verify that the summary includes the total number of bytes and the
- // currently transferred bytes only for the downloads that are not stopped.
- // For simplicity, we assume that after a download is added to the list, its
- // current state is immediately propagated to the summary object, which is
- // true in the current implementation, though it is not guaranteed as all the
- // download operations may happen asynchronously.
- do_check_false(publicSummary.allHaveStopped);
- do_check_eq(publicSummary.progressTotalBytes, TEST_DATA_SHORT.length * 2);
- do_check_eq(publicSummary.progressCurrentBytes, TEST_DATA_SHORT.length);
-
- do_check_false(privateSummary.allHaveStopped);
- do_check_eq(privateSummary.progressTotalBytes, TEST_DATA_SHORT.length * 2);
- do_check_eq(privateSummary.progressCurrentBytes, TEST_DATA_SHORT.length);
-
- do_check_false(combinedSummary.allHaveStopped);
- do_check_eq(combinedSummary.progressTotalBytes, TEST_DATA_SHORT.length * 4);
- do_check_eq(combinedSummary.progressCurrentBytes, TEST_DATA_SHORT.length * 2);
-
- yield inProgressPublicDownload.cancel();
-
- // Stopping the download should have excluded it from the summary.
- do_check_true(publicSummary.allHaveStopped);
- do_check_eq(publicSummary.progressTotalBytes, 0);
- do_check_eq(publicSummary.progressCurrentBytes, 0);
-
- do_check_false(privateSummary.allHaveStopped);
- do_check_eq(privateSummary.progressTotalBytes, TEST_DATA_SHORT.length * 2);
- do_check_eq(privateSummary.progressCurrentBytes, TEST_DATA_SHORT.length);
-
- do_check_false(combinedSummary.allHaveStopped);
- do_check_eq(combinedSummary.progressTotalBytes, TEST_DATA_SHORT.length * 2);
- do_check_eq(combinedSummary.progressCurrentBytes, TEST_DATA_SHORT.length);
-
- yield inProgressPrivateDownload.cancel();
-
- // All the downloads should be stopped now.
- do_check_true(publicSummary.allHaveStopped);
- do_check_eq(publicSummary.progressTotalBytes, 0);
- do_check_eq(publicSummary.progressCurrentBytes, 0);
-
- do_check_true(privateSummary.allHaveStopped);
- do_check_eq(privateSummary.progressTotalBytes, 0);
- do_check_eq(privateSummary.progressCurrentBytes, 0);
-
- do_check_true(combinedSummary.allHaveStopped);
- do_check_eq(combinedSummary.progressTotalBytes, 0);
- do_check_eq(combinedSummary.progressCurrentBytes, 0);
-});
-
-/**
- * Checks that views receive the summary change notification. This is tested on
- * the combined summary when adding a public download, as we assume that if we
- * pass the test in this case we will also pass it in the others.
- */
-add_task(function* test_DownloadSummary_notifications()
-{
- let list = yield promiseNewList();
- let summary = yield Downloads.getSummary(Downloads.ALL);
-
- let download = yield promiseNewDownload();
- yield list.add(download);
-
- // Check that we receive change notifications.
- let receivedOnSummaryChanged = false;
- yield summary.addView({
- onSummaryChanged: function () {
- receivedOnSummaryChanged = true;
- },
- });
- yield download.start();
- do_check_true(receivedOnSummaryChanged);
-});
diff --git a/toolkit/components/jsdownloads/test/unit/test_DownloadStore.js b/toolkit/components/jsdownloads/test/unit/test_DownloadStore.js
deleted file mode 100644
index 3a23dfbe3..000000000
--- a/toolkit/components/jsdownloads/test/unit/test_DownloadStore.js
+++ /dev/null
@@ -1,315 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 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 DownloadStore object.
- */
-
-"use strict";
-
-// Globals
-
-XPCOMUtils.defineLazyModuleGetter(this, "DownloadStore",
- "resource://gre/modules/DownloadStore.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "OS",
- "resource://gre/modules/osfile.jsm")
-
-/**
- * Returns a new DownloadList object with an associated DownloadStore.
- *
- * @param aStorePath
- * String pointing to the file to be associated with the DownloadStore,
- * or undefined to use a non-existing temporary file. In this case, the
- * temporary file is deleted when the test file execution finishes.
- *
- * @return {Promise}
- * @resolves Array [ Newly created DownloadList , associated DownloadStore ].
- * @rejects JavaScript exception.
- */
-function promiseNewListAndStore(aStorePath)
-{
- return promiseNewList().then(function (aList) {
- let path = aStorePath || getTempFile(TEST_STORE_FILE_NAME).path;
- let store = new DownloadStore(aList, path);
- return [aList, store];
- });
-}
-
-// Tests
-
-/**
- * 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 promiseNewDownload(httpUrl("source.txt")));
- listForSave.add(yield Downloads.createDownload({
- source: { url: httpUrl("empty.txt"),
- referrer: TEST_REFERRER_URL },
- target: getTempFile(TEST_TARGET_FILE_NAME),
- }));
-
- // This PDF download should not be serialized because it never succeeds.
- let pdfDownload = yield Downloads.createDownload({
- source: { url: httpUrl("empty.txt"),
- referrer: TEST_REFERRER_URL },
- target: getTempFile(TEST_TARGET_FILE_NAME),
- saver: "pdf",
- });
- listForSave.add(pdfDownload);
-
- // If we used a callback to adjust the channel, the download should
- // not be serialized because we can't recreate it across sessions.
- let adjustedDownload = yield Downloads.createDownload({
- source: { url: httpUrl("empty.txt"),
- adjustChannel: () => Promise.resolve() },
- target: getTempFile(TEST_TARGET_FILE_NAME),
- });
- listForSave.add(adjustedDownload);
-
- let legacyDownload = yield promiseStartLegacyDownload();
- yield legacyDownload.cancel();
- listForSave.add(legacyDownload);
-
- yield storeForSave.save();
- yield storeForLoad.load();
-
- // Remove the PDF and adjusted downloads because they should not appear here.
- listForSave.remove(adjustedDownload);
- listForSave.remove(pdfDownload);
-
- let itemsForSave = yield listForSave.getAll();
- let itemsForLoad = yield listForLoad.getAll();
-
- do_check_eq(itemsForSave.length, itemsForLoad.length);
-
- // Downloads should be reloaded in the same order.
- for (let i = 0; i < itemsForSave.length; i++) {
- // The reloaded downloads are different objects.
- do_check_neq(itemsForSave[i], itemsForLoad[i]);
-
- // The reloaded downloads have the same properties.
- do_check_eq(itemsForSave[i].source.url,
- itemsForLoad[i].source.url);
- do_check_eq(itemsForSave[i].source.referrer,
- itemsForLoad[i].source.referrer);
- do_check_eq(itemsForSave[i].target.path,
- itemsForLoad[i].target.path);
- do_check_eq(itemsForSave[i].saver.toSerializable(),
- itemsForLoad[i].saver.toSerializable());
- }
-});
-
-/**
- * Checks that saving an empty list deletes any existing file.
- */
-add_task(function* test_save_empty()
-{
- let [, store] = yield promiseNewListAndStore();
-
- let createdFile = yield OS.File.open(store.path, { create: true });
- yield createdFile.close();
-
- yield store.save();
-
- do_check_false(yield OS.File.exists(store.path));
-
- // If the file does not exist, saving should not generate exceptions.
- yield store.save();
-});
-
-/**
- * Checks that loading from a missing file results in an empty list.
- */
-add_task(function* test_load_empty()
-{
- let [list, store] = yield promiseNewListAndStore();
-
- do_check_false(yield OS.File.exists(store.path));
-
- yield store.load();
-
- let items = yield list.getAll();
- do_check_eq(items.length, 0);
-});
-
-/**
- * Loads downloads from a string in a predefined format. The purpose of this
- * test is to verify that the JSON format used in previous versions can be
- * loaded, assuming the file is reloaded on the same platform.
- */
-add_task(function* test_load_string_predefined()
-{
- let [list, store] = yield promiseNewListAndStore();
-
- // The platform-dependent file name should be generated dynamically.
- let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
- let filePathLiteral = JSON.stringify(targetPath);
- let sourceUriLiteral = JSON.stringify(httpUrl("source.txt"));
- let emptyUriLiteral = JSON.stringify(httpUrl("empty.txt"));
- let referrerUriLiteral = JSON.stringify(TEST_REFERRER_URL);
-
- let string = "{\"list\":[{\"source\":" + sourceUriLiteral + "," +
- "\"target\":" + filePathLiteral + "}," +
- "{\"source\":{\"url\":" + emptyUriLiteral + "," +
- "\"referrer\":" + referrerUriLiteral + "}," +
- "\"target\":" + filePathLiteral + "}]}";
-
- yield OS.File.writeAtomic(store.path,
- new TextEncoder().encode(string),
- { tmpPath: store.path + ".tmp" });
-
- yield store.load();
-
- let items = yield list.getAll();
-
- do_check_eq(items.length, 2);
-
- do_check_eq(items[0].source.url, httpUrl("source.txt"));
- do_check_eq(items[0].target.path, targetPath);
-
- do_check_eq(items[1].source.url, httpUrl("empty.txt"));
- do_check_eq(items[1].source.referrer, TEST_REFERRER_URL);
- do_check_eq(items[1].target.path, targetPath);
-});
-
-/**
- * Loads downloads from a well-formed JSON string containing unrecognized data.
- */
-add_task(function* test_load_string_unrecognized()
-{
- let [list, store] = yield promiseNewListAndStore();
-
- // The platform-dependent file name should be generated dynamically.
- let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
- let filePathLiteral = JSON.stringify(targetPath);
- let sourceUriLiteral = JSON.stringify(httpUrl("source.txt"));
-
- let string = "{\"list\":[{\"source\":null," +
- "\"target\":null}," +
- "{\"source\":{\"url\":" + sourceUriLiteral + "}," +
- "\"target\":{\"path\":" + filePathLiteral + "}," +
- "\"saver\":{\"type\":\"copy\"}}]}";
-
- yield OS.File.writeAtomic(store.path,
- new TextEncoder().encode(string),
- { tmpPath: store.path + ".tmp" });
-
- yield store.load();
-
- let items = yield list.getAll();
-
- do_check_eq(items.length, 1);
-
- do_check_eq(items[0].source.url, httpUrl("source.txt"));
- do_check_eq(items[0].target.path, targetPath);
-});
-
-/**
- * Loads downloads from a malformed JSON string.
- */
-add_task(function* test_load_string_malformed()
-{
- let [list, store] = yield promiseNewListAndStore();
-
- let string = "{\"list\":[{\"source\":null,\"target\":null}," +
- "{\"source\":{\"url\":\"about:blank\"}}}";
-
- yield OS.File.writeAtomic(store.path, new TextEncoder().encode(string),
- { tmpPath: store.path + ".tmp" });
-
- try {
- yield store.load();
- do_throw("Exception expected when JSON data is malformed.");
- } catch (ex) {
- if (ex.name != "SyntaxError") {
- throw ex;
- }
- do_print("The expected SyntaxError exception was thrown.");
- }
-
- let items = yield list.getAll();
-
- do_check_eq(items.length, 0);
-});
-
-/**
- * Saves downloads with unknown properties to a file and then reloads
- * them to ensure that these properties are preserved.
- */
-add_task(function* test_save_reload_unknownProperties()
-{
- let [listForSave, storeForSave] = yield promiseNewListAndStore();
- let [listForLoad, storeForLoad] = yield promiseNewListAndStore(
- storeForSave.path);
-
- let download1 = yield promiseNewDownload(httpUrl("source.txt"));
- // startTime should be ignored as it is a known property, and error
- // is ignored by serialization
- download1._unknownProperties = { peanut: "butter",
- orange: "marmalade",
- startTime: 77,
- error: { message: "Passed" } };
- listForSave.add(download1);
-
- let download2 = yield promiseStartLegacyDownload();
- yield download2.cancel();
- download2._unknownProperties = { number: 5, object: { test: "string" } };
- listForSave.add(download2);
-
- let download3 = yield Downloads.createDownload({
- source: { url: httpUrl("empty.txt"),
- referrer: TEST_REFERRER_URL,
- source1: "download3source1",
- source2: "download3source2" },
- target: { path: getTempFile(TEST_TARGET_FILE_NAME).path,
- target1: "download3target1",
- target2: "download3target2" },
- saver : { type: "copy",
- saver1: "download3saver1",
- saver2: "download3saver2" },
- });
- listForSave.add(download3);
-
- yield storeForSave.save();
- yield storeForLoad.load();
-
- let itemsForSave = yield listForSave.getAll();
- let itemsForLoad = yield listForLoad.getAll();
-
- do_check_eq(itemsForSave.length, itemsForLoad.length);
-
- do_check_eq(Object.keys(itemsForLoad[0]._unknownProperties).length, 2);
- do_check_eq(itemsForLoad[0]._unknownProperties.peanut, "butter");
- do_check_eq(itemsForLoad[0]._unknownProperties.orange, "marmalade");
- do_check_false("startTime" in itemsForLoad[0]._unknownProperties);
- do_check_false("error" in itemsForLoad[0]._unknownProperties);
-
- do_check_eq(Object.keys(itemsForLoad[1]._unknownProperties).length, 2);
- do_check_eq(itemsForLoad[1]._unknownProperties.number, 5);
- do_check_eq(itemsForLoad[1]._unknownProperties.object.test, "string");
-
- do_check_eq(Object.keys(itemsForLoad[2].source._unknownProperties).length, 2);
- do_check_eq(itemsForLoad[2].source._unknownProperties.source1,
- "download3source1");
- do_check_eq(itemsForLoad[2].source._unknownProperties.source2,
- "download3source2");
-
- do_check_eq(Object.keys(itemsForLoad[2].target._unknownProperties).length, 2);
- do_check_eq(itemsForLoad[2].target._unknownProperties.target1,
- "download3target1");
- do_check_eq(itemsForLoad[2].target._unknownProperties.target2,
- "download3target2");
-
- do_check_eq(Object.keys(itemsForLoad[2].saver._unknownProperties).length, 2);
- do_check_eq(itemsForLoad[2].saver._unknownProperties.saver1,
- "download3saver1");
- do_check_eq(itemsForLoad[2].saver._unknownProperties.saver2,
- "download3saver2");
-});
diff --git a/toolkit/components/jsdownloads/test/unit/test_Downloads.js b/toolkit/components/jsdownloads/test/unit/test_Downloads.js
deleted file mode 100644
index 2027beee1..000000000
--- a/toolkit/components/jsdownloads/test/unit/test_Downloads.js
+++ /dev/null
@@ -1,194 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 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 functions located directly in the "Downloads" object.
- */
-
-"use strict";
-
-// Tests
-
-/**
- * Tests that the createDownload function exists and can be called. More
- * detailed tests are implemented separately for the DownloadCore module.
- */
-add_task(function* test_createDownload()
-{
- // Creates a simple Download object without starting the download.
- yield Downloads.createDownload({
- source: { url: "about:blank" },
- target: { path: getTempFile(TEST_TARGET_FILE_NAME).path },
- saver: { type: "copy" },
- });
-});
-
-/**
- * Tests createDownload for private download.
- */
-add_task(function* test_createDownload_private()
-{
- let download = yield Downloads.createDownload({
- source: { url: "about:blank", isPrivate: true },
- target: { path: getTempFile(TEST_TARGET_FILE_NAME).path },
- saver: { type: "copy" }
- });
- do_check_true(download.source.isPrivate);
-});
-
-/**
- * Tests createDownload for normal (public) download.
- */
-add_task(function* test_createDownload_public()
-{
- let tempPath = getTempFile(TEST_TARGET_FILE_NAME).path;
- let download = yield Downloads.createDownload({
- source: { url: "about:blank", isPrivate: false },
- target: { path: tempPath },
- saver: { type: "copy" }
- });
- do_check_false(download.source.isPrivate);
-
- download = yield Downloads.createDownload({
- source: { url: "about:blank" },
- target: { path: tempPath },
- saver: { type: "copy" }
- });
- do_check_false(download.source.isPrivate);
-});
-
-/**
- * Tests createDownload for a pdf saver throws if only given a url.
- */
-add_task(function* test_createDownload_pdf()
-{
- let download = yield Downloads.createDownload({
- source: { url: "about:blank" },
- target: { path: getTempFile(TEST_TARGET_FILE_NAME).path },
- saver: { type: "pdf" },
- });
-
- try {
- yield download.start();
- do_throw("The download should have failed.");
- } catch (ex) {
- if (!(ex instanceof Downloads.Error) || !ex.becauseSourceFailed) {
- throw ex;
- }
- }
-
- do_check_false(download.succeeded);
- 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);
- do_check_false(yield OS.File.exists(download.target.path));
-});
-
-/**
- * Tests "fetch" with nsIURI and nsIFile as arguments.
- */
-add_task(function* test_fetch_uri_file_arguments()
-{
- let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
- yield Downloads.fetch(NetUtil.newURI(httpUrl("source.txt")), targetFile);
- yield promiseVerifyContents(targetFile.path, TEST_DATA_SHORT);
-});
-
-/**
- * Tests "fetch" with DownloadSource and DownloadTarget as arguments.
- */
-add_task(function* test_fetch_object_arguments()
-{
- let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
- yield Downloads.fetch({ url: httpUrl("source.txt") }, { path: targetPath });
- yield promiseVerifyContents(targetPath, TEST_DATA_SHORT);
-});
-
-/**
- * Tests "fetch" with string arguments.
- */
-add_task(function* test_fetch_string_arguments()
-{
- let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
- yield Downloads.fetch(httpUrl("source.txt"), targetPath);
- yield promiseVerifyContents(targetPath, TEST_DATA_SHORT);
-
- targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
- yield Downloads.fetch(new String(httpUrl("source.txt")),
- new String(targetPath));
- yield promiseVerifyContents(targetPath, TEST_DATA_SHORT);
-});
-
-/**
- * Tests that the getList function returns the same list when called multiple
- * times with the same argument, but returns different lists when called with
- * different arguments. More detailed tests are implemented separately for the
- * DownloadList module.
- */
-add_task(function* test_getList()
-{
- let publicListOne = yield Downloads.getList(Downloads.PUBLIC);
- let privateListOne = yield Downloads.getList(Downloads.PRIVATE);
-
- let publicListTwo = yield Downloads.getList(Downloads.PUBLIC);
- let privateListTwo = yield Downloads.getList(Downloads.PRIVATE);
-
- do_check_eq(publicListOne, publicListTwo);
- do_check_eq(privateListOne, privateListTwo);
-
- do_check_neq(publicListOne, privateListOne);
-});
-
-/**
- * Tests that the getSummary function returns the same summary when called
- * multiple times with the same argument, but returns different summaries when
- * called with different arguments. More detailed tests are implemented
- * separately for the DownloadSummary object in the DownloadList module.
- */
-add_task(function* test_getSummary()
-{
- let publicSummaryOne = yield Downloads.getSummary(Downloads.PUBLIC);
- let privateSummaryOne = yield Downloads.getSummary(Downloads.PRIVATE);
-
- let publicSummaryTwo = yield Downloads.getSummary(Downloads.PUBLIC);
- let privateSummaryTwo = yield Downloads.getSummary(Downloads.PRIVATE);
-
- do_check_eq(publicSummaryOne, publicSummaryTwo);
- do_check_eq(privateSummaryOne, privateSummaryTwo);
-
- do_check_neq(publicSummaryOne, privateSummaryOne);
-});
-
-/**
- * Tests that the getSystemDownloadsDirectory returns a non-empty download
- * directory string.
- */
-add_task(function* test_getSystemDownloadsDirectory()
-{
- let downloadDir = yield Downloads.getSystemDownloadsDirectory();
- do_check_neq(downloadDir, "");
-});
-
-/**
- * Tests that the getPreferredDownloadsDirectory returns a non-empty download
- * directory string.
- */
-add_task(function* test_getPreferredDownloadsDirectory()
-{
- let downloadDir = yield Downloads.getPreferredDownloadsDirectory();
- do_check_neq(downloadDir, "");
-});
-
-/**
- * Tests that the getTemporaryDownloadsDirectory returns a non-empty download
- * directory string.
- */
-add_task(function* test_getTemporaryDownloadsDirectory()
-{
- let downloadDir = yield Downloads.getTemporaryDownloadsDirectory();
- do_check_neq(downloadDir, "");
-});
diff --git a/toolkit/components/jsdownloads/test/unit/test_PrivateTemp.js b/toolkit/components/jsdownloads/test/unit/test_PrivateTemp.js
deleted file mode 100644
index 1308e9782..000000000
--- a/toolkit/components/jsdownloads/test/unit/test_PrivateTemp.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 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/ */
-
-"use strict";
-
-/*
- * The temporary directory downloads saves to, should be only readable
- * for the current user.
- */
-add_task(function* test_private_temp() {
-
- let download = yield promiseStartExternalHelperAppServiceDownload(
- httpUrl("empty.txt"));
-
- yield promiseDownloadStopped(download);
-
- var targetFile = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
- targetFile.initWithPath(download.target.path);
-
- // 488 is the decimal value of 0o700.
- equal(targetFile.parent.permissions, 448);
-});
diff --git a/toolkit/components/jsdownloads/test/unit/xpcshell.ini b/toolkit/components/jsdownloads/test/unit/xpcshell.ini
deleted file mode 100644
index 8de554540..000000000
--- a/toolkit/components/jsdownloads/test/unit/xpcshell.ini
+++ /dev/null
@@ -1,19 +0,0 @@
-[DEFAULT]
-head = head.js
-tail =
-skip-if = toolkit == 'android'
-
-# Note: The "tail.js" file is not defined in the "tail" key because it calls
-# the "add_test_task" function, that does not work properly in tail files.
-support-files =
- common_test_Download.js
-
-[test_DownloadCore.js]
-[test_DownloadImport.js]
-[test_DownloadIntegration.js]
-[test_DownloadLegacy.js]
-[test_DownloadList.js]
-[test_Downloads.js]
-[test_DownloadStore.js]
-[test_PrivateTemp.js]
-skip-if = os != 'linux'