diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /toolkit/components/jsdownloads/test/unit/test_DownloadList.js | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'toolkit/components/jsdownloads/test/unit/test_DownloadList.js')
-rw-r--r-- | toolkit/components/jsdownloads/test/unit/test_DownloadList.js | 564 |
1 files changed, 564 insertions, 0 deletions
diff --git a/toolkit/components/jsdownloads/test/unit/test_DownloadList.js b/toolkit/components/jsdownloads/test/unit/test_DownloadList.js new file mode 100644 index 000000000..71e880741 --- /dev/null +++ b/toolkit/components/jsdownloads/test/unit/test_DownloadList.js @@ -0,0 +1,564 @@ +/* -*- 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); +}); |