Bug 1845311 - [Part 2] Use ChromeUtils.defineLazyGetter in more places r=arai,webcomp...
[gecko.git] / toolkit / components / downloads / test / unit / test_DownloadIntegration.js
blob7ee34e83079e6726a5f8ee0a4d061a78d8117283
1 /* Any copyright is dedicated to the Public Domain.
2  * http://creativecommons.org/publicdomain/zero/1.0/ */
4 /**
5  * Tests the DownloadIntegration object.
6  */
8 "use strict";
10 // Globals
12 /**
13  * Notifies the prompt observers and verify the expected downloads count.
14  *
15  * @param aIsPrivate
16  *        Flag to know is test private observers.
17  * @param aExpectedCount
18  *        the expected downloads count for quit and offline observers.
19  * @param aExpectedPBCount
20  *        the expected downloads count for private browsing observer.
21  */
22 function notifyPromptObservers(aIsPrivate, aExpectedCount, aExpectedPBCount) {
23   let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].createInstance(
24     Ci.nsISupportsPRBool
25   );
27   // Notify quit application requested observer.
28   DownloadIntegration._testPromptDownloads = -1;
29   Services.obs.notifyObservers(cancelQuit, "quit-application-requested");
30   Assert.equal(DownloadIntegration._testPromptDownloads, aExpectedCount);
32   // Notify offline requested observer.
33   DownloadIntegration._testPromptDownloads = -1;
34   Services.obs.notifyObservers(cancelQuit, "offline-requested");
35   Assert.equal(DownloadIntegration._testPromptDownloads, aExpectedCount);
37   if (aIsPrivate) {
38     // Notify last private browsing requested observer.
39     DownloadIntegration._testPromptDownloads = -1;
40     Services.obs.notifyObservers(cancelQuit, "last-pb-context-exiting");
41     Assert.equal(DownloadIntegration._testPromptDownloads, aExpectedPBCount);
42   }
44   delete DownloadIntegration._testPromptDownloads;
47 // Tests
49 /**
50  * Allows re-enabling the real download directory logic during one test.
51  */
52 function allowDirectoriesInTest() {
53   DownloadIntegration.allowDirectories = true;
54   function cleanup() {
55     DownloadIntegration.allowDirectories = false;
56   }
57   registerCleanupFunction(cleanup);
58   return cleanup;
61 ChromeUtils.defineLazyGetter(this, "gStringBundle", function () {
62   return Services.strings.createBundle(
63     "chrome://mozapps/locale/downloads/downloads.properties"
64   );
65 });
67 /**
68  * Tests that getSystemDownloadsDirectory returns an existing directory or
69  * creates a new directory depending on the platform. Instead of the real
70  * directory, this test is executed in the temporary directory so we can safely
71  * delete the created folder to check whether it is created again.
72  */
73 add_task(async function test_getSystemDownloadsDirectory_exists_or_creates() {
74   let tempDir = Services.dirsvc.get("TmpD", Ci.nsIFile);
75   let downloadDir;
77   // OSX / Linux / Windows but not XP/2k
78   if (
79     Services.appinfo.OS == "Darwin" ||
80     Services.appinfo.OS == "Linux" ||
81     (Services.appinfo.OS == "WINNT" &&
82       parseFloat(Services.sysinfo.getProperty("version")) >= 6)
83   ) {
84     downloadDir = await DownloadIntegration.getSystemDownloadsDirectory();
85     Assert.equal(downloadDir, tempDir.path);
86     Assert.ok(await IOUtils.exists(downloadDir));
88     let info = await IOUtils.stat(downloadDir);
89     Assert.equal(info.type, "directory");
90   } else {
91     let targetPath = PathUtils.join(
92       tempDir.path,
93       gStringBundle.GetStringFromName("downloadsFolder")
94     );
95     try {
96       await IOUtils.remove(targetPath);
97     } catch (e) {}
98     downloadDir = await DownloadIntegration.getSystemDownloadsDirectory();
99     Assert.equal(downloadDir, targetPath);
100     Assert.ok(await IOUtils.exists(downloadDir));
102     let info = await IOUtils.stat(downloadDir);
103     Assert.equal(info.type, "directory");
104     await IOUtils.remove(targetPath);
105   }
109  * Tests that the real directory returned by getSystemDownloadsDirectory is not
110  * the one that is used during unit tests. Since this is the actual downloads
111  * directory of the operating system, we don't try to delete it afterwards.
112  */
113 add_task(async function test_getSystemDownloadsDirectory_real() {
114   let fakeDownloadDir = await DownloadIntegration.getSystemDownloadsDirectory();
116   let cleanup = allowDirectoriesInTest();
117   let realDownloadDir = await DownloadIntegration.getSystemDownloadsDirectory();
118   cleanup();
120   Assert.notEqual(fakeDownloadDir, realDownloadDir);
124  * Tests that the getPreferredDownloadsDirectory returns a valid download
125  * directory string path.
126  */
127 add_task(async function test_getPreferredDownloadsDirectory() {
128   let cleanupDirectories = allowDirectoriesInTest();
130   let folderListPrefName = "browser.download.folderList";
131   let dirPrefName = "browser.download.dir";
132   function cleanupPrefs() {
133     Services.prefs.clearUserPref(folderListPrefName);
134     Services.prefs.clearUserPref(dirPrefName);
135   }
136   registerCleanupFunction(cleanupPrefs);
138   // For legacy cloudstorage users with folderListPrefName as 3,
139   // Should return the system downloads directory because the dir preference
140   // is not set.
141   Services.prefs.setIntPref(folderListPrefName, 3);
142   let systemDir = await DownloadIntegration.getSystemDownloadsDirectory();
143   let downloadDir = await DownloadIntegration.getPreferredDownloadsDirectory();
144   Assert.notEqual(downloadDir, "");
145   Assert.equal(downloadDir, systemDir);
147   // Should return the system downloads directory.
148   Services.prefs.setIntPref(folderListPrefName, 1);
149   systemDir = await DownloadIntegration.getSystemDownloadsDirectory();
150   downloadDir = await DownloadIntegration.getPreferredDownloadsDirectory();
151   Assert.notEqual(downloadDir, "");
152   Assert.equal(downloadDir, systemDir);
154   // Should return the desktop directory.
155   Services.prefs.setIntPref(folderListPrefName, 0);
156   downloadDir = await DownloadIntegration.getPreferredDownloadsDirectory();
157   Assert.notEqual(downloadDir, "");
158   Assert.equal(downloadDir, Services.dirsvc.get("Desk", Ci.nsIFile).path);
160   // Should return the system downloads directory because the dir preference
161   // is not set.
162   Services.prefs.setIntPref(folderListPrefName, 2);
163   downloadDir = await DownloadIntegration.getPreferredDownloadsDirectory();
164   Assert.notEqual(downloadDir, "");
165   Assert.equal(downloadDir, systemDir);
167   // Should return the directory which is listed in the dir preference.
168   let time = new Date().getTime();
169   let tempDir = Services.dirsvc.get("TmpD", Ci.nsIFile);
170   tempDir.append(time);
171   Services.prefs.setComplexValue("browser.download.dir", Ci.nsIFile, tempDir);
172   downloadDir = await DownloadIntegration.getPreferredDownloadsDirectory();
173   Assert.notEqual(downloadDir, "");
174   Assert.equal(downloadDir, tempDir.path);
175   Assert.ok(await IOUtils.exists(downloadDir));
176   await IOUtils.remove(tempDir.path);
178   // Should return the system downloads directory beacause the path is invalid
179   // in the dir preference.
180   tempDir = Services.dirsvc.get("TmpD", Ci.nsIFile);
181   tempDir.append("dir_not_exist");
182   tempDir.append(time);
183   Services.prefs.setComplexValue("browser.download.dir", Ci.nsIFile, tempDir);
184   downloadDir = await DownloadIntegration.getPreferredDownloadsDirectory();
185   Assert.equal(downloadDir, systemDir);
187   // Should return the system downloads directory because the folderList
188   // preference is invalid
189   Services.prefs.setIntPref(folderListPrefName, 999);
190   downloadDir = await DownloadIntegration.getPreferredDownloadsDirectory();
191   Assert.equal(downloadDir, systemDir);
193   cleanupPrefs();
194   cleanupDirectories();
198  * Tests that the getTemporaryDownloadsDirectory returns a valid download
199  * directory string path.
200  */
201 add_task(async function test_getTemporaryDownloadsDirectory() {
202   let cleanup = allowDirectoriesInTest();
204   let downloadDir = await DownloadIntegration.getTemporaryDownloadsDirectory();
205   Assert.notEqual(downloadDir, "");
207   if ("nsILocalFileMac" in Ci) {
208     let preferredDownloadDir =
209       await DownloadIntegration.getPreferredDownloadsDirectory();
210     Assert.equal(downloadDir, preferredDownloadDir);
211   } else {
212     let tempDir = Services.dirsvc.get("TmpD", Ci.nsIFile);
213     Assert.equal(downloadDir, tempDir.path);
214   }
216   cleanup();
219 // Tests DownloadObserver
222  * Re-enables the default observers for the following tests.
224  * This takes effect the first time a DownloadList object is created, and lasts
225  * until this test file has completed.
226  */
227 add_task(async function test_observers_setup() {
228   DownloadIntegration.allowObservers = true;
229   registerCleanupFunction(function () {
230     DownloadIntegration.allowObservers = false;
231   });
235  * Tests notifications prompts when observers are notified if there are public
236  * and private active downloads.
237  */
238 add_task(async function test_notifications() {
239   for (let isPrivate of [false, true]) {
240     mustInterruptResponses();
242     let list = await promiseNewList(isPrivate);
243     let download1 = await promiseNewDownload(httpUrl("interruptible.txt"));
244     let download2 = await promiseNewDownload(httpUrl("interruptible.txt"));
245     let download3 = await promiseNewDownload(httpUrl("interruptible.txt"));
246     let promiseAttempt1 = download1.start();
247     let promiseAttempt2 = download2.start();
248     download3.start().catch(() => {});
250     // Add downloads to list.
251     await list.add(download1);
252     await list.add(download2);
253     await list.add(download3);
254     // Cancel third download
255     await download3.cancel();
257     notifyPromptObservers(isPrivate, 2, 2);
259     // Allow the downloads to complete.
260     continueResponses();
261     await promiseAttempt1;
262     await promiseAttempt2;
264     // Clean up.
265     await list.remove(download1);
266     await list.remove(download2);
267     await list.remove(download3);
268   }
272  * Tests that notifications prompts observers are not notified if there are no
273  * public or private active downloads.
274  */
275 add_task(async function test_no_notifications() {
276   for (let isPrivate of [false, true]) {
277     let list = await promiseNewList(isPrivate);
278     let download1 = await promiseNewDownload(httpUrl("interruptible.txt"));
279     let download2 = await promiseNewDownload(httpUrl("interruptible.txt"));
280     download1.start().catch(() => {});
281     download2.start().catch(() => {});
283     // Add downloads to list.
284     await list.add(download1);
285     await list.add(download2);
287     await download1.cancel();
288     await download2.cancel();
290     notifyPromptObservers(isPrivate, 0, 0);
292     // Clean up.
293     await list.remove(download1);
294     await list.remove(download2);
295   }
299  * Tests notifications prompts when observers are notified if there are public
300  * and private active downloads at the same time.
301  */
302 add_task(async function test_mix_notifications() {
303   mustInterruptResponses();
305   let publicList = await promiseNewList();
306   let privateList = await Downloads.getList(Downloads.PRIVATE);
307   let download1 = await promiseNewDownload(httpUrl("interruptible.txt"));
308   let download2 = await promiseNewDownload(httpUrl("interruptible.txt"));
309   let promiseAttempt1 = download1.start();
310   let promiseAttempt2 = download2.start();
312   // Add downloads to lists.
313   await publicList.add(download1);
314   await privateList.add(download2);
316   notifyPromptObservers(true, 2, 1);
318   // Allow the downloads to complete.
319   continueResponses();
320   await promiseAttempt1;
321   await promiseAttempt2;
323   // Clean up.
324   await publicList.remove(download1);
325   await privateList.remove(download2);
329  * Tests suspending and resuming as well as going offline and then online again.
330  * The downloads should stop when suspending and start again when resuming.
331  */
332 add_task(async function test_suspend_resume() {
333   // The default wake delay is 10 seconds, so set the wake delay to be much
334   // faster for these tests.
335   Services.prefs.setIntPref("browser.download.manager.resumeOnWakeDelay", 5);
337   let addDownload = function (list) {
338     return (async function () {
339       let download = await promiseNewDownload(httpUrl("interruptible.txt"));
340       download.start().catch(() => {});
341       list.add(download);
342       return download;
343     })();
344   };
346   let publicList = await promiseNewList();
347   let privateList = await promiseNewList(true);
349   let download1 = await addDownload(publicList);
350   let download2 = await addDownload(publicList);
351   let download3 = await addDownload(privateList);
352   let download4 = await addDownload(privateList);
353   let download5 = await addDownload(publicList);
355   // First, check that the downloads are all canceled when going to sleep.
356   Services.obs.notifyObservers(null, "sleep_notification");
357   Assert.ok(download1.canceled);
358   Assert.ok(download2.canceled);
359   Assert.ok(download3.canceled);
360   Assert.ok(download4.canceled);
361   Assert.ok(download5.canceled);
363   // Remove a download. It should not be started again.
364   publicList.remove(download5);
365   Assert.ok(download5.canceled);
367   // When waking up again, the downloads start again after the wake delay. To be
368   // more robust, don't check after a delay but instead just wait for the
369   // downloads to finish.
370   Services.obs.notifyObservers(null, "wake_notification");
371   await download1.whenSucceeded();
372   await download2.whenSucceeded();
373   await download3.whenSucceeded();
374   await download4.whenSucceeded();
376   // Downloads should no longer be canceled. However, as download5 was removed
377   // from the public list, it will not be restarted.
378   Assert.ok(!download1.canceled);
379   Assert.ok(download5.canceled);
381   // Create four new downloads and check for going offline and then online again.
383   download1 = await addDownload(publicList);
384   download2 = await addDownload(publicList);
385   download3 = await addDownload(privateList);
386   download4 = await addDownload(privateList);
388   // Going offline should cancel the downloads.
389   Services.obs.notifyObservers(null, "network:offline-about-to-go-offline");
390   Assert.ok(download1.canceled);
391   Assert.ok(download2.canceled);
392   Assert.ok(download3.canceled);
393   Assert.ok(download4.canceled);
395   // Going back online should start the downloads again.
396   Services.obs.notifyObservers(
397     null,
398     "network:offline-status-changed",
399     "online"
400   );
401   await download1.whenSucceeded();
402   await download2.whenSucceeded();
403   await download3.whenSucceeded();
404   await download4.whenSucceeded();
406   Services.prefs.clearUserPref("browser.download.manager.resumeOnWakeDelay");
410  * Tests both the downloads list and the in-progress downloads are clear when
411  * private browsing observer is notified.
412  */
413 add_task(async function test_exit_private_browsing() {
414   mustInterruptResponses();
416   let privateList = await promiseNewList(true);
417   let download1 = await promiseNewDownload(httpUrl("source.txt"));
418   let download2 = await promiseNewDownload(httpUrl("interruptible.txt"));
419   let promiseAttempt1 = download1.start();
420   download2.start();
422   // Add downloads to list.
423   await privateList.add(download1);
424   await privateList.add(download2);
426   // Complete the download.
427   await promiseAttempt1;
429   Assert.equal((await privateList.getAll()).length, 2);
431   // Simulate exiting the private browsing.
432   await new Promise(resolve => {
433     DownloadIntegration._testResolveClearPrivateList = resolve;
434     Services.obs.notifyObservers(null, "last-pb-context-exited");
435   });
436   delete DownloadIntegration._testResolveClearPrivateList;
438   Assert.equal((await privateList.getAll()).length, 0);
440   continueResponses();