|
1 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim:set ts=2 sw=2 sts=2 et: */ |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 /** |
|
8 * Test preventive maintenance |
|
9 * For every maintenance query create an uncoherent db and check that we take |
|
10 * correct fix steps, without polluting valid data. |
|
11 */ |
|
12 |
|
13 // Include PlacesDBUtils module |
|
14 Components.utils.import("resource://gre/modules/PlacesDBUtils.jsm"); |
|
15 |
|
16 const FINISHED_MAINTENANCE_NOTIFICATION_TOPIC = "places-maintenance-finished"; |
|
17 |
|
18 // Get services and database connection |
|
19 let hs = PlacesUtils.history; |
|
20 let bs = PlacesUtils.bookmarks; |
|
21 let ts = PlacesUtils.tagging; |
|
22 let as = PlacesUtils.annotations; |
|
23 let fs = PlacesUtils.favicons; |
|
24 |
|
25 let mDBConn = hs.QueryInterface(Ci.nsPIPlacesDatabase).DBConnection; |
|
26 |
|
27 //------------------------------------------------------------------------------ |
|
28 // Helpers |
|
29 |
|
30 let defaultBookmarksMaxId = 0; |
|
31 function cleanDatabase() { |
|
32 mDBConn.executeSimpleSQL("DELETE FROM moz_places"); |
|
33 mDBConn.executeSimpleSQL("DELETE FROM moz_historyvisits"); |
|
34 mDBConn.executeSimpleSQL("DELETE FROM moz_anno_attributes"); |
|
35 mDBConn.executeSimpleSQL("DELETE FROM moz_annos"); |
|
36 mDBConn.executeSimpleSQL("DELETE FROM moz_items_annos"); |
|
37 mDBConn.executeSimpleSQL("DELETE FROM moz_inputhistory"); |
|
38 mDBConn.executeSimpleSQL("DELETE FROM moz_keywords"); |
|
39 mDBConn.executeSimpleSQL("DELETE FROM moz_favicons"); |
|
40 mDBConn.executeSimpleSQL("DELETE FROM moz_bookmarks WHERE id > " + defaultBookmarksMaxId); |
|
41 } |
|
42 |
|
43 function addPlace(aUrl, aFavicon) { |
|
44 let stmt = mDBConn.createStatement( |
|
45 "INSERT INTO moz_places (url, favicon_id) VALUES (:url, :favicon)"); |
|
46 stmt.params["url"] = aUrl || "http://www.mozilla.org"; |
|
47 stmt.params["favicon"] = aFavicon || null; |
|
48 stmt.execute(); |
|
49 stmt.finalize(); |
|
50 return mDBConn.lastInsertRowID; |
|
51 } |
|
52 |
|
53 function addBookmark(aPlaceId, aType, aParent, aKeywordId, aFolderType, aTitle) { |
|
54 let stmt = mDBConn.createStatement( |
|
55 "INSERT INTO moz_bookmarks (fk, type, parent, keyword_id, folder_type, " |
|
56 + "title, guid) " |
|
57 + "VALUES (:place_id, :type, :parent, :keyword_id, :folder_type, :title, " |
|
58 + "GENERATE_GUID())"); |
|
59 stmt.params["place_id"] = aPlaceId || null; |
|
60 stmt.params["type"] = aType || bs.TYPE_BOOKMARK; |
|
61 stmt.params["parent"] = aParent || bs.unfiledBookmarksFolder; |
|
62 stmt.params["keyword_id"] = aKeywordId || null; |
|
63 stmt.params["folder_type"] = aFolderType || null; |
|
64 stmt.params["title"] = typeof(aTitle) == "string" ? aTitle : null; |
|
65 stmt.execute(); |
|
66 stmt.finalize(); |
|
67 return mDBConn.lastInsertRowID; |
|
68 } |
|
69 |
|
70 //------------------------------------------------------------------------------ |
|
71 // Tests |
|
72 |
|
73 let tests = []; |
|
74 |
|
75 //------------------------------------------------------------------------------ |
|
76 |
|
77 tests.push({ |
|
78 name: "A.1", |
|
79 desc: "Remove obsolete annotations from moz_annos", |
|
80 |
|
81 _obsoleteWeaveAttribute: "weave/test", |
|
82 _placeId: null, |
|
83 |
|
84 setup: function() { |
|
85 // Add a place to ensure place_id = 1 is valid. |
|
86 this._placeId = addPlace(); |
|
87 // Add an obsolete attribute. |
|
88 let stmt = mDBConn.createStatement( |
|
89 "INSERT INTO moz_anno_attributes (name) VALUES (:anno)" |
|
90 ); |
|
91 stmt.params['anno'] = this._obsoleteWeaveAttribute; |
|
92 stmt.execute(); |
|
93 stmt.finalize(); |
|
94 stmt = mDBConn.createStatement( |
|
95 "INSERT INTO moz_annos (place_id, anno_attribute_id) " |
|
96 + "VALUES (:place_id, " |
|
97 + "(SELECT id FROM moz_anno_attributes WHERE name = :anno)" |
|
98 + ")" |
|
99 ); |
|
100 stmt.params['place_id'] = this._placeId; |
|
101 stmt.params['anno'] = this._obsoleteWeaveAttribute; |
|
102 stmt.execute(); |
|
103 stmt.finalize(); |
|
104 }, |
|
105 |
|
106 check: function() { |
|
107 // Check that the obsolete annotation has been removed. |
|
108 let stmt = mDBConn.createStatement( |
|
109 "SELECT id FROM moz_anno_attributes WHERE name = :anno" |
|
110 ); |
|
111 stmt.params['anno'] = this._obsoleteWeaveAttribute; |
|
112 do_check_false(stmt.executeStep()); |
|
113 stmt.finalize(); |
|
114 } |
|
115 }); |
|
116 |
|
117 tests.push({ |
|
118 name: "A.2", |
|
119 desc: "Remove obsolete annotations from moz_items_annos", |
|
120 |
|
121 _obsoleteSyncAttribute: "sync/children", |
|
122 _obsoleteGuidAttribute: "placesInternal/GUID", |
|
123 _obsoleteWeaveAttribute: "weave/test", |
|
124 _placeId: null, |
|
125 _bookmarkId: null, |
|
126 |
|
127 setup: function() { |
|
128 // Add a place to ensure place_id = 1 is valid. |
|
129 this._placeId = addPlace(); |
|
130 // Add a bookmark. |
|
131 this._bookmarkId = addBookmark(this._placeId); |
|
132 // Add an obsolete attribute. |
|
133 let stmt = mDBConn.createStatement( |
|
134 "INSERT INTO moz_anno_attributes (name) " |
|
135 + "VALUES (:anno1), (:anno2), (:anno3)" |
|
136 ); |
|
137 stmt.params['anno1'] = this._obsoleteSyncAttribute; |
|
138 stmt.params['anno2'] = this._obsoleteGuidAttribute; |
|
139 stmt.params['anno3'] = this._obsoleteWeaveAttribute; |
|
140 stmt.execute(); |
|
141 stmt.finalize(); |
|
142 stmt = mDBConn.createStatement( |
|
143 "INSERT INTO moz_items_annos (item_id, anno_attribute_id) " |
|
144 + "SELECT :item_id, id " |
|
145 + "FROM moz_anno_attributes " |
|
146 + "WHERE name IN (:anno1, :anno2, :anno3)" |
|
147 ); |
|
148 stmt.params['item_id'] = this._bookmarkId; |
|
149 stmt.params['anno1'] = this._obsoleteSyncAttribute; |
|
150 stmt.params['anno2'] = this._obsoleteGuidAttribute; |
|
151 stmt.params['anno3'] = this._obsoleteWeaveAttribute; |
|
152 stmt.execute(); |
|
153 stmt.finalize(); |
|
154 }, |
|
155 |
|
156 check: function() { |
|
157 // Check that the obsolete annotations have been removed. |
|
158 let stmt = mDBConn.createStatement( |
|
159 "SELECT id FROM moz_anno_attributes " |
|
160 + "WHERE name IN (:anno1, :anno2, :anno3)" |
|
161 ); |
|
162 stmt.params['anno1'] = this._obsoleteSyncAttribute; |
|
163 stmt.params['anno2'] = this._obsoleteGuidAttribute; |
|
164 stmt.params['anno3'] = this._obsoleteWeaveAttribute; |
|
165 do_check_false(stmt.executeStep()); |
|
166 stmt.finalize(); |
|
167 } |
|
168 }); |
|
169 |
|
170 tests.push({ |
|
171 name: "A.3", |
|
172 desc: "Remove unused attributes", |
|
173 |
|
174 _usedPageAttribute: "usedPage", |
|
175 _usedItemAttribute: "usedItem", |
|
176 _unusedAttribute: "unused", |
|
177 _placeId: null, |
|
178 _bookmarkId: null, |
|
179 |
|
180 setup: function() { |
|
181 // Add a place to ensure place_id = 1 is valid |
|
182 this._placeId = addPlace(); |
|
183 // add a bookmark |
|
184 this._bookmarkId = addBookmark(this._placeId); |
|
185 // Add a used attribute and an unused one. |
|
186 let stmt = mDBConn.createStatement("INSERT INTO moz_anno_attributes (name) VALUES (:anno)"); |
|
187 stmt.params['anno'] = this._usedPageAttribute; |
|
188 stmt.execute(); |
|
189 stmt.reset(); |
|
190 stmt.params['anno'] = this._usedItemAttribute; |
|
191 stmt.execute(); |
|
192 stmt.reset(); |
|
193 stmt.params['anno'] = this._unusedAttribute; |
|
194 stmt.execute(); |
|
195 stmt.finalize(); |
|
196 |
|
197 stmt = mDBConn.createStatement("INSERT INTO moz_annos (place_id, anno_attribute_id) VALUES(:place_id, (SELECT id FROM moz_anno_attributes WHERE name = :anno))"); |
|
198 stmt.params['place_id'] = this._placeId; |
|
199 stmt.params['anno'] = this._usedPageAttribute; |
|
200 stmt.execute(); |
|
201 stmt.finalize(); |
|
202 stmt = mDBConn.createStatement("INSERT INTO moz_items_annos (item_id, anno_attribute_id) VALUES(:item_id, (SELECT id FROM moz_anno_attributes WHERE name = :anno))"); |
|
203 stmt.params['item_id'] = this._bookmarkId; |
|
204 stmt.params['anno'] = this._usedItemAttribute; |
|
205 stmt.execute(); |
|
206 stmt.finalize(); |
|
207 }, |
|
208 |
|
209 check: function() { |
|
210 // Check that used attributes are still there |
|
211 let stmt = mDBConn.createStatement("SELECT id FROM moz_anno_attributes WHERE name = :anno"); |
|
212 stmt.params['anno'] = this._usedPageAttribute; |
|
213 do_check_true(stmt.executeStep()); |
|
214 stmt.reset(); |
|
215 stmt.params['anno'] = this._usedItemAttribute; |
|
216 do_check_true(stmt.executeStep()); |
|
217 stmt.reset(); |
|
218 // Check that unused attribute has been removed |
|
219 stmt.params['anno'] = this._unusedAttribute; |
|
220 do_check_false(stmt.executeStep()); |
|
221 stmt.finalize(); |
|
222 } |
|
223 }); |
|
224 |
|
225 //------------------------------------------------------------------------------ |
|
226 |
|
227 tests.push({ |
|
228 name: "B.1", |
|
229 desc: "Remove annotations with an invalid attribute", |
|
230 |
|
231 _usedPageAttribute: "usedPage", |
|
232 _placeId: null, |
|
233 |
|
234 setup: function() { |
|
235 // Add a place to ensure place_id = 1 is valid |
|
236 this._placeId = addPlace(); |
|
237 // Add a used attribute. |
|
238 let stmt = mDBConn.createStatement("INSERT INTO moz_anno_attributes (name) VALUES (:anno)"); |
|
239 stmt.params['anno'] = this._usedPageAttribute; |
|
240 stmt.execute(); |
|
241 stmt.finalize(); |
|
242 stmt = mDBConn.createStatement("INSERT INTO moz_annos (place_id, anno_attribute_id) VALUES(:place_id, (SELECT id FROM moz_anno_attributes WHERE name = :anno))"); |
|
243 stmt.params['place_id'] = this._placeId; |
|
244 stmt.params['anno'] = this._usedPageAttribute; |
|
245 stmt.execute(); |
|
246 stmt.finalize(); |
|
247 // Add an annotation with a nonexistent attribute |
|
248 stmt = mDBConn.createStatement("INSERT INTO moz_annos (place_id, anno_attribute_id) VALUES(:place_id, 1337)"); |
|
249 stmt.params['place_id'] = this._placeId; |
|
250 stmt.execute(); |
|
251 stmt.finalize(); |
|
252 }, |
|
253 |
|
254 check: function() { |
|
255 // Check that used attribute is still there |
|
256 let stmt = mDBConn.createStatement("SELECT id FROM moz_anno_attributes WHERE name = :anno"); |
|
257 stmt.params['anno'] = this._usedPageAttribute; |
|
258 do_check_true(stmt.executeStep()); |
|
259 stmt.finalize(); |
|
260 // check that annotation with valid attribute is still there |
|
261 stmt = mDBConn.createStatement("SELECT id FROM moz_annos WHERE anno_attribute_id = (SELECT id FROM moz_anno_attributes WHERE name = :anno)"); |
|
262 stmt.params['anno'] = this._usedPageAttribute; |
|
263 do_check_true(stmt.executeStep()); |
|
264 stmt.finalize(); |
|
265 // Check that annotation with bogus attribute has been removed |
|
266 stmt = mDBConn.createStatement("SELECT id FROM moz_annos WHERE anno_attribute_id = 1337"); |
|
267 do_check_false(stmt.executeStep()); |
|
268 stmt.finalize(); |
|
269 } |
|
270 }); |
|
271 |
|
272 //------------------------------------------------------------------------------ |
|
273 |
|
274 tests.push({ |
|
275 name: "B.2", |
|
276 desc: "Remove orphan page annotations", |
|
277 |
|
278 _usedPageAttribute: "usedPage", |
|
279 _placeId: null, |
|
280 |
|
281 setup: function() { |
|
282 // Add a place to ensure place_id = 1 is valid |
|
283 this._placeId = addPlace(); |
|
284 // Add a used attribute. |
|
285 let stmt = mDBConn.createStatement("INSERT INTO moz_anno_attributes (name) VALUES (:anno)"); |
|
286 stmt.params['anno'] = this._usedPageAttribute; |
|
287 stmt.execute(); |
|
288 stmt.finalize(); |
|
289 stmt = mDBConn.createStatement("INSERT INTO moz_annos (place_id, anno_attribute_id) VALUES(:place_id, (SELECT id FROM moz_anno_attributes WHERE name = :anno))"); |
|
290 stmt.params['place_id'] = this._placeId; |
|
291 stmt.params['anno'] = this._usedPageAttribute; |
|
292 stmt.execute(); |
|
293 stmt.reset(); |
|
294 // Add an annotation to a nonexistent page |
|
295 stmt.params['place_id'] = 1337; |
|
296 stmt.params['anno'] = this._usedPageAttribute; |
|
297 stmt.execute(); |
|
298 stmt.finalize(); |
|
299 }, |
|
300 |
|
301 check: function() { |
|
302 // Check that used attribute is still there |
|
303 let stmt = mDBConn.createStatement("SELECT id FROM moz_anno_attributes WHERE name = :anno"); |
|
304 stmt.params['anno'] = this._usedPageAttribute; |
|
305 do_check_true(stmt.executeStep()); |
|
306 stmt.finalize(); |
|
307 // check that annotation with valid attribute is still there |
|
308 stmt = mDBConn.createStatement("SELECT id FROM moz_annos WHERE anno_attribute_id = (SELECT id FROM moz_anno_attributes WHERE name = :anno)"); |
|
309 stmt.params['anno'] = this._usedPageAttribute; |
|
310 do_check_true(stmt.executeStep()); |
|
311 stmt.finalize(); |
|
312 // Check that an annotation to a nonexistent page has been removed |
|
313 stmt = mDBConn.createStatement("SELECT id FROM moz_annos WHERE place_id = 1337"); |
|
314 do_check_false(stmt.executeStep()); |
|
315 stmt.finalize(); |
|
316 } |
|
317 }); |
|
318 |
|
319 //------------------------------------------------------------------------------ |
|
320 tests.push({ |
|
321 name: "C.1", |
|
322 desc: "fix missing Places root", |
|
323 |
|
324 setup: function() { |
|
325 // Sanity check: ensure that roots are intact. |
|
326 do_check_eq(bs.getFolderIdForItem(bs.placesRoot), 0); |
|
327 do_check_eq(bs.getFolderIdForItem(bs.bookmarksMenuFolder), bs.placesRoot); |
|
328 do_check_eq(bs.getFolderIdForItem(bs.tagsFolder), bs.placesRoot); |
|
329 do_check_eq(bs.getFolderIdForItem(bs.unfiledBookmarksFolder), bs.placesRoot); |
|
330 do_check_eq(bs.getFolderIdForItem(bs.toolbarFolder), bs.placesRoot); |
|
331 |
|
332 // Remove the root. |
|
333 mDBConn.executeSimpleSQL("DELETE FROM moz_bookmarks WHERE parent = 0"); |
|
334 let stmt = mDBConn.createStatement("SELECT id FROM moz_bookmarks WHERE parent = 0"); |
|
335 do_check_false(stmt.executeStep()); |
|
336 stmt.finalize(); |
|
337 }, |
|
338 |
|
339 check: function() { |
|
340 // Ensure the roots have been correctly restored. |
|
341 do_check_eq(bs.getFolderIdForItem(bs.placesRoot), 0); |
|
342 do_check_eq(bs.getFolderIdForItem(bs.bookmarksMenuFolder), bs.placesRoot); |
|
343 do_check_eq(bs.getFolderIdForItem(bs.tagsFolder), bs.placesRoot); |
|
344 do_check_eq(bs.getFolderIdForItem(bs.unfiledBookmarksFolder), bs.placesRoot); |
|
345 do_check_eq(bs.getFolderIdForItem(bs.toolbarFolder), bs.placesRoot); |
|
346 } |
|
347 }); |
|
348 |
|
349 //------------------------------------------------------------------------------ |
|
350 tests.push({ |
|
351 name: "C.2", |
|
352 desc: "Fix roots titles", |
|
353 |
|
354 setup: function() { |
|
355 // Sanity check: ensure that roots titles are correct. We can use our check. |
|
356 this.check(); |
|
357 // Change some roots' titles. |
|
358 bs.setItemTitle(bs.placesRoot, "bad title"); |
|
359 do_check_eq(bs.getItemTitle(bs.placesRoot), "bad title"); |
|
360 bs.setItemTitle(bs.unfiledBookmarksFolder, "bad title"); |
|
361 do_check_eq(bs.getItemTitle(bs.unfiledBookmarksFolder), "bad title"); |
|
362 }, |
|
363 |
|
364 check: function() { |
|
365 // Ensure all roots titles are correct. |
|
366 do_check_eq(bs.getItemTitle(bs.placesRoot), ""); |
|
367 do_check_eq(bs.getItemTitle(bs.bookmarksMenuFolder), |
|
368 PlacesUtils.getString("BookmarksMenuFolderTitle")); |
|
369 do_check_eq(bs.getItemTitle(bs.tagsFolder), |
|
370 PlacesUtils.getString("TagsFolderTitle")); |
|
371 do_check_eq(bs.getItemTitle(bs.unfiledBookmarksFolder), |
|
372 PlacesUtils.getString("UnsortedBookmarksFolderTitle")); |
|
373 do_check_eq(bs.getItemTitle(bs.toolbarFolder), |
|
374 PlacesUtils.getString("BookmarksToolbarFolderTitle")); |
|
375 } |
|
376 }); |
|
377 |
|
378 //------------------------------------------------------------------------------ |
|
379 |
|
380 tests.push({ |
|
381 name: "D.1", |
|
382 desc: "Remove items without a valid place", |
|
383 |
|
384 _validItemId: null, |
|
385 _invalidItemId: null, |
|
386 _placeId: null, |
|
387 |
|
388 setup: function() { |
|
389 // Add a place to ensure place_id = 1 is valid |
|
390 this.placeId = addPlace(); |
|
391 // Insert a valid bookmark |
|
392 this._validItemId = addBookmark(this.placeId); |
|
393 // Insert a bookmark with an invalid place |
|
394 this._invalidItemId = addBookmark(1337); |
|
395 }, |
|
396 |
|
397 check: function() { |
|
398 // Check that valid bookmark is still there |
|
399 let stmt = mDBConn.createStatement("SELECT id FROM moz_bookmarks WHERE id = :item_id"); |
|
400 stmt.params["item_id"] = this._validItemId; |
|
401 do_check_true(stmt.executeStep()); |
|
402 stmt.reset(); |
|
403 // Check that invalid bookmark has been removed |
|
404 stmt.params["item_id"] = this._invalidItemId; |
|
405 do_check_false(stmt.executeStep()); |
|
406 stmt.finalize(); |
|
407 } |
|
408 }); |
|
409 |
|
410 //------------------------------------------------------------------------------ |
|
411 |
|
412 tests.push({ |
|
413 name: "D.2", |
|
414 desc: "Remove items that are not uri bookmarks from tag containers", |
|
415 |
|
416 _tagId: null, |
|
417 _bookmarkId: null, |
|
418 _separatorId: null, |
|
419 _folderId: null, |
|
420 _placeId: null, |
|
421 |
|
422 setup: function() { |
|
423 // Add a place to ensure place_id = 1 is valid |
|
424 this._placeId = addPlace(); |
|
425 // Create a tag |
|
426 this._tagId = addBookmark(null, bs.TYPE_FOLDER, bs.tagsFolder); |
|
427 // Insert a bookmark in the tag |
|
428 this._bookmarkId = addBookmark(this._placeId, bs.TYPE_BOOKMARK, this._tagId); |
|
429 // Insert a separator in the tag |
|
430 this._separatorId = addBookmark(null, bs.TYPE_SEPARATOR, this._tagId); |
|
431 // Insert a folder in the tag |
|
432 this._folderId = addBookmark(null, bs.TYPE_FOLDER, this._tagId); |
|
433 }, |
|
434 |
|
435 check: function() { |
|
436 // Check that valid bookmark is still there |
|
437 let stmt = mDBConn.createStatement("SELECT id FROM moz_bookmarks WHERE type = :type AND parent = :parent"); |
|
438 stmt.params["type"] = bs.TYPE_BOOKMARK; |
|
439 stmt.params["parent"] = this._tagId; |
|
440 do_check_true(stmt.executeStep()); |
|
441 stmt.reset(); |
|
442 // Check that separator is no more there |
|
443 stmt.params["type"] = bs.TYPE_SEPARATOR; |
|
444 stmt.params["parent"] = this._tagId; |
|
445 do_check_false(stmt.executeStep()); |
|
446 stmt.reset(); |
|
447 // Check that folder is no more there |
|
448 stmt.params["type"] = bs.TYPE_FOLDER; |
|
449 stmt.params["parent"] = this._tagId; |
|
450 do_check_false(stmt.executeStep()); |
|
451 stmt.finalize(); |
|
452 } |
|
453 }); |
|
454 |
|
455 //------------------------------------------------------------------------------ |
|
456 |
|
457 tests.push({ |
|
458 name: "D.3", |
|
459 desc: "Remove empty tags", |
|
460 |
|
461 _tagId: null, |
|
462 _bookmarkId: null, |
|
463 _emptyTagId: null, |
|
464 _placeId: null, |
|
465 |
|
466 setup: function() { |
|
467 // Add a place to ensure place_id = 1 is valid |
|
468 this._placeId = addPlace(); |
|
469 // Create a tag |
|
470 this._tagId = addBookmark(null, bs.TYPE_FOLDER, bs.tagsFolder); |
|
471 // Insert a bookmark in the tag |
|
472 this._bookmarkId = addBookmark(this._placeId, bs.TYPE_BOOKMARK, this._tagId); |
|
473 // Create another tag (empty) |
|
474 this._emptyTagId = addBookmark(null, bs.TYPE_FOLDER, bs.tagsFolder); |
|
475 }, |
|
476 |
|
477 check: function() { |
|
478 // Check that valid bookmark is still there |
|
479 let stmt = mDBConn.createStatement("SELECT id FROM moz_bookmarks WHERE id = :id AND type = :type AND parent = :parent"); |
|
480 stmt.params["id"] = this._bookmarkId; |
|
481 stmt.params["type"] = bs.TYPE_BOOKMARK; |
|
482 stmt.params["parent"] = this._tagId; |
|
483 do_check_true(stmt.executeStep()); |
|
484 stmt.reset(); |
|
485 stmt.params["id"] = this._tagId; |
|
486 stmt.params["type"] = bs.TYPE_FOLDER; |
|
487 stmt.params["parent"] = bs.tagsFolder; |
|
488 do_check_true(stmt.executeStep()); |
|
489 stmt.reset(); |
|
490 stmt.params["id"] = this._emptyTagId; |
|
491 stmt.params["type"] = bs.TYPE_FOLDER; |
|
492 stmt.params["parent"] = bs.tagsFolder; |
|
493 do_check_false(stmt.executeStep()); |
|
494 stmt.finalize(); |
|
495 } |
|
496 }); |
|
497 |
|
498 //------------------------------------------------------------------------------ |
|
499 |
|
500 tests.push({ |
|
501 name: "D.4", |
|
502 desc: "Move orphan items to unsorted folder", |
|
503 |
|
504 _orphanBookmarkId: null, |
|
505 _orphanSeparatorId: null, |
|
506 _orphanFolderId: null, |
|
507 _bookmarkId: null, |
|
508 _placeId: null, |
|
509 |
|
510 setup: function() { |
|
511 // Add a place to ensure place_id = 1 is valid |
|
512 this._placeId = addPlace(); |
|
513 // Insert an orphan bookmark |
|
514 this._orphanBookmarkId = addBookmark(this._placeId, bs.TYPE_BOOKMARK, 8888); |
|
515 // Insert an orphan separator |
|
516 this._orphanSeparatorId = addBookmark(null, bs.TYPE_SEPARATOR, 8888); |
|
517 // Insert a orphan folder |
|
518 this._orphanFolderId = addBookmark(null, bs.TYPE_FOLDER, 8888); |
|
519 // Create a child of the last created folder |
|
520 this._bookmarkId = addBookmark(this._placeId, bs.TYPE_BOOKMARK, this._orphanFolderId); |
|
521 }, |
|
522 |
|
523 check: function() { |
|
524 // Check that bookmarks are now children of a real folder (unsorted) |
|
525 let stmt = mDBConn.createStatement("SELECT id FROM moz_bookmarks WHERE id = :item_id AND parent = :parent"); |
|
526 stmt.params["item_id"] = this._orphanBookmarkId; |
|
527 stmt.params["parent"] = bs.unfiledBookmarksFolder; |
|
528 do_check_true(stmt.executeStep()); |
|
529 stmt.reset(); |
|
530 stmt.params["item_id"] = this._orphanSeparatorId; |
|
531 stmt.params["parent"] = bs.unfiledBookmarksFolder; |
|
532 do_check_true(stmt.executeStep()); |
|
533 stmt.reset(); |
|
534 stmt.params["item_id"] = this._orphanFolderId; |
|
535 stmt.params["parent"] = bs.unfiledBookmarksFolder; |
|
536 do_check_true(stmt.executeStep()); |
|
537 stmt.reset(); |
|
538 stmt.params["item_id"] = this._bookmarkId; |
|
539 stmt.params["parent"] = this._orphanFolderId; |
|
540 do_check_true(stmt.executeStep()); |
|
541 stmt.finalize(); |
|
542 } |
|
543 }); |
|
544 |
|
545 //------------------------------------------------------------------------------ |
|
546 |
|
547 tests.push({ |
|
548 name: "D.5", |
|
549 desc: "Fix wrong keywords", |
|
550 |
|
551 _validKeywordItemId: null, |
|
552 _invalidKeywordItemId: null, |
|
553 _validKeywordId: 1, |
|
554 _invalidKeywordId: 8888, |
|
555 _placeId: null, |
|
556 |
|
557 setup: function() { |
|
558 // Insert a keyword |
|
559 let stmt = mDBConn.createStatement("INSERT INTO moz_keywords (id, keyword) VALUES(:id, :keyword)"); |
|
560 stmt.params["id"] = this._validKeywordId; |
|
561 stmt.params["keyword"] = "used"; |
|
562 stmt.execute(); |
|
563 stmt.finalize(); |
|
564 // Add a place to ensure place_id = 1 is valid |
|
565 this._placeId = addPlace(); |
|
566 // Add a bookmark using the keyword |
|
567 this._validKeywordItemId = addBookmark(this._placeId, bs.TYPE_BOOKMARK, bs.unfiledBookmarksFolder, this._validKeywordId); |
|
568 // Add a bookmark using a nonexistent keyword |
|
569 this._invalidKeywordItemId = addBookmark(this._placeId, bs.TYPE_BOOKMARK, bs.unfiledBookmarksFolder, this._invalidKeywordId); |
|
570 }, |
|
571 |
|
572 check: function() { |
|
573 // Check that item with valid keyword is there |
|
574 let stmt = mDBConn.createStatement("SELECT id FROM moz_bookmarks WHERE id = :item_id AND keyword_id = :keyword"); |
|
575 stmt.params["item_id"] = this._validKeywordItemId; |
|
576 stmt.params["keyword"] = this._validKeywordId; |
|
577 do_check_true(stmt.executeStep()); |
|
578 stmt.reset(); |
|
579 // Check that item with invalid keyword has been corrected |
|
580 stmt.params["item_id"] = this._invalidKeywordItemId; |
|
581 stmt.params["keyword"] = this._invalidKeywordId; |
|
582 do_check_false(stmt.executeStep()); |
|
583 stmt.finalize(); |
|
584 // Check that item with invalid keyword has not been removed |
|
585 stmt = mDBConn.createStatement("SELECT id FROM moz_bookmarks WHERE id = :item_id"); |
|
586 stmt.params["item_id"] = this._invalidKeywordItemId; |
|
587 do_check_true(stmt.executeStep()); |
|
588 stmt.finalize(); |
|
589 } |
|
590 }); |
|
591 |
|
592 //------------------------------------------------------------------------------ |
|
593 |
|
594 tests.push({ |
|
595 name: "D.6", |
|
596 desc: "Fix wrong item types | bookmarks", |
|
597 |
|
598 _separatorId: null, |
|
599 _folderId: null, |
|
600 _placeId: null, |
|
601 |
|
602 setup: function() { |
|
603 // Add a place to ensure place_id = 1 is valid |
|
604 this._placeId = addPlace(); |
|
605 // Add a separator with a fk |
|
606 this._separatorId = addBookmark(this._placeId, bs.TYPE_SEPARATOR); |
|
607 // Add a folder with a fk |
|
608 this._folderId = addBookmark(this._placeId, bs.TYPE_FOLDER); |
|
609 }, |
|
610 |
|
611 check: function() { |
|
612 // Check that items with an fk have been converted to bookmarks |
|
613 let stmt = mDBConn.createStatement("SELECT id FROM moz_bookmarks WHERE id = :item_id AND type = :type"); |
|
614 stmt.params["item_id"] = this._separatorId; |
|
615 stmt.params["type"] = bs.TYPE_BOOKMARK; |
|
616 do_check_true(stmt.executeStep()); |
|
617 stmt.reset(); |
|
618 stmt.params["item_id"] = this._folderId; |
|
619 stmt.params["type"] = bs.TYPE_BOOKMARK; |
|
620 do_check_true(stmt.executeStep()); |
|
621 stmt.finalize(); |
|
622 } |
|
623 }); |
|
624 |
|
625 //------------------------------------------------------------------------------ |
|
626 |
|
627 tests.push({ |
|
628 name: "D.7", |
|
629 desc: "Fix wrong item types | bookmarks", |
|
630 |
|
631 _validBookmarkId: null, |
|
632 _invalidBookmarkId: null, |
|
633 _placeId: null, |
|
634 |
|
635 setup: function() { |
|
636 // Add a place to ensure place_id = 1 is valid |
|
637 this._placeId = addPlace(); |
|
638 // Add a bookmark with a valid place id |
|
639 this._validBookmarkId = addBookmark(this._placeId, bs.TYPE_BOOKMARK); |
|
640 // Add a bookmark with a null place id |
|
641 this._invalidBookmarkId = addBookmark(null, bs.TYPE_BOOKMARK); |
|
642 }, |
|
643 |
|
644 check: function() { |
|
645 // Check valid bookmark |
|
646 let stmt = mDBConn.createStatement("SELECT id FROM moz_bookmarks WHERE id = :item_id AND type = :type"); |
|
647 stmt.params["item_id"] = this._validBookmarkId; |
|
648 stmt.params["type"] = bs.TYPE_BOOKMARK; |
|
649 do_check_true(stmt.executeStep()); |
|
650 stmt.reset(); |
|
651 // Check invalid bookmark has been converted to a folder |
|
652 stmt.params["item_id"] = this._invalidBookmarkId; |
|
653 stmt.params["type"] = bs.TYPE_FOLDER; |
|
654 do_check_true(stmt.executeStep()); |
|
655 stmt.finalize(); |
|
656 } |
|
657 }); |
|
658 |
|
659 //------------------------------------------------------------------------------ |
|
660 |
|
661 tests.push({ |
|
662 name: "D.9", |
|
663 desc: "Fix wrong parents", |
|
664 |
|
665 _bookmarkId: null, |
|
666 _separatorId: null, |
|
667 _bookmarkId1: null, |
|
668 _bookmarkId2: null, |
|
669 _placeId: null, |
|
670 |
|
671 setup: function() { |
|
672 // Add a place to ensure place_id = 1 is valid |
|
673 this._placeId = addPlace(); |
|
674 // Insert a bookmark |
|
675 this._bookmarkId = addBookmark(this._placeId, bs.TYPE_BOOKMARK); |
|
676 // Insert a separator |
|
677 this._separatorId = addBookmark(null, bs.TYPE_SEPARATOR); |
|
678 // Create 3 children of these items |
|
679 this._bookmarkId1 = addBookmark(this._placeId, bs.TYPE_BOOKMARK, this._bookmarkId); |
|
680 this._bookmarkId2 = addBookmark(this._placeId, bs.TYPE_BOOKMARK, this._separatorId); |
|
681 }, |
|
682 |
|
683 check: function() { |
|
684 // Check that bookmarks are now children of a real folder (unsorted) |
|
685 let stmt = mDBConn.createStatement("SELECT id FROM moz_bookmarks WHERE id = :item_id AND parent = :parent"); |
|
686 stmt.params["item_id"] = this._bookmarkId1; |
|
687 stmt.params["parent"] = bs.unfiledBookmarksFolder; |
|
688 do_check_true(stmt.executeStep()); |
|
689 stmt.reset(); |
|
690 stmt.params["item_id"] = this._bookmarkId2; |
|
691 stmt.params["parent"] = bs.unfiledBookmarksFolder; |
|
692 do_check_true(stmt.executeStep()); |
|
693 stmt.finalize(); |
|
694 } |
|
695 }); |
|
696 |
|
697 //------------------------------------------------------------------------------ |
|
698 |
|
699 tests.push({ |
|
700 name: "D.10", |
|
701 desc: "Recalculate positions", |
|
702 |
|
703 _unfiledBookmarks: [], |
|
704 _toolbarBookmarks: [], |
|
705 |
|
706 setup: function() { |
|
707 const NUM_BOOKMARKS = 20; |
|
708 bs.runInBatchMode({ |
|
709 runBatched: function (aUserData) { |
|
710 // Add bookmarks to two folders to better perturbate the table. |
|
711 for (let i = 0; i < NUM_BOOKMARKS; i++) { |
|
712 bs.insertBookmark(PlacesUtils.unfiledBookmarksFolderId, |
|
713 NetUtil.newURI("http://example.com/"), |
|
714 bs.DEFAULT_INDEX, "testbookmark"); |
|
715 } |
|
716 for (let i = 0; i < NUM_BOOKMARKS; i++) { |
|
717 bs.insertBookmark(PlacesUtils.toolbarFolderId, |
|
718 NetUtil.newURI("http://example.com/"), |
|
719 bs.DEFAULT_INDEX, "testbookmark"); |
|
720 } |
|
721 } |
|
722 }, null); |
|
723 |
|
724 function randomize_positions(aParent, aResultArray) { |
|
725 let stmt = mDBConn.createStatement( |
|
726 "UPDATE moz_bookmarks SET position = :rand " + |
|
727 "WHERE id IN ( " + |
|
728 "SELECT id FROM moz_bookmarks WHERE parent = :parent " + |
|
729 "ORDER BY RANDOM() LIMIT 1 " + |
|
730 ") " |
|
731 ); |
|
732 for (let i = 0; i < (NUM_BOOKMARKS / 2); i++) { |
|
733 stmt.params["parent"] = aParent; |
|
734 stmt.params["rand"] = Math.round(Math.random() * (NUM_BOOKMARKS - 1)); |
|
735 stmt.execute(); |
|
736 stmt.reset(); |
|
737 } |
|
738 stmt.finalize(); |
|
739 |
|
740 // Build the expected ordered list of bookmarks. |
|
741 stmt = mDBConn.createStatement( |
|
742 "SELECT id, position " + |
|
743 "FROM moz_bookmarks WHERE parent = :parent " + |
|
744 "ORDER BY position ASC, ROWID ASC " |
|
745 ); |
|
746 stmt.params["parent"] = aParent; |
|
747 while (stmt.executeStep()) { |
|
748 aResultArray.push(stmt.row.id); |
|
749 print(stmt.row.id + "\t" + stmt.row.position + "\t" + |
|
750 (aResultArray.length - 1)); |
|
751 } |
|
752 stmt.finalize(); |
|
753 } |
|
754 |
|
755 // Set random positions for the added bookmarks. |
|
756 randomize_positions(PlacesUtils.unfiledBookmarksFolderId, |
|
757 this._unfiledBookmarks); |
|
758 randomize_positions(PlacesUtils.toolbarFolderId, this._toolbarBookmarks); |
|
759 }, |
|
760 |
|
761 check: function() { |
|
762 function check_order(aParent, aResultArray) { |
|
763 // Build the expected ordered list of bookmarks. |
|
764 let stmt = mDBConn.createStatement( |
|
765 "SELECT id, position FROM moz_bookmarks WHERE parent = :parent " + |
|
766 "ORDER BY position ASC" |
|
767 ); |
|
768 stmt.params["parent"] = aParent; |
|
769 let pass = true; |
|
770 while (stmt.executeStep()) { |
|
771 print(stmt.row.id + "\t" + stmt.row.position); |
|
772 if (aResultArray.indexOf(stmt.row.id) != stmt.row.position) { |
|
773 pass = false; |
|
774 } |
|
775 } |
|
776 stmt.finalize(); |
|
777 if (!pass) { |
|
778 dump_table("moz_bookmarks"); |
|
779 do_throw("Unexpected unfiled bookmarks order."); |
|
780 } |
|
781 } |
|
782 |
|
783 check_order(PlacesUtils.unfiledBookmarksFolderId, this._unfiledBookmarks); |
|
784 check_order(PlacesUtils.toolbarFolderId, this._toolbarBookmarks); |
|
785 } |
|
786 }); |
|
787 |
|
788 //------------------------------------------------------------------------------ |
|
789 |
|
790 tests.push({ |
|
791 name: "D.12", |
|
792 desc: "Fix empty-named tags", |
|
793 |
|
794 setup: function() { |
|
795 // Add a place to ensure place_id = 1 is valid |
|
796 let placeId = addPlace(); |
|
797 // Create a empty-named tag. |
|
798 this._untitledTagId = addBookmark(null, bs.TYPE_FOLDER, bs.tagsFolder, null, null, ""); |
|
799 // Insert a bookmark in the tag, otherwise it will be removed. |
|
800 addBookmark(placeId, bs.TYPE_BOOKMARK, this._untitledTagId); |
|
801 // Create a empty-named folder. |
|
802 this._untitledFolderId = addBookmark(null, bs.TYPE_FOLDER, bs.toolbarFolder, null, null, ""); |
|
803 // Create a titled tag. |
|
804 this._titledTagId = addBookmark(null, bs.TYPE_FOLDER, bs.tagsFolder, null, null, "titledTag"); |
|
805 // Insert a bookmark in the tag, otherwise it will be removed. |
|
806 addBookmark(placeId, bs.TYPE_BOOKMARK, this._titledTagId); |
|
807 // Create a titled folder. |
|
808 this._titledFolderId = addBookmark(null, bs.TYPE_FOLDER, bs.toolbarFolder, null, null, "titledFolder"); |
|
809 }, |
|
810 |
|
811 check: function() { |
|
812 // Check that valid bookmark is still there |
|
813 let stmt = mDBConn.createStatement( |
|
814 "SELECT title FROM moz_bookmarks WHERE id = :id" |
|
815 ); |
|
816 stmt.params["id"] = this._untitledTagId; |
|
817 do_check_true(stmt.executeStep()); |
|
818 do_check_eq(stmt.row.title, "(notitle)"); |
|
819 stmt.reset(); |
|
820 stmt.params["id"] = this._untitledFolderId; |
|
821 do_check_true(stmt.executeStep()); |
|
822 do_check_eq(stmt.row.title, ""); |
|
823 stmt.reset(); |
|
824 stmt.params["id"] = this._titledTagId; |
|
825 do_check_true(stmt.executeStep()); |
|
826 do_check_eq(stmt.row.title, "titledTag"); |
|
827 stmt.reset(); |
|
828 stmt.params["id"] = this._titledFolderId; |
|
829 do_check_true(stmt.executeStep()); |
|
830 do_check_eq(stmt.row.title, "titledFolder"); |
|
831 stmt.finalize(); |
|
832 } |
|
833 }); |
|
834 |
|
835 //------------------------------------------------------------------------------ |
|
836 |
|
837 tests.push({ |
|
838 name: "E.1", |
|
839 desc: "Remove orphan icons", |
|
840 |
|
841 _placeId: null, |
|
842 |
|
843 setup: function() { |
|
844 // Insert favicon entries |
|
845 let stmt = mDBConn.createStatement("INSERT INTO moz_favicons (id, url) VALUES(:favicon_id, :url)"); |
|
846 stmt.params["favicon_id"] = 1; |
|
847 stmt.params["url"] = "http://www1.mozilla.org/favicon.ico"; |
|
848 stmt.execute(); |
|
849 stmt.reset(); |
|
850 stmt.params["favicon_id"] = 2; |
|
851 stmt.params["url"] = "http://www2.mozilla.org/favicon.ico"; |
|
852 stmt.execute(); |
|
853 stmt.finalize(); |
|
854 // Insert a place using the existing favicon entry |
|
855 this._placeId = addPlace("http://www.mozilla.org", 1); |
|
856 }, |
|
857 |
|
858 check: function() { |
|
859 // Check that used icon is still there |
|
860 let stmt = mDBConn.createStatement("SELECT id FROM moz_favicons WHERE id = :favicon_id"); |
|
861 stmt.params["favicon_id"] = 1; |
|
862 do_check_true(stmt.executeStep()); |
|
863 stmt.reset(); |
|
864 // Check that unused icon has been removed |
|
865 stmt.params["favicon_id"] = 2; |
|
866 do_check_false(stmt.executeStep()); |
|
867 stmt.finalize(); |
|
868 } |
|
869 }); |
|
870 |
|
871 //------------------------------------------------------------------------------ |
|
872 |
|
873 tests.push({ |
|
874 name: "F.1", |
|
875 desc: "Remove orphan visits", |
|
876 |
|
877 _placeId: null, |
|
878 _invalidPlaceId: 1337, |
|
879 |
|
880 setup: function() { |
|
881 // Add a place to ensure place_id = 1 is valid |
|
882 this._placeId = addPlace(); |
|
883 // Add a valid visit and an invalid one |
|
884 stmt = mDBConn.createStatement("INSERT INTO moz_historyvisits(place_id) VALUES (:place_id)"); |
|
885 stmt.params["place_id"] = this._placeId; |
|
886 stmt.execute(); |
|
887 stmt.reset(); |
|
888 stmt.params["place_id"] = this._invalidPlaceId; |
|
889 stmt.execute(); |
|
890 stmt.finalize(); |
|
891 }, |
|
892 |
|
893 check: function() { |
|
894 // Check that valid visit is still there |
|
895 let stmt = mDBConn.createStatement("SELECT id FROM moz_historyvisits WHERE place_id = :place_id"); |
|
896 stmt.params["place_id"] = this._placeId; |
|
897 do_check_true(stmt.executeStep()); |
|
898 stmt.reset(); |
|
899 // Check that invalid visit has been removed |
|
900 stmt.params["place_id"] = this._invalidPlaceId; |
|
901 do_check_false(stmt.executeStep()); |
|
902 stmt.finalize(); |
|
903 } |
|
904 }); |
|
905 |
|
906 //------------------------------------------------------------------------------ |
|
907 |
|
908 tests.push({ |
|
909 name: "G.1", |
|
910 desc: "Remove orphan input history", |
|
911 |
|
912 _placeId: null, |
|
913 _invalidPlaceId: 1337, |
|
914 |
|
915 setup: function() { |
|
916 // Add a place to ensure place_id = 1 is valid |
|
917 this._placeId = addPlace(); |
|
918 // Add input history entries |
|
919 let stmt = mDBConn.createStatement("INSERT INTO moz_inputhistory (place_id, input) VALUES (:place_id, :input)"); |
|
920 stmt.params["place_id"] = this._placeId; |
|
921 stmt.params["input"] = "moz"; |
|
922 stmt.execute(); |
|
923 stmt.reset(); |
|
924 stmt.params["place_id"] = this._invalidPlaceId; |
|
925 stmt.params["input"] = "moz"; |
|
926 stmt.execute(); |
|
927 stmt.finalize(); |
|
928 }, |
|
929 |
|
930 check: function() { |
|
931 // Check that inputhistory on valid place is still there |
|
932 let stmt = mDBConn.createStatement("SELECT place_id FROM moz_inputhistory WHERE place_id = :place_id"); |
|
933 stmt.params["place_id"] = this._placeId; |
|
934 do_check_true(stmt.executeStep()); |
|
935 stmt.reset(); |
|
936 // Check that inputhistory on invalid place has gone |
|
937 stmt.params["place_id"] = this._invalidPlaceId; |
|
938 do_check_false(stmt.executeStep()); |
|
939 stmt.finalize(); |
|
940 } |
|
941 }); |
|
942 |
|
943 //------------------------------------------------------------------------------ |
|
944 |
|
945 tests.push({ |
|
946 name: "H.1", |
|
947 desc: "Remove item annos with an invalid attribute", |
|
948 |
|
949 _usedItemAttribute: "usedItem", |
|
950 _bookmarkId: null, |
|
951 _placeId: null, |
|
952 |
|
953 setup: function() { |
|
954 // Add a place to ensure place_id = 1 is valid |
|
955 this._placeId = addPlace(); |
|
956 // Insert a bookmark |
|
957 this._bookmarkId = addBookmark(this._placeId); |
|
958 // Add a used attribute. |
|
959 let stmt = mDBConn.createStatement("INSERT INTO moz_anno_attributes (name) VALUES (:anno)"); |
|
960 stmt.params['anno'] = this._usedItemAttribute; |
|
961 stmt.execute(); |
|
962 stmt.finalize(); |
|
963 stmt = mDBConn.createStatement("INSERT INTO moz_items_annos (item_id, anno_attribute_id) VALUES(:item_id, (SELECT id FROM moz_anno_attributes WHERE name = :anno))"); |
|
964 stmt.params['item_id'] = this._bookmarkId; |
|
965 stmt.params['anno'] = this._usedItemAttribute; |
|
966 stmt.execute(); |
|
967 stmt.finalize(); |
|
968 // Add an annotation with a nonexistent attribute |
|
969 stmt = mDBConn.createStatement("INSERT INTO moz_items_annos (item_id, anno_attribute_id) VALUES(:item_id, 1337)"); |
|
970 stmt.params['item_id'] = this._bookmarkId; |
|
971 stmt.execute(); |
|
972 stmt.finalize(); |
|
973 }, |
|
974 |
|
975 check: function() { |
|
976 // Check that used attribute is still there |
|
977 let stmt = mDBConn.createStatement("SELECT id FROM moz_anno_attributes WHERE name = :anno"); |
|
978 stmt.params['anno'] = this._usedItemAttribute; |
|
979 do_check_true(stmt.executeStep()); |
|
980 stmt.finalize(); |
|
981 // check that annotation with valid attribute is still there |
|
982 stmt = mDBConn.createStatement("SELECT id FROM moz_items_annos WHERE anno_attribute_id = (SELECT id FROM moz_anno_attributes WHERE name = :anno)"); |
|
983 stmt.params['anno'] = this._usedItemAttribute; |
|
984 do_check_true(stmt.executeStep()); |
|
985 stmt.finalize(); |
|
986 // Check that annotation with bogus attribute has been removed |
|
987 stmt = mDBConn.createStatement("SELECT id FROM moz_items_annos WHERE anno_attribute_id = 1337"); |
|
988 do_check_false(stmt.executeStep()); |
|
989 stmt.finalize(); |
|
990 } |
|
991 }); |
|
992 |
|
993 //------------------------------------------------------------------------------ |
|
994 |
|
995 tests.push({ |
|
996 name: "H.2", |
|
997 desc: "Remove orphan item annotations", |
|
998 |
|
999 _usedItemAttribute: "usedItem", |
|
1000 _bookmarkId: null, |
|
1001 _invalidBookmarkId: 8888, |
|
1002 _placeId: null, |
|
1003 |
|
1004 setup: function() { |
|
1005 // Add a place to ensure place_id = 1 is valid |
|
1006 this._placeId = addPlace(); |
|
1007 // Insert a bookmark |
|
1008 this._bookmarkId = addBookmark(this._placeId); |
|
1009 // Add a used attribute. |
|
1010 stmt = mDBConn.createStatement("INSERT INTO moz_anno_attributes (name) VALUES (:anno)"); |
|
1011 stmt.params['anno'] = this._usedItemAttribute; |
|
1012 stmt.execute(); |
|
1013 stmt.finalize(); |
|
1014 stmt = mDBConn.createStatement("INSERT INTO moz_items_annos (item_id, anno_attribute_id) VALUES (:item_id, (SELECT id FROM moz_anno_attributes WHERE name = :anno))"); |
|
1015 stmt.params["item_id"] = this._bookmarkId; |
|
1016 stmt.params["anno"] = this._usedItemAttribute; |
|
1017 stmt.execute(); |
|
1018 stmt.reset(); |
|
1019 // Add an annotation to a nonexistent item |
|
1020 stmt.params["item_id"] = this._invalidBookmarkId; |
|
1021 stmt.params["anno"] = this._usedItemAttribute; |
|
1022 stmt.execute(); |
|
1023 stmt.finalize(); |
|
1024 }, |
|
1025 |
|
1026 check: function() { |
|
1027 // Check that used attribute is still there |
|
1028 let stmt = mDBConn.createStatement("SELECT id FROM moz_anno_attributes WHERE name = :anno"); |
|
1029 stmt.params['anno'] = this._usedItemAttribute; |
|
1030 do_check_true(stmt.executeStep()); |
|
1031 stmt.finalize(); |
|
1032 // check that annotation with valid attribute is still there |
|
1033 stmt = mDBConn.createStatement("SELECT id FROM moz_items_annos WHERE anno_attribute_id = (SELECT id FROM moz_anno_attributes WHERE name = :anno)"); |
|
1034 stmt.params['anno'] = this._usedItemAttribute; |
|
1035 do_check_true(stmt.executeStep()); |
|
1036 stmt.finalize(); |
|
1037 // Check that an annotation to a nonexistent page has been removed |
|
1038 stmt = mDBConn.createStatement("SELECT id FROM moz_items_annos WHERE item_id = 8888"); |
|
1039 do_check_false(stmt.executeStep()); |
|
1040 stmt.finalize(); |
|
1041 } |
|
1042 }); |
|
1043 |
|
1044 |
|
1045 //------------------------------------------------------------------------------ |
|
1046 |
|
1047 tests.push({ |
|
1048 name: "I.1", |
|
1049 desc: "Remove unused keywords", |
|
1050 |
|
1051 _bookmarkId: null, |
|
1052 _placeId: null, |
|
1053 |
|
1054 setup: function() { |
|
1055 // Insert 2 keywords |
|
1056 let stmt = mDBConn.createStatement("INSERT INTO moz_keywords (id, keyword) VALUES(:id, :keyword)"); |
|
1057 stmt.params["id"] = 1; |
|
1058 stmt.params["keyword"] = "used"; |
|
1059 stmt.execute(); |
|
1060 stmt.reset(); |
|
1061 stmt.params["id"] = 2; |
|
1062 stmt.params["keyword"] = "unused"; |
|
1063 stmt.execute(); |
|
1064 stmt.finalize(); |
|
1065 // Add a place to ensure place_id = 1 is valid |
|
1066 this._placeId = addPlace(); |
|
1067 // Insert a bookmark using the "used" keyword |
|
1068 this._bookmarkId = addBookmark(this._placeId, bs.TYPE_BOOKMARK, bs.unfiledBookmarksFolder, 1); |
|
1069 }, |
|
1070 |
|
1071 check: function() { |
|
1072 // Check that "used" keyword is still there |
|
1073 let stmt = mDBConn.createStatement("SELECT id FROM moz_keywords WHERE keyword = :keyword"); |
|
1074 stmt.params["keyword"] = "used"; |
|
1075 do_check_true(stmt.executeStep()); |
|
1076 stmt.reset(); |
|
1077 // Check that "unused" keyword has gone |
|
1078 stmt.params["keyword"] = "unused"; |
|
1079 do_check_false(stmt.executeStep()); |
|
1080 stmt.finalize(); |
|
1081 } |
|
1082 }); |
|
1083 |
|
1084 |
|
1085 //------------------------------------------------------------------------------ |
|
1086 |
|
1087 tests.push({ |
|
1088 name: "L.1", |
|
1089 desc: "Fix wrong favicon ids", |
|
1090 |
|
1091 _validIconPlaceId: null, |
|
1092 _invalidIconPlaceId: null, |
|
1093 |
|
1094 setup: function() { |
|
1095 // Insert a favicon entry |
|
1096 let stmt = mDBConn.createStatement("INSERT INTO moz_favicons (id, url) VALUES(1, :url)"); |
|
1097 stmt.params["url"] = "http://www.mozilla.org/favicon.ico"; |
|
1098 stmt.execute(); |
|
1099 stmt.finalize(); |
|
1100 // Insert a place using the existing favicon entry |
|
1101 this._validIconPlaceId = addPlace("http://www1.mozilla.org", 1); |
|
1102 |
|
1103 // Insert a place using a nonexistent favicon entry |
|
1104 this._invalidIconPlaceId = addPlace("http://www2.mozilla.org", 1337); |
|
1105 }, |
|
1106 |
|
1107 check: function() { |
|
1108 // Check that bogus favicon is not there |
|
1109 let stmt = mDBConn.createStatement("SELECT id FROM moz_places WHERE favicon_id = :favicon_id"); |
|
1110 stmt.params["favicon_id"] = 1337; |
|
1111 do_check_false(stmt.executeStep()); |
|
1112 stmt.reset(); |
|
1113 // Check that valid favicon is still there |
|
1114 stmt.params["favicon_id"] = 1; |
|
1115 do_check_true(stmt.executeStep()); |
|
1116 stmt.finalize(); |
|
1117 // Check that place entries are there |
|
1118 stmt = mDBConn.createStatement("SELECT id FROM moz_places WHERE id = :place_id"); |
|
1119 stmt.params["place_id"] = this._validIconPlaceId; |
|
1120 do_check_true(stmt.executeStep()); |
|
1121 stmt.reset(); |
|
1122 stmt.params["place_id"] = this._invalidIconPlaceId; |
|
1123 do_check_true(stmt.executeStep()); |
|
1124 stmt.finalize(); |
|
1125 } |
|
1126 }); |
|
1127 |
|
1128 //------------------------------------------------------------------------------ |
|
1129 |
|
1130 tests.push({ |
|
1131 name: "L.2", |
|
1132 desc: "Recalculate visit_count and last_visit_date", |
|
1133 |
|
1134 setup: function() { |
|
1135 function setVisitCount(aURL, aValue) { |
|
1136 let stmt = mDBConn.createStatement( |
|
1137 "UPDATE moz_places SET visit_count = :count WHERE url = :url" |
|
1138 ); |
|
1139 stmt.params.count = aValue; |
|
1140 stmt.params.url = aURL; |
|
1141 stmt.execute(); |
|
1142 stmt.finalize(); |
|
1143 } |
|
1144 function setLastVisitDate(aURL, aValue) { |
|
1145 let stmt = mDBConn.createStatement( |
|
1146 "UPDATE moz_places SET last_visit_date = :date WHERE url = :url" |
|
1147 ); |
|
1148 stmt.params.date = aValue; |
|
1149 stmt.params.url = aURL; |
|
1150 stmt.execute(); |
|
1151 stmt.finalize(); |
|
1152 } |
|
1153 |
|
1154 let now = Date.now() * 1000; |
|
1155 // Add a page with 1 visit. |
|
1156 let url = "http://1.moz.org/"; |
|
1157 yield promiseAddVisits({ uri: uri(url), visitDate: now++ }); |
|
1158 // Add a page with 1 visit and set wrong visit_count. |
|
1159 url = "http://2.moz.org/"; |
|
1160 yield promiseAddVisits({ uri: uri(url), visitDate: now++ }); |
|
1161 setVisitCount(url, 10); |
|
1162 // Add a page with 1 visit and set wrong last_visit_date. |
|
1163 url = "http://3.moz.org/"; |
|
1164 yield promiseAddVisits({ uri: uri(url), visitDate: now++ }); |
|
1165 setLastVisitDate(url, now++); |
|
1166 // Add a page with 1 visit and set wrong stats. |
|
1167 url = "http://4.moz.org/"; |
|
1168 yield promiseAddVisits({ uri: uri(url), visitDate: now++ }); |
|
1169 setVisitCount(url, 10); |
|
1170 setLastVisitDate(url, now++); |
|
1171 |
|
1172 // Add a page without visits. |
|
1173 let url = "http://5.moz.org/"; |
|
1174 addPlace(url); |
|
1175 // Add a page without visits and set wrong visit_count. |
|
1176 url = "http://6.moz.org/"; |
|
1177 addPlace(url); |
|
1178 setVisitCount(url, 10); |
|
1179 // Add a page without visits and set wrong last_visit_date. |
|
1180 url = "http://7.moz.org/"; |
|
1181 addPlace(url); |
|
1182 setLastVisitDate(url, now++); |
|
1183 // Add a page without visits and set wrong stats. |
|
1184 url = "http://8.moz.org/"; |
|
1185 addPlace(url); |
|
1186 setVisitCount(url, 10); |
|
1187 setLastVisitDate(url, now++); |
|
1188 }, |
|
1189 |
|
1190 check: function() { |
|
1191 let stmt = mDBConn.createStatement( |
|
1192 "SELECT h.id FROM moz_places h " + |
|
1193 "JOIN moz_historyvisits v ON v.place_id = h.id AND visit_type NOT IN (0,4,7,8) " + |
|
1194 "GROUP BY h.id HAVING h.visit_count <> count(*) " + |
|
1195 "UNION ALL " + |
|
1196 "SELECT h.id FROM moz_places h " + |
|
1197 "JOIN moz_historyvisits v ON v.place_id = h.id " + |
|
1198 "GROUP BY h.id HAVING h.last_visit_date <> MAX(v.visit_date) " |
|
1199 ); |
|
1200 do_check_false(stmt.executeStep()); |
|
1201 stmt.finalize(); |
|
1202 } |
|
1203 }); |
|
1204 |
|
1205 //------------------------------------------------------------------------------ |
|
1206 |
|
1207 tests.push({ |
|
1208 name: "L.3", |
|
1209 desc: "recalculate hidden for redirects.", |
|
1210 |
|
1211 setup: function() { |
|
1212 promiseAddVisits([ |
|
1213 { uri: NetUtil.newURI("http://l3.moz.org/"), |
|
1214 transition: TRANSITION_TYPED }, |
|
1215 { uri: NetUtil.newURI("http://l3.moz.org/redirecting/"), |
|
1216 transition: TRANSITION_TYPED }, |
|
1217 { uri: NetUtil.newURI("http://l3.moz.org/redirecting2/"), |
|
1218 transition: TRANSITION_REDIRECT_TEMPORARY, |
|
1219 referrer: NetUtil.newURI("http://l3.moz.org/redirecting/") }, |
|
1220 { uri: NetUtil.newURI("http://l3.moz.org/target/"), |
|
1221 transition: TRANSITION_REDIRECT_PERMANENT, |
|
1222 referrer: NetUtil.newURI("http://l3.moz.org/redirecting2/") }, |
|
1223 ]); |
|
1224 }, |
|
1225 |
|
1226 asyncCheck: function(aCallback) { |
|
1227 let stmt = mDBConn.createAsyncStatement( |
|
1228 "SELECT h.url FROM moz_places h WHERE h.hidden = 1" |
|
1229 ); |
|
1230 stmt.executeAsync({ |
|
1231 _count: 0, |
|
1232 handleResult: function(aResultSet) { |
|
1233 for (let row; (row = aResultSet.getNextRow());) { |
|
1234 let url = row.getResultByIndex(0); |
|
1235 do_check_true(/redirecting/.test(url)); |
|
1236 this._count++; |
|
1237 } |
|
1238 }, |
|
1239 handleError: function(aError) { |
|
1240 }, |
|
1241 handleCompletion: function(aReason) { |
|
1242 dump_table("moz_places"); |
|
1243 dump_table("moz_historyvisits"); |
|
1244 do_check_eq(aReason, Ci.mozIStorageStatementCallback.REASON_FINISHED); |
|
1245 do_check_eq(this._count, 2); |
|
1246 aCallback(); |
|
1247 } |
|
1248 }); |
|
1249 stmt.finalize(); |
|
1250 } |
|
1251 }); |
|
1252 |
|
1253 //------------------------------------------------------------------------------ |
|
1254 |
|
1255 tests.push({ |
|
1256 name: "Z", |
|
1257 desc: "Sanity: Preventive maintenance does not touch valid items", |
|
1258 |
|
1259 _uri1: uri("http://www1.mozilla.org"), |
|
1260 _uri2: uri("http://www2.mozilla.org"), |
|
1261 _folderId: null, |
|
1262 _bookmarkId: null, |
|
1263 _separatorId: null, |
|
1264 |
|
1265 setup: function() { |
|
1266 // use valid api calls to create a bunch of items |
|
1267 yield promiseAddVisits([ |
|
1268 { uri: this._uri1 }, |
|
1269 { uri: this._uri2 }, |
|
1270 ]); |
|
1271 |
|
1272 this._folderId = bs.createFolder(bs.toolbarFolder, "testfolder", |
|
1273 bs.DEFAULT_INDEX); |
|
1274 do_check_true(this._folderId > 0); |
|
1275 this._bookmarkId = bs.insertBookmark(this._folderId, this._uri1, |
|
1276 bs.DEFAULT_INDEX, "testbookmark"); |
|
1277 do_check_true(this._bookmarkId > 0); |
|
1278 this._separatorId = bs.insertSeparator(bs.unfiledBookmarksFolder, |
|
1279 bs.DEFAULT_INDEX); |
|
1280 do_check_true(this._separatorId > 0); |
|
1281 ts.tagURI(this._uri1, ["testtag"]); |
|
1282 fs.setAndFetchFaviconForPage(this._uri2, SMALLPNG_DATA_URI, false, |
|
1283 PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE); |
|
1284 bs.setKeywordForBookmark(this._bookmarkId, "testkeyword"); |
|
1285 as.setPageAnnotation(this._uri2, "anno", "anno", 0, as.EXPIRE_NEVER); |
|
1286 as.setItemAnnotation(this._bookmarkId, "anno", "anno", 0, as.EXPIRE_NEVER); |
|
1287 }, |
|
1288 |
|
1289 asyncCheck: function (aCallback) { |
|
1290 // Check that all items are correct |
|
1291 PlacesUtils.asyncHistory.isURIVisited(this._uri1, function(aURI, aIsVisited) { |
|
1292 do_check_true(aIsVisited); |
|
1293 PlacesUtils.asyncHistory.isURIVisited(this._uri2, function(aURI, aIsVisited) { |
|
1294 do_check_true(aIsVisited); |
|
1295 |
|
1296 do_check_eq(bs.getBookmarkURI(this._bookmarkId).spec, this._uri1.spec); |
|
1297 do_check_eq(bs.getItemIndex(this._folderId), 0); |
|
1298 |
|
1299 do_check_eq(bs.getItemType(this._folderId), bs.TYPE_FOLDER); |
|
1300 do_check_eq(bs.getItemType(this._separatorId), bs.TYPE_SEPARATOR); |
|
1301 |
|
1302 do_check_eq(ts.getTagsForURI(this._uri1).length, 1); |
|
1303 do_check_eq(bs.getKeywordForBookmark(this._bookmarkId), "testkeyword"); |
|
1304 do_check_eq(as.getPageAnnotation(this._uri2, "anno"), "anno"); |
|
1305 do_check_eq(as.getItemAnnotation(this._bookmarkId, "anno"), "anno"); |
|
1306 |
|
1307 fs.getFaviconURLForPage(this._uri2, function (aFaviconURI) { |
|
1308 do_check_true(aFaviconURI.equals(SMALLPNG_DATA_URI)); |
|
1309 aCallback(); |
|
1310 }); |
|
1311 }.bind(this)); |
|
1312 }.bind(this)); |
|
1313 } |
|
1314 }); |
|
1315 |
|
1316 //------------------------------------------------------------------------------ |
|
1317 |
|
1318 // main |
|
1319 function run_test() |
|
1320 { |
|
1321 run_next_test(); |
|
1322 } |
|
1323 |
|
1324 add_task(function test_preventive_maintenance() |
|
1325 { |
|
1326 // Force initialization of the bookmarks hash. This test could cause |
|
1327 // it to go out of sync due to direct queries on the database. |
|
1328 yield promiseAddVisits(uri("http://force.bookmarks.hash")); |
|
1329 do_check_false(bs.isBookmarked(uri("http://force.bookmarks.hash"))); |
|
1330 |
|
1331 // Get current bookmarks max ID for cleanup |
|
1332 let stmt = mDBConn.createStatement("SELECT MAX(id) FROM moz_bookmarks"); |
|
1333 stmt.executeStep(); |
|
1334 defaultBookmarksMaxId = stmt.getInt32(0); |
|
1335 stmt.finalize(); |
|
1336 do_check_true(defaultBookmarksMaxId > 0); |
|
1337 |
|
1338 for ([, test] in Iterator(tests)) { |
|
1339 dump("\nExecuting test: " + test.name + "\n" + "*** " + test.desc + "\n"); |
|
1340 yield test.setup(); |
|
1341 |
|
1342 let promiseMaintenanceFinished = |
|
1343 promiseTopicObserved(FINISHED_MAINTENANCE_NOTIFICATION_TOPIC); |
|
1344 PlacesDBUtils.maintenanceOnIdle(); |
|
1345 yield promiseMaintenanceFinished; |
|
1346 |
|
1347 // Check the lastMaintenance time has been saved. |
|
1348 do_check_neq(Services.prefs.getIntPref("places.database.lastMaintenance"), null); |
|
1349 |
|
1350 if (test.asyncCheck) { |
|
1351 let deferred = Promise.defer(); |
|
1352 test.asyncCheck(deferred.resolve); |
|
1353 yield deferred.promise; |
|
1354 } else { |
|
1355 test.check(); |
|
1356 } |
|
1357 |
|
1358 cleanDatabase(); |
|
1359 } |
|
1360 |
|
1361 // Sanity check: all roots should be intact |
|
1362 do_check_eq(bs.getFolderIdForItem(bs.placesRoot), 0); |
|
1363 do_check_eq(bs.getFolderIdForItem(bs.bookmarksMenuFolder), bs.placesRoot); |
|
1364 do_check_eq(bs.getFolderIdForItem(bs.tagsFolder), bs.placesRoot); |
|
1365 do_check_eq(bs.getFolderIdForItem(bs.unfiledBookmarksFolder), bs.placesRoot); |
|
1366 do_check_eq(bs.getFolderIdForItem(bs.toolbarFolder), bs.placesRoot); |
|
1367 }); |