Bug 1323333 - Tests for new bookmark deduping. draft
authorKit Cambridge <kit@yakshaving.ninja>
Thu, 27 Apr 2017 15:47:11 -0700
changeset 569797 49c71c016a876ab1fe126bfe3dc26b6d4ed6edbf
parent 569796 73531e63fdae220e3008e5ab5404b139eb0e8001
child 626305 d8498f75854ae540be48ad864757fad423cade7c
push id56282
push userbmo:kit@mozilla.com
push dateThu, 27 Apr 2017 22:47:44 +0000
bugs1323333
milestone55.0a1
Bug 1323333 - Tests for new bookmark deduping. MozReview-Commit-ID: 9CuSxZJHu2R
services/sync/tests/unit/test_bookmark_duping.js
--- a/services/sync/tests/unit/test_bookmark_duping.js
+++ b/services/sync/tests/unit/test_bookmark_duping.js
@@ -127,67 +127,217 @@ async function validate(collection, expe
     // All server records and the entire bookmark tree.
     do_print("Server records:\n" + JSON.stringify(collection.payloads(), undefined, 2));
     let tree = await PlacesUtils.promiseBookmarksTree("", { includeItemIds: true });
     do_print("Local bookmark tree:\n" + JSON.stringify(tree, undefined, 2));
     ok(false);
   }
 }
 
+function nodesToInfos(nodes) {
+  return nodes.map(node => {
+    let info = {
+      guid: node.guid,
+      index: node.index,
+    };
+    if (node.children) {
+      info.children = nodesToInfos(node.children);
+    }
+    return info;
+  });
+}
+
+async function assertTreeMatches(rootGuid, expected, message) {
+  let root = await PlacesUtils.promiseBookmarksTree(rootGuid);
+  let actual = nodesToInfos(root.children);
+
+  _(`Expected structure for ${rootGuid}`, JSON.stringify(expected));
+  _(`Actual structure for ${rootGuid}`, JSON.stringify(actual));
+  deepEqual(actual, expected, message);
+}
+
+add_task(async function test_dedupe_subtrees() {
+  _("Ensure that congruent subtrees are deduped");
+
+  let { server, collection } = await this.setup();
+
+  let parentFolderGuid = Utils.makeGUID();
+  let fxGuid = Utils.makeGUID();
+  let tbGuid = Utils.makeGUID();
+  let startFolderGuid = Utils.makeGUID();
+  let bzGuid = Utils.makeGUID();
+  let nightlyGuid = Utils.makeGUID();
+
+  let serverRecords = [{
+    id: parentFolderGuid,
+    type: "folder",
+    title: "Parent folder",
+    parentid: "menu",
+    children: [tbGuid, fxGuid, startFolderGuid],
+  }, {
+    id: fxGuid,
+    type: "bookmark",
+    bmkUri: "http://getfirefox.com/",
+    title: "Get Firefox!",
+    parentid: parentFolderGuid,
+  }, {
+    id: tbGuid,
+    type: "bookmark",
+    bmkUri: "http://getthunderbird.com/",
+    title: "Get Thunderbird!",
+    parentid: parentFolderGuid,
+  }, {
+    id: startFolderGuid,
+    type: "folder",
+    title: "Getting Started",
+    parentid: parentFolderGuid,
+    children: [nightlyGuid, bzGuid],
+  }, {
+    id: bzGuid,
+    type: "bookmark",
+    bmkUri: "https://bugzilla.mozilla.org/",
+    title: "Bugzilla",
+    parentid: startFolderGuid,
+  }, {
+    id: nightlyGuid,
+    type: "bookmark",
+    bmkUri: "https://nightly.mozilla.org/",
+    title: "Nightly",
+    parentid: startFolderGuid,
+  }];
+
+  try {
+    _("Create subtree on server");
+    for (let record of serverRecords) {
+      collection.insert(record.id, encryptPayload(record), Date.now() / 1000 + 500);
+    }
+
+    // The local subtree has different GUIDs and child bookmarks in a different
+    // order.
+    let supportGuid = PlacesUtils.history.makeGuid();
+    _("Create local subtree");
+    await PlacesUtils.bookmarks.insertTree({
+      guid: PlacesUtils.bookmarks.menuGuid,
+      children: [{
+        type: PlacesUtils.bookmarks.TYPE_FOLDER,
+        title: "Parent folder",
+        children: [{
+          title: "Get Firefox!",
+          url: "http://getfirefox.com/",
+        }, {
+          type: PlacesUtils.bookmarks.TYPE_FOLDER,
+          title: "Getting Started",
+          children: [{
+            title: "Bugzilla",
+            url: "https://bugzilla.mozilla.org/",
+          }, {
+            // A local bookmark that's not on the server, and that we should
+            // move into the collapsed folder.
+            guid: supportGuid,
+            title: "Help and Tutorials",
+            url: "https://support.mozilla.org",
+          }, {
+            title: "Nightly",
+            url: "https://nightly.mozilla.org/",
+          }],
+        }, {
+          title: "Get Thunderbird!",
+          url: "http://getthunderbird.com/",
+        }],
+      }],
+    });
+
+    _("Sync to flatten dupes");
+    engine.sync();
+
+    assertTreeMatches(PlacesUtils.bookmarks.menuGuid, [{
+      guid: parentFolderGuid,
+      index: 0,
+      children: [{
+        guid: tbGuid,
+        index: 0,
+      }, {
+        guid: fxGuid,
+        index: 1,
+      }, {
+        guid: startFolderGuid,
+        index: 2,
+        children: [{
+          guid: nightlyGuid,
+          index: 0,
+        }, {
+          guid: bzGuid,
+          index: 1,
+        }, {
+          guid: supportGuid,
+          index: 2,
+        }],
+      }],
+    }], "New local dupes should be merged with existing remote items");
+
+    // and a final sanity check - use the validator
+    await validate(collection);
+  } finally {
+    await cleanup(server);
+  }
+});
+
 add_task(async function test_dupe_bookmark() {
   _("Ensure that a bookmark we consider a dupe is handled correctly.");
 
   let { server, collection } = await this.setup();
 
   try {
     // The parent folder and one bookmark in it.
     let {id: folder1_id, guid: folder1_guid } = await createFolder(bms.toolbarFolder, "Folder 1");
     let {guid: bmk1_guid} = await createBookmark(folder1_id, "http://getfirefox.com/", "Get Firefox!");
 
-    engine.sync();
-
-    // We've added the bookmark, its parent (folder1) plus "menu", "toolbar", "unfiled", and "mobile".
-    equal(collection.count(), 6);
-    equal((await getFolderChildrenIDs(folder1_id)).length, 1);
-
-    // Now create a new incoming record that looks alot like a dupe.
+    // Create a remote bookmark that's a dupe of the local bookmark.
     let newGUID = Utils.makeGUID();
     let to_apply = {
       id: newGUID,
       bmkUri: "http://getfirefox.com/",
       type: "bookmark",
       title: "Get Firefox!",
       parentName: "Folder 1",
       parentid: folder1_guid,
     };
+    collection.insert(newGUID, encryptPayload(to_apply), Date.now() / 1000 + 500);
 
-    collection.insert(newGUID, encryptPayload(to_apply), Date.now() / 1000 + 500);
-    _("Syncing so new dupe record is processed");
-    engine.lastSync = engine.lastSync - 5;
     engine.sync();
 
-    // We should have logically deleted the dupe record.
-    equal(collection.count(), 7);
-    ok(getServerRecord(collection, bmk1_guid).deleted);
-    // and physically removed from the local store.
+    // We've added the bookmark's parent (folder1) plus "menu", "toolbar", "unfiled", and "mobile".
+    equal(collection.count(), 6);
+    // and physically removed the local dupe.
     await promiseNoLocalItem(bmk1_guid);
-    // Parent should still only have 1 item.
+    // Parent should only have 1 item.
     equal((await getFolderChildrenIDs(folder1_id)).length, 1);
     // The parent record on the server should now reference the new GUID and not the old.
     let serverRecord = getServerRecord(collection, folder1_guid);
     ok(!serverRecord.children.includes(bmk1_guid));
     ok(serverRecord.children.includes(newGUID));
 
     // and a final sanity check - use the validator
     await validate(collection);
   } finally {
     await cleanup(server);
   }
 });
 
+add_task(async function test_dedupe_keeps_explicit_dupes() {
+  // The "multiple empty folders with different contents" test from bug 1213369.
+  // Make sure we use local and remote indices to match these explicit dupes.
+});
+
+/* TODO: These semantics are no longer correct. We'll never dedupe across
+   parents; reparenting a similar item *will* result in a dupe. Tests that
+   insert dupes into remote collections are also wrong, since they don't
+   update the parent and will cause validation failures. */
+
+/*
 add_task(async function test_dupe_reparented_bookmark() {
   _("Ensure that a bookmark we consider a dupe from a different parent is handled correctly");
 
   let { server, collection } = await this.setup();
 
   try {
     // The parent folder and one bookmark in it.
     let {id: folder1_id, guid: folder1_guid } = await createFolder(bms.toolbarFolder, "Folder 1");
@@ -641,8 +791,9 @@ add_task(async function test_dupe_empty_
     // original folder should be logically deleted.
     ok(getServerRecord(collection, folder1_guid).deleted);
     await promiseNoLocalItem(folder1_guid);
   } finally {
     await cleanup(server);
   }
 });
 // XXX - TODO - folders with children. Bug 1293163
+*/