Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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/. */
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 */
13 // Include PlacesDBUtils module
14 Components.utils.import("resource://gre/modules/PlacesDBUtils.jsm");
16 const FINISHED_MAINTENANCE_NOTIFICATION_TOPIC = "places-maintenance-finished";
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;
25 let mDBConn = hs.QueryInterface(Ci.nsPIPlacesDatabase).DBConnection;
27 //------------------------------------------------------------------------------
28 // Helpers
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 }
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 }
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 }
70 //------------------------------------------------------------------------------
71 // Tests
73 let tests = [];
75 //------------------------------------------------------------------------------
77 tests.push({
78 name: "A.1",
79 desc: "Remove obsolete annotations from moz_annos",
81 _obsoleteWeaveAttribute: "weave/test",
82 _placeId: null,
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 },
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 });
117 tests.push({
118 name: "A.2",
119 desc: "Remove obsolete annotations from moz_items_annos",
121 _obsoleteSyncAttribute: "sync/children",
122 _obsoleteGuidAttribute: "placesInternal/GUID",
123 _obsoleteWeaveAttribute: "weave/test",
124 _placeId: null,
125 _bookmarkId: null,
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 },
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 });
170 tests.push({
171 name: "A.3",
172 desc: "Remove unused attributes",
174 _usedPageAttribute: "usedPage",
175 _usedItemAttribute: "usedItem",
176 _unusedAttribute: "unused",
177 _placeId: null,
178 _bookmarkId: null,
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();
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 },
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 });
225 //------------------------------------------------------------------------------
227 tests.push({
228 name: "B.1",
229 desc: "Remove annotations with an invalid attribute",
231 _usedPageAttribute: "usedPage",
232 _placeId: null,
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 },
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 });
272 //------------------------------------------------------------------------------
274 tests.push({
275 name: "B.2",
276 desc: "Remove orphan page annotations",
278 _usedPageAttribute: "usedPage",
279 _placeId: null,
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 },
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 });
319 //------------------------------------------------------------------------------
320 tests.push({
321 name: "C.1",
322 desc: "fix missing Places root",
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);
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 },
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 });
349 //------------------------------------------------------------------------------
350 tests.push({
351 name: "C.2",
352 desc: "Fix roots titles",
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 },
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 });
378 //------------------------------------------------------------------------------
380 tests.push({
381 name: "D.1",
382 desc: "Remove items without a valid place",
384 _validItemId: null,
385 _invalidItemId: null,
386 _placeId: null,
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 },
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 });
410 //------------------------------------------------------------------------------
412 tests.push({
413 name: "D.2",
414 desc: "Remove items that are not uri bookmarks from tag containers",
416 _tagId: null,
417 _bookmarkId: null,
418 _separatorId: null,
419 _folderId: null,
420 _placeId: null,
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 },
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 });
455 //------------------------------------------------------------------------------
457 tests.push({
458 name: "D.3",
459 desc: "Remove empty tags",
461 _tagId: null,
462 _bookmarkId: null,
463 _emptyTagId: null,
464 _placeId: null,
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 },
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 });
498 //------------------------------------------------------------------------------
500 tests.push({
501 name: "D.4",
502 desc: "Move orphan items to unsorted folder",
504 _orphanBookmarkId: null,
505 _orphanSeparatorId: null,
506 _orphanFolderId: null,
507 _bookmarkId: null,
508 _placeId: null,
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 },
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 });
545 //------------------------------------------------------------------------------
547 tests.push({
548 name: "D.5",
549 desc: "Fix wrong keywords",
551 _validKeywordItemId: null,
552 _invalidKeywordItemId: null,
553 _validKeywordId: 1,
554 _invalidKeywordId: 8888,
555 _placeId: null,
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 },
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 });
592 //------------------------------------------------------------------------------
594 tests.push({
595 name: "D.6",
596 desc: "Fix wrong item types | bookmarks",
598 _separatorId: null,
599 _folderId: null,
600 _placeId: null,
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 },
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 });
625 //------------------------------------------------------------------------------
627 tests.push({
628 name: "D.7",
629 desc: "Fix wrong item types | bookmarks",
631 _validBookmarkId: null,
632 _invalidBookmarkId: null,
633 _placeId: null,
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 },
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 });
659 //------------------------------------------------------------------------------
661 tests.push({
662 name: "D.9",
663 desc: "Fix wrong parents",
665 _bookmarkId: null,
666 _separatorId: null,
667 _bookmarkId1: null,
668 _bookmarkId2: null,
669 _placeId: null,
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 },
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 });
697 //------------------------------------------------------------------------------
699 tests.push({
700 name: "D.10",
701 desc: "Recalculate positions",
703 _unfiledBookmarks: [],
704 _toolbarBookmarks: [],
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);
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();
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 }
755 // Set random positions for the added bookmarks.
756 randomize_positions(PlacesUtils.unfiledBookmarksFolderId,
757 this._unfiledBookmarks);
758 randomize_positions(PlacesUtils.toolbarFolderId, this._toolbarBookmarks);
759 },
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 }
783 check_order(PlacesUtils.unfiledBookmarksFolderId, this._unfiledBookmarks);
784 check_order(PlacesUtils.toolbarFolderId, this._toolbarBookmarks);
785 }
786 });
788 //------------------------------------------------------------------------------
790 tests.push({
791 name: "D.12",
792 desc: "Fix empty-named tags",
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 },
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 });
835 //------------------------------------------------------------------------------
837 tests.push({
838 name: "E.1",
839 desc: "Remove orphan icons",
841 _placeId: null,
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 },
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 });
871 //------------------------------------------------------------------------------
873 tests.push({
874 name: "F.1",
875 desc: "Remove orphan visits",
877 _placeId: null,
878 _invalidPlaceId: 1337,
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 },
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 });
906 //------------------------------------------------------------------------------
908 tests.push({
909 name: "G.1",
910 desc: "Remove orphan input history",
912 _placeId: null,
913 _invalidPlaceId: 1337,
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 },
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 });
943 //------------------------------------------------------------------------------
945 tests.push({
946 name: "H.1",
947 desc: "Remove item annos with an invalid attribute",
949 _usedItemAttribute: "usedItem",
950 _bookmarkId: null,
951 _placeId: null,
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 },
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 });
993 //------------------------------------------------------------------------------
995 tests.push({
996 name: "H.2",
997 desc: "Remove orphan item annotations",
999 _usedItemAttribute: "usedItem",
1000 _bookmarkId: null,
1001 _invalidBookmarkId: 8888,
1002 _placeId: null,
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 },
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 });
1045 //------------------------------------------------------------------------------
1047 tests.push({
1048 name: "I.1",
1049 desc: "Remove unused keywords",
1051 _bookmarkId: null,
1052 _placeId: null,
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 },
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 });
1085 //------------------------------------------------------------------------------
1087 tests.push({
1088 name: "L.1",
1089 desc: "Fix wrong favicon ids",
1091 _validIconPlaceId: null,
1092 _invalidIconPlaceId: null,
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);
1103 // Insert a place using a nonexistent favicon entry
1104 this._invalidIconPlaceId = addPlace("http://www2.mozilla.org", 1337);
1105 },
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 });
1128 //------------------------------------------------------------------------------
1130 tests.push({
1131 name: "L.2",
1132 desc: "Recalculate visit_count and last_visit_date",
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 }
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++);
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 },
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 });
1205 //------------------------------------------------------------------------------
1207 tests.push({
1208 name: "L.3",
1209 desc: "recalculate hidden for redirects.",
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 },
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 });
1253 //------------------------------------------------------------------------------
1255 tests.push({
1256 name: "Z",
1257 desc: "Sanity: Preventive maintenance does not touch valid items",
1259 _uri1: uri("http://www1.mozilla.org"),
1260 _uri2: uri("http://www2.mozilla.org"),
1261 _folderId: null,
1262 _bookmarkId: null,
1263 _separatorId: null,
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 ]);
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 },
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);
1296 do_check_eq(bs.getBookmarkURI(this._bookmarkId).spec, this._uri1.spec);
1297 do_check_eq(bs.getItemIndex(this._folderId), 0);
1299 do_check_eq(bs.getItemType(this._folderId), bs.TYPE_FOLDER);
1300 do_check_eq(bs.getItemType(this._separatorId), bs.TYPE_SEPARATOR);
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");
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 });
1316 //------------------------------------------------------------------------------
1318 // main
1319 function run_test()
1320 {
1321 run_next_test();
1322 }
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")));
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);
1338 for ([, test] in Iterator(tests)) {
1339 dump("\nExecuting test: " + test.name + "\n" + "*** " + test.desc + "\n");
1340 yield test.setup();
1342 let promiseMaintenanceFinished =
1343 promiseTopicObserved(FINISHED_MAINTENANCE_NOTIFICATION_TOPIC);
1344 PlacesDBUtils.maintenanceOnIdle();
1345 yield promiseMaintenanceFinished;
1347 // Check the lastMaintenance time has been saved.
1348 do_check_neq(Services.prefs.getIntPref("places.database.lastMaintenance"), null);
1350 if (test.asyncCheck) {
1351 let deferred = Promise.defer();
1352 test.asyncCheck(deferred.resolve);
1353 yield deferred.promise;
1354 } else {
1355 test.check();
1356 }
1358 cleanDatabase();
1359 }
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 });