summaryrefslogtreecommitdiffstats
path: root/services/sync/tests/unit/test_bookmark_tracker.js
diff options
context:
space:
mode:
Diffstat (limited to 'services/sync/tests/unit/test_bookmark_tracker.js')
-rw-r--r--services/sync/tests/unit/test_bookmark_tracker.js1537
1 files changed, 1537 insertions, 0 deletions
diff --git a/services/sync/tests/unit/test_bookmark_tracker.js b/services/sync/tests/unit/test_bookmark_tracker.js
new file mode 100644
index 000000000..9b9242579
--- /dev/null
+++ b/services/sync/tests/unit/test_bookmark_tracker.js
@@ -0,0 +1,1537 @@
+/* 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/Task.jsm");
+Cu.import("resource://services-sync/constants.js");
+Cu.import("resource://services-sync/engines/bookmarks.js");
+Cu.import("resource://services-sync/engines.js");
+Cu.import("resource://services-sync/service.js");
+Cu.import("resource://services-sync/util.js");
+Cu.import("resource:///modules/PlacesUIUtils.jsm");
+
+Service.engineManager.register(BookmarksEngine);
+var engine = Service.engineManager.get("bookmarks");
+var store = engine._store;
+var tracker = engine._tracker;
+
+store.wipe();
+tracker.persistChangedIDs = false;
+
+const DAY_IN_MS = 24 * 60 * 60 * 1000;
+
+// Test helpers.
+function* verifyTrackerEmpty() {
+ let changes = engine.pullNewChanges();
+ equal(changes.count(), 0);
+ equal(tracker.score, 0);
+}
+
+function* resetTracker() {
+ tracker.clearChangedIDs();
+ tracker.resetScore();
+}
+
+function* cleanup() {
+ store.wipe();
+ yield resetTracker();
+ yield stopTracking();
+}
+
+// startTracking is a signal that the test wants to notice things that happen
+// after this is called (ie, things already tracked should be discarded.)
+function* startTracking() {
+ Svc.Obs.notify("weave:engine:start-tracking");
+}
+
+function* stopTracking() {
+ Svc.Obs.notify("weave:engine:stop-tracking");
+}
+
+function* verifyTrackedItems(tracked) {
+ let changes = engine.pullNewChanges();
+ let trackedIDs = new Set(changes.ids());
+ for (let guid of tracked) {
+ ok(changes.has(guid), `${guid} should be tracked`);
+ ok(changes.getModifiedTimestamp(guid) > 0,
+ `${guid} should have a modified time`);
+ trackedIDs.delete(guid);
+ }
+ equal(trackedIDs.size, 0, `Unhandled tracked IDs: ${
+ JSON.stringify(Array.from(trackedIDs))}`);
+}
+
+function* verifyTrackedCount(expected) {
+ let changes = engine.pullNewChanges();
+ equal(changes.count(), expected);
+}
+
+// Copied from PlacesSyncUtils.jsm.
+function findAnnoItems(anno, val) {
+ let annos = PlacesUtils.annotations;
+ return annos.getItemsWithAnnotation(anno, {}).filter(id =>
+ annos.getItemAnnotation(id, anno) == val);
+}
+
+add_task(function* test_tracking() {
+ _("Test starting and stopping the tracker");
+
+ let folder = PlacesUtils.bookmarks.createFolder(
+ PlacesUtils.bookmarks.bookmarksMenuFolder,
+ "Test Folder", PlacesUtils.bookmarks.DEFAULT_INDEX);
+ function createBmk() {
+ return PlacesUtils.bookmarks.insertBookmark(
+ folder, Utils.makeURI("http://getfirefox.com"),
+ PlacesUtils.bookmarks.DEFAULT_INDEX, "Get Firefox!");
+ }
+
+ try {
+ _("Create bookmark. Won't show because we haven't started tracking yet");
+ createBmk();
+ yield verifyTrackedCount(0);
+ do_check_eq(tracker.score, 0);
+
+ _("Tell the tracker to start tracking changes.");
+ yield startTracking();
+ createBmk();
+ // We expect two changed items because the containing folder
+ // changed as well (new child).
+ yield verifyTrackedCount(2);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
+
+ _("Notifying twice won't do any harm.");
+ yield startTracking();
+ createBmk();
+ yield verifyTrackedCount(3);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 4);
+
+ _("Let's stop tracking again.");
+ yield resetTracker();
+ yield stopTracking();
+ createBmk();
+ yield verifyTrackedCount(0);
+ do_check_eq(tracker.score, 0);
+
+ _("Notifying twice won't do any harm.");
+ yield stopTracking();
+ createBmk();
+ yield verifyTrackedCount(0);
+ do_check_eq(tracker.score, 0);
+
+ } finally {
+ _("Clean up.");
+ yield cleanup();
+ }
+});
+
+add_task(function* test_batch_tracking() {
+ _("Test tracker does the correct thing during and after a places 'batch'");
+
+ yield startTracking();
+
+ PlacesUtils.bookmarks.runInBatchMode({
+ runBatched: function() {
+ let folder = PlacesUtils.bookmarks.createFolder(
+ PlacesUtils.bookmarks.bookmarksMenuFolder,
+ "Test Folder", PlacesUtils.bookmarks.DEFAULT_INDEX);
+ // We should be tracking the new folder and its parent (and need to jump
+ // through blocking hoops...)
+ Async.promiseSpinningly(Task.spawn(verifyTrackedCount(2)));
+ // But not have bumped the score.
+ do_check_eq(tracker.score, 0);
+ }
+ }, null);
+
+ // Out of batch mode - tracker should be the same, but score should be up.
+ yield verifyTrackedCount(2);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE);
+ yield cleanup();
+});
+
+add_task(function* test_nested_batch_tracking() {
+ _("Test tracker does the correct thing if a places 'batch' is nested");
+
+ yield startTracking();
+
+ PlacesUtils.bookmarks.runInBatchMode({
+ runBatched: function() {
+
+ PlacesUtils.bookmarks.runInBatchMode({
+ runBatched: function() {
+ let folder = PlacesUtils.bookmarks.createFolder(
+ PlacesUtils.bookmarks.bookmarksMenuFolder,
+ "Test Folder", PlacesUtils.bookmarks.DEFAULT_INDEX);
+ // We should be tracking the new folder and its parent (and need to jump
+ // through blocking hoops...)
+ Async.promiseSpinningly(Task.spawn(verifyTrackedCount(2)));
+ // But not have bumped the score.
+ do_check_eq(tracker.score, 0);
+ }
+ }, null);
+ _("inner batch complete.");
+ // should still not have a score as the outer batch is pending.
+ do_check_eq(tracker.score, 0);
+ }
+ }, null);
+
+ // Out of both batches - tracker should be the same, but score should be up.
+ yield verifyTrackedCount(2);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE);
+ yield cleanup();
+});
+
+add_task(function* test_tracker_sql_batching() {
+ _("Test tracker does the correct thing when it is forced to batch SQL queries");
+
+ const SQLITE_MAX_VARIABLE_NUMBER = 999;
+ let numItems = SQLITE_MAX_VARIABLE_NUMBER * 2 + 10;
+ let createdIDs = [];
+
+ yield startTracking();
+
+ PlacesUtils.bookmarks.runInBatchMode({
+ runBatched: function() {
+ for (let i = 0; i < numItems; i++) {
+ let syncBmkID = PlacesUtils.bookmarks.insertBookmark(
+ PlacesUtils.bookmarks.unfiledBookmarksFolder,
+ Utils.makeURI("https://example.org/" + i),
+ PlacesUtils.bookmarks.DEFAULT_INDEX,
+ "Sync Bookmark " + i);
+ createdIDs.push(syncBmkID);
+ }
+ }
+ }, null);
+
+ do_check_eq(createdIDs.length, numItems);
+ yield verifyTrackedCount(numItems + 1); // the folder is also tracked.
+ yield cleanup();
+});
+
+add_task(function* test_onItemAdded() {
+ _("Items inserted via the synchronous bookmarks API should be tracked");
+
+ try {
+ yield startTracking();
+
+ _("Insert a folder using the sync API");
+ let syncFolderID = PlacesUtils.bookmarks.createFolder(
+ PlacesUtils.bookmarks.bookmarksMenuFolder, "Sync Folder",
+ PlacesUtils.bookmarks.DEFAULT_INDEX);
+ let syncFolderGUID = engine._store.GUIDForId(syncFolderID);
+ yield verifyTrackedItems(["menu", syncFolderGUID]);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
+
+ yield resetTracker();
+ yield startTracking();
+
+ _("Insert a bookmark using the sync API");
+ let syncBmkID = PlacesUtils.bookmarks.insertBookmark(syncFolderID,
+ Utils.makeURI("https://example.org/sync"),
+ PlacesUtils.bookmarks.DEFAULT_INDEX,
+ "Sync Bookmark");
+ let syncBmkGUID = engine._store.GUIDForId(syncBmkID);
+ yield verifyTrackedItems([syncFolderGUID, syncBmkGUID]);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
+
+ yield resetTracker();
+ yield startTracking();
+
+ _("Insert a separator using the sync API");
+ let syncSepID = PlacesUtils.bookmarks.insertSeparator(
+ PlacesUtils.bookmarks.bookmarksMenuFolder,
+ PlacesUtils.bookmarks.getItemIndex(syncFolderID));
+ let syncSepGUID = engine._store.GUIDForId(syncSepID);
+ yield verifyTrackedItems(["menu", syncSepGUID]);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
+ } finally {
+ _("Clean up.");
+ yield cleanup();
+ }
+});
+
+add_task(function* test_async_onItemAdded() {
+ _("Items inserted via the asynchronous bookmarks API should be tracked");
+
+ try {
+ yield startTracking();
+
+ _("Insert a folder using the async API");
+ let asyncFolder = yield PlacesUtils.bookmarks.insert({
+ type: PlacesUtils.bookmarks.TYPE_FOLDER,
+ parentGuid: PlacesUtils.bookmarks.menuGuid,
+ title: "Async Folder",
+ });
+ yield verifyTrackedItems(["menu", asyncFolder.guid]);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
+
+ yield resetTracker();
+ yield startTracking();
+
+ _("Insert a bookmark using the async API");
+ let asyncBmk = yield PlacesUtils.bookmarks.insert({
+ type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
+ parentGuid: asyncFolder.guid,
+ url: "https://example.org/async",
+ title: "Async Bookmark",
+ });
+ yield verifyTrackedItems([asyncFolder.guid, asyncBmk.guid]);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
+
+ yield resetTracker();
+ yield startTracking();
+
+ _("Insert a separator using the async API");
+ let asyncSep = yield PlacesUtils.bookmarks.insert({
+ type: PlacesUtils.bookmarks.TYPE_SEPARATOR,
+ parentGuid: PlacesUtils.bookmarks.menuGuid,
+ index: asyncFolder.index,
+ });
+ yield verifyTrackedItems(["menu", asyncSep.guid]);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
+ } finally {
+ _("Clean up.");
+ yield cleanup();
+ }
+});
+
+add_task(function* test_async_onItemChanged() {
+ _("Items updated using the asynchronous bookmarks API should be tracked");
+
+ try {
+ yield stopTracking();
+
+ _("Insert a bookmark");
+ let fxBmk = yield PlacesUtils.bookmarks.insert({
+ type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
+ parentGuid: PlacesUtils.bookmarks.menuGuid,
+ url: "http://getfirefox.com",
+ title: "Get Firefox!",
+ });
+ _(`Firefox GUID: ${fxBmk.guid}`);
+
+ yield startTracking();
+
+ _("Update the bookmark using the async API");
+ yield PlacesUtils.bookmarks.update({
+ guid: fxBmk.guid,
+ title: "Download Firefox",
+ url: "https://www.mozilla.org/firefox",
+ // PlacesUtils.bookmarks.update rejects last modified dates older than
+ // the added date.
+ lastModified: new Date(Date.now() + DAY_IN_MS),
+ });
+
+ yield verifyTrackedItems([fxBmk.guid]);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 3);
+ } finally {
+ _("Clean up.");
+ yield cleanup();
+ }
+});
+
+add_task(function* test_onItemChanged_itemDates() {
+ _("Changes to item dates should be tracked");
+
+ try {
+ yield stopTracking();
+
+ _("Insert a bookmark");
+ let fx_id = PlacesUtils.bookmarks.insertBookmark(
+ PlacesUtils.bookmarks.bookmarksMenuFolder,
+ Utils.makeURI("http://getfirefox.com"),
+ PlacesUtils.bookmarks.DEFAULT_INDEX,
+ "Get Firefox!");
+ let fx_guid = engine._store.GUIDForId(fx_id);
+ _(`Firefox GUID: ${fx_guid}`);
+
+ yield startTracking();
+
+ _("Reset the bookmark's added date");
+ // Convert to microseconds for PRTime.
+ let dateAdded = (Date.now() - DAY_IN_MS) * 1000;
+ PlacesUtils.bookmarks.setItemDateAdded(fx_id, dateAdded);
+ yield verifyTrackedItems([fx_guid]);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE);
+ yield resetTracker();
+
+ _("Set the bookmark's last modified date");
+ let dateModified = Date.now() * 1000;
+ PlacesUtils.bookmarks.setItemLastModified(fx_id, dateModified);
+ yield verifyTrackedItems([fx_guid]);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE);
+ } finally {
+ _("Clean up.");
+ yield cleanup();
+ }
+});
+
+add_task(function* test_onItemChanged_changeBookmarkURI() {
+ _("Changes to bookmark URIs should be tracked");
+
+ try {
+ yield stopTracking();
+
+ _("Insert a bookmark");
+ let fx_id = PlacesUtils.bookmarks.insertBookmark(
+ PlacesUtils.bookmarks.bookmarksMenuFolder,
+ Utils.makeURI("http://getfirefox.com"),
+ PlacesUtils.bookmarks.DEFAULT_INDEX,
+ "Get Firefox!");
+ let fx_guid = engine._store.GUIDForId(fx_id);
+ _(`Firefox GUID: ${fx_guid}`);
+
+ _("Set a tracked annotation to make sure we only notify once");
+ PlacesUtils.annotations.setItemAnnotation(
+ fx_id, PlacesSyncUtils.bookmarks.DESCRIPTION_ANNO, "A test description", 0,
+ PlacesUtils.annotations.EXPIRE_NEVER);
+
+ yield startTracking();
+
+ _("Change the bookmark's URI");
+ PlacesUtils.bookmarks.changeBookmarkURI(fx_id,
+ Utils.makeURI("https://www.mozilla.org/firefox"));
+ yield verifyTrackedItems([fx_guid]);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE);
+ } finally {
+ _("Clean up.");
+ yield cleanup();
+ }
+});
+
+add_task(function* test_onItemTagged() {
+ _("Items tagged using the synchronous API should be tracked");
+
+ try {
+ yield stopTracking();
+
+ _("Create a folder");
+ let folder = PlacesUtils.bookmarks.createFolder(
+ PlacesUtils.bookmarks.bookmarksMenuFolder, "Parent",
+ PlacesUtils.bookmarks.DEFAULT_INDEX);
+ let folderGUID = engine._store.GUIDForId(folder);
+ _("Folder ID: " + folder);
+ _("Folder GUID: " + folderGUID);
+
+ _("Track changes to tags");
+ let uri = Utils.makeURI("http://getfirefox.com");
+ let b = PlacesUtils.bookmarks.insertBookmark(
+ folder, uri,
+ PlacesUtils.bookmarks.DEFAULT_INDEX, "Get Firefox!");
+ let bGUID = engine._store.GUIDForId(b);
+ _("New item is " + b);
+ _("GUID: " + bGUID);
+
+ yield startTracking();
+
+ _("Tag the item");
+ PlacesUtils.tagging.tagURI(uri, ["foo"]);
+
+ // bookmark should be tracked, folder should not be.
+ yield verifyTrackedItems([bGUID]);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 5);
+ } finally {
+ _("Clean up.");
+ yield cleanup();
+ }
+});
+
+add_task(function* test_onItemUntagged() {
+ _("Items untagged using the synchronous API should be tracked");
+
+ try {
+ yield stopTracking();
+
+ _("Insert tagged bookmarks");
+ let uri = Utils.makeURI("http://getfirefox.com");
+ let fx1ID = PlacesUtils.bookmarks.insertBookmark(
+ PlacesUtils.bookmarks.bookmarksMenuFolder, uri,
+ PlacesUtils.bookmarks.DEFAULT_INDEX, "Get Firefox!");
+ let fx1GUID = engine._store.GUIDForId(fx1ID);
+ // Different parent and title; same URL.
+ let fx2ID = PlacesUtils.bookmarks.insertBookmark(
+ PlacesUtils.bookmarks.toolbarFolder, uri,
+ PlacesUtils.bookmarks.DEFAULT_INDEX, "Download Firefox");
+ let fx2GUID = engine._store.GUIDForId(fx2ID);
+ PlacesUtils.tagging.tagURI(uri, ["foo"]);
+
+ yield startTracking();
+
+ _("Remove the tag");
+ PlacesUtils.tagging.untagURI(uri, ["foo"]);
+
+ yield verifyTrackedItems([fx1GUID, fx2GUID]);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
+ } finally {
+ _("Clean up.");
+ yield cleanup();
+ }
+});
+
+add_task(function* test_async_onItemUntagged() {
+ _("Items untagged using the asynchronous API should be tracked");
+
+ try {
+ yield stopTracking();
+
+ _("Insert tagged bookmarks");
+ let fxBmk1 = yield PlacesUtils.bookmarks.insert({
+ type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
+ parentGuid: PlacesUtils.bookmarks.menuGuid,
+ url: "http://getfirefox.com",
+ title: "Get Firefox!",
+ });
+ let fxBmk2 = yield PlacesUtils.bookmarks.insert({
+ type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
+ parentGuid: PlacesUtils.bookmarks.toolbarGuid,
+ url: "http://getfirefox.com",
+ title: "Download Firefox",
+ });
+ let tag = yield PlacesUtils.bookmarks.insert({
+ type: PlacesUtils.bookmarks.TYPE_FOLDER,
+ parentGuid: PlacesUtils.bookmarks.tagsGuid,
+ title: "some tag",
+ });
+ let fxTag = yield PlacesUtils.bookmarks.insert({
+ type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
+ parentGuid: tag.guid,
+ url: "http://getfirefox.com",
+ });
+
+ yield startTracking();
+
+ _("Remove the tag using the async bookmarks API");
+ yield PlacesUtils.bookmarks.remove(fxTag.guid);
+
+ yield verifyTrackedItems([fxBmk1.guid, fxBmk2.guid]);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
+ } finally {
+ _("Clean up.");
+ yield cleanup();
+ }
+});
+
+add_task(function* test_async_onItemTagged() {
+ _("Items tagged using the asynchronous API should be tracked");
+
+ try {
+ yield stopTracking();
+
+ _("Insert untagged bookmarks");
+ let folder1 = yield PlacesUtils.bookmarks.insert({
+ type: PlacesUtils.bookmarks.TYPE_FOLDER,
+ parentGuid: PlacesUtils.bookmarks.menuGuid,
+ title: "Folder 1",
+ });
+ let fxBmk1 = yield PlacesUtils.bookmarks.insert({
+ type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
+ parentGuid: folder1.guid,
+ url: "http://getfirefox.com",
+ title: "Get Firefox!",
+ });
+ let folder2 = yield PlacesUtils.bookmarks.insert({
+ type: PlacesUtils.bookmarks.TYPE_FOLDER,
+ parentGuid: PlacesUtils.bookmarks.menuGuid,
+ title: "Folder 2",
+ });
+ // Different parent and title; same URL.
+ let fxBmk2 = yield PlacesUtils.bookmarks.insert({
+ type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
+ parentGuid: folder2.guid,
+ url: "http://getfirefox.com",
+ title: "Download Firefox",
+ });
+
+ yield startTracking();
+
+ // This will change once tags are moved into a separate table (bug 424160).
+ // We specifically test this case because Bookmarks.jsm updates tagged
+ // bookmarks and notifies observers.
+ _("Insert a tag using the async bookmarks API");
+ let tag = yield PlacesUtils.bookmarks.insert({
+ type: PlacesUtils.bookmarks.TYPE_FOLDER,
+ parentGuid: PlacesUtils.bookmarks.tagsGuid,
+ title: "some tag",
+ });
+
+ _("Tag an item using the async bookmarks API");
+ yield PlacesUtils.bookmarks.insert({
+ type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
+ parentGuid: tag.guid,
+ url: "http://getfirefox.com",
+ });
+
+ yield verifyTrackedItems([fxBmk1.guid, fxBmk2.guid]);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 6);
+ } finally {
+ _("Clean up.");
+ yield cleanup();
+ }
+});
+
+add_task(function* test_onItemKeywordChanged() {
+ _("Keyword changes via the synchronous API should be tracked");
+
+ try {
+ yield stopTracking();
+ let folder = PlacesUtils.bookmarks.createFolder(
+ PlacesUtils.bookmarks.bookmarksMenuFolder, "Parent",
+ PlacesUtils.bookmarks.DEFAULT_INDEX);
+ let folderGUID = engine._store.GUIDForId(folder);
+ _("Track changes to keywords");
+ let uri = Utils.makeURI("http://getfirefox.com");
+ let b = PlacesUtils.bookmarks.insertBookmark(
+ folder, uri,
+ PlacesUtils.bookmarks.DEFAULT_INDEX, "Get Firefox!");
+ let bGUID = engine._store.GUIDForId(b);
+ _("New item is " + b);
+ _("GUID: " + bGUID);
+
+ yield startTracking();
+
+ _("Give the item a keyword");
+ PlacesUtils.bookmarks.setKeywordForBookmark(b, "the_keyword");
+
+ // bookmark should be tracked, folder should not be.
+ yield verifyTrackedItems([bGUID]);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE);
+
+ } finally {
+ _("Clean up.");
+ yield cleanup();
+ }
+});
+
+add_task(function* test_async_onItemKeywordChanged() {
+ _("Keyword changes via the asynchronous API should be tracked");
+
+ try {
+ yield stopTracking();
+
+ _("Insert two bookmarks with the same URL");
+ let fxBmk1 = yield PlacesUtils.bookmarks.insert({
+ type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
+ parentGuid: PlacesUtils.bookmarks.menuGuid,
+ url: "http://getfirefox.com",
+ title: "Get Firefox!",
+ });
+ let fxBmk2 = yield PlacesUtils.bookmarks.insert({
+ type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
+ parentGuid: PlacesUtils.bookmarks.toolbarGuid,
+ url: "http://getfirefox.com",
+ title: "Download Firefox",
+ });
+
+ yield startTracking();
+
+ _("Add a keyword for both items");
+ yield PlacesUtils.keywords.insert({
+ keyword: "the_keyword",
+ url: "http://getfirefox.com",
+ postData: "postData",
+ });
+
+ yield verifyTrackedItems([fxBmk1.guid, fxBmk2.guid]);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
+ } finally {
+ _("Clean up.");
+ yield cleanup();
+ }
+});
+
+add_task(function* test_async_onItemKeywordDeleted() {
+ _("Keyword deletions via the asynchronous API should be tracked");
+
+ try {
+ yield stopTracking();
+
+ _("Insert two bookmarks with the same URL and keywords");
+ let fxBmk1 = yield PlacesUtils.bookmarks.insert({
+ type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
+ parentGuid: PlacesUtils.bookmarks.menuGuid,
+ url: "http://getfirefox.com",
+ title: "Get Firefox!",
+ });
+ let fxBmk2 = yield PlacesUtils.bookmarks.insert({
+ type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
+ parentGuid: PlacesUtils.bookmarks.toolbarGuid,
+ url: "http://getfirefox.com",
+ title: "Download Firefox",
+ });
+ yield PlacesUtils.keywords.insert({
+ keyword: "the_keyword",
+ url: "http://getfirefox.com",
+ });
+
+ yield startTracking();
+
+ _("Remove the keyword");
+ yield PlacesUtils.keywords.remove("the_keyword");
+
+ yield verifyTrackedItems([fxBmk1.guid, fxBmk2.guid]);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
+ } finally {
+ _("Clean up.");
+ yield cleanup();
+ }
+});
+
+add_task(function* test_onItemPostDataChanged() {
+ _("Post data changes should be tracked");
+
+ try {
+ yield stopTracking();
+
+ _("Insert a bookmark");
+ let fx_id = PlacesUtils.bookmarks.insertBookmark(
+ PlacesUtils.bookmarks.bookmarksMenuFolder,
+ Utils.makeURI("http://getfirefox.com"),
+ PlacesUtils.bookmarks.DEFAULT_INDEX,
+ "Get Firefox!");
+ let fx_guid = engine._store.GUIDForId(fx_id);
+ _(`Firefox GUID: ${fx_guid}`);
+
+ yield startTracking();
+
+ // PlacesUtils.setPostDataForBookmark is deprecated, but still used by
+ // PlacesTransactions.NewBookmark.
+ _("Post data for the bookmark should be ignored");
+ yield PlacesUtils.setPostDataForBookmark(fx_id, "postData");
+ yield verifyTrackerEmpty();
+ } finally {
+ _("Clean up.");
+ yield cleanup();
+ }
+});
+
+add_task(function* test_onItemAnnoChanged() {
+ _("Item annotations should be tracked");
+
+ try {
+ yield stopTracking();
+ let folder = PlacesUtils.bookmarks.createFolder(
+ PlacesUtils.bookmarks.bookmarksMenuFolder, "Parent",
+ PlacesUtils.bookmarks.DEFAULT_INDEX);
+ let folderGUID = engine._store.GUIDForId(folder);
+ _("Track changes to annos.");
+ let b = PlacesUtils.bookmarks.insertBookmark(
+ folder, Utils.makeURI("http://getfirefox.com"),
+ PlacesUtils.bookmarks.DEFAULT_INDEX, "Get Firefox!");
+ let bGUID = engine._store.GUIDForId(b);
+ _("New item is " + b);
+ _("GUID: " + bGUID);
+
+ yield startTracking();
+ PlacesUtils.annotations.setItemAnnotation(
+ b, PlacesSyncUtils.bookmarks.DESCRIPTION_ANNO, "A test description", 0,
+ PlacesUtils.annotations.EXPIRE_NEVER);
+ // bookmark should be tracked, folder should not.
+ yield verifyTrackedItems([bGUID]);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE);
+ yield resetTracker();
+
+ PlacesUtils.annotations.removeItemAnnotation(b,
+ PlacesSyncUtils.bookmarks.DESCRIPTION_ANNO);
+ yield verifyTrackedItems([bGUID]);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE);
+ } finally {
+ _("Clean up.");
+ yield cleanup();
+ }
+});
+
+add_task(function* test_onItemAdded_filtered_root() {
+ _("Items outside the change roots should not be tracked");
+
+ try {
+ yield startTracking();
+
+ _("Create a new root");
+ let rootID = PlacesUtils.bookmarks.createFolder(
+ PlacesUtils.bookmarks.placesRoot,
+ "New root",
+ PlacesUtils.bookmarks.DEFAULT_INDEX);
+ let rootGUID = engine._store.GUIDForId(rootID);
+ _(`New root GUID: ${rootGUID}`);
+
+ _("Insert a bookmark underneath the new root");
+ let untrackedBmkID = PlacesUtils.bookmarks.insertBookmark(
+ rootID,
+ Utils.makeURI("http://getthunderbird.com"),
+ PlacesUtils.bookmarks.DEFAULT_INDEX,
+ "Get Thunderbird!");
+ let untrackedBmkGUID = engine._store.GUIDForId(untrackedBmkID);
+ _(`New untracked bookmark GUID: ${untrackedBmkGUID}`);
+
+ _("Insert a bookmark underneath the Places root");
+ let rootBmkID = PlacesUtils.bookmarks.insertBookmark(
+ PlacesUtils.bookmarks.placesRoot,
+ Utils.makeURI("http://getfirefox.com"),
+ PlacesUtils.bookmarks.DEFAULT_INDEX, "Get Firefox!");
+ let rootBmkGUID = engine._store.GUIDForId(rootBmkID);
+ _(`New Places root bookmark GUID: ${rootBmkGUID}`);
+
+ _("New root and bookmark should be ignored");
+ yield verifyTrackedItems([]);
+ // ...But we'll still increment the score and filter out the changes at
+ // sync time.
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 6);
+ } finally {
+ _("Clean up.");
+ yield cleanup();
+ }
+});
+
+add_task(function* test_onItemDeleted_filtered_root() {
+ _("Deleted items outside the change roots should be tracked");
+
+ try {
+ yield stopTracking();
+
+ _("Insert a bookmark underneath the Places root");
+ let rootBmkID = PlacesUtils.bookmarks.insertBookmark(
+ PlacesUtils.bookmarks.placesRoot,
+ Utils.makeURI("http://getfirefox.com"),
+ PlacesUtils.bookmarks.DEFAULT_INDEX, "Get Firefox!");
+ let rootBmkGUID = engine._store.GUIDForId(rootBmkID);
+ _(`New Places root bookmark GUID: ${rootBmkGUID}`);
+
+ yield startTracking();
+
+ PlacesUtils.bookmarks.removeItem(rootBmkID);
+
+ // We shouldn't upload tombstones for items in filtered roots, but the
+ // `onItemRemoved` observer doesn't have enough context to determine
+ // the root, so we'll end up uploading it.
+ yield verifyTrackedItems([rootBmkGUID]);
+ // We'll increment the counter twice (once for the removed item, and once
+ // for the Places root), then filter out the root.
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
+ } finally {
+ _("Clean up.");
+ yield cleanup();
+ }
+});
+
+add_task(function* test_onPageAnnoChanged() {
+ _("Page annotations should not be tracked");
+
+ try {
+ yield stopTracking();
+
+ _("Insert a bookmark without an annotation");
+ let pageURI = Utils.makeURI("http://getfirefox.com");
+ PlacesUtils.bookmarks.insertBookmark(
+ PlacesUtils.bookmarks.bookmarksMenuFolder,
+ pageURI,
+ PlacesUtils.bookmarks.DEFAULT_INDEX,
+ "Get Firefox!");
+
+ yield startTracking();
+
+ _("Add a page annotation");
+ PlacesUtils.annotations.setPageAnnotation(pageURI, "URIProperties/characterSet",
+ "UTF-8", 0, PlacesUtils.annotations.EXPIRE_NEVER);
+ yield verifyTrackerEmpty();
+ yield resetTracker();
+
+ _("Remove the page annotation");
+ PlacesUtils.annotations.removePageAnnotation(pageURI,
+ "URIProperties/characterSet");
+ yield verifyTrackerEmpty();
+ } finally {
+ _("Clean up.");
+ yield cleanup();
+ }
+});
+
+add_task(function* test_onFaviconChanged() {
+ _("Favicon changes should not be tracked");
+
+ try {
+ yield stopTracking();
+
+ let pageURI = Utils.makeURI("http://getfirefox.com");
+ let iconURI = Utils.makeURI("http://getfirefox.com/icon");
+ PlacesUtils.bookmarks.insertBookmark(
+ PlacesUtils.bookmarks.bookmarksMenuFolder,
+ pageURI,
+ PlacesUtils.bookmarks.DEFAULT_INDEX,
+ "Get Firefox!");
+
+ yield PlacesTestUtils.addVisits(pageURI);
+
+ yield startTracking();
+
+ _("Favicon annotations should be ignored");
+ let iconURL = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAA" +
+ "AAAA6fptVAAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJggg==";
+
+ PlacesUtils.favicons.replaceFaviconDataFromDataURL(iconURI, iconURL, 0,
+ Services.scriptSecurityManager.getSystemPrincipal());
+
+ yield new Promise(resolve => {
+ PlacesUtils.favicons.setAndFetchFaviconForPage(pageURI, iconURI, true,
+ PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, (iconURI, dataLen, data, mimeType) => {
+ resolve();
+ },
+ Services.scriptSecurityManager.getSystemPrincipal());
+ });
+ yield verifyTrackerEmpty();
+ } finally {
+ _("Clean up.");
+ yield cleanup();
+ }
+});
+
+add_task(function* test_onLivemarkAdded() {
+ _("New livemarks should be tracked");
+
+ try {
+ yield startTracking();
+
+ _("Insert a livemark");
+ let livemark = yield PlacesUtils.livemarks.addLivemark({
+ parentGuid: PlacesUtils.bookmarks.menuGuid,
+ // Use a local address just in case, to avoid potential aborts for
+ // non-local connections.
+ feedURI: Utils.makeURI("http://localhost:0"),
+ });
+ // Prevent the livemark refresh timer from requesting the URI.
+ livemark.terminate();
+
+ yield verifyTrackedItems(["menu", livemark.guid]);
+ // Three changes: one for the parent, one for creating the livemark
+ // folder, and one for setting the "livemark/feedURI" anno on the folder.
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 3);
+ } finally {
+ _("Clean up.");
+ yield cleanup();
+ }
+});
+
+add_task(function* test_onLivemarkDeleted() {
+ _("Deleted livemarks should be tracked");
+
+ try {
+ yield stopTracking();
+
+ _("Insert a livemark");
+ let livemark = yield PlacesUtils.livemarks.addLivemark({
+ parentGuid: PlacesUtils.bookmarks.menuGuid,
+ feedURI: Utils.makeURI("http://localhost:0"),
+ });
+ livemark.terminate();
+
+ yield startTracking();
+
+ _("Remove a livemark");
+ yield PlacesUtils.livemarks.removeLivemark({
+ guid: livemark.guid,
+ });
+
+ yield verifyTrackedItems(["menu", livemark.guid]);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
+ } finally {
+ _("Clean up.");
+ yield cleanup();
+ }
+});
+
+add_task(function* test_onItemMoved() {
+ _("Items moved via the synchronous API should be tracked");
+
+ try {
+ let fx_id = PlacesUtils.bookmarks.insertBookmark(
+ PlacesUtils.bookmarks.bookmarksMenuFolder,
+ Utils.makeURI("http://getfirefox.com"),
+ PlacesUtils.bookmarks.DEFAULT_INDEX,
+ "Get Firefox!");
+ let fx_guid = engine._store.GUIDForId(fx_id);
+ _("Firefox GUID: " + fx_guid);
+ let tb_id = PlacesUtils.bookmarks.insertBookmark(
+ PlacesUtils.bookmarks.bookmarksMenuFolder,
+ Utils.makeURI("http://getthunderbird.com"),
+ PlacesUtils.bookmarks.DEFAULT_INDEX,
+ "Get Thunderbird!");
+ let tb_guid = engine._store.GUIDForId(tb_id);
+ _("Thunderbird GUID: " + tb_guid);
+
+ yield startTracking();
+
+ // Moving within the folder will just track the folder.
+ PlacesUtils.bookmarks.moveItem(
+ tb_id, PlacesUtils.bookmarks.bookmarksMenuFolder, 0);
+ yield verifyTrackedItems(['menu']);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE);
+ yield resetTracker();
+
+ // Moving a bookmark to a different folder will track the old
+ // folder, the new folder and the bookmark.
+ PlacesUtils.bookmarks.moveItem(fx_id, PlacesUtils.bookmarks.toolbarFolder,
+ PlacesUtils.bookmarks.DEFAULT_INDEX);
+ yield verifyTrackedItems(['menu', 'toolbar', fx_guid]);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 3);
+
+ } finally {
+ _("Clean up.");
+ yield cleanup();
+ }
+});
+
+add_task(function* test_async_onItemMoved_update() {
+ _("Items moved via the asynchronous API should be tracked");
+
+ try {
+ yield stopTracking();
+
+ let fxBmk = yield PlacesUtils.bookmarks.insert({
+ type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
+ parentGuid: PlacesUtils.bookmarks.menuGuid,
+ url: "http://getfirefox.com",
+ title: "Get Firefox!",
+ });
+ let tbBmk = yield PlacesUtils.bookmarks.insert({
+ type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
+ parentGuid: PlacesUtils.bookmarks.menuGuid,
+ url: "http://getthunderbird.com",
+ title: "Get Thunderbird!",
+ });
+
+ yield startTracking();
+
+ _("Repositioning a bookmark should track the folder");
+ yield PlacesUtils.bookmarks.update({
+ guid: tbBmk.guid,
+ parentGuid: PlacesUtils.bookmarks.menuGuid,
+ index: 0,
+ });
+ yield verifyTrackedItems(['menu']);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE);
+ yield resetTracker();
+
+ _("Reparenting a bookmark should track both folders and the bookmark");
+ yield PlacesUtils.bookmarks.update({
+ guid: tbBmk.guid,
+ parentGuid: PlacesUtils.bookmarks.toolbarGuid,
+ index: PlacesUtils.bookmarks.DEFAULT_INDEX,
+ });
+ yield verifyTrackedItems(['menu', 'toolbar', tbBmk.guid]);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 3);
+ } finally {
+ _("Clean up.");
+ yield cleanup();
+ }
+});
+
+add_task(function* test_async_onItemMoved_reorder() {
+ _("Items reordered via the asynchronous API should be tracked");
+
+ try {
+ yield stopTracking();
+
+ _("Insert out-of-order bookmarks");
+ let fxBmk = yield PlacesUtils.bookmarks.insert({
+ type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
+ parentGuid: PlacesUtils.bookmarks.menuGuid,
+ url: "http://getfirefox.com",
+ title: "Get Firefox!",
+ });
+ _(`Firefox GUID: ${fxBmk.guid}`);
+
+ let tbBmk = yield PlacesUtils.bookmarks.insert({
+ type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
+ parentGuid: PlacesUtils.bookmarks.menuGuid,
+ url: "http://getthunderbird.com",
+ title: "Get Thunderbird!",
+ });
+ _(`Thunderbird GUID: ${tbBmk.guid}`);
+
+ let mozBmk = yield PlacesUtils.bookmarks.insert({
+ type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
+ parentGuid: PlacesUtils.bookmarks.menuGuid,
+ url: "https://mozilla.org",
+ title: "Mozilla",
+ });
+ _(`Mozilla GUID: ${mozBmk.guid}`);
+
+ yield startTracking();
+
+ _("Reorder bookmarks");
+ yield PlacesUtils.bookmarks.reorder(PlacesUtils.bookmarks.menuGuid,
+ [mozBmk.guid, fxBmk.guid, tbBmk.guid]);
+
+ // As with setItemIndex, we should only track the folder if we reorder
+ // its children, but we should bump the score for every changed item.
+ yield verifyTrackedItems(["menu"]);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 3);
+ } finally {
+ _("Clean up.");
+ yield cleanup();
+ }
+});
+
+add_task(function* test_onItemMoved_setItemIndex() {
+ _("Items with updated indices should be tracked");
+
+ try {
+ yield stopTracking();
+
+ let folder_id = PlacesUtils.bookmarks.createFolder(
+ PlacesUtils.bookmarks.bookmarksMenuFolder,
+ "Test folder",
+ PlacesUtils.bookmarks.DEFAULT_INDEX);
+ let folder_guid = engine._store.GUIDForId(folder_id);
+ _(`Folder GUID: ${folder_guid}`);
+
+ let tb_id = PlacesUtils.bookmarks.insertBookmark(
+ folder_id,
+ Utils.makeURI("http://getthunderbird.com"),
+ PlacesUtils.bookmarks.DEFAULT_INDEX,
+ "Thunderbird");
+ let tb_guid = engine._store.GUIDForId(tb_id);
+ _(`Thunderbird GUID: ${tb_guid}`);
+
+ let fx_id = PlacesUtils.bookmarks.insertBookmark(
+ folder_id,
+ Utils.makeURI("http://getfirefox.com"),
+ PlacesUtils.bookmarks.DEFAULT_INDEX,
+ "Firefox");
+ let fx_guid = engine._store.GUIDForId(fx_id);
+ _(`Firefox GUID: ${fx_guid}`);
+
+ let moz_id = PlacesUtils.bookmarks.insertBookmark(
+ PlacesUtils.bookmarks.bookmarksMenuFolder,
+ Utils.makeURI("https://mozilla.org"),
+ PlacesUtils.bookmarks.DEFAULT_INDEX,
+ "Mozilla"
+ );
+ let moz_guid = engine._store.GUIDForId(moz_id);
+ _(`Mozilla GUID: ${moz_guid}`);
+
+ yield startTracking();
+
+ // PlacesSortFolderByNameTransaction exercises
+ // PlacesUtils.bookmarks.setItemIndex.
+ let txn = new PlacesSortFolderByNameTransaction(folder_id);
+
+ // We're reordering items within the same folder, so only the folder
+ // should be tracked.
+ _("Execute the sort folder transaction");
+ txn.doTransaction();
+ yield verifyTrackedItems([folder_guid]);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE);
+ yield resetTracker();
+
+ _("Undo the sort folder transaction");
+ txn.undoTransaction();
+ yield verifyTrackedItems([folder_guid]);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE);
+ } finally {
+ _("Clean up.");
+ yield cleanup();
+ }
+});
+
+add_task(function* test_onItemDeleted_removeFolderTransaction() {
+ _("Folders removed in a transaction should be tracked");
+
+ try {
+ yield stopTracking();
+
+ _("Create a folder with two children");
+ let folder_id = PlacesUtils.bookmarks.createFolder(
+ PlacesUtils.bookmarks.bookmarksMenuFolder,
+ "Test folder",
+ PlacesUtils.bookmarks.DEFAULT_INDEX);
+ let folder_guid = engine._store.GUIDForId(folder_id);
+ _(`Folder GUID: ${folder_guid}`);
+ let fx_id = PlacesUtils.bookmarks.insertBookmark(
+ folder_id,
+ Utils.makeURI("http://getfirefox.com"),
+ PlacesUtils.bookmarks.DEFAULT_INDEX,
+ "Get Firefox!");
+ let fx_guid = engine._store.GUIDForId(fx_id);
+ _(`Firefox GUID: ${fx_guid}`);
+ let tb_id = PlacesUtils.bookmarks.insertBookmark(
+ folder_id,
+ Utils.makeURI("http://getthunderbird.com"),
+ PlacesUtils.bookmarks.DEFAULT_INDEX,
+ "Get Thunderbird!");
+ let tb_guid = engine._store.GUIDForId(tb_id);
+ _(`Thunderbird GUID: ${tb_guid}`);
+
+ yield startTracking();
+
+ let txn = PlacesUtils.bookmarks.getRemoveFolderTransaction(folder_id);
+ // We haven't executed the transaction yet.
+ yield verifyTrackerEmpty();
+
+ _("Execute the remove folder transaction");
+ txn.doTransaction();
+ yield verifyTrackedItems(["menu", folder_guid, fx_guid, tb_guid]);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 6);
+ yield resetTracker();
+
+ _("Undo the remove folder transaction");
+ txn.undoTransaction();
+
+ // At this point, the restored folder has the same ID, but a different GUID.
+ let new_folder_guid = yield PlacesUtils.promiseItemGuid(folder_id);
+
+ yield verifyTrackedItems(["menu", new_folder_guid]);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
+ yield resetTracker();
+
+ _("Redo the transaction");
+ txn.redoTransaction();
+ yield verifyTrackedItems(["menu", new_folder_guid]);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
+ } finally {
+ _("Clean up.");
+ yield cleanup();
+ }
+});
+
+add_task(function* test_treeMoved() {
+ _("Moving an entire tree of bookmarks should track the parents");
+
+ try {
+ // Create a couple of parent folders.
+ let folder1_id = PlacesUtils.bookmarks.createFolder(
+ PlacesUtils.bookmarks.bookmarksMenuFolder,
+ "First test folder",
+ PlacesUtils.bookmarks.DEFAULT_INDEX);
+ let folder1_guid = engine._store.GUIDForId(folder1_id);
+
+ // A second folder in the first.
+ let folder2_id = PlacesUtils.bookmarks.createFolder(
+ folder1_id,
+ "Second test folder",
+ PlacesUtils.bookmarks.DEFAULT_INDEX);
+ let folder2_guid = engine._store.GUIDForId(folder2_id);
+
+ // Create a couple of bookmarks in the second folder.
+ let fx_id = PlacesUtils.bookmarks.insertBookmark(
+ folder2_id,
+ Utils.makeURI("http://getfirefox.com"),
+ PlacesUtils.bookmarks.DEFAULT_INDEX,
+ "Get Firefox!");
+ let fx_guid = engine._store.GUIDForId(fx_id);
+ let tb_id = PlacesUtils.bookmarks.insertBookmark(
+ folder2_id,
+ Utils.makeURI("http://getthunderbird.com"),
+ PlacesUtils.bookmarks.DEFAULT_INDEX,
+ "Get Thunderbird!");
+ let tb_guid = engine._store.GUIDForId(tb_id);
+
+ yield startTracking();
+
+ // Move folder 2 to be a sibling of folder1.
+ PlacesUtils.bookmarks.moveItem(
+ folder2_id, PlacesUtils.bookmarks.bookmarksMenuFolder, 0);
+ // the menu and both folders should be tracked, the children should not be.
+ yield verifyTrackedItems(['menu', folder1_guid, folder2_guid]);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 3);
+ } finally {
+ _("Clean up.");
+ yield cleanup();
+ }
+});
+
+add_task(function* test_onItemDeleted() {
+ _("Bookmarks deleted via the synchronous API should be tracked");
+
+ try {
+ let fx_id = PlacesUtils.bookmarks.insertBookmark(
+ PlacesUtils.bookmarks.bookmarksMenuFolder,
+ Utils.makeURI("http://getfirefox.com"),
+ PlacesUtils.bookmarks.DEFAULT_INDEX,
+ "Get Firefox!");
+ let fx_guid = engine._store.GUIDForId(fx_id);
+ let tb_id = PlacesUtils.bookmarks.insertBookmark(
+ PlacesUtils.bookmarks.bookmarksMenuFolder,
+ Utils.makeURI("http://getthunderbird.com"),
+ PlacesUtils.bookmarks.DEFAULT_INDEX,
+ "Get Thunderbird!");
+ let tb_guid = engine._store.GUIDForId(tb_id);
+
+ yield startTracking();
+
+ // Delete the last item - the item and parent should be tracked.
+ PlacesUtils.bookmarks.removeItem(tb_id);
+
+ yield verifyTrackedItems(['menu', tb_guid]);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
+ } finally {
+ _("Clean up.");
+ yield cleanup();
+ }
+});
+
+add_task(function* test_async_onItemDeleted() {
+ _("Bookmarks deleted via the asynchronous API should be tracked");
+
+ try {
+ yield stopTracking();
+
+ let fxBmk = yield PlacesUtils.bookmarks.insert({
+ type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
+ parentGuid: PlacesUtils.bookmarks.menuGuid,
+ url: "http://getfirefox.com",
+ title: "Get Firefox!",
+ });
+ let tbBmk = yield PlacesUtils.bookmarks.insert({
+ type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
+ parentGuid: PlacesUtils.bookmarks.menuGuid,
+ url: "http://getthunderbird.com",
+ title: "Get Thunderbird!",
+ });
+
+ yield startTracking();
+
+ _("Delete the first item");
+ yield PlacesUtils.bookmarks.remove(fxBmk.guid);
+
+ yield verifyTrackedItems(["menu", fxBmk.guid]);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 2);
+ } finally {
+ _("Clean up.");
+ yield cleanup();
+ }
+});
+
+add_task(function* test_async_onItemDeleted_eraseEverything() {
+ _("Erasing everything should track all deleted items");
+
+ try {
+ yield stopTracking();
+
+ let fxBmk = yield PlacesUtils.bookmarks.insert({
+ type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
+ parentGuid: PlacesUtils.bookmarks.mobileGuid,
+ url: "http://getfirefox.com",
+ title: "Get Firefox!",
+ });
+ _(`Firefox GUID: ${fxBmk.guid}`);
+ let tbBmk = yield PlacesUtils.bookmarks.insert({
+ type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
+ parentGuid: PlacesUtils.bookmarks.mobileGuid,
+ url: "http://getthunderbird.com",
+ title: "Get Thunderbird!",
+ });
+ _(`Thunderbird GUID: ${tbBmk.guid}`);
+ let mozBmk = yield PlacesUtils.bookmarks.insert({
+ type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
+ parentGuid: PlacesUtils.bookmarks.menuGuid,
+ url: "https://mozilla.org",
+ title: "Mozilla",
+ });
+ _(`Mozilla GUID: ${mozBmk.guid}`);
+ let mdnBmk = yield PlacesUtils.bookmarks.insert({
+ type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
+ parentGuid: PlacesUtils.bookmarks.menuGuid,
+ url: "https://developer.mozilla.org",
+ title: "MDN",
+ });
+ _(`MDN GUID: ${mdnBmk.guid}`);
+ let bugsFolder = yield PlacesUtils.bookmarks.insert({
+ type: PlacesUtils.bookmarks.TYPE_FOLDER,
+ parentGuid: PlacesUtils.bookmarks.toolbarGuid,
+ title: "Bugs",
+ });
+ _(`Bugs folder GUID: ${bugsFolder.guid}`);
+ let bzBmk = yield PlacesUtils.bookmarks.insert({
+ type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
+ parentGuid: bugsFolder.guid,
+ url: "https://bugzilla.mozilla.org",
+ title: "Bugzilla",
+ });
+ _(`Bugzilla GUID: ${bzBmk.guid}`);
+ let bugsChildFolder = yield PlacesUtils.bookmarks.insert({
+ type: PlacesUtils.bookmarks.TYPE_FOLDER,
+ parentGuid: bugsFolder.guid,
+ title: "Bugs child",
+ });
+ _(`Bugs child GUID: ${bugsChildFolder.guid}`);
+ let bugsGrandChildBmk = yield PlacesUtils.bookmarks.insert({
+ type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
+ parentGuid: bugsChildFolder.guid,
+ url: "https://example.com",
+ title: "Bugs grandchild",
+ });
+ _(`Bugs grandchild GUID: ${bugsGrandChildBmk.guid}`);
+
+ yield startTracking();
+
+ yield PlacesUtils.bookmarks.eraseEverything();
+
+ // `eraseEverything` removes all items from the database before notifying
+ // observers. Because of this, grandchild lookup in the tracker's
+ // `onItemRemoved` observer will fail. That means we won't track
+ // (bzBmk.guid, bugsGrandChildBmk.guid, bugsChildFolder.guid), even
+ // though we should.
+ yield verifyTrackedItems(["menu", mozBmk.guid, mdnBmk.guid, "toolbar",
+ bugsFolder.guid, "mobile", fxBmk.guid,
+ tbBmk.guid]);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 10);
+ } finally {
+ _("Clean up.");
+ yield cleanup();
+ }
+});
+
+add_task(function* test_onItemDeleted_removeFolderChildren() {
+ _("Removing a folder's children should track the folder and its children");
+
+ try {
+ let fx_id = PlacesUtils.bookmarks.insertBookmark(
+ PlacesUtils.mobileFolderId,
+ Utils.makeURI("http://getfirefox.com"),
+ PlacesUtils.bookmarks.DEFAULT_INDEX,
+ "Get Firefox!");
+ let fx_guid = engine._store.GUIDForId(fx_id);
+ _(`Firefox GUID: ${fx_guid}`);
+
+ let tb_id = PlacesUtils.bookmarks.insertBookmark(
+ PlacesUtils.mobileFolderId,
+ Utils.makeURI("http://getthunderbird.com"),
+ PlacesUtils.bookmarks.DEFAULT_INDEX,
+ "Get Thunderbird!");
+ let tb_guid = engine._store.GUIDForId(tb_id);
+ _(`Thunderbird GUID: ${tb_guid}`);
+
+ let moz_id = PlacesUtils.bookmarks.insertBookmark(
+ PlacesUtils.bookmarks.bookmarksMenuFolder,
+ Utils.makeURI("https://mozilla.org"),
+ PlacesUtils.bookmarks.DEFAULT_INDEX,
+ "Mozilla"
+ );
+ let moz_guid = engine._store.GUIDForId(moz_id);
+ _(`Mozilla GUID: ${moz_guid}`);
+
+ yield startTracking();
+
+ _(`Mobile root ID: ${PlacesUtils.mobileFolderId}`);
+ PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.mobileFolderId);
+
+ yield verifyTrackedItems(["mobile", fx_guid, tb_guid]);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 4);
+ } finally {
+ _("Clean up.");
+ yield cleanup();
+ }
+});
+
+add_task(function* test_onItemDeleted_tree() {
+ _("Deleting a tree of bookmarks should track all items");
+
+ try {
+ // Create a couple of parent folders.
+ let folder1_id = PlacesUtils.bookmarks.createFolder(
+ PlacesUtils.bookmarks.bookmarksMenuFolder,
+ "First test folder",
+ PlacesUtils.bookmarks.DEFAULT_INDEX);
+ let folder1_guid = engine._store.GUIDForId(folder1_id);
+
+ // A second folder in the first.
+ let folder2_id = PlacesUtils.bookmarks.createFolder(
+ folder1_id,
+ "Second test folder",
+ PlacesUtils.bookmarks.DEFAULT_INDEX);
+ let folder2_guid = engine._store.GUIDForId(folder2_id);
+
+ // Create a couple of bookmarks in the second folder.
+ let fx_id = PlacesUtils.bookmarks.insertBookmark(
+ folder2_id,
+ Utils.makeURI("http://getfirefox.com"),
+ PlacesUtils.bookmarks.DEFAULT_INDEX,
+ "Get Firefox!");
+ let fx_guid = engine._store.GUIDForId(fx_id);
+ let tb_id = PlacesUtils.bookmarks.insertBookmark(
+ folder2_id,
+ Utils.makeURI("http://getthunderbird.com"),
+ PlacesUtils.bookmarks.DEFAULT_INDEX,
+ "Get Thunderbird!");
+ let tb_guid = engine._store.GUIDForId(tb_id);
+
+ yield startTracking();
+
+ // Delete folder2 - everything we created should be tracked.
+ PlacesUtils.bookmarks.removeItem(folder2_id);
+
+ yield verifyTrackedItems([fx_guid, tb_guid, folder1_guid, folder2_guid]);
+ do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE * 6);
+ } finally {
+ _("Clean up.");
+ yield cleanup();
+ }
+});
+
+add_task(function* test_mobile_query() {
+ _("Ensure we correctly create the mobile query");
+
+ try {
+ // Creates the organizer queries as a side effect.
+ let leftPaneId = PlacesUIUtils.leftPaneFolderId;
+ _(`Left pane root ID: ${leftPaneId}`);
+
+ let allBookmarksIds = findAnnoItems("PlacesOrganizer/OrganizerQuery", "AllBookmarks");
+ equal(allBookmarksIds.length, 1, "Should create folder with all bookmarks queries");
+ let allBookmarkGuid = yield PlacesUtils.promiseItemGuid(allBookmarksIds[0]);
+
+ _("Try creating query after organizer is ready");
+ tracker._ensureMobileQuery();
+ let queryIds = findAnnoItems("PlacesOrganizer/OrganizerQuery", "MobileBookmarks");
+ equal(queryIds.length, 0, "Should not create query without any mobile bookmarks");
+
+ _("Insert mobile bookmark, then create query");
+ yield PlacesUtils.bookmarks.insert({
+ parentGuid: PlacesUtils.bookmarks.mobileGuid,
+ url: "https://mozilla.org",
+ });
+ tracker._ensureMobileQuery();
+ queryIds = findAnnoItems("PlacesOrganizer/OrganizerQuery", "MobileBookmarks", {});
+ equal(queryIds.length, 1, "Should create query once mobile bookmarks exist");
+
+ let queryId = queryIds[0];
+ let queryGuid = yield PlacesUtils.promiseItemGuid(queryId);
+
+ let queryInfo = yield PlacesUtils.bookmarks.fetch(queryGuid);
+ equal(queryInfo.url, `place:folder=${PlacesUtils.mobileFolderId}`, "Query should point to mobile root");
+ equal(queryInfo.title, "Mobile Bookmarks", "Query title should be localized");
+ equal(queryInfo.parentGuid, allBookmarkGuid, "Should append mobile query to all bookmarks queries");
+
+ _("Rename root and query, then recreate");
+ yield PlacesUtils.bookmarks.update({
+ guid: PlacesUtils.bookmarks.mobileGuid,
+ title: "renamed root",
+ });
+ yield PlacesUtils.bookmarks.update({
+ guid: queryGuid,
+ title: "renamed query",
+ });
+ tracker._ensureMobileQuery();
+ let rootInfo = yield PlacesUtils.bookmarks.fetch(PlacesUtils.bookmarks.mobileGuid);
+ equal(rootInfo.title, "Mobile Bookmarks", "Should fix root title");
+ queryInfo = yield PlacesUtils.bookmarks.fetch(queryGuid);
+ equal(queryInfo.title, "Mobile Bookmarks", "Should fix query title");
+
+ _("Point query to different folder");
+ yield PlacesUtils.bookmarks.update({
+ guid: queryGuid,
+ url: "place:folder=BOOKMARKS_MENU",
+ });
+ tracker._ensureMobileQuery();
+ queryInfo = yield PlacesUtils.bookmarks.fetch(queryGuid);
+ equal(queryInfo.url.href, `place:folder=${PlacesUtils.mobileFolderId}`,
+ "Should fix query URL to point to mobile root");
+
+ _("We shouldn't track the query or the left pane root");
+ yield verifyTrackedCount(0);
+ do_check_eq(tracker.score, 0);
+ } finally {
+ _("Clean up.");
+ yield cleanup();
+ }
+});