Bug 615410 - Have bookmarks generate new-style GUIDs. r=mconnor
☠☠ backed out by 84fe21efcb57 ☠ ☠
authorPhilipp von Weitershausen <philipp@weitershausen.de>
Mon, 06 Dec 2010 15:51:38 -0800
changeset 58761 3e74c1c15b63bece3bef6664d19cb69cb39eefa6
parent 58760 a29a2a0ae764266dc436b105723a7364a577dff7
child 58762 81d8bf53ab01179d684cb78c4384c96eaa5b01fd
push id17416
push userpweitershausen@mozilla.com
push dateTue, 07 Dec 2010 07:05:47 +0000
treeherdermozilla-central@4d16d58becaf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmconnor
bugs615410
Bug 615410 - Have bookmarks generate new-style GUIDs. r=mconnor
services/sync/modules/engines/bookmarks.js
services/sync/tests/unit/test_bookmark_predecessor.js
services/sync/tests/unit/test_bookmark_store.js
services/sync/tests/unit/test_bookmark_tracker.js
--- a/services/sync/modules/engines/bookmarks.js
+++ b/services/sync/modules/engines/bookmarks.js
@@ -16,16 +16,17 @@
  * The Initial Developer of the Original Code is Mozilla.
  * Portions created by the Initial Developer are Copyright (C) 2007
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *  Dan Mills <thunder@mozilla.com>
  *  Jono DiCarlo <jdicarlo@mozilla.org>
  *  Anant Narayanan <anant@kix.in>
+ *  Philipp von Weitershausen <philipp@weitershausen.de>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -37,16 +38,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 const EXPORTED_SYMBOLS = ['BookmarksEngine', 'BookmarksSharingManager'];
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
+const GUID_ANNO = "sync/guid";
 const PARENT_ANNO = "weave/parent";
 const PREDECESSOR_ANNO = "weave/predecessor";
 const SERVICE_NOT_SUPPORTED = "Service not supported on this platform";
 const FOLDER_SORTINDEX = 1000000;
 
 try {
   Cu.import("resource://gre/modules/PlacesUtils.jsm");
 }
@@ -86,38 +88,26 @@ Utils.lazy2(kSpecialIds, "mobile", funct
     return root[0];
 
   // Create the special mobile folder to store mobile bookmarks
   let mobile = Svc.Bookmark.createFolder(Svc.Bookmark.placesRoot, "mobile", -1);
   Utils.anno(mobile, anno, 1);
   return mobile;
 });
 
-// Create some helper functions to convert GUID/ids
-function idForGUID(guid) {
-  if (guid in kSpecialIds)
-    return kSpecialIds[guid];
-  return Svc.Bookmark.getItemIdForGUID(guid);
-}
-function GUIDForId(placeId) {
-  for (let [guid, id] in Iterator(kSpecialIds))
-    if (placeId == id)
-      return guid;
-  return Svc.Bookmark.getItemGUID(placeId);
-}
-
 function BookmarksEngine() {
   SyncEngine.call(this, "Bookmarks");
   this._handleImport();
 }
 BookmarksEngine.prototype = {
   __proto__: SyncEngine.prototype,
   _recordObj: PlacesItem,
   _storeObj: BookmarksStore,
   _trackerObj: BookmarksTracker,
+  version: 2,
 
   _handleImport: function _handleImport() {
     Svc.Obs.add("bookmarks-restore-begin", function() {
       this._log.debug("Ignoring changes from importing bookmarks");
       this._tracker.ignoreAll = true;
     }, this);
 
     Svc.Obs.add("bookmarks-restore-success", function() {
@@ -146,17 +136,17 @@ BookmarksEngine.prototype = {
     // Lazily create a mapping of folder titles and separator positions to GUID
     this.__defineGetter__("_lazyMap", function() {
       delete this._lazyMap;
 
       let lazyMap = {};
       for (let guid in this._store.getAllIDs()) {
         // Figure out what key to store the mapping
         let key;
-        let id = idForGUID(guid);
+        let id = this._store.idForGUID(guid);
         switch (Svc.Bookmark.getItemType(id)) {
           case Svc.Bookmark.TYPE_BOOKMARK:
             key = "b" + Svc.Bookmark.getBookmarkURI(id).spec + ":" +
               Svc.Bookmark.getItemTitle(id);
             break;
           case Svc.Bookmark.TYPE_FOLDER:
             key = "f" + Svc.Bookmark.getItemTitle(id);
             break;
@@ -252,18 +242,18 @@ function BookmarksStore(name) {
 
   // Explicitly nullify our references to our cached services so we don't leak
   Svc.Obs.add("places-shutdown", function() {
     this.__bms = null;
     this.__hsvc = null;
     this.__ls = null;
     this.__ms = null;
     this.__ts = null;
-    if (this.__frecencyStm)
-      this.__frecencyStm.finalize();
+    for each ([query, stmt] in Iterator(this._stmts))
+      stmt.finalize();
   }, this);
 }
 BookmarksStore.prototype = {
   __proto__: Store.prototype,
 
   __bms: null,
   get _bms() {
     if (!this.__bms)
@@ -271,17 +261,18 @@ BookmarksStore.prototype = {
                    getService(Ci.nsINavBookmarksService);
     return this.__bms;
   },
 
   __hsvc: null,
   get _hsvc() {
     if (!this.__hsvc)
       this.__hsvc = Cc["@mozilla.org/browser/nav-history-service;1"].
-                    getService(Ci.nsINavHistoryService);
+                    getService(Ci.nsINavHistoryService).
+                    QueryInterface(Ci.nsPIPlacesDatabase);
     return this.__hsvc;
   },
 
   __ls: null,
   get _ls() {
     if (!this.__ls)
       this.__ls = Cc["@mozilla.org/browser/livemark-service;2"].
                   getService(Ci.nsILivemarkService);
@@ -309,17 +300,17 @@ BookmarksStore.prototype = {
     if (!this.__ts)
       this.__ts = Cc["@mozilla.org/browser/tagging-service;1"].
                   getService(Ci.nsITaggingService);
     return this.__ts;
   },
 
 
   itemExists: function BStore_itemExists(id) {
-    return idForGUID(id) > 0;
+    return this.idForGUID(id) > 0;
   },
 
   // Hash of old GUIDs to the new renamed GUIDs
   aliases: {},
 
   applyIncoming: function BStore_applyIncoming(record) {
     // Ignore (accidental?) root changes
     if (record.id in kSpecialIds) {
@@ -365,17 +356,17 @@ BookmarksStore.prototype = {
         break;
       }
     }
 
     // Figure out the local id of the parent GUID if available
     let parentGUID = record.parentid;
     record._orphan = false;
     if (parentGUID != null) {
-      let parentId = idForGUID(parentGUID);
+      let parentId = this.idForGUID(parentGUID);
 
       // Default to unfiled if we don't have the parent yet
       if (parentId <= 0) {
         this._log.trace("Reparenting to unfiled until parent is synced");
         record._orphan = true;
         parentId = kSpecialIds.unfiled;
       }
 
@@ -387,31 +378,31 @@ BookmarksStore.prototype = {
     let predGUID = record.predecessorid;
     record._insertPos = Svc.Bookmark.DEFAULT_INDEX;
     if (!record._orphan) {
       // No predecessor means it's the first item
       if (predGUID == null)
         record._insertPos = 0;
       else {
         // The insert position is one after the predecessor of the same parent
-        let predId = idForGUID(predGUID);
+        let predId = this.idForGUID(predGUID);
         if (predId != -1 && this._getParentGUIDForId(predId) == parentGUID) {
           record._insertPos = Svc.Bookmark.getItemIndex(predId) + 1;
           record._predId = predId;
         }
         else
           this._log.trace("Appending to end until predecessor is synced");
       }
     }
 
     // Do the normal processing of incoming records
     Store.prototype.applyIncoming.apply(this, arguments);
 
     // Do some post-processing if we have an item
-    let itemId = idForGUID(record.id);
+    let itemId = this.idForGUID(record.id);
     if (itemId > 0) {
       // Move any children that are looking for this folder as a parent
       if (record.type == "folder")
         this._reparentOrphans(itemId);
 
       // Create an annotation to remember that it needs a parent
       // XXX Work around Bug 510628 by prepending parenT
       if (record._orphan)
@@ -442,17 +433,17 @@ BookmarksStore.prototype = {
       Utils.anno(id, anno) == val);
   },
 
   /**
    * For the provided parent item, attach its children to it
    */
   _reparentOrphans: function _reparentOrphans(parentId) {
     // Find orphans and reunite with this folder parent
-    let parentGUID = GUIDForId(parentId);
+    let parentGUID = this.GUIDForId(parentId);
     let orphans = this._findAnnoItems(PARENT_ANNO, parentGUID);
 
     this._log.debug("Reparenting orphans " + orphans + " to " + parentId);
     orphans.forEach(function(orphan) {
       // Append the orphan under the parent unless it's supposed to be first
       let insertPos = Svc.Bookmark.DEFAULT_INDEX;
       if (!Svc.Annos.itemHasAnnotation(orphan, PREDECESSOR_ANNO))
         insertPos = 0;
@@ -491,17 +482,17 @@ BookmarksStore.prototype = {
         break;
     } while (itemId != stopId);
   },
 
   /**
    * For the provided predecessor item, attach its followers to it
    */
   _attachFollowers: function BStore__attachFollowers(predId) {
-    let predGUID = GUIDForId(predId);
+    let predGUID = this.GUIDForId(predId);
     let followers = this._findAnnoItems(PREDECESSOR_ANNO, predGUID);
     if (followers.length > 1)
       this._log.warn(predId + " has more than one followers: " + followers);
 
     // Start at the first follower and move the chain of followers
     let parent = Svc.Bookmark.getFolderIdForItem(predId);
     followers.forEach(function(follow) {
       this._log.trace("Repositioning " + follow + " behind " + predId);
@@ -587,17 +578,17 @@ BookmarksStore.prototype = {
       return;
     }
 
     this._log.trace("Setting GUID of new item " + newId + " to " + record.id);
     this._setGUID(newId, record.id);
   },
 
   remove: function BStore_remove(record) {
-    let itemId = idForGUID(record.id);
+    let itemId = this.idForGUID(record.id);
     if (itemId <= 0) {
       this._log.debug("Item " + record.id + " already removed");
       return;
     }
     var type = this._bms.getItemType(itemId);
 
     switch (type) {
     case this._bms.TYPE_BOOKMARK:
@@ -615,17 +606,17 @@ BookmarksStore.prototype = {
       break;
     default:
       this._log.error("remove: Unknown item type: " + type);
       break;
     }
   },
 
   update: function BStore_update(record) {
-    let itemId = idForGUID(record.id);
+    let itemId = this.idForGUID(record.id);
 
     if (itemId <= 0) {
       this._log.debug("Skipping update for unknown item: " + record.id);
       return;
     }
 
     this._log.trace("Updating " + record.id + " (" + itemId + ")");
 
@@ -698,33 +689,24 @@ BookmarksStore.prototype = {
     this._findAnnoItems(PARENT_ANNO, oldID).forEach(function(itemId) {
       Utils.anno(itemId, PARENT_ANNO, "T" + newID);
     }, this);
     this._findAnnoItems(PREDECESSOR_ANNO, oldID).forEach(function(itemId) {
       Utils.anno(itemId, PREDECESSOR_ANNO, "R" + newID);
     }, this);
 
     // Make sure there's an item to change GUIDs
-    let itemId = idForGUID(oldID);
+    let itemId = this.idForGUID(oldID);
     if (itemId <= 0)
       return;
 
     this._log.debug("Changing GUID " + oldID + " to " + newID);
     this._setGUID(itemId, newID);
   },
 
-  _setGUID: function BStore__setGUID(itemId, guid) {
-    let collision = idForGUID(guid);
-    if (collision != -1) {
-      this._log.warn("Freeing up GUID " + guid  + " used by " + collision);
-      Svc.Annos.removeItemAnnotation(collision, "placesInternal/GUID");
-    }
-    Svc.Bookmark.setItemGUID(itemId, guid);
-  },
-
   _getNode: function BStore__getNode(folder) {
     let query = this._hsvc.getNewQuery();
     query.setFolders([folder], 1);
     return this._hsvc.executeQuery(query, this._hsvc.getNewQueryOptions()).root;
   },
 
   _getTags: function BStore__getTags(uri) {
     try {
@@ -753,17 +735,17 @@ BookmarksStore.prototype = {
       return Utils.anno(id, "bookmarks/staticTitle");
     } catch (e) {
       return "";
     }
   },
 
   // Create a record starting from the weave id (places guid)
   createRecord: function createRecord(id, collection) {
-    let placeId = idForGUID(id);
+    let placeId = this.idForGUID(id);
     let record;
     if (placeId <= 0) { // deleted item
       record = new PlacesItem(collection, id);
       record.deleted = true;
       return record;
     }
 
     let parent = Svc.Bookmark.getFolderIdForItem(placeId);
@@ -843,28 +825,151 @@ BookmarksStore.prototype = {
 
     record.parentid = this._getParentGUIDForId(placeId);
     record.predecessorid = this._getPredecessorGUIDForId(placeId);
     record.sortindex = this._calculateIndex(record);
 
     return record;
   },
 
-  __frecencyStm: null,
+  _stmts: {},
+  _getStmt: function(query) {
+    if (query in this._stmts)
+      return this._stmts[query];
+
+    this._log.trace("Creating SQL statement: " + query);
+    return this._stmts[query] = Utils.createStatement(this._hsvc.DBConnection,
+                                                      query);
+  },
+
   get _frecencyStm() {
-    if (!this.__frecencyStm) {
-      this._log.trace("Creating SQL statement: _frecencyStm");
-      this.__frecencyStm = Utils.createStatement(
-        Svc.History.DBConnection,
+    return this._getStmt(
         "SELECT frecency " +
         "FROM moz_places " +
         "WHERE url = :url " +
         "LIMIT 1");
+  },
+
+  get _addGUIDAnnotationNameStm() {
+    let stmt = this._getStmt(
+      "INSERT OR IGNORE INTO moz_anno_attributes (name) VALUES (:anno_name)");
+    stmt.params.anno_name = GUID_ANNO;
+    return stmt;
+  },
+
+  get _checkGUIDItemAnnotationStm() {
+    let stmt = this._getStmt(
+      "SELECT b.id AS item_id, " +
+        "(SELECT id FROM moz_anno_attributes WHERE name = :anno_name) AS name_id, " +
+        "a.id AS anno_id, a.dateAdded AS anno_date " +
+      "FROM moz_bookmarks b " +
+      "LEFT JOIN moz_items_annos a ON a.item_id = b.id " +
+                                 "AND a.anno_attribute_id = name_id " +
+      "WHERE b.id = :item_id");
+    stmt.params.anno_name = GUID_ANNO;
+    return stmt;
+  },
+
+  get _addItemAnnotationStm() {
+    return this._getStmt(
+    "INSERT OR REPLACE INTO moz_items_annos " +
+      "(id, item_id, anno_attribute_id, mime_type, content, flags, " +
+       "expiration, type, dateAdded, lastModified) " +
+    "VALUES (:id, :item_id, :name_id, :mime_type, :content, :flags, " +
+            ":expiration, :type, :date_added, :last_modified)");
+  },
+
+  // Some helper functions to handle GUIDs
+  _setGUID: function _setGUID(id, guid) {
+    if (arguments.length == 1)
+      guid = Utils.makeGUID();
+
+    // Ensure annotation name exists
+    Utils.queryAsync(this._addGUIDAnnotationNameStm);
+
+    let stmt = this._checkGUIDItemAnnotationStm;
+    stmt.params.item_id = id;
+    let result = Utils.queryAsync(stmt, ["item_id", "name_id", "anno_id",
+                                         "anno_date"])[0];
+    if (!result) {
+      let log = Log4Moz.repository.getLogger("Engine.Bookmarks");
+      log.warn("Couldn't annotate bookmark id " + id);
+      return guid;
     }
-    return this.__frecencyStm;
+
+    stmt = this._addItemAnnotationStm;
+    if (result.anno_id) {
+      stmt.params.id = result.anno_id;
+      stmt.params.date_added = result.anno_date;
+    } else {
+      stmt.params.id = null;
+      stmt.params.date_added = Date.now() * 1000;
+    }
+    stmt.params.item_id = result.item_id;
+    stmt.params.name_id = result.name_id;
+    stmt.params.content = guid;
+    stmt.params.flags = 0;
+    stmt.params.expiration = Ci.nsIAnnotationService.EXPIRE_NEVER;
+    stmt.params.type = Ci.nsIAnnotationService.TYPE_STRING;
+    stmt.params.last_modified = Date.now() * 1000;
+    Utils.queryAsync(stmt);
+
+    return guid;
+  },
+
+  get _guidForIdStm() {
+    let stmt = this._getStmt(
+      "SELECT a.content AS guid " +
+      "FROM moz_items_annos a " +
+      "JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id " +
+      "JOIN moz_bookmarks b ON b.id = a.item_id " +
+      "WHERE n.name = :anno_name AND b.id = :item_id");
+    stmt.params.anno_name = GUID_ANNO;
+    return stmt;
+  },
+
+  GUIDForId: function GUIDForId(id) {
+    for (let [guid, specialId] in Iterator(kSpecialIds))
+      if (id == specialId)
+         return guid;
+
+    let stmt = this._guidForIdStm;
+    stmt.params.item_id = id;
+
+    // Use the existing GUID if it exists
+    let result = Utils.queryAsync(stmt, ["guid"])[0];
+    if (result)
+      return result.guid;
+
+    // Give the uri a GUID if it doesn't have one
+    return this._setGUID(id);
+  },
+
+  get _idForGUIDStm() {
+    let stmt = this._getStmt(
+      "SELECT a.item_id AS item_id " +
+      "FROM moz_items_annos a " +
+      "JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id " +
+      "WHERE n.name = :anno_name AND a.content = :guid");
+    stmt.params.anno_name = GUID_ANNO;
+    return stmt;
+  },
+
+  idForGUID: function idForGUID(guid) {
+    if (guid in kSpecialIds)
+      return kSpecialIds[guid];
+
+    let stmt = this._idForGUIDStm;
+    // guid might be a String object rather than a string.
+    stmt.params.guid = guid.toString();
+
+    let result = Utils.queryAsync(stmt, ["item_id"])[0];
+    if (result)
+      return result.item_id;
+    return -1;
   },
 
   _calculateIndex: function _calculateIndex(record) {
     // Ensure folders have a very high sort index so they're not synced last.
     if (record.type == "folder")
       return FOLDER_SORTINDEX;
 
     // For anything directly under the toolbar, give it a boost of more than an
@@ -893,17 +998,17 @@ BookmarksStore.prototype = {
     catch(ex) {}
 
     let parentid = this._bms.getFolderIdForItem(itemId);
     if (parentid == -1) {
       this._log.debug("Found orphan bookmark, reparenting to unfiled");
       parentid = this._bms.unfiledBookmarksFolder;
       this._bms.moveItem(itemId, parentid, -1);
     }
-    return GUIDForId(parentid);
+    return this.GUIDForId(parentid);
   },
 
   _getPredecessorGUIDForId: function BStore__getPredecessorGUIDForId(itemId) {
     // Give the predecessor annotation if it exists
     try {
       // XXX Work around Bug 510628 by removing prepended predecessoR
       return Utils.anno(itemId, PREDECESSOR_ANNO).slice(1);
     }
@@ -937,33 +1042,33 @@ BookmarksStore.prototype = {
       this._log.debug("Fixing " + itemId + " to be at position " + itemPos);
       Svc.Bookmark.moveItem(itemId, parentId, itemPos);
 
       // There must be no predecessor for this item!
       if (itemPos == 0)
         return;
     }
 
-    return GUIDForId(predecessorId);
+    return this.GUIDForId(predecessorId);
   },
 
   _getChildren: function BStore_getChildren(guid, items) {
     let node = guid; // the recursion case
     if (typeof(node) == "string") // callers will give us the guid as the first arg
-      node = this._getNode(idForGUID(guid));
+      node = this._getNode(this.idForGUID(guid));
 
     if (node.type == node.RESULT_TYPE_FOLDER &&
         !this._ls.isLivemark(node.itemId)) {
       node.QueryInterface(Ci.nsINavHistoryQueryResultNode);
       node.containerOpen = true;
 
       // Remember all the children GUIDs and recursively get more
       for (var i = 0; i < node.childCount; i++) {
         let child = node.getChild(i);
-        items[GUIDForId(child.itemId)] = true;
+        items[this.GUIDForId(child.itemId)] = true;
         this._getChildren(child, items);
       }
     }
 
     return items;
   },
 
   _tagURI: function BStore_tagURI(bmkURI, tags) {
@@ -1051,24 +1156,29 @@ BookmarksTracker.prototype = {
   },
 
   QueryInterface: XPCOMUtils.generateQI([
     Ci.nsINavBookmarkObserver,
     Ci.nsINavBookmarkObserver_MOZILLA_1_9_1_ADDITIONS,
     Ci.nsISupportsWeakReference
   ]),
 
+  _GUIDForId: function _GUIDForId(item_id) {
+    // Isn't indirection fun...
+    return Engines.get("bookmarks")._store.GUIDForId(item_id);
+  },
+
   /**
    * Add a bookmark (places) id to be uploaded and bump up the sync score
    *
    * @param itemId
    *        Places internal id of the bookmark to upload
    */
   _addId: function BMT__addId(itemId) {
-    if (this.addChangedID(GUIDForId(itemId)))
+    if (this.addChangedID(this._GUIDForId(itemId, true)))
       this._upScore();
   },
 
   /**
    * Add the successor id for the item that follows the given item
    */
   _addSuccessor: function BMT__addSuccessor(itemId) {
     let parentId = Svc.Bookmark.getFolderIdForItem(itemId);
@@ -1097,17 +1207,17 @@ BookmarksTracker.prototype = {
     if (this.ignoreAll)
       return true;
 
     // Ensure that the mobile bookmarks query is correct in the UI
     this._ensureMobileQuery();
 
     // Make sure to remove items that have the exclude annotation
     if (Svc.Annos.itemHasAnnotation(itemId, "places/excludeFromBackup")) {
-      this.removeChangedID(GUIDForId(itemId));
+      this.removeChangedID(this._GUIDForId(itemId, true));
       return true;
     }
 
     // Get the folder id if we weren't given one
     if (folder == null)
       folder = this._bms.getFolderIdForItem(itemId);
 
     let tags = kSpecialIds.tags;
--- a/services/sync/tests/unit/test_bookmark_predecessor.js
+++ b/services/sync/tests/unit/test_bookmark_predecessor.js
@@ -1,25 +1,23 @@
 _("Make sure bad bookmarks can still get their predecessors");
 Cu.import("resource://services-sync/engines/bookmarks.js");
 Cu.import("resource://services-sync/util.js");
 
 function run_test() {
-  let baseuri = "http://fake/uri/";
-
   _("Starting with a clean slate of no bookmarks");
   let store = new (new BookmarksEngine())._storeObj();
   store.wipe();
 
   let uri = Utils.makeURI("http://uri/");
   function insert(pos, folder) {
     folder = folder || Svc.Bookmark.toolbarFolder;
     let name = "pos" + pos;
     let bmk = Svc.Bookmark.insertBookmark(folder, uri, pos, name);
-    Svc.Bookmark.setItemGUID(bmk, name);
+    store._setGUID(bmk, name);
     return bmk;
   }
 
   _("Creating a couple bookmarks that create holes");
   let first = insert(5);
   let second = insert(10);
 
   _("Making sure the record created for the first has no predecessor");
--- a/services/sync/tests/unit/test_bookmark_store.js
+++ b/services/sync/tests/unit/test_bookmark_store.js
@@ -8,31 +8,30 @@ let tburi = Utils.makeURI("http://getthu
 
 function test_bookmark_create() {
   try {
     _("Ensure the record isn't present yet.");
     let ids = Svc.Bookmark.getBookmarkIdsForURI(fxuri, {});
     do_check_eq(ids.length, 0);
 
     _("Let's create a new record.");
-    let fxrecord = new Bookmark("bookmarks",
-                                "{5d81b87c-d5fc-42d9-a114-d69b7342f10e}0");
+    let fxrecord = new Bookmark("bookmarks", "get-firefox1");
     fxrecord.bmkUri        = fxuri.spec;
     fxrecord.description   = "Firefox is awesome.";
     fxrecord.title         = "Get Firefox!";
     fxrecord.tags          = ["firefox", "awesome", "browser"];
     fxrecord.keyword       = "awesome";
     fxrecord.loadInSidebar = false;
     fxrecord.parentName    = "Bookmarks Toolbar";
     fxrecord.parentid      = "toolbar";
     store.applyIncoming(fxrecord);
 
     _("Verify it has been created correctly.");
-    let id = Svc.Bookmark.getItemIdForGUID(fxrecord.id);
-    do_check_eq(Svc.Bookmark.getItemGUID(id), fxrecord.id);
+    let id = store.idForGUID(fxrecord.id);
+    do_check_eq(store.GUIDForId(id), fxrecord.id);
     do_check_eq(Svc.Bookmark.getItemType(id), Svc.Bookmark.TYPE_BOOKMARK);
     do_check_eq(Svc.Bookmark.getItemTitle(id), fxrecord.title);
     do_check_eq(Svc.Bookmark.getFolderIdForItem(id),
                 Svc.Bookmark.toolbarFolder);
     do_check_eq(Svc.Bookmark.getKeywordForBookmark(id), fxrecord.keyword);
 
     _("Have the store create a new record object. Verify that it has the same data.");
     let newrecord = store.createRecord(fxrecord.id);
@@ -49,25 +48,24 @@ function test_bookmark_create() {
     _("Clean up.");
     store.wipe();
   }
 }
 
 function test_folder_create() {
   try {
     _("Create a folder.");
-    let folder = new BookmarkFolder("bookmarks",
-                                    "{5d81b87c-d5fc-42d9-a114-d69b7342f10e}0");
+    let folder = new BookmarkFolder("bookmarks", "testfolder-1");
     folder.parentName = "Bookmarks Toolbar";
     folder.parentid   = "toolbar";
     folder.title      = "Test Folder";
     store.applyIncoming(folder);
 
     _("Verify it has been created correctly.");
-    let id = Svc.Bookmark.getItemIdForGUID(folder.id);
+    let id = store.idForGUID(folder.id);
     do_check_eq(Svc.Bookmark.getItemType(id), Svc.Bookmark.TYPE_FOLDER);
     do_check_eq(Svc.Bookmark.getItemTitle(id), folder.title);
     do_check_eq(Svc.Bookmark.getFolderIdForItem(id),
                 Svc.Bookmark.toolbarFolder);
 
     _("Have the store create a new record object. Verify that it has the same data.");
     let newrecord = store.createRecord(folder.id);
     do_check_true(newrecord instanceof BookmarkFolder);
@@ -82,51 +80,51 @@ function test_folder_create() {
   }
 }
 
 function test_move_folder() {
   try {
     _("Create two folders and a bookmark in one of them.");
     let folder1_id = Svc.Bookmark.createFolder(
       Svc.Bookmark.toolbarFolder, "Folder1", 0);
-    let folder1_guid = Svc.Bookmark.getItemGUID(folder1_id);
+    let folder1_guid = store.GUIDForId(folder1_id);
     let folder2_id = Svc.Bookmark.createFolder(
       Svc.Bookmark.toolbarFolder, "Folder2", 0);
-    let folder2_guid = Svc.Bookmark.getItemGUID(folder2_id);
+    let folder2_guid = store.GUIDForId(folder2_id);
     let bmk_id = Svc.Bookmark.insertBookmark(
       folder1_id, fxuri, Svc.Bookmark.DEFAULT_INDEX, "Get Firefox!");
-    let bmk_guid = Svc.Bookmark.getItemGUID(bmk_id);
+    let bmk_guid = store.GUIDForId(bmk_id);
 
     _("Get a record, reparent it and apply it to the store.");
     let record = store.createRecord(bmk_guid);
     do_check_eq(record.parentid, folder1_guid);
     record.parentid = folder2_guid;
     record.description = ""; //TODO for some reason we need this
     store.applyIncoming(record);
 
     _("Verify the new parent.");
     let new_folder_id = Svc.Bookmark.getFolderIdForItem(bmk_id);
-    do_check_eq(Svc.Bookmark.getItemGUID(new_folder_id), folder2_guid);
+    do_check_eq(store.GUIDForId(new_folder_id), folder2_guid);
   } finally {
     _("Clean up.");
     store.wipe();
   }
 }
 
 function test_move_order() {
   try {
     _("Create two bookmarks");
     let bmk1_id = Svc.Bookmark.insertBookmark(
       Svc.Bookmark.toolbarFolder, fxuri, Svc.Bookmark.DEFAULT_INDEX,
       "Get Firefox!");
-    let bmk1_guid = Svc.Bookmark.getItemGUID(bmk1_id);
+    let bmk1_guid = store.GUIDForId(bmk1_id);
     let bmk2_id = Svc.Bookmark.insertBookmark(
       Svc.Bookmark.toolbarFolder, tburi, Svc.Bookmark.DEFAULT_INDEX,
       "Get Thunderbird!");
-    let bmk2_guid = Svc.Bookmark.getItemGUID(bmk2_id);
+    let bmk2_guid = store.GUIDForId(bmk2_id);
 
     _("Verify order.");
     do_check_eq(Svc.Bookmark.getItemIndex(bmk1_id), 0);
     do_check_eq(Svc.Bookmark.getItemIndex(bmk2_id), 1);
     let rec1 = store.createRecord(bmk1_guid);
     let rec2 = store.createRecord(bmk2_guid);
     do_check_eq(rec1.predecessorid, undefined);
     do_check_eq(rec2.predecessorid, rec1.id);
--- a/services/sync/tests/unit/test_bookmark_tracker.js
+++ b/services/sync/tests/unit/test_bookmark_tracker.js
@@ -1,13 +1,15 @@
+Cu.import("resource://services-sync/engines.js");
 Cu.import("resource://services-sync/engines/bookmarks.js");
 Cu.import("resource://services-sync/util.js");
 
 function run_test() {
-  let engine = new BookmarksEngine();
+  Engines.register(BookmarksEngine);
+  let engine = Engines.get("bookmarks");
   engine._store.wipe();
 
   _("Verify we've got an empty tracker to work with.");
   let tracker = engine._tracker;
   do_check_eq([id for (id in tracker.changedIDs)].length, 0);
 
   let folder = Svc.Bookmark.createFolder(Svc.Bookmark.bookmarksMenuFolder,
                                          "Test Folder",