toolkit/components/places/tests/unit/test_preventive_maintenance.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

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();
  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();
  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();
  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();
  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();
  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();
  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++;
  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();
  1248     });
  1249     stmt.finalize();
  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));
  1314 });
  1316 //------------------------------------------------------------------------------
  1318 // main
  1319 function run_test()
  1321   run_next_test();
  1324 add_task(function test_preventive_maintenance()
  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();
  1358     cleanDatabase();
  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 });

mercurial