gecko/services/sync/tests/unit/test_bookmark_engine.js

372 lines
12 KiB
JavaScript

Cu.import("resource://services-sync/engines.js");
Cu.import("resource://services-sync/engines/bookmarks.js");
Cu.import("resource://services-sync/record.js");
Cu.import("resource://services-sync/log4moz.js");
Cu.import("resource://services-sync/util.js");
Cu.import("resource://services-sync/service.js");
Cu.import("resource://gre/modules/PlacesUtils.jsm");
Engines.register(BookmarksEngine);
function makeEngine() {
return new BookmarksEngine();
}
var syncTesting = new SyncTestingInfrastructure(makeEngine);
function test_ID_caching() {
_("Ensure that Places IDs are not cached.");
let engine = new BookmarksEngine();
let store = engine._store;
_("All IDs: " + JSON.stringify(store.getAllIDs()));
let mobileID = store.idForGUID("mobile");
_("Change the GUID for that item, and drop the mobile anno.");
store._setGUID(mobileID, "abcdefghijkl");
Svc.Annos.removeItemAnnotation(mobileID, "mobile/bookmarksRoot");
let err;
let newMobileID;
// With noCreate, we don't find an entry.
try {
newMobileID = store.idForGUID("mobile", true);
_("New mobile ID: " + newMobileID);
} catch (ex) {
err = ex;
_("Error: " + Utils.exceptionStr(err));
}
do_check_true(!err);
// With !noCreate, lookup works, and it's different.
newMobileID = store.idForGUID("mobile", false);
_("New mobile ID: " + newMobileID);
do_check_true(!!newMobileID);
do_check_neq(newMobileID, mobileID);
// And it's repeatable, even with creation enabled.
do_check_eq(newMobileID, store.idForGUID("mobile", false));
do_check_eq(store.GUIDForId(mobileID), "abcdefghijkl");
}
function test_processIncoming_error_orderChildren() {
_("Ensure that _orderChildren() is called even when _processIncoming() throws an error.");
do_test_pending();
Svc.Prefs.set("clusterURL", "http://localhost:8080/");
Svc.Prefs.set("username", "foo");
let collection = new ServerCollection();
let engine = new BookmarksEngine();
let store = engine._store;
let global = new ServerWBO('global',
{engines: {bookmarks: {version: engine.version,
syncID: engine.syncID}}});
let server = httpd_setup({
"/1.0/foo/storage/meta/global": global.handler(),
"/1.0/foo/storage/bookmarks": collection.handler()
});
try {
let folder1_id = Svc.Bookmark.createFolder(
Svc.Bookmark.toolbarFolder, "Folder 1", 0);
let folder1_guid = store.GUIDForId(folder1_id);
let fxuri = Utils.makeURI("http://getfirefox.com/");
let tburi = Utils.makeURI("http://getthunderbird.com/");
let bmk1_id = Svc.Bookmark.insertBookmark(
folder1_id, fxuri, Svc.Bookmark.DEFAULT_INDEX, "Get Firefox!");
let bmk1_guid = store.GUIDForId(bmk1_id);
let bmk2_id = Svc.Bookmark.insertBookmark(
folder1_id, tburi, Svc.Bookmark.DEFAULT_INDEX, "Get Thunderbird!");
let bmk2_guid = store.GUIDForId(bmk2_id);
// Create a server record for folder1 where we flip the order of
// the children.
let folder1_payload = store.createRecord(folder1_guid).cleartext;
folder1_payload.children.reverse();
collection.wbos[folder1_guid] = new ServerWBO(
folder1_guid, encryptPayload(folder1_payload));
// Create a bogus record that when synced down will provoke a
// network error which in turn provokes an exception in _processIncoming.
const BOGUS_GUID = "zzzzzzzzzzzz";
let bogus_record = collection.wbos[BOGUS_GUID]
= new ServerWBO(BOGUS_GUID, "I'm a bogus record!");
bogus_record.get = function get() {
throw "Sync this!";
};
// Make the 10 minutes old so it will only be synced in the toFetch phase.
bogus_record.modified = Date.now() / 1000 - 60 * 10;
engine.lastSync = Date.now() / 1000 - 60;
engine.toFetch = [BOGUS_GUID];
let error;
try {
engine.sync();
} catch(ex) {
error = ex;
}
do_check_true(!!error);
// Verify that the bookmark order has been applied.
let new_children = store.createRecord(folder1_guid).children;
do_check_eq(new_children.length, 2);
do_check_eq(new_children[0], folder1_payload.children[0]);
do_check_eq(new_children[1], folder1_payload.children[1]);
do_check_eq(Svc.Bookmark.getItemIndex(bmk1_id), 1);
do_check_eq(Svc.Bookmark.getItemIndex(bmk2_id), 0);
} finally {
store.wipe();
server.stop(do_test_finished);
Svc.Prefs.resetBranch("");
Records.clearCache();
syncTesting = new SyncTestingInfrastructure(makeEngine);
}
}
function test_restorePromptsReupload() {
_("Ensure that restoring from a backup will reupload all records.");
do_test_pending();
Svc.Prefs.set("username", "foo");
Service.serverURL = "http://localhost:8080/";
Service.clusterURL = "http://localhost:8080/";
let collection = new ServerCollection({}, true);
let engine = new BookmarksEngine();
let store = engine._store;
let global = new ServerWBO('global',
{engines: {bookmarks: {version: engine.version,
syncID: engine.syncID}}});
let server = httpd_setup({
"/1.0/foo/storage/meta/global": global.handler(),
"/1.0/foo/storage/bookmarks": collection.handler()
});
Svc.Obs.notify("weave:engine:start-tracking"); // We skip usual startup...
try {
let folder1_id = Svc.Bookmark.createFolder(
Svc.Bookmark.toolbarFolder, "Folder 1", 0);
let folder1_guid = store.GUIDForId(folder1_id);
_("Folder 1: " + folder1_id + ", " + folder1_guid);
let fxuri = Utils.makeURI("http://getfirefox.com/");
let tburi = Utils.makeURI("http://getthunderbird.com/");
_("Create a single record.");
let bmk1_id = Svc.Bookmark.insertBookmark(
folder1_id, fxuri, Svc.Bookmark.DEFAULT_INDEX, "Get Firefox!");
let bmk1_guid = store.GUIDForId(bmk1_id);
_("Get Firefox!: " + bmk1_id + ", " + bmk1_guid);
let dirSvc = Cc["@mozilla.org/file/directory_service;1"]
.getService(Ci.nsIProperties);
let backupFile = dirSvc.get("TmpD", Ci.nsILocalFile);
_("Make a backup.");
backupFile.append("t_b_e_" + Date.now() + ".json");
_("Backing up to file " + backupFile.path);
backupFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, 0600);
PlacesUtils.backupBookmarksToFile(backupFile);
_("Create a different record and sync.");
let bmk2_id = Svc.Bookmark.insertBookmark(
folder1_id, tburi, Svc.Bookmark.DEFAULT_INDEX, "Get Thunderbird!");
let bmk2_guid = store.GUIDForId(bmk2_id);
_("Get Thunderbird!: " + bmk2_id + ", " + bmk2_guid);
Svc.Bookmark.removeItem(bmk1_id);
let error;
try {
engine.sync();
} catch(ex) {
error = ex;
_("Got error: " + Utils.exceptionStr(ex));
}
do_check_true(!error);
_("Verify that there's only one bookmark on the server, and it's Thunderbird.");
// Of course, there's also the Bookmarks Toolbar and Bookmarks Menu...
let wbos = [id for ([id, wbo] in Iterator(collection.wbos))
if (["menu", "toolbar", "mobile", folder1_guid].indexOf(id) == -1)];
do_check_eq(wbos.length, 1);
do_check_eq(wbos[0], bmk2_guid);
_("Now restore from a backup.");
PlacesUtils.restoreBookmarksFromJSONFile(backupFile);
_("Ensure we have the bookmarks we expect locally.");
let guids = store.getAllIDs();
_("GUIDs: " + JSON.stringify(guids));
let found = false;
let count = 0;
let newFX;
for (let guid in guids) {
count++;
let id = store.idForGUID(guid, true);
// Only one bookmark, so _all_ should be Firefox!
if (Svc.Bookmark.getItemType(id) == Svc.Bookmark.TYPE_BOOKMARK) {
let uri = Svc.Bookmark.getBookmarkURI(id);
_("Found URI " + uri.spec + " for GUID " + guid);
do_check_eq(uri.spec, fxuri.spec);
newFX = guid; // Save the new GUID after restore.
found = true; // Only runs if the above check passes.
}
}
_("We found it: " + found);
do_check_true(found);
_("Have the correct number of IDs locally, too.");
do_check_eq(count, ["menu", "toolbar", folder1_id, bmk1_id].length);
_("Sync again. This'll wipe bookmarks from the server.");
try {
engine.sync();
} catch(ex) {
error = ex;
_("Got error: " + Utils.exceptionStr(ex));
}
do_check_true(!error);
_("Verify that there's only one bookmark on the server, and it's Firefox.");
// Of course, there's also the Bookmarks Toolbar and Bookmarks Menu...
wbos = [JSON.parse(JSON.parse(wbo.payload).ciphertext)
for ([id, wbo] in Iterator(collection.wbos))
if (wbo.payload)];
_("WBOs: " + JSON.stringify(wbos));
let bookmarks = [wbo for each (wbo in wbos) if (wbo.type == "bookmark")];
do_check_eq(bookmarks.length, 1);
do_check_eq(bookmarks[0].id, newFX);
do_check_eq(bookmarks[0].bmkUri, fxuri.spec);
do_check_eq(bookmarks[0].title, "Get Firefox!");
_("Our old friend Folder 1 is still in play.");
let folders = [wbo for each (wbo in wbos)
if ((wbo.type == "folder") &&
(wbo.id != "menu") &&
(wbo.id != "toolbar"))];
do_check_eq(folders.length, 1);
do_check_eq(folders[0].title, "Folder 1");
} finally {
store.wipe();
server.stop(do_test_finished);
Svc.Prefs.resetBranch("");
Records.clearCache();
syncTesting = new SyncTestingInfrastructure(makeEngine);
}
}
// Bug 632287.
function test_mismatched_types() {
_("Ensure that handling a record that changes type causes deletion " +
"then re-adding.");
function FakeRecord(constructor, r) {
constructor.call(this, "bookmarks", r.id);
for (let x in r) {
this[x] = r[x];
}
}
let oldRecord = {
"id": "l1nZZXfB8nC7",
"type":"folder",
"parentName":"Bookmarks Toolbar",
"title":"Innerst i Sneglehode",
"description":null,
"parentid": "toolbar"
};
let newRecord = {
"id": "l1nZZXfB8nC7",
"type":"livemark",
"siteUri":"http://sneglehode.wordpress.com/",
"feedUri":"http://sneglehode.wordpress.com/feed/",
"parentName":"Bookmarks Toolbar",
"title":"Innerst i Sneglehode",
"description":null,
"children":
["HCRq40Rnxhrd", "YeyWCV1RVsYw", "GCceVZMhvMbP", "sYi2hevdArlF",
"vjbZlPlSyGY8", "UtjUhVyrpeG6", "rVq8WMG2wfZI", "Lx0tcy43ZKhZ",
"oT74WwV8_j4P", "IztsItWVSo3-"],
"parentid": "toolbar"
};
do_test_pending();
Svc.Prefs.set("username", "foo");
Service.serverURL = "http://localhost:8080/";
Service.clusterURL = "http://localhost:8080/";
let collection = new ServerCollection({}, true);
let engine = new BookmarksEngine();
let store = engine._store;
let global = new ServerWBO('global',
{engines: {bookmarks: {version: engine.version,
syncID: engine.syncID}}});
_("GUID: " + store.GUIDForId(6, true));
let server = httpd_setup({
"/1.0/foo/storage/meta/global": global.handler(),
"/1.0/foo/storage/bookmarks": collection.handler()
});
try {
let bms = store._bms;
let oldR = new FakeRecord(BookmarkFolder, oldRecord);
let newR = new FakeRecord(Livemark, newRecord);
oldR._parent = Svc.Bookmark.toolbarFolder;
newR._parent = Svc.Bookmark.toolbarFolder;
store.applyIncoming(oldR);
_("Applied old. It's a folder.");
let oldID = store.idForGUID(oldR.id);
_("Old ID: " + oldID);
do_check_eq(bms.getItemType(oldID), bms.TYPE_FOLDER);
do_check_false(store._ls.isLivemark(oldID));
store.applyIncoming(newR);
let newID = store.idForGUID(newR.id);
_("New ID: " + newID);
_("Applied new. It's a livemark.");
do_check_eq(bms.getItemType(newID), bms.TYPE_FOLDER);
do_check_true(store._ls.isLivemark(newID));
} finally {
store.wipe();
server.stop(do_test_finished);
Svc.Prefs.resetBranch("");
Records.clearCache();
syncTesting = new SyncTestingInfrastructure(makeEngine);
}
}
function run_test() {
initTestLogging("Trace");
Log4Moz.repository.getLogger("Engine.Bookmarks").level = Log4Moz.Level.Trace;
CollectionKeys.generateNewKeys();
test_processIncoming_error_orderChildren();
test_ID_caching();
test_mismatched_types();
test_restorePromptsReupload();
}