1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/components/jsdownloads/test/unit/test_DownloadStore.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,298 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 et sw=2 tw=80: */ 1.6 +/* Any copyright is dedicated to the Public Domain. 1.7 + * http://creativecommons.org/publicdomain/zero/1.0/ */ 1.8 + 1.9 +/** 1.10 + * Tests the DownloadStore object. 1.11 + */ 1.12 + 1.13 +"use strict"; 1.14 + 1.15 +//////////////////////////////////////////////////////////////////////////////// 1.16 +//// Globals 1.17 + 1.18 +XPCOMUtils.defineLazyModuleGetter(this, "DownloadStore", 1.19 + "resource://gre/modules/DownloadStore.jsm"); 1.20 +XPCOMUtils.defineLazyModuleGetter(this, "OS", 1.21 + "resource://gre/modules/osfile.jsm") 1.22 + 1.23 +/** 1.24 + * Returns a new DownloadList object with an associated DownloadStore. 1.25 + * 1.26 + * @param aStorePath 1.27 + * String pointing to the file to be associated with the DownloadStore, 1.28 + * or undefined to use a non-existing temporary file. In this case, the 1.29 + * temporary file is deleted when the test file execution finishes. 1.30 + * 1.31 + * @return {Promise} 1.32 + * @resolves Array [ Newly created DownloadList , associated DownloadStore ]. 1.33 + * @rejects JavaScript exception. 1.34 + */ 1.35 +function promiseNewListAndStore(aStorePath) 1.36 +{ 1.37 + return promiseNewList().then(function (aList) { 1.38 + let path = aStorePath || getTempFile(TEST_STORE_FILE_NAME).path; 1.39 + let store = new DownloadStore(aList, path); 1.40 + return [aList, store]; 1.41 + }); 1.42 +} 1.43 + 1.44 +//////////////////////////////////////////////////////////////////////////////// 1.45 +//// Tests 1.46 + 1.47 +/** 1.48 + * Saves downloads to a file, then reloads them. 1.49 + */ 1.50 +add_task(function test_save_reload() 1.51 +{ 1.52 + let [listForSave, storeForSave] = yield promiseNewListAndStore(); 1.53 + let [listForLoad, storeForLoad] = yield promiseNewListAndStore( 1.54 + storeForSave.path); 1.55 + 1.56 + listForSave.add(yield promiseNewDownload(httpUrl("source.txt"))); 1.57 + listForSave.add(yield Downloads.createDownload({ 1.58 + source: { url: httpUrl("empty.txt"), 1.59 + referrer: TEST_REFERRER_URL }, 1.60 + target: getTempFile(TEST_TARGET_FILE_NAME), 1.61 + })); 1.62 + 1.63 + let legacyDownload = yield promiseStartLegacyDownload(); 1.64 + yield legacyDownload.cancel(); 1.65 + listForSave.add(legacyDownload); 1.66 + 1.67 + yield storeForSave.save(); 1.68 + yield storeForLoad.load(); 1.69 + 1.70 + let itemsForSave = yield listForSave.getAll(); 1.71 + let itemsForLoad = yield listForLoad.getAll(); 1.72 + 1.73 + do_check_eq(itemsForSave.length, itemsForLoad.length); 1.74 + 1.75 + // Downloads should be reloaded in the same order. 1.76 + for (let i = 0; i < itemsForSave.length; i++) { 1.77 + // The reloaded downloads are different objects. 1.78 + do_check_neq(itemsForSave[i], itemsForLoad[i]); 1.79 + 1.80 + // The reloaded downloads have the same properties. 1.81 + do_check_eq(itemsForSave[i].source.url, 1.82 + itemsForLoad[i].source.url); 1.83 + do_check_eq(itemsForSave[i].source.referrer, 1.84 + itemsForLoad[i].source.referrer); 1.85 + do_check_eq(itemsForSave[i].target.path, 1.86 + itemsForLoad[i].target.path); 1.87 + do_check_eq(itemsForSave[i].saver.toSerializable(), 1.88 + itemsForLoad[i].saver.toSerializable()); 1.89 + } 1.90 +}); 1.91 + 1.92 +/** 1.93 + * Checks that saving an empty list deletes any existing file. 1.94 + */ 1.95 +add_task(function test_save_empty() 1.96 +{ 1.97 + let [list, store] = yield promiseNewListAndStore(); 1.98 + 1.99 + let createdFile = yield OS.File.open(store.path, { create: true }); 1.100 + yield createdFile.close(); 1.101 + 1.102 + yield store.save(); 1.103 + 1.104 + do_check_false(yield OS.File.exists(store.path)); 1.105 + 1.106 + // If the file does not exist, saving should not generate exceptions. 1.107 + yield store.save(); 1.108 +}); 1.109 + 1.110 +/** 1.111 + * Checks that loading from a missing file results in an empty list. 1.112 + */ 1.113 +add_task(function test_load_empty() 1.114 +{ 1.115 + let [list, store] = yield promiseNewListAndStore(); 1.116 + 1.117 + do_check_false(yield OS.File.exists(store.path)); 1.118 + 1.119 + yield store.load(); 1.120 + 1.121 + let items = yield list.getAll(); 1.122 + do_check_eq(items.length, 0); 1.123 +}); 1.124 + 1.125 +/** 1.126 + * Loads downloads from a string in a predefined format. The purpose of this 1.127 + * test is to verify that the JSON format used in previous versions can be 1.128 + * loaded, assuming the file is reloaded on the same platform. 1.129 + */ 1.130 +add_task(function test_load_string_predefined() 1.131 +{ 1.132 + let [list, store] = yield promiseNewListAndStore(); 1.133 + 1.134 + // The platform-dependent file name should be generated dynamically. 1.135 + let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path; 1.136 + let filePathLiteral = JSON.stringify(targetPath); 1.137 + let sourceUriLiteral = JSON.stringify(httpUrl("source.txt")); 1.138 + let emptyUriLiteral = JSON.stringify(httpUrl("empty.txt")); 1.139 + let referrerUriLiteral = JSON.stringify(TEST_REFERRER_URL); 1.140 + 1.141 + let string = "{\"list\":[{\"source\":" + sourceUriLiteral + "," + 1.142 + "\"target\":" + filePathLiteral + "}," + 1.143 + "{\"source\":{\"url\":" + emptyUriLiteral + "," + 1.144 + "\"referrer\":" + referrerUriLiteral + "}," + 1.145 + "\"target\":" + filePathLiteral + "}]}"; 1.146 + 1.147 + yield OS.File.writeAtomic(store.path, 1.148 + new TextEncoder().encode(string), 1.149 + { tmpPath: store.path + ".tmp" }); 1.150 + 1.151 + yield store.load(); 1.152 + 1.153 + let items = yield list.getAll(); 1.154 + 1.155 + do_check_eq(items.length, 2); 1.156 + 1.157 + do_check_eq(items[0].source.url, httpUrl("source.txt")); 1.158 + do_check_eq(items[0].target.path, targetPath); 1.159 + 1.160 + do_check_eq(items[1].source.url, httpUrl("empty.txt")); 1.161 + do_check_eq(items[1].source.referrer, TEST_REFERRER_URL); 1.162 + do_check_eq(items[1].target.path, targetPath); 1.163 +}); 1.164 + 1.165 +/** 1.166 + * Loads downloads from a well-formed JSON string containing unrecognized data. 1.167 + */ 1.168 +add_task(function test_load_string_unrecognized() 1.169 +{ 1.170 + let [list, store] = yield promiseNewListAndStore(); 1.171 + 1.172 + // The platform-dependent file name should be generated dynamically. 1.173 + let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path; 1.174 + let filePathLiteral = JSON.stringify(targetPath); 1.175 + let sourceUriLiteral = JSON.stringify(httpUrl("source.txt")); 1.176 + 1.177 + let string = "{\"list\":[{\"source\":null," + 1.178 + "\"target\":null}," + 1.179 + "{\"source\":{\"url\":" + sourceUriLiteral + "}," + 1.180 + "\"target\":{\"path\":" + filePathLiteral + "}," + 1.181 + "\"saver\":{\"type\":\"copy\"}}]}"; 1.182 + 1.183 + yield OS.File.writeAtomic(store.path, 1.184 + new TextEncoder().encode(string), 1.185 + { tmpPath: store.path + ".tmp" }); 1.186 + 1.187 + yield store.load(); 1.188 + 1.189 + let items = yield list.getAll(); 1.190 + 1.191 + do_check_eq(items.length, 1); 1.192 + 1.193 + do_check_eq(items[0].source.url, httpUrl("source.txt")); 1.194 + do_check_eq(items[0].target.path, targetPath); 1.195 +}); 1.196 + 1.197 +/** 1.198 + * Loads downloads from a malformed JSON string. 1.199 + */ 1.200 +add_task(function test_load_string_malformed() 1.201 +{ 1.202 + let [list, store] = yield promiseNewListAndStore(); 1.203 + 1.204 + let string = "{\"list\":[{\"source\":null,\"target\":null}," + 1.205 + "{\"source\":{\"url\":\"about:blank\"}}}"; 1.206 + 1.207 + yield OS.File.writeAtomic(store.path, new TextEncoder().encode(string), 1.208 + { tmpPath: store.path + ".tmp" }); 1.209 + 1.210 + try { 1.211 + yield store.load(); 1.212 + do_throw("Exception expected when JSON data is malformed."); 1.213 + } catch (ex if ex.name == "SyntaxError") { 1.214 + do_print("The expected SyntaxError exception was thrown."); 1.215 + } 1.216 + 1.217 + let items = yield list.getAll(); 1.218 + 1.219 + do_check_eq(items.length, 0); 1.220 +}); 1.221 + 1.222 +/** 1.223 + * Saves downloads with unknown properties to a file and then reloads 1.224 + * them to ensure that these properties are preserved. 1.225 + */ 1.226 +add_task(function test_save_reload_unknownProperties() 1.227 +{ 1.228 + let [listForSave, storeForSave] = yield promiseNewListAndStore(); 1.229 + let [listForLoad, storeForLoad] = yield promiseNewListAndStore( 1.230 + storeForSave.path); 1.231 + 1.232 + let download1 = yield promiseNewDownload(httpUrl("source.txt")); 1.233 + // startTime should be ignored as it is a known property, and error 1.234 + // is ignored by serialization 1.235 + download1._unknownProperties = { peanut: "butter", 1.236 + orange: "marmalade", 1.237 + startTime: 77, 1.238 + error: { message: "Passed" } }; 1.239 + listForSave.add(download1); 1.240 + 1.241 + let download2 = yield promiseStartLegacyDownload(); 1.242 + yield download2.cancel(); 1.243 + download2._unknownProperties = { number: 5, object: { test: "string" } }; 1.244 + listForSave.add(download2); 1.245 + 1.246 + let download3 = yield Downloads.createDownload({ 1.247 + source: { url: httpUrl("empty.txt"), 1.248 + referrer: TEST_REFERRER_URL, 1.249 + source1: "download3source1", 1.250 + source2: "download3source2" }, 1.251 + target: { path: getTempFile(TEST_TARGET_FILE_NAME).path, 1.252 + target1: "download3target1", 1.253 + target2: "download3target2" }, 1.254 + saver : { type: "copy", 1.255 + saver1: "download3saver1", 1.256 + saver2: "download3saver2" }, 1.257 + }); 1.258 + listForSave.add(download3); 1.259 + 1.260 + yield storeForSave.save(); 1.261 + yield storeForLoad.load(); 1.262 + 1.263 + let itemsForSave = yield listForSave.getAll(); 1.264 + let itemsForLoad = yield listForLoad.getAll(); 1.265 + 1.266 + do_check_eq(itemsForSave.length, itemsForLoad.length); 1.267 + 1.268 + do_check_eq(Object.keys(itemsForLoad[0]._unknownProperties).length, 2); 1.269 + do_check_eq(itemsForLoad[0]._unknownProperties.peanut, "butter"); 1.270 + do_check_eq(itemsForLoad[0]._unknownProperties.orange, "marmalade"); 1.271 + do_check_false("startTime" in itemsForLoad[0]._unknownProperties); 1.272 + do_check_false("error" in itemsForLoad[0]._unknownProperties); 1.273 + 1.274 + do_check_eq(Object.keys(itemsForLoad[1]._unknownProperties).length, 2); 1.275 + do_check_eq(itemsForLoad[1]._unknownProperties.number, 5); 1.276 + do_check_eq(itemsForLoad[1]._unknownProperties.object.test, "string"); 1.277 + 1.278 + do_check_eq(Object.keys(itemsForLoad[2].source._unknownProperties).length, 2); 1.279 + do_check_eq(itemsForLoad[2].source._unknownProperties.source1, 1.280 + "download3source1"); 1.281 + do_check_eq(itemsForLoad[2].source._unknownProperties.source2, 1.282 + "download3source2"); 1.283 + 1.284 + do_check_eq(Object.keys(itemsForLoad[2].target._unknownProperties).length, 2); 1.285 + do_check_eq(itemsForLoad[2].target._unknownProperties.target1, 1.286 + "download3target1"); 1.287 + do_check_eq(itemsForLoad[2].target._unknownProperties.target2, 1.288 + "download3target2"); 1.289 + 1.290 + do_check_eq(Object.keys(itemsForLoad[2].saver._unknownProperties).length, 2); 1.291 + do_check_eq(itemsForLoad[2].saver._unknownProperties.saver1, 1.292 + "download3saver1"); 1.293 + do_check_eq(itemsForLoad[2].saver._unknownProperties.saver2, 1.294 + "download3saver2"); 1.295 +}); 1.296 + 1.297 +//////////////////////////////////////////////////////////////////////////////// 1.298 +//// Termination 1.299 + 1.300 +let tailFile = do_get_file("tail.js"); 1.301 +Services.scriptloader.loadSubScript(NetUtil.newURI(tailFile).spec);