1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/services/sync/tests/unit/test_bookmark_smart_bookmarks.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,235 @@ 1.4 +/* Any copyright is dedicated to the Public Domain. 1.5 + http://creativecommons.org/publicdomain/zero/1.0/ */ 1.6 + 1.7 +Cu.import("resource://gre/modules/PlacesUtils.jsm"); 1.8 +Cu.import("resource://gre/modules/Log.jsm"); 1.9 +Cu.import("resource://services-sync/engines.js"); 1.10 +Cu.import("resource://services-sync/engines/bookmarks.js"); 1.11 +Cu.import("resource://services-sync/service.js"); 1.12 +Cu.import("resource://services-sync/util.js"); 1.13 +Cu.import("resource://testing-common/services/sync/utils.js"); 1.14 + 1.15 +const SMART_BOOKMARKS_ANNO = "Places/SmartBookmark"; 1.16 +var IOService = Cc["@mozilla.org/network/io-service;1"] 1.17 + .getService(Ci.nsIIOService); 1.18 +("http://www.mozilla.com", null, null); 1.19 + 1.20 + 1.21 +Service.engineManager.register(BookmarksEngine); 1.22 +let engine = Service.engineManager.get("bookmarks"); 1.23 +let store = engine._store; 1.24 + 1.25 +// Clean up after other tests. Only necessary in XULRunner. 1.26 +store.wipe(); 1.27 + 1.28 +function newSmartBookmark(parent, uri, position, title, queryID) { 1.29 + let id = PlacesUtils.bookmarks.insertBookmark(parent, uri, position, title); 1.30 + PlacesUtils.annotations.setItemAnnotation(id, SMART_BOOKMARKS_ANNO, 1.31 + queryID, 0, 1.32 + PlacesUtils.annotations.EXPIRE_NEVER); 1.33 + return id; 1.34 +} 1.35 + 1.36 +function smartBookmarkCount() { 1.37 + // We do it this way because PlacesUtils.annotations.getItemsWithAnnotation 1.38 + // doesn't work the same (or at all?) between 3.6 and 4.0. 1.39 + let out = {}; 1.40 + PlacesUtils.annotations.getItemsWithAnnotation(SMART_BOOKMARKS_ANNO, out); 1.41 + return out.value; 1.42 +} 1.43 + 1.44 +function clearBookmarks() { 1.45 + _("Cleaning up existing items."); 1.46 + PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.bookmarks.bookmarksMenuFolder); 1.47 + PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.bookmarks.tagsFolder); 1.48 + PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.bookmarks.toolbarFolder); 1.49 + PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.bookmarks.unfiledBookmarksFolder); 1.50 + startCount = smartBookmarkCount(); 1.51 +} 1.52 + 1.53 +function serverForFoo(engine) { 1.54 + return serverForUsers({"foo": "password"}, { 1.55 + meta: {global: {engines: {bookmarks: {version: engine.version, 1.56 + syncID: engine.syncID}}}}, 1.57 + bookmarks: {} 1.58 + }); 1.59 +} 1.60 + 1.61 +// Verify that Places smart bookmarks have their annotation uploaded and 1.62 +// handled locally. 1.63 +add_test(function test_annotation_uploaded() { 1.64 + let server = serverForFoo(engine); 1.65 + new SyncTestingInfrastructure(server.server); 1.66 + 1.67 + let startCount = smartBookmarkCount(); 1.68 + 1.69 + _("Start count is " + startCount); 1.70 + 1.71 + if (startCount > 0) { 1.72 + // This can happen in XULRunner. 1.73 + clearBookmarks(); 1.74 + _("Start count is now " + startCount); 1.75 + } 1.76 + 1.77 + _("Create a smart bookmark in the toolbar."); 1.78 + let parent = PlacesUtils.toolbarFolderId; 1.79 + let uri = 1.80 + Utils.makeURI("place:sort=" + 1.81 + Ci.nsINavHistoryQueryOptions.SORT_BY_VISITCOUNT_DESCENDING + 1.82 + "&maxResults=10"); 1.83 + let title = "Most Visited"; 1.84 + 1.85 + let mostVisitedID = newSmartBookmark(parent, uri, -1, title, "MostVisited"); 1.86 + 1.87 + _("New item ID: " + mostVisitedID); 1.88 + do_check_true(!!mostVisitedID); 1.89 + 1.90 + let annoValue = PlacesUtils.annotations.getItemAnnotation(mostVisitedID, 1.91 + SMART_BOOKMARKS_ANNO); 1.92 + _("Anno: " + annoValue); 1.93 + do_check_eq("MostVisited", annoValue); 1.94 + 1.95 + let guid = store.GUIDForId(mostVisitedID); 1.96 + _("GUID: " + guid); 1.97 + do_check_true(!!guid); 1.98 + 1.99 + _("Create record object and verify that it's sane."); 1.100 + let record = store.createRecord(guid); 1.101 + do_check_true(record instanceof Bookmark); 1.102 + do_check_true(record instanceof BookmarkQuery); 1.103 + 1.104 + do_check_eq(record.bmkUri, uri.spec); 1.105 + 1.106 + _("Make sure the new record carries with it the annotation."); 1.107 + do_check_eq("MostVisited", record.queryId); 1.108 + 1.109 + _("Our count has increased since we started."); 1.110 + do_check_eq(smartBookmarkCount(), startCount + 1); 1.111 + 1.112 + _("Sync record to the server."); 1.113 + let collection = server.user("foo").collection("bookmarks"); 1.114 + 1.115 + try { 1.116 + engine.sync(); 1.117 + let wbos = collection.keys(function (id) { 1.118 + return ["menu", "toolbar", "mobile"].indexOf(id) == -1; 1.119 + }); 1.120 + do_check_eq(wbos.length, 1); 1.121 + 1.122 + _("Verify that the server WBO has the annotation."); 1.123 + let serverGUID = wbos[0]; 1.124 + do_check_eq(serverGUID, guid); 1.125 + let serverWBO = collection.wbo(serverGUID); 1.126 + do_check_true(!!serverWBO); 1.127 + let body = JSON.parse(JSON.parse(serverWBO.payload).ciphertext); 1.128 + do_check_eq(body.queryId, "MostVisited"); 1.129 + 1.130 + _("We still have the right count."); 1.131 + do_check_eq(smartBookmarkCount(), startCount + 1); 1.132 + 1.133 + _("Clear local records; now we can't find it."); 1.134 + 1.135 + // "Clear" by changing attributes: if we delete it, apparently it sticks 1.136 + // around as a deleted record... 1.137 + PlacesUtils.bookmarks.setItemTitle(mostVisitedID, "Not Most Visited"); 1.138 + PlacesUtils.bookmarks.changeBookmarkURI( 1.139 + mostVisitedID, Utils.makeURI("http://something/else")); 1.140 + PlacesUtils.annotations.removeItemAnnotation(mostVisitedID, 1.141 + SMART_BOOKMARKS_ANNO); 1.142 + store.wipe(); 1.143 + engine.resetClient(); 1.144 + do_check_eq(smartBookmarkCount(), startCount); 1.145 + 1.146 + _("Sync. Verify that the downloaded record carries the annotation."); 1.147 + engine.sync(); 1.148 + 1.149 + _("Verify that the Places DB now has an annotated bookmark."); 1.150 + _("Our count has increased again."); 1.151 + do_check_eq(smartBookmarkCount(), startCount + 1); 1.152 + 1.153 + _("Find by GUID and verify that it's annotated."); 1.154 + let newID = store.idForGUID(serverGUID); 1.155 + let newAnnoValue = PlacesUtils.annotations.getItemAnnotation( 1.156 + newID, SMART_BOOKMARKS_ANNO); 1.157 + do_check_eq(newAnnoValue, "MostVisited"); 1.158 + do_check_eq(PlacesUtils.bookmarks.getBookmarkURI(newID).spec, uri.spec); 1.159 + 1.160 + _("Test updating."); 1.161 + let newRecord = store.createRecord(serverGUID); 1.162 + do_check_eq(newRecord.queryId, newAnnoValue); 1.163 + newRecord.queryId = "LeastVisited"; 1.164 + store.update(newRecord); 1.165 + do_check_eq("LeastVisited", PlacesUtils.annotations.getItemAnnotation( 1.166 + newID, SMART_BOOKMARKS_ANNO)); 1.167 + 1.168 + 1.169 + } finally { 1.170 + // Clean up. 1.171 + store.wipe(); 1.172 + Svc.Prefs.resetBranch(""); 1.173 + Service.recordManager.clearCache(); 1.174 + server.stop(run_next_test); 1.175 + } 1.176 +}); 1.177 + 1.178 +add_test(function test_smart_bookmarks_duped() { 1.179 + let server = serverForFoo(engine); 1.180 + new SyncTestingInfrastructure(server.server); 1.181 + 1.182 + let parent = PlacesUtils.toolbarFolderId; 1.183 + let uri = 1.184 + Utils.makeURI("place:sort=" + 1.185 + Ci.nsINavHistoryQueryOptions.SORT_BY_VISITCOUNT_DESCENDING + 1.186 + "&maxResults=10"); 1.187 + let title = "Most Visited"; 1.188 + let mostVisitedID = newSmartBookmark(parent, uri, -1, title, "MostVisited"); 1.189 + let mostVisitedGUID = store.GUIDForId(mostVisitedID); 1.190 + 1.191 + let record = store.createRecord(mostVisitedGUID); 1.192 + 1.193 + _("Prepare sync."); 1.194 + let collection = server.user("foo").collection("bookmarks"); 1.195 + 1.196 + try { 1.197 + engine._syncStartup(); 1.198 + 1.199 + _("Verify that mapDupe uses the anno, discovering a dupe regardless of URI."); 1.200 + do_check_eq(mostVisitedGUID, engine._mapDupe(record)); 1.201 + 1.202 + record.bmkUri = "http://foo/"; 1.203 + do_check_eq(mostVisitedGUID, engine._mapDupe(record)); 1.204 + do_check_neq(PlacesUtils.bookmarks.getBookmarkURI(mostVisitedID).spec, 1.205 + record.bmkUri); 1.206 + 1.207 + _("Verify that different annos don't dupe."); 1.208 + let other = new BookmarkQuery("bookmarks", "abcdefabcdef"); 1.209 + other.queryId = "LeastVisited"; 1.210 + other.parentName = "Bookmarks Toolbar"; 1.211 + other.bmkUri = "place:foo"; 1.212 + other.title = ""; 1.213 + do_check_eq(undefined, engine._findDupe(other)); 1.214 + 1.215 + _("Handle records without a queryId entry."); 1.216 + record.bmkUri = uri; 1.217 + delete record.queryId; 1.218 + do_check_eq(mostVisitedGUID, engine._mapDupe(record)); 1.219 + 1.220 + engine._syncFinish(); 1.221 + 1.222 + } finally { 1.223 + // Clean up. 1.224 + store.wipe(); 1.225 + server.stop(do_test_finished); 1.226 + Svc.Prefs.resetBranch(""); 1.227 + Service.recordManager.clearCache(); 1.228 + } 1.229 +}); 1.230 + 1.231 +function run_test() { 1.232 + initTestLogging("Trace"); 1.233 + Log.repository.getLogger("Sync.Engine.Bookmarks").level = Log.Level.Trace; 1.234 + 1.235 + generateNewKeys(Service.collectionKeys); 1.236 + 1.237 + run_next_test(); 1.238 +}