diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /services/sync/tests/unit/test_bookmark_tracker.js | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'services/sync/tests/unit/test_bookmark_tracker.js')
-rw-r--r-- | services/sync/tests/unit/test_bookmark_tracker.js | 1537 |
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(); + } +}); |