gecko-dev/toolkit/components/jsdownloads/test/unit/test_DownloadIntegration.js

435 lines
14 KiB
JavaScript

/* 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();
let promiseAttempt2 = 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();
});