Merge lp:~jamesh/bindwood/sync-from-couch into lp:bindwood

Proposed by James Henstridge
Status: Merged
Approved by: dobey
Approved revision: 46
Merged at revision: 34
Proposed branch: lp:~jamesh/bindwood/sync-from-couch
Merge into: lp:bindwood
Prerequisite: lp:~jamesh/bindwood/sync-guid-map
Diff against target: 525 lines (+485/-2)
2 files modified
modules/sync.jsm (+181/-2)
mozmill/tests/test_sync_from_couch.js (+304/-0)
To merge this branch: bzr merge lp:~jamesh/bindwood/sync-from-couch
Reviewer Review Type Date Requested Status
Manuel de la Peña (community) Approve
Stuart Langridge (community) Approve
Review via email: mp+50498@code.launchpad.net

Commit message

Add code to the new synchroniser to create local bookmarks from CouchDB documents.

Description of the change

Create local bookmarks based on incoming documents from CouchDB.

Unlike the existing Bindwood schema, I am relying on a reference to the parent item in each bookmark, and treat the children list in folder items as an ordering hint.

If there is no local bookmark for a given bookmark, we create them under unfiledBookmarksFolder and reparent them when processing the parent record. This way we should get the same result no matter which order we receive the records.

Since we won't necessarily have imported all the children when processing a folder record, we don't bother trying to place the bookmarks in order. Instead, we make a note of the requested child ordering so that it can be applied after all the bookmarks have been imported.

To post a comment you must log in.
Revision history for this message
Stuart Langridge (sil) wrote :

Will this affect the website bookmark rendering code?

sil

Revision history for this message
James Henstridge (jamesh) wrote :

Looking at the bookmarks web code, it ignores folders entirely, and only deals with the "uri" and "title" attributes on leaf bookmarks, so that part doesn't matter.

One place where my changes may be an issue is the detection of available profiles. Currently it uses a view that searches for documents with an ID of the form "root_*". In my new code, I haven't been generating that document, but it would certainly be possible to add that back in.

Revision history for this message
Stuart Langridge (sil) wrote :

All tests now pass (natty, FF4). Looking good.

review: Approve
Revision history for this message
Manuel de la Peña (mandel) wrote :

Looks good when testing on M.

review: Approve
Revision history for this message
Ubuntu One Auto Pilot (otto-pilot) wrote :

The prerequisite lp:~jamesh/bindwood/sync-guid-map has not yet been merged into lp:bindwood.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'modules/sync.jsm'
2--- modules/sync.jsm 2011-02-22 11:07:07 +0000
3+++ modules/sync.jsm 2011-02-22 11:07:07 +0000
4@@ -19,6 +19,13 @@
5 const GUID_ANNOTATION = "bindwood/uuid";
6 const PARENT_ANNOTATION = "bindwood/parent";
7
8+const RECORD_PREFIX = (
9+ "http://www.freedesktop.org/wiki/Specifications/desktopcouch/");
10+const TYPE_BOOKMARK = RECORD_PREFIX + "bookmark";
11+const TYPE_FOLDER = RECORD_PREFIX + "folder";
12+const TYPE_FEED = RECORD_PREFIX + "feed";
13+const TYPE_SEPARATOR = RECORD_PREFIX + "separator";
14+
15 const Cc = Components.classes;
16 const Ci = Components.interfaces;
17 const Cr = Components.results;
18@@ -29,8 +36,12 @@
19 .getService(Ci.nsILivemarkService);
20 var annotationService = Cc["@mozilla.org/browser/annotation-service;1"]
21 .getService(Ci.nsIAnnotationService);
22+var historyService = Cc["@mozilla.org/browser/nav-history-service;1"]
23+ .getService(Ci.nsINavHistoryService);
24 var uuidService = Cc["@mozilla.org/uuid-generator;1"]
25 .getService(Ci.nsIUUIDGenerator);
26+var ioService = Cc["@mozilla.org/network/io-service;1"]
27+ .getService(Ci.nsIIOService);
28
29
30 function Synchroniser(couch, profile) {
31@@ -38,6 +49,7 @@
32 this.profile = profile;
33 this.last_seq = 0;
34 this.guid_item_map = {};
35+ this.folders_to_reorder = {};
36 }
37
38 Synchroniser.prototype = {
39@@ -193,8 +205,175 @@
40 },
41
42 processRecord: function (doc) {
43- /* Process incoming document */
44- }
45+ var item_id = this.guid_to_id(doc._id);
46+ // XXX: We should perform duplicate detection here if item_id
47+ // is null.
48+ if (item_id != null) {
49+ this.updateItem(item_id, doc);
50+ } else {
51+ this.createItem(doc);
52+ }
53+ },
54+
55+ createItem: function(doc) {
56+ if (doc._deleted) {
57+ /* Bookmark must have been created and deleted within the
58+ * period of one sync cycle, so ignore. */
59+ return;
60+ }
61+ // Determine the parent folder. If it doesn't exist,
62+ // temporarily add it as an unfiled bookmark to handle later.
63+ var parent_id = this.guid_to_id(doc.parent_guid);
64+ var has_parent = (parent_id != null);
65+ if (!has_parent) {
66+ parent_id = bookmarksService.unfiledBookmarksFolder;
67+ }
68+
69+ var item_id;
70+ switch (doc.record_type) {
71+ case TYPE_BOOKMARK:
72+ var uri = ioService.newURI(doc.uri, null, null);
73+ item_id = bookmarksService.insertBookmark(
74+ parent_id, uri, bookmarksService.DEFAULT_INDEX, doc.title);
75+ break;
76+ case TYPE_FOLDER:
77+ item_id = bookmarksService.createFolder(
78+ parent_id, doc.title, bookmarksService.DEFAULT_INDEX);
79+ this.reparent_orphans(item_id, doc._id);
80+ this.folders_to_reorder[doc._id] = doc.children;
81+ break;
82+ case TYPE_FEED:
83+ var site_uri = ioService.newURI(doc.site_uri, null, null);
84+ var feed_uri = ioService.newURI(doc.feed_uri, null, null);
85+ item_id = livemarkService.createLivemark(
86+ parent_id, doc.title, site_uri, feed_uri,
87+ bookmarksService.DEFAULT_INDEX);
88+ break;
89+ case TYPE_SEPARATOR:
90+ item_id = bookmarksService.insertSeparator(
91+ parent_id, bookmarksService.DEFAULT_INDEX);
92+ break;
93+ default:
94+ item_id = null;
95+ }
96+ if (item_id) {
97+ this.set_guid(item_id, doc._id);
98+ if (!has_parent) {
99+ this.set_orphan(item_id, doc.parent_guid);
100+ }
101+ }
102+ },
103+
104+ updateItem: function(item_id, doc) {
105+ if (doc._deleted) {
106+ // Document has been deleted in Couch: propagate to local.
107+ bookmarksService.removeItem(item_id);
108+ return;
109+ }
110+
111+ var parent_id = this.guid_to_id(doc.parent_guid);
112+ if (parent_id == null) {
113+ this.set_orphan(item_id, doc.parent_guid);
114+ } else {
115+ if (bookmarksService.getFolderIdForItem(item_id) != parent_id) {
116+ bookmarksService.moveItem(
117+ item_id, parent_id, bookmarksService.DEFAULT_INDEX);
118+ }
119+ annotationService.removeItemAnnotation(
120+ item_id, PARENT_ANNOTATION);
121+ }
122+
123+ switch (doc.record_type) {
124+ case TYPE_BOOKMARK:
125+ var uri = ioService.newURI(doc.uri, null, null);
126+ bookmarksService.setItemTitle(item_id, doc.title);
127+ bookmarksService.changeBookmarkURI(item_id, uri);
128+ break;
129+ case TYPE_FOLDER:
130+ bookmarksService.setItemTitle(item_id, doc.title);
131+ this.folders_to_reorder[doc._id] = doc.children;
132+ break;
133+ case TYPE_FEED:
134+ var site_uri = ioService.newURI(doc.site_uri, null, null);
135+ var feed_uri = ioService.newURI(doc.feed_uri, null, null);
136+ bookmarksService.setItemTitle(item_id, doc.title);
137+ livemarkService.setSiteURI(item_id, site_uri);
138+ livemarkService.setFeedURI(item_id, feed_uri);
139+ break;
140+ case TYPE_SEPARATOR:
141+ item_id = bookmarksService.insertSeparator(
142+ parent_id, bookmarksService.DEFAULT_INDEX);
143+ break;
144+ default:
145+ item_id = null;
146+ }
147+ },
148+
149+ set_orphan: function (item_id, parent_guid) {
150+ annotationService.setItemAnnotation(
151+ item_id, PARENT_ANNOTATION, parent_guid,
152+ 0, annotationService.EXPIRE_NEVER);
153+ },
154+
155+ reparent_orphans: function (parent_id, parent_guid) {
156+ var items = annotationService.getItemsWithAnnotation(
157+ PARENT_ANNOTATION, {});
158+ for each (orphan_id in items) {
159+ if (annotationService.getItemAnnotation(
160+ orphan_id, PARENT_ANNOTATION) != parent_guid) {
161+ continue;
162+ }
163+ // XXX: check for errors
164+ bookmarksService.moveItem(
165+ orphan_id, parent_id, bookmarksService.DEFAULT_INDEX)
166+ annotationService.removeItemAnnotation(
167+ orphan_id, PARENT_ANNOTATION);
168+ }
169+ },
170+
171+ get_folder_children: function(parent_id) {
172+ var query = historyService.getNewQuery();
173+ var options = historyService.getNewQueryOptions();
174+ query.setFolders([parent_id], 1);
175+ var root = historyService.executeQuery(query, options).root;
176+
177+ var children = [];
178+ root.containerOpen = true;
179+ for (var i = 0; i < root.childCount; i++) {
180+ var child = root.getChild(i);
181+ children.push(child.itemId);
182+ }
183+ return children;
184+ },
185+
186+ reorder_children: function() {
187+ for (var parent_guid in this.folders_to_reorder) {
188+ var parent_id = this.guid_to_id(parent_guid);
189+ if (!parent_id)
190+ continue;
191+
192+ var children = this.get_folder_children(parent_id);
193+ var idx = 0;
194+ for each (child_guid in this.folders_to_reorder[parent_guid]) {
195+ var child_id = this.guid_to_id(child_guid);
196+ if (!child_id)
197+ continue;
198+
199+ // Set the item's index.
200+ bookmarksService.setItemIndex(child_id, idx++);
201+
202+ // Remove from the list of existing children, if they exist.
203+ var existing_idx = children.indexOf(child_id);
204+ if (existing_idx >= 0)
205+ children.splice(existing_idx, 1);
206+ }
207+ // Stick the remaining items at the end of the folder.
208+ for each (var child_id in children) {
209+ bookmarksService.setItemIndex(child_id, idx++);
210+ }
211+ }
212+ this.folders_to_reorder = {}
213+ },
214 };
215
216
217
218=== added file 'mozmill/tests/test_sync_from_couch.js'
219--- mozmill/tests/test_sync_from_couch.js 1970-01-01 00:00:00 +0000
220+++ mozmill/tests/test_sync_from_couch.js 2011-02-22 11:07:07 +0000
221@@ -0,0 +1,304 @@
222+var bm = require("../shared-modules/bookmarks");
223+
224+const TIMEOUT = 5000;
225+
226+const LOCAL_TEST_FOLDER = collector.addHttpResource('../test-files/');
227+const LOCAL_TEST_PAGE = LOCAL_TEST_FOLDER + 'test.html';
228+const LOCAL_TEST_FEED = LOCAL_TEST_FOLDER + 'feed.atom';
229+
230+var setupModule = function(module) {
231+ module.controller = mozmill.getBrowserController();
232+ module.jum = {}
233+ module.sync = {}
234+ Cu.import("resource://mozmill/modules/jum.js", module.jum);
235+ Cu.import("resource://bindwood/sync.jsm", module.sync);
236+ module.synchroniser = null;
237+ bm.clearBookmarks();
238+};
239+
240+
241+var setupTest = function() {
242+ synchroniser = new sync.Synchroniser(null, "profile_name");
243+};
244+
245+var teardownTest = function() {
246+ bm.clearBookmarks();
247+};
248+
249+var test_create_bookmark = function() {
250+ synchroniser.processRecord({
251+ _id: '12345',
252+ record_type: 'http://www.freedesktop.org/wiki/Specifications/desktopcouch/bookmark',
253+ parent_guid: 'toolbar_profile_name',
254+ title: 'Bookmark title',
255+ uri: LOCAL_TEST_PAGE,
256+ });
257+ var bookmark_id = synchroniser.guid_to_id('12345');
258+ jum.assertEquals(bm.bookmarksService.getItemType(bookmark_id),
259+ bm.bookmarksService.TYPE_BOOKMARK);
260+ jum.assertEquals(bm.bookmarksService.getFolderIdForItem(bookmark_id),
261+ bm.bookmarksService.toolbarFolder);
262+ jum.assertEquals(bm.bookmarksService.getItemTitle(bookmark_id),
263+ 'Bookmark title');
264+ jum.assertEquals(bm.bookmarksService.getBookmarkURI(bookmark_id).spec,
265+ LOCAL_TEST_PAGE);
266+};
267+
268+var test_update_bookmark = function() {
269+ doc = {
270+ _id: '12345',
271+ record_type: 'http://www.freedesktop.org/wiki/Specifications/desktopcouch/bookmark',
272+ parent_guid: 'toolbar_profile_name',
273+ title: 'Bookmark title',
274+ uri: LOCAL_TEST_PAGE,
275+ };
276+ synchroniser.processRecord(doc);
277+ doc.title = 'New title';
278+ doc.uri = LOCAL_TEST_PAGE + "#updated";
279+ synchroniser.processRecord(doc);
280+
281+ var bookmark_id = synchroniser.guid_to_id('12345');
282+ jum.assertEquals(bm.bookmarksService.getItemTitle(bookmark_id),
283+ 'New title');
284+ jum.assertEquals(bm.bookmarksService.getBookmarkURI(bookmark_id).spec,
285+ LOCAL_TEST_PAGE + "#updated");
286+};
287+
288+var test_create_folder = function() {
289+ synchroniser.processRecord({
290+ _id: '12345',
291+ record_type: 'http://www.freedesktop.org/wiki/Specifications/desktopcouch/folder',
292+ parent_guid: 'toolbar_profile_name',
293+ title: 'Folder',
294+ children: [],
295+ });
296+ var bookmark_id = synchroniser.guid_to_id('12345');
297+ jum.assertEquals(bm.bookmarksService.getItemType(bookmark_id),
298+ bm.bookmarksService.TYPE_FOLDER);
299+ jum.assertEquals(bm.bookmarksService.getFolderIdForItem(bookmark_id),
300+ bm.bookmarksService.toolbarFolder);
301+ jum.assertEquals(
302+ bm.bookmarksService.getItemTitle(bookmark_id), 'Folder');
303+ // Reordering of folder's children has been scheduled.
304+ jum.assertNotEquals(synchroniser.folders_to_reorder['12345'], null);
305+};
306+
307+var test_update_folder = function() {
308+ doc = {
309+ _id: '12345',
310+ record_type: 'http://www.freedesktop.org/wiki/Specifications/desktopcouch/folder',
311+ parent_guid: 'toolbar_profile_name',
312+ title: 'Folder',
313+ children: [],
314+ };
315+ synchroniser.processRecord(doc);
316+ doc.title = 'Updated folder';
317+ synchroniser.processRecord(doc);
318+
319+ var bookmark_id = synchroniser.guid_to_id('12345');
320+ jum.assertEquals(bm.bookmarksService.getItemTitle(bookmark_id),
321+ 'Updated folder');
322+ // Reordering of folder's children has been scheduled.
323+ jum.assertNotEquals(synchroniser.folders_to_reorder['12345'], null);
324+};
325+
326+var test_create_livemark = function() {
327+ synchroniser.processRecord({
328+ _id: '12345',
329+ record_type: 'http://www.freedesktop.org/wiki/Specifications/desktopcouch/feed',
330+ parent_guid: 'toolbar_profile_name',
331+ title: 'Livemark',
332+ site_uri: "http://www.example.com/",
333+ feed_uri: LOCAL_TEST_FEED,
334+ });
335+ var bookmark_id = synchroniser.guid_to_id('12345');
336+ jum.assertTrue(bm.livemarkService.isLivemark(bookmark_id))
337+ jum.assertEquals(bm.bookmarksService.getFolderIdForItem(bookmark_id),
338+ bm.bookmarksService.toolbarFolder);
339+ jum.assertEquals(
340+ bm.bookmarksService.getItemTitle(bookmark_id), 'Livemark');
341+ jum.assertEquals(bm.livemarkService.getSiteURI(bookmark_id).spec,
342+ "http://www.example.com/");
343+ jum.assertEquals(bm.livemarkService.getFeedURI(bookmark_id).spec,
344+ LOCAL_TEST_FEED);
345+};
346+
347+var test_update_livemark = function() {
348+ doc = {
349+ _id: '12345',
350+ record_type: 'http://www.freedesktop.org/wiki/Specifications/desktopcouch/feed',
351+ parent_guid: 'toolbar_profile_name',
352+ title: 'Livemark',
353+ site_uri: "http://www.example.com/",
354+ feed_uri: LOCAL_TEST_FEED,
355+ };
356+ synchroniser.processRecord(doc);
357+ doc.title = 'New title';
358+ doc.feed_uri = LOCAL_TEST_FEED + "#updated";
359+ synchroniser.processRecord(doc);
360+
361+ var bookmark_id = synchroniser.guid_to_id('12345');
362+ jum.assertEquals(bm.bookmarksService.getItemTitle(bookmark_id),
363+ 'New title');
364+ jum.assertEquals(bm.livemarkService.getFeedURI(bookmark_id).spec,
365+ LOCAL_TEST_FEED + "#updated");
366+};
367+
368+var test_create_separator = function() {
369+ synchroniser.processRecord({
370+ _id: '12345',
371+ record_type: 'http://www.freedesktop.org/wiki/Specifications/desktopcouch/separator',
372+ parent_guid: 'toolbar_profile_name',
373+ });
374+ var bookmark_id = synchroniser.guid_to_id('12345');
375+ jum.assertEquals(bm.bookmarksService.getItemType(bookmark_id),
376+ bm.bookmarksService.TYPE_SEPARATOR);
377+ jum.assertEquals(bm.bookmarksService.getFolderIdForItem(bookmark_id),
378+ bm.bookmarksService.toolbarFolder);
379+};
380+
381+var test_update_separator = function() {
382+ doc = {
383+ _id: '12345',
384+ record_type: 'http://www.freedesktop.org/wiki/Specifications/desktopcouch/separator',
385+ parent_guid: 'toolbar_profile_name',
386+ };
387+ synchroniser.processRecord(doc);
388+ // No properties to change on the separator, but verify that the
389+ // update code path runs anyway.
390+ synchroniser.processRecord(doc);
391+ var bookmark_id = synchroniser.guid_to_id('12345');
392+ jum.assertEquals(bm.bookmarksService.getItemType(bookmark_id),
393+ bm.bookmarksService.TYPE_SEPARATOR);
394+};
395+
396+var test_update_item_reparent = function() {
397+ doc = {
398+ _id: '12345',
399+ record_type: 'http://www.freedesktop.org/wiki/Specifications/desktopcouch/bookmark',
400+ parent_guid: 'toolbar_profile_name',
401+ title: 'Bookmark title',
402+ uri: LOCAL_TEST_PAGE,
403+ };
404+ synchroniser.processRecord(doc);
405+ var bookmark_id = synchroniser.guid_to_id('12345');
406+ jum.assertEquals(bm.bookmarksService.getFolderIdForItem(bookmark_id),
407+ bm.bookmarksService.toolbarFolder);
408+
409+ // Move to a new parent folder.
410+ doc.parent_guid = "menu_profile_name";
411+ synchroniser.processRecord(doc);
412+ jum.assertEquals(bm.bookmarksService.getFolderIdForItem(bookmark_id),
413+ bm.bookmarksService.bookmarksMenuFolder);
414+};
415+
416+var test_create_parent_then_child = function() {
417+ synchroniser.processRecord({
418+ _id: '12345',
419+ record_type: 'http://www.freedesktop.org/wiki/Specifications/desktopcouch/folder',
420+ parent_guid: 'toolbar_profile_name',
421+ title: 'Folder',
422+ children: ['67890'],
423+ });
424+ var parent_id = synchroniser.guid_to_id('12345');
425+ jum.assertEquals(bm.bookmarksService.getFolderIdForItem(parent_id),
426+ bm.bookmarksService.toolbarFolder);
427+ // Reordering of folder's children has been scheduled.
428+ jum.assertNotEquals(synchroniser.folders_to_reorder['12345'], null);
429+
430+ synchroniser.processRecord({
431+ _id: '67890',
432+ record_type: 'http://www.freedesktop.org/wiki/Specifications/desktopcouch/bookmark',
433+ parent_guid: '12345',
434+ title: 'Bookmark title',
435+ uri: LOCAL_TEST_PAGE,
436+ });
437+ var child_id = synchroniser.guid_to_id('67890');
438+ jum.assertEquals(bm.bookmarksService.getFolderIdForItem(child_id),
439+ parent_id);
440+};
441+
442+var test_create_child_then_parent = function() {
443+ synchroniser.processRecord({
444+ _id: '67890',
445+ record_type: 'http://www.freedesktop.org/wiki/Specifications/desktopcouch/bookmark',
446+ parent_guid: '12345',
447+ title: 'Bookmark title',
448+ uri: LOCAL_TEST_PAGE,
449+ });
450+ var child_id = synchroniser.guid_to_id('67890');
451+ // The bookmark is temporarily stashed in unfiled bookmarks.
452+ jum.assertEquals(bm.bookmarksService.getFolderIdForItem(child_id),
453+ bm.bookmarksService.unfiledBookmarksFolder);
454+
455+ synchroniser.processRecord({
456+ _id: '12345',
457+ record_type: 'http://www.freedesktop.org/wiki/Specifications/desktopcouch/folder',
458+ parent_guid: 'toolbar_profile_name',
459+ title: 'Folder',
460+ children: ['67890'],
461+ });
462+ var parent_id = synchroniser.guid_to_id('12345');
463+ jum.assertEquals(bm.bookmarksService.getFolderIdForItem(parent_id),
464+ bm.bookmarksService.toolbarFolder);
465+ // The child has been reparented.
466+ jum.assertEquals(bm.bookmarksService.getFolderIdForItem(child_id),
467+ parent_id);
468+ // Reordering of folder's children has been scheduled.
469+ jum.assertNotEquals(synchroniser.folders_to_reorder['12345'], null);
470+};
471+
472+var test_reorder_children = function() {
473+ synchroniser.processRecord({
474+ _id: 'parent',
475+ record_type: 'http://www.freedesktop.org/wiki/Specifications/desktopcouch/folder',
476+ parent_guid: 'toolbar_profile_name',
477+ title: 'Folder',
478+ children: ['child1', 'child2', 'child3', 'missing_child'],
479+ });
480+ var parent_id = synchroniser.guid_to_id('parent');
481+ // Add an untracked bookmark to the folder.
482+ var untracked_child = bm.bookmarksService.insertBookmark(
483+ parent_id, bm.createURI(LOCAL_TEST_PAGE),
484+ bm.bookmarksService.DEFAULT_INDEX,
485+ "Untracked bookmark");
486+
487+ // Add expected children.
488+ synchroniser.processRecord({
489+ _id: 'child1',
490+ record_type: 'http://www.freedesktop.org/wiki/Specifications/desktopcouch/bookmark',
491+ parent_guid: 'parent',
492+ title: 'Child 1',
493+ uri: LOCAL_TEST_PAGE + "#child1",
494+ });
495+ synchroniser.processRecord({
496+ _id: 'child3',
497+ record_type: 'http://www.freedesktop.org/wiki/Specifications/desktopcouch/bookmark',
498+ parent_guid: 'parent',
499+ title: 'Child 3',
500+ uri: LOCAL_TEST_PAGE + "#child1",
501+ });
502+ synchroniser.processRecord({
503+ _id: 'child2',
504+ record_type: 'http://www.freedesktop.org/wiki/Specifications/desktopcouch/bookmark',
505+ parent_guid: 'parent',
506+ title: 'Child 2',
507+ uri: LOCAL_TEST_PAGE + "#child1",
508+ });
509+
510+ // The parent has been scheduled for reordering, so trigger
511+ // reordering.
512+ jum.assertNotEquals(synchroniser.folders_to_reorder['parent'], null);
513+ synchroniser.reorder_children();
514+
515+ // Children should now be in the requested order, with the
516+ // untracked child at the end.
517+ jum.assertEquals(bm.bookmarksService.getIdForItemAt(parent_id, 0),
518+ synchroniser.guid_to_id('child1'));
519+ jum.assertEquals(bm.bookmarksService.getIdForItemAt(parent_id, 1),
520+ synchroniser.guid_to_id('child2'));
521+ jum.assertEquals(bm.bookmarksService.getIdForItemAt(parent_id, 2),
522+ synchroniser.guid_to_id('child3'));
523+ jum.assertEquals(bm.bookmarksService.getIdForItemAt(parent_id, 3),
524+ untracked_child);
525+};

Subscribers

People subscribed via source and target branches