diff options
Diffstat (limited to 'toolkit/components/places/tests/migration/test_current_from_v34.js')
-rw-r--r-- | toolkit/components/places/tests/migration/test_current_from_v34.js | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/toolkit/components/places/tests/migration/test_current_from_v34.js b/toolkit/components/places/tests/migration/test_current_from_v34.js new file mode 100644 index 000000000..115bcec67 --- /dev/null +++ b/toolkit/components/places/tests/migration/test_current_from_v34.js @@ -0,0 +1,141 @@ +Cu.importGlobalProperties(["URL", "crypto"]); + +const { TYPE_BOOKMARK, TYPE_FOLDER } = Ci.nsINavBookmarksService; +const { EXPIRE_NEVER, TYPE_INT32 } = Ci.nsIAnnotationService; + +function makeGuid() { + return ChromeUtils.base64URLEncode(crypto.getRandomValues(new Uint8Array(9)), { + pad: false, + }); +} + +// These queries are more or less copied directly from Bookmarks.jsm, but +// operate on the old, pre-migration DB. We can't use any of the Places SQL +// functions yet, because those are only registered for the main connection. +function* insertItem(db, info) { + let [parentInfo] = yield db.execute(` + SELECT b.id, (SELECT count(*) FROM moz_bookmarks + WHERE parent = b.id) AS childCount + FROM moz_bookmarks b + WHERE b.guid = :parentGuid`, + { parentGuid: info.parentGuid }); + + let guid = makeGuid(); + yield db.execute(` + INSERT INTO moz_bookmarks (fk, type, parent, position, guid) + VALUES ((SELECT id FROM moz_places WHERE url = :url), + :type, :parent, :position, :guid)`, + { url: info.url || "nonexistent", type: info.type, guid, + // Just append items. + position: parentInfo.getResultByName("childCount"), + parent: parentInfo.getResultByName("id") }); + + let id = (yield db.execute(` + SELECT id FROM moz_bookmarks WHERE guid = :guid LIMIT 1`, + { guid }))[0].getResultByName("id"); + + return { id, guid }; +} + +function insertBookmark(db, info) { + return db.executeTransaction(function* () { + if (info.type == TYPE_BOOKMARK) { + // We don't have access to the hash function here, so we omit the + // `url_hash` column. These will be fixed up automatically during + // migration. + let url = new URL(info.url); + let placeGuid = makeGuid(); + yield db.execute(` + INSERT INTO moz_places (url, rev_host, hidden, frecency, guid) + VALUES (:url, :rev_host, 0, -1, :guid)`, + { url: url.href, guid: placeGuid, + rev_host: PlacesUtils.getReversedHost(url) }); + } + return yield* insertItem(db, info); + }); +} + +function* insertAnno(db, itemId, name, value) { + yield db.execute(`INSERT OR IGNORE INTO moz_anno_attributes (name) + VALUES (:name)`, { name }); + yield db.execute(` + INSERT INTO moz_items_annos + (item_id, anno_attribute_id, content, flags, + expiration, type, dateAdded, lastModified) + VALUES (:itemId, + (SELECT id FROM moz_anno_attributes + WHERE name = :name), + 1, 0, :expiration, :type, 0, 0) + `, { itemId, name, expiration: EXPIRE_NEVER, type: TYPE_INT32 }); +} + +function insertMobileFolder(db) { + return db.executeTransaction(function* () { + let item = yield* insertItem(db, { + type: TYPE_FOLDER, + parentGuid: "root________", + }); + yield* insertAnno(db, item.id, "mobile/bookmarksRoot", 1); + return item; + }); +} + +var mobileId, mobileGuid, fxGuid; +var dupeMobileId, dupeMobileGuid, tbGuid; + +add_task(function* setup() { + yield setupPlacesDatabase("places_v34.sqlite"); + // Setup database contents to be migrated. + let path = OS.Path.join(OS.Constants.Path.profileDir, DB_FILENAME); + let db = yield Sqlite.openConnection({ path }); + + do_print("Create mobile folder with bookmarks"); + ({ id: mobileId, guid: mobileGuid } = yield insertMobileFolder(db)); + ({ guid: fxGuid } = yield insertBookmark(db, { + type: TYPE_BOOKMARK, + url: "http://getfirefox.com", + parentGuid: mobileGuid, + })); + + // We should only have one mobile folder, but, in case an old version of Sync + // did the wrong thing and created multiple mobile folders, we should merge + // their contents into the new mobile root. + do_print("Create second mobile folder with different bookmarks"); + ({ id: dupeMobileId, guid: dupeMobileGuid } = yield insertMobileFolder(db)); + ({ guid: tbGuid } = yield insertBookmark(db, { + type: TYPE_BOOKMARK, + url: "http://getthunderbird.com", + parentGuid: dupeMobileGuid, + })); + + yield db.close(); +}); + +add_task(function* database_is_valid() { + // Accessing the database for the first time triggers migration. + Assert.equal(PlacesUtils.history.databaseStatus, + PlacesUtils.history.DATABASE_STATUS_UPGRADED); + + let db = yield PlacesUtils.promiseDBConnection(); + Assert.equal((yield db.getSchemaVersion()), CURRENT_SCHEMA_VERSION); +}); + +add_task(function* test_mobile_root() { + let fxBmk = yield PlacesUtils.bookmarks.fetch(fxGuid); + equal(fxBmk.parentGuid, PlacesUtils.bookmarks.mobileGuid, + "Firefox bookmark should be moved to new mobile root"); + equal(fxBmk.index, 0, "Firefox bookmark should be first child of new root"); + + let tbBmk = yield PlacesUtils.bookmarks.fetch(tbGuid); + equal(tbBmk.parentGuid, PlacesUtils.bookmarks.mobileGuid, + "Thunderbird bookmark should be moved to new mobile root"); + equal(tbBmk.index, 1, + "Thunderbird bookmark should be second child of new root"); + + let mobileRootId = PlacesUtils.promiseItemId( + PlacesUtils.bookmarks.mobileGuid); + let annoItemIds = PlacesUtils.annotations.getItemsWithAnnotation( + PlacesUtils.MOBILE_ROOT_ANNO, {}); + deepEqual(annoItemIds, [mobileRootId], + "Only mobile root should have mobile anno"); +}); |