toolkit/components/jsdownloads/test/unit/test_DownloadStore.js

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim: set ts=2 et sw=2 tw=80: */
michael@0 3 /* Any copyright is dedicated to the Public Domain.
michael@0 4 * http://creativecommons.org/publicdomain/zero/1.0/ */
michael@0 5
michael@0 6 /**
michael@0 7 * Tests the DownloadStore object.
michael@0 8 */
michael@0 9
michael@0 10 "use strict";
michael@0 11
michael@0 12 ////////////////////////////////////////////////////////////////////////////////
michael@0 13 //// Globals
michael@0 14
michael@0 15 XPCOMUtils.defineLazyModuleGetter(this, "DownloadStore",
michael@0 16 "resource://gre/modules/DownloadStore.jsm");
michael@0 17 XPCOMUtils.defineLazyModuleGetter(this, "OS",
michael@0 18 "resource://gre/modules/osfile.jsm")
michael@0 19
michael@0 20 /**
michael@0 21 * Returns a new DownloadList object with an associated DownloadStore.
michael@0 22 *
michael@0 23 * @param aStorePath
michael@0 24 * String pointing to the file to be associated with the DownloadStore,
michael@0 25 * or undefined to use a non-existing temporary file. In this case, the
michael@0 26 * temporary file is deleted when the test file execution finishes.
michael@0 27 *
michael@0 28 * @return {Promise}
michael@0 29 * @resolves Array [ Newly created DownloadList , associated DownloadStore ].
michael@0 30 * @rejects JavaScript exception.
michael@0 31 */
michael@0 32 function promiseNewListAndStore(aStorePath)
michael@0 33 {
michael@0 34 return promiseNewList().then(function (aList) {
michael@0 35 let path = aStorePath || getTempFile(TEST_STORE_FILE_NAME).path;
michael@0 36 let store = new DownloadStore(aList, path);
michael@0 37 return [aList, store];
michael@0 38 });
michael@0 39 }
michael@0 40
michael@0 41 ////////////////////////////////////////////////////////////////////////////////
michael@0 42 //// Tests
michael@0 43
michael@0 44 /**
michael@0 45 * Saves downloads to a file, then reloads them.
michael@0 46 */
michael@0 47 add_task(function test_save_reload()
michael@0 48 {
michael@0 49 let [listForSave, storeForSave] = yield promiseNewListAndStore();
michael@0 50 let [listForLoad, storeForLoad] = yield promiseNewListAndStore(
michael@0 51 storeForSave.path);
michael@0 52
michael@0 53 listForSave.add(yield promiseNewDownload(httpUrl("source.txt")));
michael@0 54 listForSave.add(yield Downloads.createDownload({
michael@0 55 source: { url: httpUrl("empty.txt"),
michael@0 56 referrer: TEST_REFERRER_URL },
michael@0 57 target: getTempFile(TEST_TARGET_FILE_NAME),
michael@0 58 }));
michael@0 59
michael@0 60 let legacyDownload = yield promiseStartLegacyDownload();
michael@0 61 yield legacyDownload.cancel();
michael@0 62 listForSave.add(legacyDownload);
michael@0 63
michael@0 64 yield storeForSave.save();
michael@0 65 yield storeForLoad.load();
michael@0 66
michael@0 67 let itemsForSave = yield listForSave.getAll();
michael@0 68 let itemsForLoad = yield listForLoad.getAll();
michael@0 69
michael@0 70 do_check_eq(itemsForSave.length, itemsForLoad.length);
michael@0 71
michael@0 72 // Downloads should be reloaded in the same order.
michael@0 73 for (let i = 0; i < itemsForSave.length; i++) {
michael@0 74 // The reloaded downloads are different objects.
michael@0 75 do_check_neq(itemsForSave[i], itemsForLoad[i]);
michael@0 76
michael@0 77 // The reloaded downloads have the same properties.
michael@0 78 do_check_eq(itemsForSave[i].source.url,
michael@0 79 itemsForLoad[i].source.url);
michael@0 80 do_check_eq(itemsForSave[i].source.referrer,
michael@0 81 itemsForLoad[i].source.referrer);
michael@0 82 do_check_eq(itemsForSave[i].target.path,
michael@0 83 itemsForLoad[i].target.path);
michael@0 84 do_check_eq(itemsForSave[i].saver.toSerializable(),
michael@0 85 itemsForLoad[i].saver.toSerializable());
michael@0 86 }
michael@0 87 });
michael@0 88
michael@0 89 /**
michael@0 90 * Checks that saving an empty list deletes any existing file.
michael@0 91 */
michael@0 92 add_task(function test_save_empty()
michael@0 93 {
michael@0 94 let [list, store] = yield promiseNewListAndStore();
michael@0 95
michael@0 96 let createdFile = yield OS.File.open(store.path, { create: true });
michael@0 97 yield createdFile.close();
michael@0 98
michael@0 99 yield store.save();
michael@0 100
michael@0 101 do_check_false(yield OS.File.exists(store.path));
michael@0 102
michael@0 103 // If the file does not exist, saving should not generate exceptions.
michael@0 104 yield store.save();
michael@0 105 });
michael@0 106
michael@0 107 /**
michael@0 108 * Checks that loading from a missing file results in an empty list.
michael@0 109 */
michael@0 110 add_task(function test_load_empty()
michael@0 111 {
michael@0 112 let [list, store] = yield promiseNewListAndStore();
michael@0 113
michael@0 114 do_check_false(yield OS.File.exists(store.path));
michael@0 115
michael@0 116 yield store.load();
michael@0 117
michael@0 118 let items = yield list.getAll();
michael@0 119 do_check_eq(items.length, 0);
michael@0 120 });
michael@0 121
michael@0 122 /**
michael@0 123 * Loads downloads from a string in a predefined format. The purpose of this
michael@0 124 * test is to verify that the JSON format used in previous versions can be
michael@0 125 * loaded, assuming the file is reloaded on the same platform.
michael@0 126 */
michael@0 127 add_task(function test_load_string_predefined()
michael@0 128 {
michael@0 129 let [list, store] = yield promiseNewListAndStore();
michael@0 130
michael@0 131 // The platform-dependent file name should be generated dynamically.
michael@0 132 let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
michael@0 133 let filePathLiteral = JSON.stringify(targetPath);
michael@0 134 let sourceUriLiteral = JSON.stringify(httpUrl("source.txt"));
michael@0 135 let emptyUriLiteral = JSON.stringify(httpUrl("empty.txt"));
michael@0 136 let referrerUriLiteral = JSON.stringify(TEST_REFERRER_URL);
michael@0 137
michael@0 138 let string = "{\"list\":[{\"source\":" + sourceUriLiteral + "," +
michael@0 139 "\"target\":" + filePathLiteral + "}," +
michael@0 140 "{\"source\":{\"url\":" + emptyUriLiteral + "," +
michael@0 141 "\"referrer\":" + referrerUriLiteral + "}," +
michael@0 142 "\"target\":" + filePathLiteral + "}]}";
michael@0 143
michael@0 144 yield OS.File.writeAtomic(store.path,
michael@0 145 new TextEncoder().encode(string),
michael@0 146 { tmpPath: store.path + ".tmp" });
michael@0 147
michael@0 148 yield store.load();
michael@0 149
michael@0 150 let items = yield list.getAll();
michael@0 151
michael@0 152 do_check_eq(items.length, 2);
michael@0 153
michael@0 154 do_check_eq(items[0].source.url, httpUrl("source.txt"));
michael@0 155 do_check_eq(items[0].target.path, targetPath);
michael@0 156
michael@0 157 do_check_eq(items[1].source.url, httpUrl("empty.txt"));
michael@0 158 do_check_eq(items[1].source.referrer, TEST_REFERRER_URL);
michael@0 159 do_check_eq(items[1].target.path, targetPath);
michael@0 160 });
michael@0 161
michael@0 162 /**
michael@0 163 * Loads downloads from a well-formed JSON string containing unrecognized data.
michael@0 164 */
michael@0 165 add_task(function test_load_string_unrecognized()
michael@0 166 {
michael@0 167 let [list, store] = yield promiseNewListAndStore();
michael@0 168
michael@0 169 // The platform-dependent file name should be generated dynamically.
michael@0 170 let targetPath = getTempFile(TEST_TARGET_FILE_NAME).path;
michael@0 171 let filePathLiteral = JSON.stringify(targetPath);
michael@0 172 let sourceUriLiteral = JSON.stringify(httpUrl("source.txt"));
michael@0 173
michael@0 174 let string = "{\"list\":[{\"source\":null," +
michael@0 175 "\"target\":null}," +
michael@0 176 "{\"source\":{\"url\":" + sourceUriLiteral + "}," +
michael@0 177 "\"target\":{\"path\":" + filePathLiteral + "}," +
michael@0 178 "\"saver\":{\"type\":\"copy\"}}]}";
michael@0 179
michael@0 180 yield OS.File.writeAtomic(store.path,
michael@0 181 new TextEncoder().encode(string),
michael@0 182 { tmpPath: store.path + ".tmp" });
michael@0 183
michael@0 184 yield store.load();
michael@0 185
michael@0 186 let items = yield list.getAll();
michael@0 187
michael@0 188 do_check_eq(items.length, 1);
michael@0 189
michael@0 190 do_check_eq(items[0].source.url, httpUrl("source.txt"));
michael@0 191 do_check_eq(items[0].target.path, targetPath);
michael@0 192 });
michael@0 193
michael@0 194 /**
michael@0 195 * Loads downloads from a malformed JSON string.
michael@0 196 */
michael@0 197 add_task(function test_load_string_malformed()
michael@0 198 {
michael@0 199 let [list, store] = yield promiseNewListAndStore();
michael@0 200
michael@0 201 let string = "{\"list\":[{\"source\":null,\"target\":null}," +
michael@0 202 "{\"source\":{\"url\":\"about:blank\"}}}";
michael@0 203
michael@0 204 yield OS.File.writeAtomic(store.path, new TextEncoder().encode(string),
michael@0 205 { tmpPath: store.path + ".tmp" });
michael@0 206
michael@0 207 try {
michael@0 208 yield store.load();
michael@0 209 do_throw("Exception expected when JSON data is malformed.");
michael@0 210 } catch (ex if ex.name == "SyntaxError") {
michael@0 211 do_print("The expected SyntaxError exception was thrown.");
michael@0 212 }
michael@0 213
michael@0 214 let items = yield list.getAll();
michael@0 215
michael@0 216 do_check_eq(items.length, 0);
michael@0 217 });
michael@0 218
michael@0 219 /**
michael@0 220 * Saves downloads with unknown properties to a file and then reloads
michael@0 221 * them to ensure that these properties are preserved.
michael@0 222 */
michael@0 223 add_task(function test_save_reload_unknownProperties()
michael@0 224 {
michael@0 225 let [listForSave, storeForSave] = yield promiseNewListAndStore();
michael@0 226 let [listForLoad, storeForLoad] = yield promiseNewListAndStore(
michael@0 227 storeForSave.path);
michael@0 228
michael@0 229 let download1 = yield promiseNewDownload(httpUrl("source.txt"));
michael@0 230 // startTime should be ignored as it is a known property, and error
michael@0 231 // is ignored by serialization
michael@0 232 download1._unknownProperties = { peanut: "butter",
michael@0 233 orange: "marmalade",
michael@0 234 startTime: 77,
michael@0 235 error: { message: "Passed" } };
michael@0 236 listForSave.add(download1);
michael@0 237
michael@0 238 let download2 = yield promiseStartLegacyDownload();
michael@0 239 yield download2.cancel();
michael@0 240 download2._unknownProperties = { number: 5, object: { test: "string" } };
michael@0 241 listForSave.add(download2);
michael@0 242
michael@0 243 let download3 = yield Downloads.createDownload({
michael@0 244 source: { url: httpUrl("empty.txt"),
michael@0 245 referrer: TEST_REFERRER_URL,
michael@0 246 source1: "download3source1",
michael@0 247 source2: "download3source2" },
michael@0 248 target: { path: getTempFile(TEST_TARGET_FILE_NAME).path,
michael@0 249 target1: "download3target1",
michael@0 250 target2: "download3target2" },
michael@0 251 saver : { type: "copy",
michael@0 252 saver1: "download3saver1",
michael@0 253 saver2: "download3saver2" },
michael@0 254 });
michael@0 255 listForSave.add(download3);
michael@0 256
michael@0 257 yield storeForSave.save();
michael@0 258 yield storeForLoad.load();
michael@0 259
michael@0 260 let itemsForSave = yield listForSave.getAll();
michael@0 261 let itemsForLoad = yield listForLoad.getAll();
michael@0 262
michael@0 263 do_check_eq(itemsForSave.length, itemsForLoad.length);
michael@0 264
michael@0 265 do_check_eq(Object.keys(itemsForLoad[0]._unknownProperties).length, 2);
michael@0 266 do_check_eq(itemsForLoad[0]._unknownProperties.peanut, "butter");
michael@0 267 do_check_eq(itemsForLoad[0]._unknownProperties.orange, "marmalade");
michael@0 268 do_check_false("startTime" in itemsForLoad[0]._unknownProperties);
michael@0 269 do_check_false("error" in itemsForLoad[0]._unknownProperties);
michael@0 270
michael@0 271 do_check_eq(Object.keys(itemsForLoad[1]._unknownProperties).length, 2);
michael@0 272 do_check_eq(itemsForLoad[1]._unknownProperties.number, 5);
michael@0 273 do_check_eq(itemsForLoad[1]._unknownProperties.object.test, "string");
michael@0 274
michael@0 275 do_check_eq(Object.keys(itemsForLoad[2].source._unknownProperties).length, 2);
michael@0 276 do_check_eq(itemsForLoad[2].source._unknownProperties.source1,
michael@0 277 "download3source1");
michael@0 278 do_check_eq(itemsForLoad[2].source._unknownProperties.source2,
michael@0 279 "download3source2");
michael@0 280
michael@0 281 do_check_eq(Object.keys(itemsForLoad[2].target._unknownProperties).length, 2);
michael@0 282 do_check_eq(itemsForLoad[2].target._unknownProperties.target1,
michael@0 283 "download3target1");
michael@0 284 do_check_eq(itemsForLoad[2].target._unknownProperties.target2,
michael@0 285 "download3target2");
michael@0 286
michael@0 287 do_check_eq(Object.keys(itemsForLoad[2].saver._unknownProperties).length, 2);
michael@0 288 do_check_eq(itemsForLoad[2].saver._unknownProperties.saver1,
michael@0 289 "download3saver1");
michael@0 290 do_check_eq(itemsForLoad[2].saver._unknownProperties.saver2,
michael@0 291 "download3saver2");
michael@0 292 });
michael@0 293
michael@0 294 ////////////////////////////////////////////////////////////////////////////////
michael@0 295 //// Termination
michael@0 296
michael@0 297 let tailFile = do_get_file("tail.js");
michael@0 298 Services.scriptloader.loadSubScript(NetUtil.newURI(tailFile).spec);

mercurial