in components/places/src/bookmark_sync/engine.rs [2905:3073]
fn test_apply() -> Result<()> {
let api = new_mem_api();
let writer = api.open_connection(ConnectionType::ReadWrite)?;
let db = api.get_sync_connection().unwrap();
let syncer = db.lock();
syncer
.execute("UPDATE moz_bookmarks SET syncChangeCounter = 0", [])
.expect("should work");
insert_local_json_tree(
&writer,
json!({
"guid": &BookmarkRootGuid::Unfiled.as_guid(),
"children": [
{
"guid": "bookmarkAAAA",
"title": "A",
"url": "http://example.com/a",
},
{
"guid": "bookmarkBBBB",
"title": "B",
"url": "http://example.com/b",
},
]
}),
);
tags::tag_url(
&writer,
&Url::parse("http://example.com/a").expect("Should parse URL for A"),
"baz",
)
.expect("Should tag A");
let records = vec![
json!({
"id": "bookmarkCCCC",
"type": "bookmark",
"parentid": "menu",
"parentName": "menu",
"dateAdded": 1_552_183_116_885u64,
"title": "C",
"bmkUri": "http://example.com/c",
"tags": ["foo", "bar"],
}),
json!({
"id": "menu",
"type": "folder",
"parentid": "places",
"parentName": "",
"dateAdded": 0,
"title": "menu",
"children": ["bookmarkCCCC"],
}),
];
// Drop the sync connection to avoid a deadlock when the sync engine locks the mutex
drop(syncer);
let engine = create_sync_engine(&api);
let incoming = records
.into_iter()
.map(IncomingBso::from_test_content)
.collect();
let mut outgoing = engine_apply_incoming(&engine, incoming);
outgoing.sort_by(|a, b| a.envelope.id.cmp(&b.envelope.id));
assert_eq!(
outgoing
.iter()
.map(|p| p.envelope.id.as_str())
.collect::<Vec<_>>(),
vec!["bookmarkAAAA", "bookmarkBBBB", "unfiled",]
);
let record_for_a = outgoing
.iter()
.find(|p| p.envelope.id == "bookmarkAAAA")
.expect("Should upload A");
let content_for_a = record_for_a.to_test_incoming_t::<BookmarkRecord>();
assert_eq!(content_for_a.tags, vec!["baz".to_string()]);
assert_local_json_tree(
&writer,
&BookmarkRootGuid::Root.as_guid(),
json!({
"guid": &BookmarkRootGuid::Root.as_guid(),
"children": [
{
"guid": &BookmarkRootGuid::Menu.as_guid(),
"children": [
{
"guid": "bookmarkCCCC",
"title": "C",
"url": "http://example.com/c",
"date_added": Timestamp(1_552_183_116_885),
},
],
},
{
"guid": &BookmarkRootGuid::Toolbar.as_guid(),
"children": [],
},
{
"guid": &BookmarkRootGuid::Unfiled.as_guid(),
"children": [
{
"guid": "bookmarkAAAA",
"title": "A",
"url": "http://example.com/a",
},
{
"guid": "bookmarkBBBB",
"title": "B",
"url": "http://example.com/b",
},
],
},
{
"guid": &BookmarkRootGuid::Mobile.as_guid(),
"children": [],
},
],
}),
);
// We haven't finished the sync yet, so all local change counts for
// items to upload should still be > 0.
let guid_for_a: SyncGuid = "bookmarkAAAA".into();
let info_for_a = get_raw_bookmark(&writer, &guid_for_a)
.expect("Should fetch info for A")
.unwrap();
assert_eq!(info_for_a._sync_change_counter, 2);
let info_for_unfiled = get_raw_bookmark(&writer, &BookmarkRootGuid::Unfiled.as_guid())
.expect("Should fetch info for unfiled")
.unwrap();
assert_eq!(info_for_unfiled._sync_change_counter, 2);
engine
.set_uploaded(
ServerTimestamp(0),
vec![
"bookmarkAAAA".into(),
"bookmarkBBBB".into(),
"unfiled".into(),
],
)
.expect("Should push synced changes back to the engine");
engine.sync_finished().expect("finish always works");
let info_for_a = get_raw_bookmark(&writer, &guid_for_a)
.expect("Should fetch info for A")
.unwrap();
assert_eq!(info_for_a._sync_change_counter, 0);
let info_for_unfiled = get_raw_bookmark(&writer, &BookmarkRootGuid::Unfiled.as_guid())
.expect("Should fetch info for unfiled")
.unwrap();
assert_eq!(info_for_unfiled._sync_change_counter, 0);
let mut tags_for_c = tags::get_tags_for_url(
&writer,
&Url::parse("http://example.com/c").expect("Should parse URL for C"),
)
.expect("Should return tags for C");
tags_for_c.sort();
assert_eq!(tags_for_c, &["bar", "foo"]);
Ok(())
}