diff options
Diffstat (limited to 'toolkit/components/jsdownloads/test/unit/test_DownloadStore.js')
-rw-r--r-- | toolkit/components/jsdownloads/test/unit/test_DownloadStore.js | 315 |
1 files changed, 315 insertions, 0 deletions
diff --git a/toolkit/components/jsdownloads/test/unit/test_DownloadStore.js b/toolkit/components/jsdownloads/test/unit/test_DownloadStore.js new file mode 100644 index 000000000..3a23dfbe3 --- /dev/null +++ b/toolkit/components/jsdownloads/test/unit/test_DownloadStore.js @@ -0,0 +1,315 @@ +/* -*- 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"); +}); |