summaryrefslogtreecommitdiffstats
path: root/toolkit/components/places/tests/migration
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/places/tests/migration')
-rw-r--r--toolkit/components/places/tests/migration/.eslintrc.js7
-rw-r--r--toolkit/components/places/tests/migration/head_migration.js46
-rw-r--r--toolkit/components/places/tests/migration/places_v10.sqlitebin0 -> 172032 bytes
-rw-r--r--toolkit/components/places/tests/migration/places_v11.sqlitebin0 -> 1081344 bytes
-rw-r--r--toolkit/components/places/tests/migration/places_v17.sqlitebin0 -> 1212416 bytes
-rw-r--r--toolkit/components/places/tests/migration/places_v19.sqlitebin0 -> 1179648 bytes
-rw-r--r--toolkit/components/places/tests/migration/places_v21.sqlitebin0 -> 1179648 bytes
-rw-r--r--toolkit/components/places/tests/migration/places_v22.sqlitebin0 -> 1179648 bytes
-rw-r--r--toolkit/components/places/tests/migration/places_v23.sqlitebin0 -> 1179648 bytes
-rw-r--r--toolkit/components/places/tests/migration/places_v24.sqlitebin0 -> 1179648 bytes
-rw-r--r--toolkit/components/places/tests/migration/places_v25.sqlitebin0 -> 1179648 bytes
-rw-r--r--toolkit/components/places/tests/migration/places_v26.sqlitebin0 -> 1179648 bytes
-rw-r--r--toolkit/components/places/tests/migration/places_v27.sqlitebin0 -> 1212416 bytes
-rw-r--r--toolkit/components/places/tests/migration/places_v28.sqlitebin0 -> 1212416 bytes
-rw-r--r--toolkit/components/places/tests/migration/places_v29.sqlitebin0 -> 1245184 bytes
-rw-r--r--toolkit/components/places/tests/migration/places_v30.sqlitebin0 -> 1212416 bytes
-rw-r--r--toolkit/components/places/tests/migration/places_v31.sqlitebin0 -> 1146880 bytes
-rw-r--r--toolkit/components/places/tests/migration/places_v32.sqlitebin0 -> 1146880 bytes
-rw-r--r--toolkit/components/places/tests/migration/places_v33.sqlitebin0 -> 1146880 bytes
-rw-r--r--toolkit/components/places/tests/migration/places_v34.sqlitebin0 -> 1146880 bytes
-rw-r--r--toolkit/components/places/tests/migration/places_v35.sqlitebin0 -> 1146880 bytes
-rw-r--r--toolkit/components/places/tests/migration/places_v6.sqlitebin0 -> 155648 bytes
-rw-r--r--toolkit/components/places/tests/migration/test_current_from_downgraded.js19
-rw-r--r--toolkit/components/places/tests/migration/test_current_from_v11.js48
-rw-r--r--toolkit/components/places/tests/migration/test_current_from_v19.js42
-rw-r--r--toolkit/components/places/tests/migration/test_current_from_v24.js36
-rw-r--r--toolkit/components/places/tests/migration/test_current_from_v25.js30
-rw-r--r--toolkit/components/places/tests/migration/test_current_from_v26.js98
-rw-r--r--toolkit/components/places/tests/migration/test_current_from_v27.js77
-rw-r--r--toolkit/components/places/tests/migration/test_current_from_v31.js46
-rw-r--r--toolkit/components/places/tests/migration/test_current_from_v34.js141
-rw-r--r--toolkit/components/places/tests/migration/test_current_from_v34_no_roots.js21
-rw-r--r--toolkit/components/places/tests/migration/test_current_from_v6.js38
-rw-r--r--toolkit/components/places/tests/migration/xpcshell.ini36
34 files changed, 685 insertions, 0 deletions
diff --git a/toolkit/components/places/tests/migration/.eslintrc.js b/toolkit/components/places/tests/migration/.eslintrc.js
new file mode 100644
index 000000000..d35787cd2
--- /dev/null
+++ b/toolkit/components/places/tests/migration/.eslintrc.js
@@ -0,0 +1,7 @@
+"use strict";
+
+module.exports = {
+ "extends": [
+ "../../../../../testing/xpcshell/xpcshell.eslintrc.js"
+ ]
+};
diff --git a/toolkit/components/places/tests/migration/head_migration.js b/toolkit/components/places/tests/migration/head_migration.js
new file mode 100644
index 000000000..1ebecd4c0
--- /dev/null
+++ b/toolkit/components/places/tests/migration/head_migration.js
@@ -0,0 +1,46 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict"
+
+var { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+
+// Import common head.
+{
+ let commonFile = do_get_file("../head_common.js", false);
+ let uri = Services.io.newFileURI(commonFile);
+ Services.scriptloader.loadSubScript(uri.spec, this);
+}
+
+// Put any other stuff relative to this test folder below.
+
+const DB_FILENAME = "places.sqlite";
+
+/**
+ * Sets the database to use for the given test. This should be the very first
+ * thing in the test, otherwise this database will not be used!
+ *
+ * @param aFileName
+ * The filename of the database to use. This database must exist in
+ * toolkit/components/places/tests/migration!
+ * @return {Promise}
+ */
+var setupPlacesDatabase = Task.async(function* (aFileName) {
+ let currentDir = yield OS.File.getCurrentDirectory();
+
+ let src = OS.Path.join(currentDir, aFileName);
+ Assert.ok((yield OS.File.exists(src)), "Database file found");
+
+ // Ensure that our database doesn't already exist.
+ let dest = OS.Path.join(OS.Constants.Path.profileDir, DB_FILENAME);
+ Assert.ok(!(yield OS.File.exists(dest)), "Database file should not exist yet");
+
+ yield OS.File.copy(src, dest);
+});
+
+// This works provided all tests in this folder use add_task.
+function run_test() {
+ run_next_test();
+}
diff --git a/toolkit/components/places/tests/migration/places_v10.sqlite b/toolkit/components/places/tests/migration/places_v10.sqlite
new file mode 100644
index 000000000..80a8ecd6a
--- /dev/null
+++ b/toolkit/components/places/tests/migration/places_v10.sqlite
Binary files differ
diff --git a/toolkit/components/places/tests/migration/places_v11.sqlite b/toolkit/components/places/tests/migration/places_v11.sqlite
new file mode 100644
index 000000000..bef27d5f5
--- /dev/null
+++ b/toolkit/components/places/tests/migration/places_v11.sqlite
Binary files differ
diff --git a/toolkit/components/places/tests/migration/places_v17.sqlite b/toolkit/components/places/tests/migration/places_v17.sqlite
new file mode 100644
index 000000000..5183cde83
--- /dev/null
+++ b/toolkit/components/places/tests/migration/places_v17.sqlite
Binary files differ
diff --git a/toolkit/components/places/tests/migration/places_v19.sqlite b/toolkit/components/places/tests/migration/places_v19.sqlite
new file mode 100644
index 000000000..11e2e6247
--- /dev/null
+++ b/toolkit/components/places/tests/migration/places_v19.sqlite
Binary files differ
diff --git a/toolkit/components/places/tests/migration/places_v21.sqlite b/toolkit/components/places/tests/migration/places_v21.sqlite
new file mode 100644
index 000000000..f72930826
--- /dev/null
+++ b/toolkit/components/places/tests/migration/places_v21.sqlite
Binary files differ
diff --git a/toolkit/components/places/tests/migration/places_v22.sqlite b/toolkit/components/places/tests/migration/places_v22.sqlite
new file mode 100644
index 000000000..30bf840b0
--- /dev/null
+++ b/toolkit/components/places/tests/migration/places_v22.sqlite
Binary files differ
diff --git a/toolkit/components/places/tests/migration/places_v23.sqlite b/toolkit/components/places/tests/migration/places_v23.sqlite
new file mode 100644
index 000000000..b519b97d2
--- /dev/null
+++ b/toolkit/components/places/tests/migration/places_v23.sqlite
Binary files differ
diff --git a/toolkit/components/places/tests/migration/places_v24.sqlite b/toolkit/components/places/tests/migration/places_v24.sqlite
new file mode 100644
index 000000000..b35f958a6
--- /dev/null
+++ b/toolkit/components/places/tests/migration/places_v24.sqlite
Binary files differ
diff --git a/toolkit/components/places/tests/migration/places_v25.sqlite b/toolkit/components/places/tests/migration/places_v25.sqlite
new file mode 100644
index 000000000..2afd1da1f
--- /dev/null
+++ b/toolkit/components/places/tests/migration/places_v25.sqlite
Binary files differ
diff --git a/toolkit/components/places/tests/migration/places_v26.sqlite b/toolkit/components/places/tests/migration/places_v26.sqlite
new file mode 100644
index 000000000..b4b238179
--- /dev/null
+++ b/toolkit/components/places/tests/migration/places_v26.sqlite
Binary files differ
diff --git a/toolkit/components/places/tests/migration/places_v27.sqlite b/toolkit/components/places/tests/migration/places_v27.sqlite
new file mode 100644
index 000000000..57dfb7562
--- /dev/null
+++ b/toolkit/components/places/tests/migration/places_v27.sqlite
Binary files differ
diff --git a/toolkit/components/places/tests/migration/places_v28.sqlite b/toolkit/components/places/tests/migration/places_v28.sqlite
new file mode 100644
index 000000000..9a27db324
--- /dev/null
+++ b/toolkit/components/places/tests/migration/places_v28.sqlite
Binary files differ
diff --git a/toolkit/components/places/tests/migration/places_v29.sqlite b/toolkit/components/places/tests/migration/places_v29.sqlite
new file mode 100644
index 000000000..f6de0fe8a
--- /dev/null
+++ b/toolkit/components/places/tests/migration/places_v29.sqlite
Binary files differ
diff --git a/toolkit/components/places/tests/migration/places_v30.sqlite b/toolkit/components/places/tests/migration/places_v30.sqlite
new file mode 100644
index 000000000..9cbabe005
--- /dev/null
+++ b/toolkit/components/places/tests/migration/places_v30.sqlite
Binary files differ
diff --git a/toolkit/components/places/tests/migration/places_v31.sqlite b/toolkit/components/places/tests/migration/places_v31.sqlite
new file mode 100644
index 000000000..9d33b9eff
--- /dev/null
+++ b/toolkit/components/places/tests/migration/places_v31.sqlite
Binary files differ
diff --git a/toolkit/components/places/tests/migration/places_v32.sqlite b/toolkit/components/places/tests/migration/places_v32.sqlite
new file mode 100644
index 000000000..239f6c5fe
--- /dev/null
+++ b/toolkit/components/places/tests/migration/places_v32.sqlite
Binary files differ
diff --git a/toolkit/components/places/tests/migration/places_v33.sqlite b/toolkit/components/places/tests/migration/places_v33.sqlite
new file mode 100644
index 000000000..6071dc6a6
--- /dev/null
+++ b/toolkit/components/places/tests/migration/places_v33.sqlite
Binary files differ
diff --git a/toolkit/components/places/tests/migration/places_v34.sqlite b/toolkit/components/places/tests/migration/places_v34.sqlite
new file mode 100644
index 000000000..474628996
--- /dev/null
+++ b/toolkit/components/places/tests/migration/places_v34.sqlite
Binary files differ
diff --git a/toolkit/components/places/tests/migration/places_v35.sqlite b/toolkit/components/places/tests/migration/places_v35.sqlite
new file mode 100644
index 000000000..5e157d778
--- /dev/null
+++ b/toolkit/components/places/tests/migration/places_v35.sqlite
Binary files differ
diff --git a/toolkit/components/places/tests/migration/places_v6.sqlite b/toolkit/components/places/tests/migration/places_v6.sqlite
new file mode 100644
index 000000000..2852a4cf9
--- /dev/null
+++ b/toolkit/components/places/tests/migration/places_v6.sqlite
Binary files differ
diff --git a/toolkit/components/places/tests/migration/test_current_from_downgraded.js b/toolkit/components/places/tests/migration/test_current_from_downgraded.js
new file mode 100644
index 000000000..6d36cab14
--- /dev/null
+++ b/toolkit/components/places/tests/migration/test_current_from_downgraded.js
@@ -0,0 +1,19 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+add_task(function* setup() {
+ yield setupPlacesDatabase(`places_v${CURRENT_SCHEMA_VERSION}.sqlite`);
+ // Downgrade the schema version to the first supported one.
+ let path = OS.Path.join(OS.Constants.Path.profileDir, DB_FILENAME);
+ let db = yield Sqlite.openConnection({ path: path });
+ yield db.setSchemaVersion(FIRST_UPGRADABLE_SCHEMA_VERSION);
+ yield db.close();
+});
+
+add_task(function* database_is_valid() {
+ Assert.equal(PlacesUtils.history.databaseStatus,
+ PlacesUtils.history.DATABASE_STATUS_UPGRADED);
+
+ let db = yield PlacesUtils.promiseDBConnection();
+ Assert.equal((yield db.getSchemaVersion()), CURRENT_SCHEMA_VERSION);
+});
diff --git a/toolkit/components/places/tests/migration/test_current_from_v11.js b/toolkit/components/places/tests/migration/test_current_from_v11.js
new file mode 100644
index 000000000..43b8fb1f6
--- /dev/null
+++ b/toolkit/components/places/tests/migration/test_current_from_v11.js
@@ -0,0 +1,48 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+add_task(function* setup() {
+ yield setupPlacesDatabase("places_v11.sqlite");
+});
+
+add_task(function* database_is_valid() {
+ 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_moz_hosts() {
+ let db = yield PlacesUtils.promiseDBConnection();
+
+ // This will throw if the column does not exist.
+ yield db.execute("SELECT host, frecency, typed, prefix FROM moz_hosts");
+
+ // moz_hosts is populated asynchronously, so we need to wait.
+ yield PlacesTestUtils.promiseAsyncUpdates();
+
+ // check the number of entries in moz_hosts equals the number of
+ // unique rev_host in moz_places
+ let rows = yield db.execute(
+ `SELECT (SELECT COUNT(host) FROM moz_hosts),
+ (SELECT COUNT(DISTINCT rev_host)
+ FROM moz_places
+ WHERE LENGTH(rev_host) > 1)
+ `);
+
+ Assert.equal(rows.length, 1);
+ let mozHostsCount = rows[0].getResultByIndex(0);
+ let mozPlacesCount = rows[0].getResultByIndex(1);
+
+ Assert.ok(mozPlacesCount > 0, "There is some url in the database");
+ Assert.equal(mozPlacesCount, mozHostsCount, "moz_hosts has the expected number of entries");
+});
+
+add_task(function* test_journal() {
+ let db = yield PlacesUtils.promiseDBConnection();
+ let rows = yield db.execute("PRAGMA journal_mode");
+ Assert.equal(rows.length, 1);
+ // WAL journal mode should be set on this database.
+ Assert.equal(rows[0].getResultByIndex(0), "wal");
+});
diff --git a/toolkit/components/places/tests/migration/test_current_from_v19.js b/toolkit/components/places/tests/migration/test_current_from_v19.js
new file mode 100644
index 000000000..b8d837e68
--- /dev/null
+++ b/toolkit/components/places/tests/migration/test_current_from_v19.js
@@ -0,0 +1,42 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const ANNO_LEGACYGUID = "placesInternal/GUID";
+
+var getTotalGuidAnnotationsCount = Task.async(function* (db) {
+ let rows = yield db.execute(
+ `SELECT count(*)
+ FROM moz_items_annos a
+ JOIN moz_anno_attributes b ON a.anno_attribute_id = b.id
+ WHERE b.name = :attr_name
+ `, { attr_name: ANNO_LEGACYGUID });
+ return rows[0].getResultByIndex(0);
+});
+
+add_task(function* setup() {
+ yield setupPlacesDatabase("places_v19.sqlite");
+});
+
+add_task(function* initial_state() {
+ let path = OS.Path.join(OS.Constants.Path.profileDir, DB_FILENAME);
+ let db = yield Sqlite.openConnection({ path: path });
+
+ Assert.equal((yield getTotalGuidAnnotationsCount(db)), 1,
+ "There should be 1 obsolete guid annotation");
+ yield db.close();
+});
+
+add_task(function* database_is_valid() {
+ 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_bookmark_guid_annotation_removed()
+{
+ let db = yield PlacesUtils.promiseDBConnection();
+ Assert.equal((yield getTotalGuidAnnotationsCount(db)), 0,
+ "There should be no more obsolete GUID annotations.");
+});
diff --git a/toolkit/components/places/tests/migration/test_current_from_v24.js b/toolkit/components/places/tests/migration/test_current_from_v24.js
new file mode 100644
index 000000000..0561b4922
--- /dev/null
+++ b/toolkit/components/places/tests/migration/test_current_from_v24.js
@@ -0,0 +1,36 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+add_task(function* setup() {
+ yield setupPlacesDatabase("places_v24.sqlite");
+});
+
+add_task(function* database_is_valid() {
+ 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_bookmark_guid_annotation_removed()
+{
+ yield PlacesUtils.bookmarks.eraseEverything();
+
+ let db = yield PlacesUtils.promiseDBConnection();
+ let m = new Map([
+ [PlacesUtils.placesRootId, PlacesUtils.bookmarks.rootGuid],
+ [PlacesUtils.bookmarksMenuFolderId, PlacesUtils.bookmarks.menuGuid],
+ [PlacesUtils.toolbarFolderId, PlacesUtils.bookmarks.toolbarGuid],
+ [PlacesUtils.unfiledBookmarksFolderId, PlacesUtils.bookmarks.unfiledGuid],
+ [PlacesUtils.tagsFolderId, PlacesUtils.bookmarks.tagsGuid],
+ [PlacesUtils.mobileFolderId, PlacesUtils.bookmarks.mobileGuid],
+ ]);
+
+ let rows = yield db.execute(`SELECT id, guid FROM moz_bookmarks`);
+ for (let row of rows) {
+ let id = row.getResultByName("id");
+ let guid = row.getResultByName("guid");
+ Assert.equal(m.get(id), guid, "The root folder has the correct GUID");
+ }
+});
diff --git a/toolkit/components/places/tests/migration/test_current_from_v25.js b/toolkit/components/places/tests/migration/test_current_from_v25.js
new file mode 100644
index 000000000..b066975fc
--- /dev/null
+++ b/toolkit/components/places/tests/migration/test_current_from_v25.js
@@ -0,0 +1,30 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+add_task(function* setup() {
+ yield setupPlacesDatabase("places_v25.sqlite");
+});
+
+add_task(function* database_is_valid() {
+ 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_dates_rounded() {
+ let root = yield PlacesUtils.promiseBookmarksTree();
+ function ensureDates(node) {
+ // When/if promiseBookmarksTree returns these as Date objects, switch this
+ // test to use getItemDateAdded and getItemLastModified. And when these
+ // methods are removed, this test can be eliminated altogether.
+ Assert.strictEqual(typeof(node.dateAdded), "number");
+ Assert.strictEqual(typeof(node.lastModified), "number");
+ Assert.strictEqual(node.dateAdded % 1000, 0);
+ Assert.strictEqual(node.lastModified % 1000, 0);
+ if ("children" in node)
+ node.children.forEach(ensureDates);
+ }
+ ensureDates(root);
+});
diff --git a/toolkit/components/places/tests/migration/test_current_from_v26.js b/toolkit/components/places/tests/migration/test_current_from_v26.js
new file mode 100644
index 000000000..7ff4bc352
--- /dev/null
+++ b/toolkit/components/places/tests/migration/test_current_from_v26.js
@@ -0,0 +1,98 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+add_task(function* setup() {
+ yield setupPlacesDatabase("places_v26.sqlite");
+ // Setup database contents to be migrated.
+ let path = OS.Path.join(OS.Constants.Path.profileDir, DB_FILENAME);
+ let db = yield Sqlite.openConnection({ path });
+ // Add pages.
+ yield db.execute(`INSERT INTO moz_places (url, guid)
+ VALUES ("http://test1.com/", "test1_______")
+ , ("http://test2.com/", "test2_______")
+ , ("http://test3.com/", "test3_______")
+ `);
+ // Add keywords.
+ yield db.execute(`INSERT INTO moz_keywords (keyword)
+ VALUES ("kw1")
+ , ("kw2")
+ , ("kw3")
+ , ("kw4")
+ , ("kw5")
+ `);
+ // Add bookmarks.
+ let now = Date.now() * 1000;
+ let index = 0;
+ yield db.execute(`INSERT INTO moz_bookmarks (type, fk, parent, position, dateAdded, lastModified, keyword_id, guid)
+ VALUES (1, (SELECT id FROM moz_places WHERE guid = 'test1_______'), 3, ${index++}, ${now}, ${now},
+ (SELECT id FROM moz_keywords WHERE keyword = 'kw1'), "bookmark1___")
+ /* same uri, different keyword */
+ , (1, (SELECT id FROM moz_places WHERE guid = 'test1_______'), 3, ${index++}, ${now}, ${now},
+ (SELECT id FROM moz_keywords WHERE keyword = 'kw2'), "bookmark2___")
+ /* different uri, same keyword as 1 */
+ , (1, (SELECT id FROM moz_places WHERE guid = 'test2_______'), 3, ${index++}, ${now}, ${now},
+ (SELECT id FROM moz_keywords WHERE keyword = 'kw1'), "bookmark3___")
+ /* same uri, same keyword as 1 */
+ , (1, (SELECT id FROM moz_places WHERE guid = 'test1_______'), 3, ${index++}, ${now}, ${now},
+ (SELECT id FROM moz_keywords WHERE keyword = 'kw1'), "bookmark4___")
+ /* same uri, same keyword as 2 */
+ , (1, (SELECT id FROM moz_places WHERE guid = 'test2_______'), 3, ${index++}, ${now}, ${now},
+ (SELECT id FROM moz_keywords WHERE keyword = 'kw2'), "bookmark5___")
+ /* different uri, same keyword as 1 */
+ , (1, (SELECT id FROM moz_places WHERE guid = 'test1_______'), 3, ${index++}, ${now}, ${now},
+ (SELECT id FROM moz_keywords WHERE keyword = 'kw3'), "bookmark6___")
+ , (1, (SELECT id FROM moz_places WHERE guid = 'test3_______'), 3, ${index++}, ${now}, ${now},
+ (SELECT id FROM moz_keywords WHERE keyword = 'kw4'), "bookmark7___")
+ /* same uri and post_data as bookmark7, different keyword */
+ , (1, (SELECT id FROM moz_places WHERE guid = 'test3_______'), 3, ${index++}, ${now}, ${now},
+ (SELECT id FROM moz_keywords WHERE keyword = 'kw5'), "bookmark8___")
+ `);
+ // Add postData.
+ yield db.execute(`INSERT INTO moz_anno_attributes (name)
+ VALUES ("bookmarkProperties/POSTData")
+ , ("someOtherAnno")`);
+ yield db.execute(`INSERT INTO moz_items_annos(anno_attribute_id, item_id, content)
+ VALUES ((SELECT id FROM moz_anno_attributes where name = "bookmarkProperties/POSTData"),
+ (SELECT id FROM moz_bookmarks WHERE guid = "bookmark3___"), "postData1")
+ , ((SELECT id FROM moz_anno_attributes where name = "bookmarkProperties/POSTData"),
+ (SELECT id FROM moz_bookmarks WHERE guid = "bookmark5___"), "postData2")
+ , ((SELECT id FROM moz_anno_attributes where name = "someOtherAnno"),
+ (SELECT id FROM moz_bookmarks WHERE guid = "bookmark5___"), "zzzzzzzzzz")
+ , ((SELECT id FROM moz_anno_attributes where name = "bookmarkProperties/POSTData"),
+ (SELECT id FROM moz_bookmarks WHERE guid = "bookmark7___"), "postData3")
+ , ((SELECT id FROM moz_anno_attributes where name = "bookmarkProperties/POSTData"),
+ (SELECT id FROM moz_bookmarks WHERE guid = "bookmark8___"), "postData3")
+ `);
+ yield db.close();
+});
+
+add_task(function* database_is_valid() {
+ 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_keywords() {
+ // When 2 urls have the same keyword, if one has postData it will be
+ // preferred.
+ let entry1 = yield PlacesUtils.keywords.fetch("kw1");
+ Assert.equal(entry1.url.href, "http://test2.com/");
+ Assert.equal(entry1.postData, "postData1");
+ let entry2 = yield PlacesUtils.keywords.fetch("kw2");
+ Assert.equal(entry2.url.href, "http://test2.com/");
+ Assert.equal(entry2.postData, "postData2");
+ let entry3 = yield PlacesUtils.keywords.fetch("kw3");
+ Assert.equal(entry3.url.href, "http://test1.com/");
+ Assert.equal(entry3.postData, null);
+ let entry4 = yield PlacesUtils.keywords.fetch("kw4");
+ Assert.equal(entry4, null);
+ let entry5 = yield PlacesUtils.keywords.fetch("kw5");
+ Assert.equal(entry5.url.href, "http://test3.com/");
+ Assert.equal(entry5.postData, "postData3");
+
+ Assert.equal((yield foreign_count("http://test1.com/")), 5); // 4 bookmark2 + 1 keywords
+ Assert.equal((yield foreign_count("http://test2.com/")), 4); // 2 bookmark2 + 2 keywords
+ Assert.equal((yield foreign_count("http://test3.com/")), 3); // 2 bookmark2 + 1 keywords
+});
diff --git a/toolkit/components/places/tests/migration/test_current_from_v27.js b/toolkit/components/places/tests/migration/test_current_from_v27.js
new file mode 100644
index 000000000..1675901eb
--- /dev/null
+++ b/toolkit/components/places/tests/migration/test_current_from_v27.js
@@ -0,0 +1,77 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+add_task(function* setup() {
+ yield setupPlacesDatabase("places_v27.sqlite");
+ // Setup database contents to be migrated.
+ let path = OS.Path.join(OS.Constants.Path.profileDir, DB_FILENAME);
+ let db = yield Sqlite.openConnection({ path });
+ // Add pages.
+ yield db.execute(`INSERT INTO moz_places (url, guid)
+ VALUES ("http://test1.com/", "test1_______")
+ , ("http://test2.com/", "test2_______")
+ `);
+ // Add keywords.
+ yield db.execute(`INSERT INTO moz_keywords (keyword, place_id, post_data)
+ VALUES ("kw1", (SELECT id FROM moz_places WHERE guid = "test2_______"), "broken data")
+ , ("kw2", (SELECT id FROM moz_places WHERE guid = "test2_______"), NULL)
+ , ("kw3", (SELECT id FROM moz_places WHERE guid = "test1_______"), "zzzzzzzzzz")
+ `);
+ // Add bookmarks.
+ let now = Date.now() * 1000;
+ let index = 0;
+ yield db.execute(`INSERT INTO moz_bookmarks (type, fk, parent, position, dateAdded, lastModified, keyword_id, guid)
+ VALUES (1, (SELECT id FROM moz_places WHERE guid = "test1_______"), 3, ${index++}, ${now}, ${now},
+ (SELECT id FROM moz_keywords WHERE keyword = "kw1"), "bookmark1___")
+ /* same uri, different keyword */
+ , (1, (SELECT id FROM moz_places WHERE guid = "test1_______"), 3, ${index++}, ${now}, ${now},
+ (SELECT id FROM moz_keywords WHERE keyword = "kw2"), "bookmark2___")
+ /* different uri, same keyword as 1 */
+ , (1, (SELECT id FROM moz_places WHERE guid = "test2_______"), 3, ${index++}, ${now}, ${now},
+ (SELECT id FROM moz_keywords WHERE keyword = "kw1"), "bookmark3___")
+ /* same uri, same keyword as 1 */
+ , (1, (SELECT id FROM moz_places WHERE guid = "test1_______"), 3, ${index++}, ${now}, ${now},
+ (SELECT id FROM moz_keywords WHERE keyword = "kw1"), "bookmark4___")
+ /* same uri, same keyword as 2 */
+ , (1, (SELECT id FROM moz_places WHERE guid = "test2_______"), 3, ${index++}, ${now}, ${now},
+ (SELECT id FROM moz_keywords WHERE keyword = "kw2"), "bookmark5___")
+ /* different uri, same keyword as 1 */
+ , (1, (SELECT id FROM moz_places WHERE guid = "test1_______"), 3, ${index++}, ${now}, ${now},
+ (SELECT id FROM moz_keywords WHERE keyword = "kw3"), "bookmark6___")
+ `);
+ // Add postData.
+ yield db.execute(`INSERT INTO moz_anno_attributes (name)
+ VALUES ("bookmarkProperties/POSTData")
+ , ("someOtherAnno")`);
+ yield db.execute(`INSERT INTO moz_items_annos(anno_attribute_id, item_id, content)
+ VALUES ((SELECT id FROM moz_anno_attributes where name = "bookmarkProperties/POSTData"),
+ (SELECT id FROM moz_bookmarks WHERE guid = "bookmark3___"), "postData1")
+ , ((SELECT id FROM moz_anno_attributes where name = "bookmarkProperties/POSTData"),
+ (SELECT id FROM moz_bookmarks WHERE guid = "bookmark5___"), "postData2")
+ , ((SELECT id FROM moz_anno_attributes where name = "someOtherAnno"),
+ (SELECT id FROM moz_bookmarks WHERE guid = "bookmark5___"), "zzzzzzzzzz")
+ `);
+ yield db.close();
+});
+
+add_task(function* database_is_valid() {
+ 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_keywords() {
+ // When 2 urls have the same keyword, if one has postData it will be
+ // preferred.
+ let entry1 = yield PlacesUtils.keywords.fetch("kw1");
+ Assert.equal(entry1.url.href, "http://test2.com/");
+ Assert.equal(entry1.postData, "postData1");
+ let entry2 = yield PlacesUtils.keywords.fetch("kw2");
+ Assert.equal(entry2.url.href, "http://test2.com/");
+ Assert.equal(entry2.postData, "postData2");
+ let entry3 = yield PlacesUtils.keywords.fetch("kw3");
+ Assert.equal(entry3.url.href, "http://test1.com/");
+ Assert.equal(entry3.postData, null);
+});
diff --git a/toolkit/components/places/tests/migration/test_current_from_v31.js b/toolkit/components/places/tests/migration/test_current_from_v31.js
new file mode 100644
index 000000000..6b9131daa
--- /dev/null
+++ b/toolkit/components/places/tests/migration/test_current_from_v31.js
@@ -0,0 +1,46 @@
+// Add pages.
+let shorturl = "http://example.com/" + "a".repeat(1981);
+let longurl = "http://example.com/" + "a".repeat(1982);
+let bmurl = "http://example.com/" + "a".repeat(1983);
+
+add_task(function* setup() {
+ yield setupPlacesDatabase("places_v31.sqlite");
+ // Setup database contents to be migrated.
+ let path = OS.Path.join(OS.Constants.Path.profileDir, DB_FILENAME);
+ let db = yield Sqlite.openConnection({ path });
+
+ yield db.execute(`INSERT INTO moz_places (url, guid, foreign_count)
+ VALUES (:shorturl, "test1_______", 0)
+ , (:longurl, "test2_______", 0)
+ , (:bmurl, "test3_______", 1)
+ `, { shorturl, longurl, bmurl });
+ // Add visits.
+ yield db.execute(`INSERT INTO moz_historyvisits (place_id)
+ VALUES ((SELECT id FROM moz_places WHERE url = :shorturl))
+ , ((SELECT id FROM moz_places WHERE url = :longurl))
+ `, { shorturl, longurl });
+ yield db.close();
+});
+
+add_task(function* database_is_valid() {
+ 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_longurls() {
+ let db = yield PlacesUtils.promiseDBConnection();
+ let rows = yield db.execute(`SELECT 1 FROM moz_places where url = :longurl`,
+ { longurl });
+ Assert.equal(rows.length, 0, "Long url should have been removed");
+ rows = yield db.execute(`SELECT 1 FROM moz_places where url = :shorturl`,
+ { shorturl });
+ Assert.equal(rows.length, 1, "Short url should have been retained");
+ rows = yield db.execute(`SELECT 1 FROM moz_places where url = :bmurl`,
+ { bmurl });
+ Assert.equal(rows.length, 1, "Bookmarked url should have been retained");
+ rows = yield db.execute(`SELECT count(*) FROM moz_historyvisits`);
+ Assert.equal(rows.length, 1, "Orphan visists should have been removed");
+});
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");
+});
diff --git a/toolkit/components/places/tests/migration/test_current_from_v34_no_roots.js b/toolkit/components/places/tests/migration/test_current_from_v34_no_roots.js
new file mode 100644
index 000000000..871fe8993
--- /dev/null
+++ b/toolkit/components/places/tests/migration/test_current_from_v34_no_roots.js
@@ -0,0 +1,21 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+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 });
+ // Remove all the roots.
+ yield db.execute("DELETE FROM moz_bookmarks");
+ 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);
+});
diff --git a/toolkit/components/places/tests/migration/test_current_from_v6.js b/toolkit/components/places/tests/migration/test_current_from_v6.js
new file mode 100644
index 000000000..a3f9dc229
--- /dev/null
+++ b/toolkit/components/places/tests/migration/test_current_from_v6.js
@@ -0,0 +1,38 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * This file tests migration from a preliminary schema version 6 that
+ * lacks frecency column and moz_inputhistory table.
+ */
+
+add_task(function* setup() {
+ yield setupPlacesDatabase("places_v6.sqlite");
+});
+
+add_task(function* corrupt_database_not_exists() {
+ let corruptPath = OS.Path.join(OS.Constants.Path.profileDir,
+ "places.sqlite.corrupt");
+ Assert.ok(!(yield OS.File.exists(corruptPath)), "Corrupt file should not exist");
+});
+
+add_task(function* database_is_valid() {
+ Assert.equal(PlacesUtils.history.databaseStatus,
+ PlacesUtils.history.DATABASE_STATUS_CORRUPT);
+
+ let db = yield PlacesUtils.promiseDBConnection();
+ Assert.equal((yield db.getSchemaVersion()), CURRENT_SCHEMA_VERSION);
+});
+
+add_task(function* check_columns() {
+ // Check the database has been replaced, these would throw otherwise.
+ let db = yield PlacesUtils.promiseDBConnection();
+ yield db.execute("SELECT frecency from moz_places");
+ yield db.execute("SELECT 1 from moz_inputhistory");
+});
+
+add_task(function* corrupt_database_exists() {
+ let corruptPath = OS.Path.join(OS.Constants.Path.profileDir,
+ "places.sqlite.corrupt");
+ Assert.ok((yield OS.File.exists(corruptPath)), "Corrupt file should exist");
+});
diff --git a/toolkit/components/places/tests/migration/xpcshell.ini b/toolkit/components/places/tests/migration/xpcshell.ini
new file mode 100644
index 000000000..aae0f75ee
--- /dev/null
+++ b/toolkit/components/places/tests/migration/xpcshell.ini
@@ -0,0 +1,36 @@
+[DEFAULT]
+head = head_migration.js
+tail =
+
+support-files =
+ places_v6.sqlite
+ places_v10.sqlite
+ places_v11.sqlite
+ places_v17.sqlite
+ places_v19.sqlite
+ places_v21.sqlite
+ places_v22.sqlite
+ places_v23.sqlite
+ places_v24.sqlite
+ places_v25.sqlite
+ places_v26.sqlite
+ places_v27.sqlite
+ places_v28.sqlite
+ places_v30.sqlite
+ places_v31.sqlite
+ places_v32.sqlite
+ places_v33.sqlite
+ places_v34.sqlite
+ places_v35.sqlite
+
+[test_current_from_downgraded.js]
+[test_current_from_v6.js]
+[test_current_from_v11.js]
+[test_current_from_v19.js]
+[test_current_from_v24.js]
+[test_current_from_v25.js]
+[test_current_from_v26.js]
+[test_current_from_v27.js]
+[test_current_from_v31.js]
+[test_current_from_v34.js]
+[test_current_from_v34_no_roots.js]