summaryrefslogtreecommitdiffstats
path: root/services/sync/tests/unit/test_bookmark_engine.js
diff options
context:
space:
mode:
Diffstat (limited to 'services/sync/tests/unit/test_bookmark_engine.js')
-rw-r--r--services/sync/tests/unit/test_bookmark_engine.js665
1 files changed, 665 insertions, 0 deletions
diff --git a/services/sync/tests/unit/test_bookmark_engine.js b/services/sync/tests/unit/test_bookmark_engine.js
new file mode 100644
index 000000000..9de6c5c0d
--- /dev/null
+++ b/services/sync/tests/unit/test_bookmark_engine.js
@@ -0,0 +1,665 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+Cu.import("resource://gre/modules/PlacesUtils.jsm");
+Cu.import("resource://gre/modules/PlacesSyncUtils.jsm");
+Cu.import("resource://gre/modules/BookmarkJSONUtils.jsm");
+Cu.import("resource://gre/modules/Log.jsm");
+Cu.import("resource://services-sync/constants.js");
+Cu.import("resource://services-sync/engines.js");
+Cu.import("resource://services-sync/engines/bookmarks.js");
+Cu.import("resource://services-sync/service.js");
+Cu.import("resource://services-sync/util.js");
+Cu.import("resource://testing-common/services/sync/utils.js");
+Cu.import("resource://gre/modules/Promise.jsm");
+
+initTestLogging("Trace");
+
+Service.engineManager.register(BookmarksEngine);
+
+function* assertChildGuids(folderGuid, expectedChildGuids, message) {
+ let tree = yield PlacesUtils.promiseBookmarksTree(folderGuid);
+ let childGuids = tree.children.map(child => child.guid);
+ deepEqual(childGuids, expectedChildGuids, message);
+}
+
+add_task(function* test_change_during_sync() {
+ _("Ensure that we track changes made during a sync.");
+
+ let engine = new BookmarksEngine(Service);
+ let store = engine._store;
+ let tracker = engine._tracker;
+ let server = serverForFoo(engine);
+ new SyncTestingInfrastructure(server.server);
+
+ let collection = server.user("foo").collection("bookmarks");
+
+ let bz_id = PlacesUtils.bookmarks.insertBookmark(
+ PlacesUtils.bookmarksMenuFolderId, Utils.makeURI("https://bugzilla.mozilla.org/"),
+ PlacesUtils.bookmarks.DEFAULT_INDEX, "Bugzilla");
+ let bz_guid = yield PlacesUtils.promiseItemGuid(bz_id);
+ _(`Bugzilla GUID: ${bz_guid}`);
+
+ Svc.Obs.notify("weave:engine:start-tracking");
+
+ try {
+ let folder1_id = PlacesUtils.bookmarks.createFolder(
+ PlacesUtils.bookmarks.toolbarFolder, "Folder 1", 0);
+ let folder1_guid = store.GUIDForId(folder1_id);
+ _(`Folder GUID: ${folder1_guid}`);
+
+ let bmk1_id = PlacesUtils.bookmarks.insertBookmark(
+ folder1_id, Utils.makeURI("http://getthunderbird.com/"),
+ PlacesUtils.bookmarks.DEFAULT_INDEX, "Get Thunderbird!");
+ let bmk1_guid = store.GUIDForId(bmk1_id);
+ _(`Thunderbird GUID: ${bmk1_guid}`);
+
+ // Sync is synchronous, so, to simulate a bookmark change made during a
+ // sync, we create a server record that adds a bookmark as a side effect.
+ let bmk2_guid = "get-firefox1"; // New child of Folder 1, created remotely.
+ let bmk3_id = -1; // New child of Folder 1, created locally during sync.
+ let folder2_guid = "folder2-1111"; // New folder, created remotely.
+ let tagQuery_guid = "tag-query111"; // New tag query child of Folder 2, created remotely.
+ let bmk4_guid = "example-org1"; // New tagged child of Folder 2, created remotely.
+ {
+ // An existing record changed on the server that should not trigger
+ // another sync when applied.
+ let bzBmk = new Bookmark("bookmarks", bz_guid);
+ bzBmk.bmkUri = "https://bugzilla.mozilla.org/";
+ bzBmk.description = "New description";
+ bzBmk.title = "Bugzilla";
+ bzBmk.tags = ["new", "tags"];
+ bzBmk.parentName = "Bookmarks Toolbar";
+ bzBmk.parentid = "toolbar";
+ collection.insert(bz_guid, encryptPayload(bzBmk.cleartext));
+
+ let remoteFolder = new BookmarkFolder("bookmarks", folder2_guid);
+ remoteFolder.title = "Folder 2";
+ remoteFolder.children = [bmk4_guid, tagQuery_guid];
+ remoteFolder.parentName = "Bookmarks Menu";
+ remoteFolder.parentid = "menu";
+ collection.insert(folder2_guid, encryptPayload(remoteFolder.cleartext));
+
+ let localFxBmk = new Bookmark("bookmarks", bmk2_guid);
+ localFxBmk.bmkUri = "http://getfirefox.com/";
+ localFxBmk.description = "Firefox is awesome.";
+ localFxBmk.title = "Get Firefox!";
+ localFxBmk.tags = ["firefox", "awesome", "browser"];
+ localFxBmk.keyword = "awesome";
+ localFxBmk.loadInSidebar = false;
+ localFxBmk.parentName = "Folder 1";
+ localFxBmk.parentid = folder1_guid;
+ let remoteFxBmk = collection.insert(bmk2_guid, encryptPayload(localFxBmk.cleartext));
+ remoteFxBmk.get = function get() {
+ _("Inserting bookmark into local store");
+ bmk3_id = PlacesUtils.bookmarks.insertBookmark(
+ folder1_id, Utils.makeURI("https://mozilla.org/"),
+ PlacesUtils.bookmarks.DEFAULT_INDEX, "Mozilla");
+
+ return ServerWBO.prototype.get.apply(this, arguments);
+ };
+
+ // A tag query referencing a nonexistent tag folder, which we should
+ // create locally when applying the record.
+ let localTagQuery = new BookmarkQuery("bookmarks", tagQuery_guid);
+ localTagQuery.bmkUri = "place:type=7&folder=999";
+ localTagQuery.title = "Taggy tags";
+ localTagQuery.folderName = "taggy";
+ localTagQuery.parentName = "Folder 2";
+ localTagQuery.parentid = folder2_guid;
+ collection.insert(tagQuery_guid, encryptPayload(localTagQuery.cleartext));
+
+ // A bookmark that should appear in the results for the tag query.
+ let localTaggedBmk = new Bookmark("bookmarks", bmk4_guid);
+ localTaggedBmk.bmkUri = "https://example.org";
+ localTaggedBmk.title = "Tagged bookmark";
+ localTaggedBmk.tags = ["taggy"];
+ localTaggedBmk.parentName = "Folder 2";
+ localTaggedBmk.parentid = folder2_guid;
+ collection.insert(bmk4_guid, encryptPayload(localTaggedBmk.cleartext));
+ }
+
+ yield* assertChildGuids(folder1_guid, [bmk1_guid], "Folder should have 1 child before first sync");
+
+ _("Perform first sync");
+ {
+ let changes = engine.pullNewChanges();
+ deepEqual(changes.ids().sort(), [folder1_guid, bmk1_guid, "toolbar"].sort(),
+ "Should track bookmark and folder created before first sync");
+ yield sync_engine_and_validate_telem(engine, false);
+ }
+
+ let bmk2_id = store.idForGUID(bmk2_guid);
+ let bmk3_guid = store.GUIDForId(bmk3_id);
+ _(`Mozilla GUID: ${bmk3_guid}`);
+ {
+ equal(store.GUIDForId(bmk2_id), bmk2_guid,
+ "Remote bookmark should be applied during first sync");
+ ok(bmk3_id > -1,
+ "Bookmark created during first sync should exist locally");
+ ok(!collection.wbo(bmk3_guid),
+ "Bookmark created during first sync shouldn't be uploaded yet");
+
+ yield* assertChildGuids(folder1_guid, [bmk1_guid, bmk3_guid, bmk2_guid],
+ "Folder 1 should have 3 children after first sync");
+ yield* assertChildGuids(folder2_guid, [bmk4_guid, tagQuery_guid],
+ "Folder 2 should have 2 children after first sync");
+ let taggedURIs = PlacesUtils.tagging.getURIsForTag("taggy");
+ equal(taggedURIs.length, 1, "Should have 1 tagged URI");
+ equal(taggedURIs[0].spec, "https://example.org/",
+ "Synced tagged bookmark should appear in tagged URI list");
+ }
+
+ _("Perform second sync");
+ {
+ let changes = engine.pullNewChanges();
+ deepEqual(changes.ids().sort(), [bmk3_guid, folder1_guid].sort(),
+ "Should track bookmark added during last sync and its parent");
+ yield sync_engine_and_validate_telem(engine, false);
+
+ ok(collection.wbo(bmk3_guid),
+ "Bookmark created during first sync should be uploaded during second sync");
+
+ yield* assertChildGuids(folder1_guid, [bmk1_guid, bmk3_guid, bmk2_guid],
+ "Folder 1 should have same children after second sync");
+ yield* assertChildGuids(folder2_guid, [bmk4_guid, tagQuery_guid],
+ "Folder 2 should have same children after second sync");
+ }
+ } finally {
+ store.wipe();
+ Svc.Prefs.resetBranch("");
+ Service.recordManager.clearCache();
+ yield new Promise(resolve => server.stop(resolve));
+ Svc.Obs.notify("weave:engine:stop-tracking");
+ }
+});
+
+add_task(function* bad_record_allIDs() {
+ let server = new SyncServer();
+ server.start();
+ let syncTesting = new SyncTestingInfrastructure(server.server);
+
+ _("Ensure that bad Places queries don't cause an error in getAllIDs.");
+ let engine = new BookmarksEngine(Service);
+ let store = engine._store;
+ let badRecordID = PlacesUtils.bookmarks.insertBookmark(
+ PlacesUtils.bookmarks.toolbarFolder,
+ Utils.makeURI("place:folder=1138"),
+ PlacesUtils.bookmarks.DEFAULT_INDEX,
+ null);
+
+ do_check_true(badRecordID > 0);
+ _("Record is " + badRecordID);
+ _("Type: " + PlacesUtils.bookmarks.getItemType(badRecordID));
+
+ _("Fetching all IDs.");
+ let all = store.getAllIDs();
+
+ _("All IDs: " + JSON.stringify(all));
+ do_check_true("menu" in all);
+ do_check_true("toolbar" in all);
+
+ _("Clean up.");
+ PlacesUtils.bookmarks.removeItem(badRecordID);
+ yield new Promise(r => server.stop(r));
+});
+
+function serverForFoo(engine) {
+ return serverForUsers({"foo": "password"}, {
+ meta: {global: {engines: {bookmarks: {version: engine.version,
+ syncID: engine.syncID}}}},
+ bookmarks: {}
+ });
+}
+
+add_task(function* test_processIncoming_error_orderChildren() {
+ _("Ensure that _orderChildren() is called even when _processIncoming() throws an error.");
+
+ let engine = new BookmarksEngine(Service);
+ let store = engine._store;
+ let server = serverForFoo(engine);
+ new SyncTestingInfrastructure(server.server);
+
+ let collection = server.user("foo").collection("bookmarks");
+
+ try {
+
+ let folder1_id = PlacesUtils.bookmarks.createFolder(
+ PlacesUtils.bookmarks.toolbarFolder, "Folder 1", 0);
+ let folder1_guid = store.GUIDForId(folder1_id);
+
+ let fxuri = Utils.makeURI("http://getfirefox.com/");
+ let tburi = Utils.makeURI("http://getthunderbird.com/");
+
+ let bmk1_id = PlacesUtils.bookmarks.insertBookmark(
+ folder1_id, fxuri, PlacesUtils.bookmarks.DEFAULT_INDEX, "Get Firefox!");
+ let bmk1_guid = store.GUIDForId(bmk1_id);
+ let bmk2_id = PlacesUtils.bookmarks.insertBookmark(
+ folder1_id, tburi, PlacesUtils.bookmarks.DEFAULT_INDEX, "Get Thunderbird!");
+ let bmk2_guid = store.GUIDForId(bmk2_id);
+
+ // Create a server record for folder1 where we flip the order of
+ // the children.
+ let folder1_payload = store.createRecord(folder1_guid).cleartext;
+ folder1_payload.children.reverse();
+ collection.insert(folder1_guid, encryptPayload(folder1_payload));
+
+ // Create a bogus record that when synced down will provoke a
+ // network error which in turn provokes an exception in _processIncoming.
+ const BOGUS_GUID = "zzzzzzzzzzzz";
+ let bogus_record = collection.insert(BOGUS_GUID, "I'm a bogus record!");
+ bogus_record.get = function get() {
+ throw "Sync this!";
+ };
+
+ // Make the 10 minutes old so it will only be synced in the toFetch phase.
+ bogus_record.modified = Date.now() / 1000 - 60 * 10;
+ engine.lastSync = Date.now() / 1000 - 60;
+ engine.toFetch = [BOGUS_GUID];
+
+ let error;
+ try {
+ yield sync_engine_and_validate_telem(engine, true)
+ } catch(ex) {
+ error = ex;
+ }
+ ok(!!error);
+
+ // Verify that the bookmark order has been applied.
+ let new_children = store.createRecord(folder1_guid).children;
+ do_check_eq(new_children.length, 2);
+ do_check_eq(new_children[0], folder1_payload.children[0]);
+ do_check_eq(new_children[1], folder1_payload.children[1]);
+
+ do_check_eq(PlacesUtils.bookmarks.getItemIndex(bmk1_id), 1);
+ do_check_eq(PlacesUtils.bookmarks.getItemIndex(bmk2_id), 0);
+
+ } finally {
+ store.wipe();
+ Svc.Prefs.resetBranch("");
+ Service.recordManager.clearCache();
+ yield new Promise(resolve => server.stop(resolve));
+ }
+});
+
+add_task(function* test_restorePromptsReupload() {
+ _("Ensure that restoring from a backup will reupload all records.");
+ let engine = new BookmarksEngine(Service);
+ let store = engine._store;
+ let server = serverForFoo(engine);
+ new SyncTestingInfrastructure(server.server);
+
+ let collection = server.user("foo").collection("bookmarks");
+
+ Svc.Obs.notify("weave:engine:start-tracking"); // We skip usual startup...
+
+ try {
+
+ let folder1_id = PlacesUtils.bookmarks.createFolder(
+ PlacesUtils.bookmarks.toolbarFolder, "Folder 1", 0);
+ let folder1_guid = store.GUIDForId(folder1_id);
+ _("Folder 1: " + folder1_id + ", " + folder1_guid);
+
+ let fxuri = Utils.makeURI("http://getfirefox.com/");
+ let tburi = Utils.makeURI("http://getthunderbird.com/");
+
+ _("Create a single record.");
+ let bmk1_id = PlacesUtils.bookmarks.insertBookmark(
+ folder1_id, fxuri, PlacesUtils.bookmarks.DEFAULT_INDEX, "Get Firefox!");
+ let bmk1_guid = store.GUIDForId(bmk1_id);
+ _("Get Firefox!: " + bmk1_id + ", " + bmk1_guid);
+
+
+ let dirSvc = Cc["@mozilla.org/file/directory_service;1"]
+ .getService(Ci.nsIProperties);
+
+ let backupFile = dirSvc.get("TmpD", Ci.nsILocalFile);
+
+ _("Make a backup.");
+ backupFile.append("t_b_e_" + Date.now() + ".json");
+
+ _("Backing up to file " + backupFile.path);
+ yield BookmarkJSONUtils.exportToFile(backupFile.path);
+
+ _("Create a different record and sync.");
+ let bmk2_id = PlacesUtils.bookmarks.insertBookmark(
+ folder1_id, tburi, PlacesUtils.bookmarks.DEFAULT_INDEX, "Get Thunderbird!");
+ let bmk2_guid = store.GUIDForId(bmk2_id);
+ _("Get Thunderbird!: " + bmk2_id + ", " + bmk2_guid);
+
+ PlacesUtils.bookmarks.removeItem(bmk1_id);
+
+ let error;
+ try {
+ yield sync_engine_and_validate_telem(engine, false);
+ } catch(ex) {
+ error = ex;
+ _("Got error: " + Log.exceptionStr(ex));
+ }
+ do_check_true(!error);
+
+ _("Verify that there's only one bookmark on the server, and it's Thunderbird.");
+ // Of course, there's also the Bookmarks Toolbar and Bookmarks Menu...
+ let wbos = collection.keys(function (id) {
+ return ["menu", "toolbar", "mobile", "unfiled", folder1_guid].indexOf(id) == -1;
+ });
+ do_check_eq(wbos.length, 1);
+ do_check_eq(wbos[0], bmk2_guid);
+
+ _("Now restore from a backup.");
+ yield BookmarkJSONUtils.importFromFile(backupFile, true);
+
+ _("Ensure we have the bookmarks we expect locally.");
+ let guids = store.getAllIDs();
+ _("GUIDs: " + JSON.stringify(guids));
+ let found = false;
+ let count = 0;
+ let newFX;
+ for (let guid in guids) {
+ count++;
+ let id = store.idForGUID(guid, true);
+ // Only one bookmark, so _all_ should be Firefox!
+ if (PlacesUtils.bookmarks.getItemType(id) == PlacesUtils.bookmarks.TYPE_BOOKMARK) {
+ let uri = PlacesUtils.bookmarks.getBookmarkURI(id);
+ _("Found URI " + uri.spec + " for GUID " + guid);
+ do_check_eq(uri.spec, fxuri.spec);
+ newFX = guid; // Save the new GUID after restore.
+ found = true; // Only runs if the above check passes.
+ }
+ }
+ _("We found it: " + found);
+ do_check_true(found);
+
+ _("Have the correct number of IDs locally, too.");
+ do_check_eq(count, ["menu", "toolbar", "mobile", "unfiled", folder1_id, bmk1_id].length);
+
+ _("Sync again. This'll wipe bookmarks from the server.");
+ try {
+ yield sync_engine_and_validate_telem(engine, false);
+ } catch(ex) {
+ error = ex;
+ _("Got error: " + Log.exceptionStr(ex));
+ }
+ do_check_true(!error);
+
+ _("Verify that there's only one bookmark on the server, and it's Firefox.");
+ // Of course, there's also the Bookmarks Toolbar and Bookmarks Menu...
+ let payloads = server.user("foo").collection("bookmarks").payloads();
+ let bookmarkWBOs = payloads.filter(function (wbo) {
+ return wbo.type == "bookmark";
+ });
+ let folderWBOs = payloads.filter(function (wbo) {
+ return ((wbo.type == "folder") &&
+ (wbo.id != "menu") &&
+ (wbo.id != "toolbar") &&
+ (wbo.id != "unfiled") &&
+ (wbo.id != "mobile"));
+ });
+
+ do_check_eq(bookmarkWBOs.length, 1);
+ do_check_eq(bookmarkWBOs[0].id, newFX);
+ do_check_eq(bookmarkWBOs[0].bmkUri, fxuri.spec);
+ do_check_eq(bookmarkWBOs[0].title, "Get Firefox!");
+
+ _("Our old friend Folder 1 is still in play.");
+ do_check_eq(folderWBOs.length, 1);
+ do_check_eq(folderWBOs[0].title, "Folder 1");
+
+ } finally {
+ store.wipe();
+ Svc.Prefs.resetBranch("");
+ Service.recordManager.clearCache();
+ let deferred = Promise.defer();
+ server.stop(deferred.resolve);
+ yield deferred.promise;
+ }
+});
+
+function FakeRecord(constructor, r) {
+ constructor.call(this, "bookmarks", r.id);
+ for (let x in r) {
+ this[x] = r[x];
+ }
+ // Borrow the constructor's conversion functions.
+ this.toSyncBookmark = constructor.prototype.toSyncBookmark;
+}
+
+// Bug 632287.
+add_task(function* test_mismatched_types() {
+ _("Ensure that handling a record that changes type causes deletion " +
+ "then re-adding.");
+
+ let oldRecord = {
+ "id": "l1nZZXfB8nC7",
+ "type":"folder",
+ "parentName":"Bookmarks Toolbar",
+ "title":"Innerst i Sneglehode",
+ "description":null,
+ "parentid": "toolbar"
+ };
+ oldRecord.cleartext = oldRecord;
+
+ let newRecord = {
+ "id": "l1nZZXfB8nC7",
+ "type":"livemark",
+ "siteUri":"http://sneglehode.wordpress.com/",
+ "feedUri":"http://sneglehode.wordpress.com/feed/",
+ "parentName":"Bookmarks Toolbar",
+ "title":"Innerst i Sneglehode",
+ "description":null,
+ "children":
+ ["HCRq40Rnxhrd", "YeyWCV1RVsYw", "GCceVZMhvMbP", "sYi2hevdArlF",
+ "vjbZlPlSyGY8", "UtjUhVyrpeG6", "rVq8WMG2wfZI", "Lx0tcy43ZKhZ",
+ "oT74WwV8_j4P", "IztsItWVSo3-"],
+ "parentid": "toolbar"
+ };
+ newRecord.cleartext = newRecord;
+
+ let engine = new BookmarksEngine(Service);
+ let store = engine._store;
+ let server = serverForFoo(engine);
+ new SyncTestingInfrastructure(server.server);
+
+ _("GUID: " + store.GUIDForId(6, true));
+
+ try {
+ let bms = PlacesUtils.bookmarks;
+ let oldR = new FakeRecord(BookmarkFolder, oldRecord);
+ let newR = new FakeRecord(Livemark, newRecord);
+ oldR.parentid = PlacesUtils.bookmarks.toolbarGuid;
+ newR.parentid = PlacesUtils.bookmarks.toolbarGuid;
+
+ store.applyIncoming(oldR);
+ _("Applied old. It's a folder.");
+ let oldID = store.idForGUID(oldR.id);
+ _("Old ID: " + oldID);
+ do_check_eq(bms.getItemType(oldID), bms.TYPE_FOLDER);
+ do_check_false(PlacesUtils.annotations
+ .itemHasAnnotation(oldID, PlacesUtils.LMANNO_FEEDURI));
+
+ store.applyIncoming(newR);
+ let newID = store.idForGUID(newR.id);
+ _("New ID: " + newID);
+
+ _("Applied new. It's a livemark.");
+ do_check_eq(bms.getItemType(newID), bms.TYPE_FOLDER);
+ do_check_true(PlacesUtils.annotations
+ .itemHasAnnotation(newID, PlacesUtils.LMANNO_FEEDURI));
+
+ } finally {
+ store.wipe();
+ Svc.Prefs.resetBranch("");
+ Service.recordManager.clearCache();
+ yield new Promise(r => server.stop(r));
+ }
+});
+
+add_task(function* test_bookmark_guidMap_fail() {
+ _("Ensure that failures building the GUID map cause early death.");
+
+ let engine = new BookmarksEngine(Service);
+ let store = engine._store;
+
+ let server = serverForFoo(engine);
+ let coll = server.user("foo").collection("bookmarks");
+ new SyncTestingInfrastructure(server.server);
+
+ // Add one item to the server.
+ let itemID = PlacesUtils.bookmarks.createFolder(
+ PlacesUtils.bookmarks.toolbarFolder, "Folder 1", 0);
+ let itemGUID = store.GUIDForId(itemID);
+ let itemPayload = store.createRecord(itemGUID).cleartext;
+ coll.insert(itemGUID, encryptPayload(itemPayload));
+
+ engine.lastSync = 1; // So we don't back up.
+
+ // Make building the GUID map fail.
+
+ let pbt = PlacesUtils.promiseBookmarksTree;
+ PlacesUtils.promiseBookmarksTree = function() { return Promise.reject("Nooo"); };
+
+ // Ensure that we throw when accessing _guidMap.
+ engine._syncStartup();
+ _("No error.");
+ do_check_false(engine._guidMapFailed);
+
+ _("We get an error if building _guidMap fails in use.");
+ let err;
+ try {
+ _(engine._guidMap);
+ } catch (ex) {
+ err = ex;
+ }
+ do_check_eq(err.code, Engine.prototype.eEngineAbortApplyIncoming);
+ do_check_eq(err.cause, "Nooo");
+
+ _("We get an error and abort during processIncoming.");
+ err = undefined;
+ try {
+ engine._processIncoming();
+ } catch (ex) {
+ err = ex;
+ }
+ do_check_eq(err, "Nooo");
+
+ PlacesUtils.promiseBookmarksTree = pbt;
+ yield new Promise(r => server.stop(r));
+});
+
+add_task(function* test_bookmark_tag_but_no_uri() {
+ _("Ensure that a bookmark record with tags, but no URI, doesn't throw an exception.");
+
+ let engine = new BookmarksEngine(Service);
+ let store = engine._store;
+
+ // We're simply checking that no exception is thrown, so
+ // no actual checks in this test.
+
+ yield PlacesSyncUtils.bookmarks.insert({
+ kind: PlacesSyncUtils.bookmarks.KINDS.BOOKMARK,
+ syncId: Utils.makeGUID(),
+ parentSyncId: "toolbar",
+ url: "http://example.com",
+ tags: ["foo"],
+ });
+ yield PlacesSyncUtils.bookmarks.insert({
+ kind: PlacesSyncUtils.bookmarks.KINDS.BOOKMARK,
+ syncId: Utils.makeGUID(),
+ parentSyncId: "toolbar",
+ url: "http://example.org",
+ tags: null,
+ });
+ yield PlacesSyncUtils.bookmarks.insert({
+ kind: PlacesSyncUtils.bookmarks.KINDS.BOOKMARK,
+ syncId: Utils.makeGUID(),
+ url: "about:fake",
+ parentSyncId: "toolbar",
+ tags: null,
+ });
+
+ let record = new FakeRecord(BookmarkFolder, {
+ parentid: "toolbar",
+ id: Utils.makeGUID(),
+ description: "",
+ tags: ["foo"],
+ title: "Taggy tag",
+ type: "folder"
+ });
+
+ store.create(record);
+ record.tags = ["bar"];
+ store.update(record);
+});
+
+add_task(function* test_misreconciled_root() {
+ _("Ensure that we don't reconcile an arbitrary record with a root.");
+
+ let engine = new BookmarksEngine(Service);
+ let store = engine._store;
+ let server = serverForFoo(engine);
+
+ // Log real hard for this test.
+ store._log.trace = store._log.debug;
+ engine._log.trace = engine._log.debug;
+
+ engine._syncStartup();
+
+ // Let's find out where the toolbar is right now.
+ let toolbarBefore = store.createRecord("toolbar", "bookmarks");
+ let toolbarIDBefore = store.idForGUID("toolbar");
+ do_check_neq(-1, toolbarIDBefore);
+
+ let parentGUIDBefore = toolbarBefore.parentid;
+ let parentIDBefore = store.idForGUID(parentGUIDBefore);
+ do_check_neq(-1, parentIDBefore);
+ do_check_eq("string", typeof(parentGUIDBefore));
+
+ _("Current parent: " + parentGUIDBefore + " (" + parentIDBefore + ").");
+
+ let to_apply = {
+ id: "zzzzzzzzzzzz",
+ type: "folder",
+ title: "Bookmarks Toolbar",
+ description: "Now you're for it.",
+ parentName: "",
+ parentid: "mobile", // Why not?
+ children: [],
+ };
+
+ let rec = new FakeRecord(BookmarkFolder, to_apply);
+ let encrypted = encryptPayload(rec.cleartext);
+ encrypted.decrypt = function () {
+ for (let x in rec) {
+ encrypted[x] = rec[x];
+ }
+ };
+
+ _("Applying record.");
+ engine._processIncoming({
+ getBatched() {
+ return this.get();
+ },
+ get: function () {
+ this.recordHandler(encrypted);
+ return {success: true}
+ },
+ });
+
+ // Ensure that afterwards, toolbar is still there.
+ // As of 2012-12-05, this only passes because Places doesn't use "toolbar" as
+ // the real GUID, instead using a generated one. Sync does the translation.
+ let toolbarAfter = store.createRecord("toolbar", "bookmarks");
+ let parentGUIDAfter = toolbarAfter.parentid;
+ let parentIDAfter = store.idForGUID(parentGUIDAfter);
+ do_check_eq(store.GUIDForId(toolbarIDBefore), "toolbar");
+ do_check_eq(parentGUIDBefore, parentGUIDAfter);
+ do_check_eq(parentIDBefore, parentIDAfter);
+
+ yield new Promise(r => server.stop(r));
+});
+
+function run_test() {
+ initTestLogging("Trace");
+ generateNewKeys(Service.collectionKeys);
+ run_next_test();
+}