|
1 /* Any copyright is dedicated to the Public Domain. |
|
2 http://creativecommons.org/publicdomain/zero/1.0/ */ |
|
3 |
|
4 /** |
|
5 * This file tests the nsIDownloadHistory Places implementation. |
|
6 */ |
|
7 |
|
8 XPCOMUtils.defineLazyServiceGetter(this, "gDownloadHistory", |
|
9 "@mozilla.org/browser/download-history;1", |
|
10 "nsIDownloadHistory"); |
|
11 |
|
12 const DOWNLOAD_URI = NetUtil.newURI("http://www.example.com/"); |
|
13 const REFERRER_URI = NetUtil.newURI("http://www.example.org/"); |
|
14 const PRIVATE_URI = NetUtil.newURI("http://www.example.net/"); |
|
15 |
|
16 /** |
|
17 * Waits for the first visit notification to be received. |
|
18 * |
|
19 * @param aCallback |
|
20 * Callback function to be called with the same arguments of onVisit. |
|
21 */ |
|
22 function waitForOnVisit(aCallback) { |
|
23 let historyObserver = { |
|
24 __proto__: NavHistoryObserver.prototype, |
|
25 onVisit: function HO_onVisit() { |
|
26 PlacesUtils.history.removeObserver(this); |
|
27 aCallback.apply(null, arguments); |
|
28 } |
|
29 }; |
|
30 PlacesUtils.history.addObserver(historyObserver, false); |
|
31 } |
|
32 |
|
33 /** |
|
34 * Waits for the first onDeleteURI notification to be received. |
|
35 * |
|
36 * @param aCallback |
|
37 * Callback function to be called with the same arguments of onDeleteURI. |
|
38 */ |
|
39 function waitForOnDeleteURI(aCallback) { |
|
40 let historyObserver = { |
|
41 __proto__: NavHistoryObserver.prototype, |
|
42 onDeleteURI: function HO_onDeleteURI() { |
|
43 PlacesUtils.history.removeObserver(this); |
|
44 aCallback.apply(null, arguments); |
|
45 } |
|
46 }; |
|
47 PlacesUtils.history.addObserver(historyObserver, false); |
|
48 } |
|
49 |
|
50 /** |
|
51 * Waits for the first onDeleteVisits notification to be received. |
|
52 * |
|
53 * @param aCallback |
|
54 * Callback function to be called with the same arguments of onDeleteVisits. |
|
55 */ |
|
56 function waitForOnDeleteVisits(aCallback) { |
|
57 let historyObserver = { |
|
58 __proto__: NavHistoryObserver.prototype, |
|
59 onDeleteVisits: function HO_onDeleteVisits() { |
|
60 PlacesUtils.history.removeObserver(this); |
|
61 aCallback.apply(null, arguments); |
|
62 } |
|
63 }; |
|
64 PlacesUtils.history.addObserver(historyObserver, false); |
|
65 } |
|
66 |
|
67 function run_test() |
|
68 { |
|
69 run_next_test(); |
|
70 } |
|
71 |
|
72 add_test(function test_dh_is_from_places() |
|
73 { |
|
74 // Test that this nsIDownloadHistory is the one places implements. |
|
75 do_check_true(gDownloadHistory instanceof Ci.mozIAsyncHistory); |
|
76 |
|
77 run_next_test(); |
|
78 }); |
|
79 |
|
80 add_test(function test_dh_addRemoveDownload() |
|
81 { |
|
82 waitForOnVisit(function DHAD_onVisit(aURI) { |
|
83 do_check_true(aURI.equals(DOWNLOAD_URI)); |
|
84 |
|
85 // Verify that the URI is already available in results at this time. |
|
86 do_check_true(!!page_in_database(DOWNLOAD_URI)); |
|
87 |
|
88 waitForOnDeleteURI(function DHRAD_onDeleteURI(aURI) { |
|
89 do_check_true(aURI.equals(DOWNLOAD_URI)); |
|
90 |
|
91 // Verify that the URI is already available in results at this time. |
|
92 do_check_false(!!page_in_database(DOWNLOAD_URI)); |
|
93 |
|
94 run_next_test(); |
|
95 }); |
|
96 gDownloadHistory.removeAllDownloads(); |
|
97 }); |
|
98 |
|
99 gDownloadHistory.addDownload(DOWNLOAD_URI, null, Date.now() * 1000); |
|
100 }); |
|
101 |
|
102 add_test(function test_dh_addMultiRemoveDownload() |
|
103 { |
|
104 promiseAddVisits({ uri: DOWNLOAD_URI, |
|
105 transition: TRANSITION_TYPED }).then(function () { |
|
106 waitForOnVisit(function DHAD_onVisit(aURI) { |
|
107 do_check_true(aURI.equals(DOWNLOAD_URI)); |
|
108 do_check_true(!!page_in_database(DOWNLOAD_URI)); |
|
109 |
|
110 waitForOnDeleteVisits(function DHRAD_onDeleteVisits(aURI) { |
|
111 do_check_true(aURI.equals(DOWNLOAD_URI)); |
|
112 do_check_true(!!page_in_database(DOWNLOAD_URI)); |
|
113 |
|
114 promiseClearHistory().then(run_next_test); |
|
115 }); |
|
116 gDownloadHistory.removeAllDownloads(); |
|
117 }); |
|
118 |
|
119 gDownloadHistory.addDownload(DOWNLOAD_URI, null, Date.now() * 1000); |
|
120 }); |
|
121 }); |
|
122 |
|
123 add_test(function test_dh_addBookmarkRemoveDownload() |
|
124 { |
|
125 PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId, |
|
126 DOWNLOAD_URI, |
|
127 PlacesUtils.bookmarks.DEFAULT_INDEX, |
|
128 "A bookmark"); |
|
129 waitForOnVisit(function DHAD_onVisit(aURI) { |
|
130 do_check_true(aURI.equals(DOWNLOAD_URI)); |
|
131 do_check_true(!!page_in_database(DOWNLOAD_URI)); |
|
132 |
|
133 waitForOnDeleteVisits(function DHRAD_onDeleteVisits(aURI) { |
|
134 do_check_true(aURI.equals(DOWNLOAD_URI)); |
|
135 do_check_true(!!page_in_database(DOWNLOAD_URI)); |
|
136 |
|
137 promiseClearHistory().then(run_next_test); |
|
138 }); |
|
139 gDownloadHistory.removeAllDownloads(); |
|
140 }); |
|
141 |
|
142 gDownloadHistory.addDownload(DOWNLOAD_URI, null, Date.now() * 1000); |
|
143 }); |
|
144 |
|
145 add_test(function test_dh_addDownload_referrer() |
|
146 { |
|
147 waitForOnVisit(function DHAD_prepareReferrer(aURI, aVisitID) { |
|
148 do_check_true(aURI.equals(REFERRER_URI)); |
|
149 let referrerVisitId = aVisitID; |
|
150 |
|
151 waitForOnVisit(function DHAD_onVisit(aURI, aVisitID, aTime, aSessionID, |
|
152 aReferringID) { |
|
153 do_check_true(aURI.equals(DOWNLOAD_URI)); |
|
154 do_check_eq(aReferringID, referrerVisitId); |
|
155 |
|
156 // Verify that the URI is already available in results at this time. |
|
157 do_check_true(!!page_in_database(DOWNLOAD_URI)); |
|
158 |
|
159 promiseClearHistory().then(run_next_test); |
|
160 }); |
|
161 |
|
162 gDownloadHistory.addDownload(DOWNLOAD_URI, REFERRER_URI, Date.now() * 1000); |
|
163 }); |
|
164 |
|
165 // Note that we don't pass the optional callback argument here because we must |
|
166 // ensure that we receive the onVisit notification before we call addDownload. |
|
167 PlacesUtils.asyncHistory.updatePlaces({ |
|
168 uri: REFERRER_URI, |
|
169 visits: [{ |
|
170 transitionType: Ci.nsINavHistoryService.TRANSITION_TYPED, |
|
171 visitDate: Date.now() * 1000 |
|
172 }] |
|
173 }); |
|
174 }); |
|
175 |
|
176 add_test(function test_dh_addDownload_disabledHistory() |
|
177 { |
|
178 waitForOnVisit(function DHAD_onVisit(aURI) { |
|
179 // We should only receive the notification for the non-private URI. This |
|
180 // test is based on the assumption that visit notifications are received in |
|
181 // the same order of the addDownload calls, which is currently true because |
|
182 // database access is serialized on the same worker thread. |
|
183 do_check_true(aURI.equals(DOWNLOAD_URI)); |
|
184 |
|
185 do_check_true(!!page_in_database(DOWNLOAD_URI)); |
|
186 do_check_false(!!page_in_database(PRIVATE_URI)); |
|
187 |
|
188 promiseClearHistory().then(run_next_test); |
|
189 }); |
|
190 |
|
191 Services.prefs.setBoolPref("places.history.enabled", false); |
|
192 gDownloadHistory.addDownload(PRIVATE_URI, REFERRER_URI, Date.now() * 1000); |
|
193 |
|
194 // The addDownload functions calls CanAddURI synchronously, thus we can set |
|
195 // the preference back to true immediately (not all apps enable places by |
|
196 // default). |
|
197 Services.prefs.setBoolPref("places.history.enabled", true); |
|
198 gDownloadHistory.addDownload(DOWNLOAD_URI, REFERRER_URI, Date.now() * 1000); |
|
199 }); |
|
200 |
|
201 /** |
|
202 * Tests that nsIDownloadHistory::AddDownload saves the additional download |
|
203 * details if the optional destination URL is specified. |
|
204 */ |
|
205 add_test(function test_dh_details() |
|
206 { |
|
207 const REMOTE_URI = NetUtil.newURI("http://localhost/"); |
|
208 const SOURCE_URI = NetUtil.newURI("http://example.com/test_dh_details"); |
|
209 const DEST_FILE_NAME = "dest.txt"; |
|
210 |
|
211 // We must build a real, valid file URI for the destination. |
|
212 let destFileUri = NetUtil.newURI(FileUtils.getFile("TmpD", [DEST_FILE_NAME])); |
|
213 |
|
214 let titleSet = false; |
|
215 let destinationFileUriSet = false; |
|
216 let destinationFileNameSet = false; |
|
217 |
|
218 function checkFinished() |
|
219 { |
|
220 if (titleSet && destinationFileUriSet && destinationFileNameSet) { |
|
221 PlacesUtils.annotations.removeObserver(annoObserver); |
|
222 PlacesUtils.history.removeObserver(historyObserver); |
|
223 |
|
224 promiseClearHistory().then(run_next_test); |
|
225 } |
|
226 }; |
|
227 |
|
228 let annoObserver = { |
|
229 onPageAnnotationSet: function AO_onPageAnnotationSet(aPage, aName) |
|
230 { |
|
231 if (aPage.equals(SOURCE_URI)) { |
|
232 let value = PlacesUtils.annotations.getPageAnnotation(aPage, aName); |
|
233 switch (aName) |
|
234 { |
|
235 case "downloads/destinationFileURI": |
|
236 destinationFileUriSet = true; |
|
237 do_check_eq(value, destFileUri.spec); |
|
238 break; |
|
239 case "downloads/destinationFileName": |
|
240 destinationFileNameSet = true; |
|
241 do_check_eq(value, DEST_FILE_NAME); |
|
242 break; |
|
243 } |
|
244 checkFinished(); |
|
245 } |
|
246 }, |
|
247 onItemAnnotationSet: function() {}, |
|
248 onPageAnnotationRemoved: function() {}, |
|
249 onItemAnnotationRemoved: function() {} |
|
250 } |
|
251 |
|
252 let historyObserver = { |
|
253 onBeginUpdateBatch: function() {}, |
|
254 onEndUpdateBatch: function() {}, |
|
255 onVisit: function() {}, |
|
256 onTitleChanged: function HO_onTitleChanged(aURI, aPageTitle) |
|
257 { |
|
258 if (aURI.equals(SOURCE_URI)) { |
|
259 titleSet = true; |
|
260 do_check_eq(aPageTitle, DEST_FILE_NAME); |
|
261 checkFinished(); |
|
262 } |
|
263 }, |
|
264 onDeleteURI: function() {}, |
|
265 onClearHistory: function() {}, |
|
266 onPageChanged: function() {}, |
|
267 onDeleteVisits: function() {} |
|
268 }; |
|
269 |
|
270 PlacesUtils.annotations.addObserver(annoObserver, false); |
|
271 PlacesUtils.history.addObserver(historyObserver, false); |
|
272 |
|
273 // Both null values and remote URIs should not cause errors. |
|
274 gDownloadHistory.addDownload(SOURCE_URI, null, Date.now() * 1000); |
|
275 gDownloadHistory.addDownload(SOURCE_URI, null, Date.now() * 1000, null); |
|
276 gDownloadHistory.addDownload(SOURCE_URI, null, Date.now() * 1000, REMOTE_URI); |
|
277 |
|
278 // Valid local file URIs should cause the download details to be saved. |
|
279 gDownloadHistory.addDownload(SOURCE_URI, null, Date.now() * 1000, |
|
280 destFileUri); |
|
281 }); |