blob: a711f89d63806c6e4ed1f7a59c19cfdc7191e290 [file] [log] [blame]
Mohamed Amir Yosefb0664a82018-05-09 12:19:251// Copyright 2018 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "components/sync_bookmarks/synced_bookmark_tracker.h"
6
Mohamed Amir Yosefc80bdd02018-06-18 12:26:327#include "base/base64.h"
8#include "base/sha1.h"
Mohamed Amir Yosef74ec6ceca2018-07-20 15:21:229#include "base/strings/utf_string_conversions.h"
Mohamed Amir Yosef05fa2162018-11-09 22:42:2010#include "base/test/metrics/histogram_tester.h"
Mohamed Amir Yosef74ec6ceca2018-07-20 15:21:2211#include "components/bookmarks/browser/bookmark_model.h"
Mohamed Amir Yosefb0664a82018-05-09 12:19:2512#include "components/bookmarks/browser/bookmark_node.h"
Mohamed Amir Yosefb6a54aa72018-11-09 13:34:0313#include "components/bookmarks/browser/bookmark_utils.h"
Mohamed Amir Yosef74ec6ceca2018-07-20 15:21:2214#include "components/bookmarks/test/test_bookmark_client.h"
Mohamed Amir Yosefc80bdd02018-06-18 12:26:3215#include "components/sync/base/time.h"
Mohamed Amir Yosefe1f51a22018-06-25 08:59:5716#include "components/sync/base/unique_position.h"
Mohamed Amir Yosefc80bdd02018-06-18 12:26:3217#include "components/sync/model/entity_data.h"
Mohamed Amir Yosefb0664a82018-05-09 12:19:2518#include "testing/gmock/include/gmock/gmock.h"
19#include "testing/gtest/include/gtest/gtest.h"
20
21using testing::Eq;
22using testing::IsNull;
23using testing::NotNull;
24
25namespace sync_bookmarks {
26
27namespace {
28
Mohamed Amir Yosef05fa2162018-11-09 22:42:2029// Redefinition of |enum CorruptionReason| in synced_bookmark_tracker.cc to be
30// used in tests.
31enum class ExpectedCorruptionReason {
32 NO_CORRUPTION = 0,
33 MISSING_SERVER_ID = 1,
34 BOOKMARK_ID_IN_TOMBSTONE = 2,
35 MISSING_BOOKMARK_ID = 3,
36 COUNT_MISMATCH = 4,
37 IDS_MISMATCH = 5,
38 kMaxValue = IDS_MISMATCH
39};
40
Mohamed Amir Yosefc80bdd02018-06-18 12:26:3241sync_pb::EntitySpecifics GenerateSpecifics(const std::string& title,
42 const std::string& url) {
43 sync_pb::EntitySpecifics specifics;
44 specifics.mutable_bookmark()->set_title(title);
45 specifics.mutable_bookmark()->set_url(url);
46 return specifics;
47}
48
Mohamed Amir Yosef74ec6ceca2018-07-20 15:21:2249std::unique_ptr<sync_pb::EntityMetadata> CreateEntityMetadata(
50 const std::string& server_id,
51 bool is_deleted) {
52 auto metadata = std::make_unique<sync_pb::EntityMetadata>();
53 metadata->set_server_id(server_id);
54 metadata->set_is_deleted(is_deleted);
55 return metadata;
56}
57
Mohamed Amir Yosefb0664a82018-05-09 12:19:2558TEST(SyncedBookmarkTrackerTest, ShouldGetAssociatedNodes) {
Mohamed Amir Yosefc80bdd02018-06-18 12:26:3259 SyncedBookmarkTracker tracker(std::vector<NodeMetadataPair>(),
60 std::make_unique<sync_pb::ModelTypeState>());
Mohamed Amir Yosefb0664a82018-05-09 12:19:2561 const std::string kSyncId = "SYNC_ID";
Mohamed Amir Yosefc80bdd02018-06-18 12:26:3262 const std::string kTitle = "Title";
63 const GURL kUrl("http://www.foo.com");
Mohamed Amir Yosefb0664a82018-05-09 12:19:2564 const int64_t kId = 1;
Mohamed Amir Yosefc80bdd02018-06-18 12:26:3265 const int64_t kServerVersion = 1000;
66 const base::Time kCreationTime(base::Time::Now() -
67 base::TimeDelta::FromSeconds(1));
Mohamed Amir Yosefe1f51a22018-06-25 08:59:5768 const syncer::UniquePosition unique_position =
69 syncer::UniquePosition::InitialPosition(
70 syncer::UniquePosition::RandomSuffix());
Mohamed Amir Yosefc80bdd02018-06-18 12:26:3271 const sync_pb::EntitySpecifics specifics =
Mohamed Amir Yosef77ac6fbe2018-06-20 10:48:4672 GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string());
Mohamed Amir Yosefc80bdd02018-06-18 12:26:3273
74 bookmarks::BookmarkNode node(kId, kUrl);
Mohamed Amir Yosefe1f51a22018-06-25 08:59:5775 tracker.Add(kSyncId, &node, kServerVersion, kCreationTime,
76 unique_position.ToProto(), specifics);
Mohamed Amir Yosefb0664a82018-05-09 12:19:2577 const SyncedBookmarkTracker::Entity* entity =
78 tracker.GetEntityForSyncId(kSyncId);
79 ASSERT_THAT(entity, NotNull());
80 EXPECT_THAT(entity->bookmark_node(), Eq(&node));
Mohamed Amir Yosefc80bdd02018-06-18 12:26:3281 EXPECT_THAT(entity->metadata()->server_id(), Eq(kSyncId));
82 EXPECT_THAT(entity->metadata()->server_version(), Eq(kServerVersion));
83 EXPECT_THAT(entity->metadata()->creation_time(),
84 Eq(syncer::TimeToProtoTime(kCreationTime)));
Mohamed Amir Yosefe1f51a22018-06-25 08:59:5785 EXPECT_TRUE(
86 syncer::UniquePosition::FromProto(entity->metadata()->unique_position())
87 .Equals(unique_position));
88
Mohamed Amir Yosefc80bdd02018-06-18 12:26:3289 syncer::EntityData data;
90 *data.specifics.mutable_bookmark() = specifics.bookmark();
Mohamed Amir Yosef812618f2018-07-26 13:25:4991 data.unique_position = unique_position.ToProto();
92 EXPECT_TRUE(entity->MatchesDataIgnoringParent(data));
Mohamed Amir Yosefb0664a82018-05-09 12:19:2593 EXPECT_THAT(tracker.GetEntityForSyncId("unknown id"), IsNull());
94}
95
Mohamed Amir Yosefb2895112018-05-18 15:32:3896TEST(SyncedBookmarkTrackerTest, ShouldReturnNullForDisassociatedNodes) {
Mohamed Amir Yosefc80bdd02018-06-18 12:26:3297 SyncedBookmarkTracker tracker(std::vector<NodeMetadataPair>(),
98 std::make_unique<sync_pb::ModelTypeState>());
Mohamed Amir Yosefb2895112018-05-18 15:32:3899 const std::string kSyncId = "SYNC_ID";
100 const int64_t kId = 1;
Mohamed Amir Yosefc80bdd02018-06-18 12:26:32101 const int64_t kServerVersion = 1000;
102 const base::Time kModificationTime(base::Time::Now() -
103 base::TimeDelta::FromSeconds(1));
Mohamed Amir Yosefe1f51a22018-06-25 08:59:57104 const sync_pb::UniquePosition unique_position;
Mohamed Amir Yosefc80bdd02018-06-18 12:26:32105 const sync_pb::EntitySpecifics specifics =
Mohamed Amir Yosef77ac6fbe2018-06-20 10:48:46106 GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string());
Mohamed Amir Yosefb2895112018-05-18 15:32:38107 bookmarks::BookmarkNode node(kId, GURL());
Mohamed Amir Yosefe1f51a22018-06-25 08:59:57108 tracker.Add(kSyncId, &node, kServerVersion, kModificationTime,
109 unique_position, specifics);
Mohamed Amir Yosefb2895112018-05-18 15:32:38110 ASSERT_THAT(tracker.GetEntityForSyncId(kSyncId), NotNull());
Mohamed Amir Yosef20451342018-06-06 08:44:17111 tracker.Remove(kSyncId);
Mohamed Amir Yosefb2895112018-05-18 15:32:38112 EXPECT_THAT(tracker.GetEntityForSyncId(kSyncId), IsNull());
113}
114
Mohamed Amir Yosefa0aa7ae82018-07-23 20:14:34115TEST(SyncedBookmarkTrackerTest, ShouldBuildBookmarkModelMetadata) {
116 SyncedBookmarkTracker tracker(std::vector<NodeMetadataPair>(),
117 std::make_unique<sync_pb::ModelTypeState>());
118 const std::string kSyncId = "SYNC_ID";
119 const std::string kTitle = "Title";
120 const GURL kUrl("http://www.foo.com");
121 const int64_t kId = 1;
122 const int64_t kServerVersion = 1000;
123 const base::Time kCreationTime(base::Time::Now() -
124 base::TimeDelta::FromSeconds(1));
125 const syncer::UniquePosition unique_position =
126 syncer::UniquePosition::InitialPosition(
127 syncer::UniquePosition::RandomSuffix());
128 const sync_pb::EntitySpecifics specifics =
129 GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string());
130
131 bookmarks::BookmarkNode node(kId, kUrl);
132 tracker.Add(kSyncId, &node, kServerVersion, kCreationTime,
133 unique_position.ToProto(), specifics);
134
135 sync_pb::BookmarkModelMetadata bookmark_model_metadata =
136 tracker.BuildBookmarkModelMetadata();
137
138 ASSERT_THAT(bookmark_model_metadata.bookmarks_metadata().size(), Eq(1));
139 EXPECT_THAT(
140 bookmark_model_metadata.bookmarks_metadata(0).metadata().server_id(),
141 Eq(kSyncId));
142}
143
Mohamed Amir Yosef77ac6fbe2018-06-20 10:48:46144TEST(SyncedBookmarkTrackerTest,
145 ShouldRequireCommitRequestWhenSequenceNumberIsIncremented) {
146 SyncedBookmarkTracker tracker(std::vector<NodeMetadataPair>(),
147 std::make_unique<sync_pb::ModelTypeState>());
148 const std::string kSyncId = "SYNC_ID";
149 const int64_t kId = 1;
150 const int64_t kServerVersion = 1000;
151 const base::Time kModificationTime(base::Time::Now() -
152 base::TimeDelta::FromSeconds(1));
Mohamed Amir Yosefe1f51a22018-06-25 08:59:57153 const sync_pb::UniquePosition unique_position;
Mohamed Amir Yosef77ac6fbe2018-06-20 10:48:46154 const sync_pb::EntitySpecifics specifics =
155 GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string());
156 bookmarks::BookmarkNode node(kId, GURL());
Mohamed Amir Yosefe1f51a22018-06-25 08:59:57157 tracker.Add(kSyncId, &node, kServerVersion, kModificationTime,
158 unique_position, specifics);
Mohamed Amir Yosef77ac6fbe2018-06-20 10:48:46159
160 EXPECT_THAT(tracker.HasLocalChanges(), Eq(false));
161 tracker.IncrementSequenceNumber(kSyncId);
162 EXPECT_THAT(tracker.HasLocalChanges(), Eq(true));
163 // TODO(crbug.com/516866): Test HasLocalChanges after submitting commit
164 // request in a separate test probably.
165}
166
Mohamed Amir Yosef88d36bf2018-08-06 18:03:48167TEST(SyncedBookmarkTrackerTest, ShouldAckSequenceNumber) {
168 SyncedBookmarkTracker tracker(std::vector<NodeMetadataPair>(),
169 std::make_unique<sync_pb::ModelTypeState>());
170 const std::string kSyncId = "SYNC_ID";
171 const int64_t kId = 1;
172 const int64_t kServerVersion = 1000;
173 const base::Time kModificationTime(base::Time::Now() -
174 base::TimeDelta::FromSeconds(1));
175 const sync_pb::UniquePosition unique_position;
176 const sync_pb::EntitySpecifics specifics =
177 GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string());
178 bookmarks::BookmarkNode node(kId, GURL());
179 tracker.Add(kSyncId, &node, kServerVersion, kModificationTime,
180 unique_position, specifics);
181
182 // Test simple scenario of ack'ing an incrememented sequence number.
183 EXPECT_THAT(tracker.HasLocalChanges(), Eq(false));
184 tracker.IncrementSequenceNumber(kSyncId);
185 EXPECT_THAT(tracker.HasLocalChanges(), Eq(true));
186 tracker.AckSequenceNumber(kSyncId);
187 EXPECT_THAT(tracker.HasLocalChanges(), Eq(false));
188
189 // Test ack'ing of a mutliple times incremented sequence number.
190 tracker.IncrementSequenceNumber(kSyncId);
191 EXPECT_THAT(tracker.HasLocalChanges(), Eq(true));
192 tracker.IncrementSequenceNumber(kSyncId);
193 tracker.IncrementSequenceNumber(kSyncId);
194 EXPECT_THAT(tracker.HasLocalChanges(), Eq(true));
195 tracker.AckSequenceNumber(kSyncId);
196 EXPECT_THAT(tracker.HasLocalChanges(), Eq(false));
197}
198
Mohamed Amir Yosefc7097a12018-07-02 18:24:16199TEST(SyncedBookmarkTrackerTest, ShouldUpdateUponCommitResponseWithNewId) {
200 SyncedBookmarkTracker tracker(std::vector<NodeMetadataPair>(),
201 std::make_unique<sync_pb::ModelTypeState>());
202 const std::string kSyncId = "SYNC_ID";
203 const std::string kNewSyncId = "NEW_SYNC_ID";
204 const int64_t kId = 1;
205 const int64_t kServerVersion = 1000;
206 const int64_t kNewServerVersion = 1001;
207 const base::Time kModificationTime(base::Time::Now() -
208 base::TimeDelta::FromSeconds(1));
209 const sync_pb::UniquePosition unique_position;
210 const sync_pb::EntitySpecifics specifics =
211 GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string());
212 bookmarks::BookmarkNode node(kId, GURL());
213 tracker.Add(kSyncId, &node, kServerVersion, kModificationTime,
214 unique_position, specifics);
215 ASSERT_THAT(tracker.GetEntityForSyncId(kSyncId), NotNull());
216 // Receive a commit response with a changed id.
217 tracker.UpdateUponCommitResponse(
218 kSyncId, kNewSyncId, /*acked_sequence_number=*/1, kNewServerVersion);
219 // Old id shouldn't be there.
220 EXPECT_THAT(tracker.GetEntityForSyncId(kSyncId), IsNull());
221
222 const SyncedBookmarkTracker::Entity* entity =
223 tracker.GetEntityForSyncId(kNewSyncId);
224 ASSERT_THAT(entity, NotNull());
225 EXPECT_THAT(entity->metadata()->server_id(), Eq(kNewSyncId));
226 EXPECT_THAT(entity->bookmark_node(), Eq(&node));
227 EXPECT_THAT(entity->metadata()->server_version(), Eq(kNewServerVersion));
228}
229
Mohamed Amir Yosefbc7cbfb2018-10-16 10:39:45230TEST(SyncedBookmarkTrackerTest, ShouldUpdateId) {
231 SyncedBookmarkTracker tracker(std::vector<NodeMetadataPair>(),
232 std::make_unique<sync_pb::ModelTypeState>());
233 const std::string kSyncId = "SYNC_ID";
234 const std::string kNewSyncId = "NEW_SYNC_ID";
235 const int64_t kServerVersion = 1000;
236 const base::Time kModificationTime(base::Time::Now() -
237 base::TimeDelta::FromSeconds(1));
238 const sync_pb::UniquePosition unique_position;
239 const sync_pb::EntitySpecifics specifics =
240 GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string());
241 bookmarks::BookmarkNode node(/*id=*/1, GURL());
242 // Track a sync entity.
243 tracker.Add(kSyncId, &node, kServerVersion, kModificationTime,
244 unique_position, specifics);
245
246 ASSERT_THAT(tracker.GetEntityForSyncId(kSyncId), NotNull());
247 // Update the sync id.
248 tracker.UpdateSyncForLocalCreationIfNeeded(kSyncId, kNewSyncId);
249 // Old id shouldn't be there.
250 EXPECT_THAT(tracker.GetEntityForSyncId(kSyncId), IsNull());
251
252 const SyncedBookmarkTracker::Entity* entity =
253 tracker.GetEntityForSyncId(kNewSyncId);
254 ASSERT_THAT(entity, NotNull());
255 EXPECT_THAT(entity->metadata()->server_id(), Eq(kNewSyncId));
256 EXPECT_THAT(entity->bookmark_node(), Eq(&node));
257 EXPECT_THAT(entity->metadata()->server_version(), Eq(kServerVersion));
258}
259
Mohamed Amir Yosef3fd347d2018-07-18 13:37:51260TEST(SyncedBookmarkTrackerTest,
261 ShouldMaintainTombstoneOrderBetweenCtorAndBuildBookmarkModelMetadata) {
262 // Feed a metadata batch of 5 entries to the constructor of the tracker.
263 // First 2 are for node, and the last 4 are for tombstones.
264
265 // Server ids.
266 const std::string kId0 = "id0";
267 const std::string kId1 = "id1";
268 const std::string kId2 = "id2";
269 const std::string kId3 = "id3";
270 const std::string kId4 = "id4";
271
272 const GURL kUrl("http://www.foo.com");
273 bookmarks::BookmarkNode node0(/*id=*/0, kUrl);
274 bookmarks::BookmarkNode node1(/*id=*/1, kUrl);
275
Mohamed Amir Yosef3fd347d2018-07-18 13:37:51276 std::vector<NodeMetadataPair> node_metadata_pairs;
Mohamed Amir Yosef74ec6ceca2018-07-20 15:21:22277 node_metadata_pairs.emplace_back(
278 &node0, CreateEntityMetadata(/*server_id=*/kId0, /*is_deleted=*/false));
279 node_metadata_pairs.emplace_back(
280 &node1, CreateEntityMetadata(/*server_id=*/kId1, /*is_deleted=*/false));
281 node_metadata_pairs.emplace_back(
282 nullptr, CreateEntityMetadata(/*server_id=*/kId2, /*is_deleted=*/true));
283 node_metadata_pairs.emplace_back(
284 nullptr, CreateEntityMetadata(/*server_id=*/kId3, /*is_deleted=*/true));
285 node_metadata_pairs.emplace_back(
286 nullptr, CreateEntityMetadata(/*server_id=*/kId4, /*is_deleted=*/true));
Mohamed Amir Yosef3fd347d2018-07-18 13:37:51287
288 SyncedBookmarkTracker tracker(std::move(node_metadata_pairs),
289 std::make_unique<sync_pb::ModelTypeState>());
290
291 sync_pb::BookmarkModelMetadata bookmark_model_metadata =
292 tracker.BuildBookmarkModelMetadata();
293
294 // Tombstones should be the last 3 entries in the metadata and in the same
295 // order as given to the constructor.
296 ASSERT_THAT(bookmark_model_metadata.bookmarks_metadata().size(), Eq(5));
297 EXPECT_THAT(
298 bookmark_model_metadata.bookmarks_metadata(2).metadata().server_id(),
299 Eq(kId2));
300 EXPECT_THAT(
301 bookmark_model_metadata.bookmarks_metadata(3).metadata().server_id(),
302 Eq(kId3));
303 EXPECT_THAT(
304 bookmark_model_metadata.bookmarks_metadata(4).metadata().server_id(),
305 Eq(kId4));
306}
307
308TEST(SyncedBookmarkTrackerTest,
309 ShouldMaintainOrderOfMarkDeletedCallsWhenBuildBookmarkModelMetadata) {
310 // Server ids.
311 const std::string kId0 = "id0";
312 const std::string kId1 = "id1";
313 const std::string kId2 = "id2";
314 const std::string kId3 = "id3";
315 const std::string kId4 = "id4";
316
317 const GURL kUrl("http://www.foo.com");
318 bookmarks::BookmarkNode node0(/*id=*/0, kUrl);
319 bookmarks::BookmarkNode node1(/*id=*/1, kUrl);
320 bookmarks::BookmarkNode node2(/*id=*/2, kUrl);
321 bookmarks::BookmarkNode node3(/*id=*/3, kUrl);
322 bookmarks::BookmarkNode node4(/*id=*/4, kUrl);
323
Mohamed Amir Yosef3fd347d2018-07-18 13:37:51324 std::vector<NodeMetadataPair> node_metadata_pairs;
Mohamed Amir Yosef74ec6ceca2018-07-20 15:21:22325 node_metadata_pairs.emplace_back(
326 &node0, CreateEntityMetadata(/*server_id=*/kId0, /*is_deleted=*/false));
327 node_metadata_pairs.emplace_back(
328 &node1, CreateEntityMetadata(/*server_id=*/kId1, /*is_deleted=*/false));
329 node_metadata_pairs.emplace_back(
330 &node2, CreateEntityMetadata(/*server_id=*/kId2, /*is_deleted=*/false));
331 node_metadata_pairs.emplace_back(
332 &node3, CreateEntityMetadata(/*server_id=*/kId3, /*is_deleted=*/false));
333 node_metadata_pairs.emplace_back(
334 &node4, CreateEntityMetadata(/*server_id=*/kId4, /*is_deleted=*/false));
Mohamed Amir Yosef3fd347d2018-07-18 13:37:51335
336 SyncedBookmarkTracker tracker(std::move(node_metadata_pairs),
337 std::make_unique<sync_pb::ModelTypeState>());
338
339 // Mark entities deleted in that order kId2, kId4, kId1
340 tracker.MarkDeleted(kId2);
341 tracker.MarkDeleted(kId4);
342 tracker.MarkDeleted(kId1);
343
344 sync_pb::BookmarkModelMetadata bookmark_model_metadata =
345 tracker.BuildBookmarkModelMetadata();
346
347 // Tombstones should be the last 3 entries in the metadata and in the same as
348 // calling MarkDeleted().
349 ASSERT_THAT(bookmark_model_metadata.bookmarks_metadata().size(), Eq(5));
350 EXPECT_THAT(
351 bookmark_model_metadata.bookmarks_metadata(2).metadata().server_id(),
352 Eq(kId2));
353 EXPECT_THAT(
354 bookmark_model_metadata.bookmarks_metadata(3).metadata().server_id(),
355 Eq(kId4));
356 EXPECT_THAT(
357 bookmark_model_metadata.bookmarks_metadata(4).metadata().server_id(),
358 Eq(kId1));
359}
360
Mohamed Amir Yosef74ec6ceca2018-07-20 15:21:22361TEST(SyncedBookmarkTrackerTest,
362 ShouldOrderParentUpdatesBeforeChildUpdatesAndDeletionsComeLast) {
363 const size_t kMaxEntries = 1000;
364
365 // Construct this structure:
366 // bookmark_bar
367 // |- node0
368 // |- node1
369 // |- node2
370
371 std::unique_ptr<bookmarks::BookmarkModel> bookmark_model =
372 bookmarks::TestBookmarkClient::CreateModel();
373
374 const bookmarks::BookmarkNode* bookmark_bar_node =
375 bookmark_model->bookmark_bar_node();
376 const bookmarks::BookmarkNode* node0 = bookmark_model->AddFolder(
377 /*parent=*/bookmark_bar_node, /*index=*/0, base::UTF8ToUTF16("node0"));
378 const bookmarks::BookmarkNode* node1 = bookmark_model->AddFolder(
379 /*parent=*/node0, /*index=*/0, base::UTF8ToUTF16("node1"));
380 const bookmarks::BookmarkNode* node2 = bookmark_model->AddFolder(
381 /*parent=*/node1, /*index=*/0, base::UTF8ToUTF16("node2"));
382
383 // Server ids.
384 const std::string kId0 = "id0";
385 const std::string kId1 = "id1";
386 const std::string kId2 = "id2";
387 const std::string kId3 = "id3";
388
389 // Prepare the metadata with shuffled order.
390 std::vector<NodeMetadataPair> node_metadata_pairs;
391 node_metadata_pairs.emplace_back(
392 node1, CreateEntityMetadata(/*server_id=*/kId1, /*is_deleted=*/false));
393 node_metadata_pairs.emplace_back(
394 nullptr, CreateEntityMetadata(/*server_id=*/kId3, /*is_deleted=*/true));
395 node_metadata_pairs.emplace_back(
396 node2, CreateEntityMetadata(/*server_id=*/kId2, /*is_deleted=*/false));
397 node_metadata_pairs.emplace_back(
398 node0, CreateEntityMetadata(/*server_id=*/kId0, /*is_deleted=*/false));
399
400 SyncedBookmarkTracker tracker(std::move(node_metadata_pairs),
401 std::make_unique<sync_pb::ModelTypeState>());
402
403 // Mark the entities that they have local changes. (in shuffled order just to
404 // verify the tracker doesn't simply maintain the order of updates similar to
405 // with deletions).
406 tracker.IncrementSequenceNumber(kId3);
407 tracker.IncrementSequenceNumber(kId1);
408 tracker.IncrementSequenceNumber(kId2);
409 tracker.IncrementSequenceNumber(kId0);
410
411 std::vector<const SyncedBookmarkTracker::Entity*> entities_with_local_change =
412 tracker.GetEntitiesWithLocalChanges(kMaxEntries);
413
414 ASSERT_THAT(entities_with_local_change.size(), Eq(4U));
415 // Verify updates are in parent before child order node0 --> node1 --> node2.
416 EXPECT_THAT(entities_with_local_change[0]->metadata()->server_id(), Eq(kId0));
417 EXPECT_THAT(entities_with_local_change[1]->metadata()->server_id(), Eq(kId1));
418 EXPECT_THAT(entities_with_local_change[2]->metadata()->server_id(), Eq(kId2));
419 // Verify that deletion is the last entry.
420 EXPECT_THAT(entities_with_local_change[3]->metadata()->server_id(), Eq(kId3));
421}
422
Mohamed Amir Yoseffb7986d882018-10-12 05:42:17423TEST(SyncedBookmarkTrackerTest, ShouldMatchModelAndMetadata) {
424 std::unique_ptr<bookmarks::BookmarkModel> model =
425 bookmarks::TestBookmarkClient::CreateModel();
426
427 const bookmarks::BookmarkNode* bookmark_bar_node = model->bookmark_bar_node();
428 const bookmarks::BookmarkNode* node = model->AddFolder(
429 /*parent=*/bookmark_bar_node, /*index=*/0, base::UTF8ToUTF16("node0"));
430
431 sync_pb::BookmarkModelMetadata model_metadata;
432 model_metadata.mutable_model_type_state()->set_initial_sync_done(true);
433 // Add entries for all the permanent nodes. TestBookmarkClient creates all the
434 // 3 permanent nodes.
435 sync_pb::BookmarkMetadata* bookmark_metadata =
436 model_metadata.add_bookmarks_metadata();
437 bookmark_metadata->set_id(model->bookmark_bar_node()->id());
438 bookmark_metadata->mutable_metadata()->set_server_id("BookmarkBarId");
439
440 bookmark_metadata = model_metadata.add_bookmarks_metadata();
441 bookmark_metadata->set_id(model->other_node()->id());
442 bookmark_metadata->mutable_metadata()->set_server_id("OtherBookmarksId");
443
444 bookmark_metadata = model_metadata.add_bookmarks_metadata();
445 bookmark_metadata->set_id(model->mobile_node()->id());
446 bookmark_metadata->mutable_metadata()->set_server_id("MobileBookmarksId");
447
448 // Add entry for the extra node.
449 bookmark_metadata = model_metadata.add_bookmarks_metadata();
450 bookmark_metadata->set_id(node->id());
451 bookmark_metadata->mutable_metadata()->set_server_id("NodeId");
452
453 // Add a tombstone entry.
454 sync_pb::BookmarkMetadata* tombstone =
455 model_metadata.add_bookmarks_metadata();
456 tombstone->mutable_metadata()->set_server_id("tombstoneId");
457 tombstone->mutable_metadata()->set_is_deleted(true);
458
Mohamed Amir Yosef05fa2162018-11-09 22:42:20459 base::HistogramTester histogram_tester;
Mohamed Amir Yoseffb7986d882018-10-12 05:42:17460 EXPECT_TRUE(SyncedBookmarkTracker::BookmarkModelMatchesMetadata(
461 model.get(), model_metadata));
Mohamed Amir Yosef05fa2162018-11-09 22:42:20462 histogram_tester.ExpectUniqueSample(
463 "Sync.BookmarksModelMetadataCorruptionReason",
464 /*sample=*/ExpectedCorruptionReason::NO_CORRUPTION, /*count=*/1);
Mohamed Amir Yoseffb7986d882018-10-12 05:42:17465}
466
Mohamed Amir Yosefb1117f742018-11-12 13:29:01467TEST(SyncedBookmarkTrackerTest,
Mikel Astiz113dc1e2018-12-18 16:58:47468 ShouldNotMatchModelAndMetadataIfMissingMobileFolder) {
Mohamed Amir Yosefb1117f742018-11-12 13:29:01469 std::unique_ptr<bookmarks::BookmarkModel> model =
470 bookmarks::TestBookmarkClient::CreateModel();
471
472 sync_pb::BookmarkModelMetadata model_metadata;
473 model_metadata.mutable_model_type_state()->set_initial_sync_done(true);
474 // Add entries for all the permanent nodes except for the Mobile bookmarks
Mikel Astiz113dc1e2018-12-18 16:58:47475 // folder.
Mohamed Amir Yosefb1117f742018-11-12 13:29:01476 sync_pb::BookmarkMetadata* bookmark_metadata =
477 model_metadata.add_bookmarks_metadata();
478 bookmark_metadata->set_id(model->bookmark_bar_node()->id());
479 bookmark_metadata->mutable_metadata()->set_server_id("BookmarkBarId");
480
481 bookmark_metadata = model_metadata.add_bookmarks_metadata();
482 bookmark_metadata->set_id(model->other_node()->id());
483 bookmark_metadata->mutable_metadata()->set_server_id("OtherBookmarksId");
484
485 base::HistogramTester histogram_tester;
Mikel Astiz113dc1e2018-12-18 16:58:47486 EXPECT_FALSE(SyncedBookmarkTracker::BookmarkModelMatchesMetadata(
Mohamed Amir Yosefb1117f742018-11-12 13:29:01487 model.get(), model_metadata));
488 histogram_tester.ExpectUniqueSample(
489 "Sync.BookmarksModelMetadataCorruptionReason",
Mikel Astiz113dc1e2018-12-18 16:58:47490 /*sample=*/ExpectedCorruptionReason::COUNT_MISMATCH, /*count=*/1);
Mohamed Amir Yosefb1117f742018-11-12 13:29:01491}
492
Mohamed Amir Yoseffb7986d882018-10-12 05:42:17493TEST(SyncedBookmarkTrackerTest, ShouldNotMatchModelAndCorruptedMetadata) {
494 std::unique_ptr<bookmarks::BookmarkModel> model =
495 bookmarks::TestBookmarkClient::CreateModel();
496
497 sync_pb::BookmarkModelMetadata model_metadata;
498 model_metadata.mutable_model_type_state()->set_initial_sync_done(true);
Mikel Astiz113dc1e2018-12-18 16:58:47499 // Add entries for 3 permanent nodes only. TestBookmarkClient creates all the
500 // 4 permanent nodes.
Mohamed Amir Yoseffb7986d882018-10-12 05:42:17501 sync_pb::BookmarkMetadata* bookmark_metadata =
502 model_metadata.add_bookmarks_metadata();
503 bookmark_metadata->set_id(model->bookmark_bar_node()->id());
504 bookmark_metadata->mutable_metadata()->set_server_id("BookmarkBarId");
505
Mikel Astiz113dc1e2018-12-18 16:58:47506 bookmark_metadata = model_metadata.add_bookmarks_metadata();
507 bookmark_metadata->set_id(model->mobile_node()->id());
508 bookmark_metadata->mutable_metadata()->set_server_id("MobileBookmarksId");
509
Mohamed Amir Yosef05fa2162018-11-09 22:42:20510 base::HistogramTester histogram_tester;
Mohamed Amir Yosefb1117f742018-11-12 13:29:01511 // The entry for the Other bookmarks is missing.
Mohamed Amir Yoseffb7986d882018-10-12 05:42:17512 EXPECT_FALSE(SyncedBookmarkTracker::BookmarkModelMatchesMetadata(
513 model.get(), model_metadata));
Mohamed Amir Yosef05fa2162018-11-09 22:42:20514 histogram_tester.ExpectBucketCount(
515 "Sync.BookmarksModelMetadataCorruptionReason",
516 /*sample=*/ExpectedCorruptionReason::COUNT_MISMATCH, /*count=*/1);
Mohamed Amir Yoseffb7986d882018-10-12 05:42:17517
Mohamed Amir Yosefb1117f742018-11-12 13:29:01518 // The entry for the Other bookmarks is missing a server id.
Mohamed Amir Yoseffb7986d882018-10-12 05:42:17519 bookmark_metadata = model_metadata.add_bookmarks_metadata();
Mohamed Amir Yosefb1117f742018-11-12 13:29:01520 bookmark_metadata->set_id(model->other_node()->id());
Mohamed Amir Yoseffb7986d882018-10-12 05:42:17521 EXPECT_FALSE(SyncedBookmarkTracker::BookmarkModelMatchesMetadata(
522 model.get(), model_metadata));
523
Mohamed Amir Yosef05fa2162018-11-09 22:42:20524 histogram_tester.ExpectBucketCount(
525 "Sync.BookmarksModelMetadataCorruptionReason",
526 /*sample=*/ExpectedCorruptionReason::MISSING_SERVER_ID, /*count=*/1);
527
Mohamed Amir Yosefb1117f742018-11-12 13:29:01528 // The entry for the Other bookmarks is missing a node id.
Mohamed Amir Yoseffb7986d882018-10-12 05:42:17529 bookmark_metadata->clear_id();
530 bookmark_metadata->mutable_metadata()->set_server_id("OtherBookmarksId");
531 EXPECT_FALSE(SyncedBookmarkTracker::BookmarkModelMatchesMetadata(
532 model.get(), model_metadata));
Mohamed Amir Yosef05fa2162018-11-09 22:42:20533 histogram_tester.ExpectBucketCount(
534 "Sync.BookmarksModelMetadataCorruptionReason",
535 /*sample=*/ExpectedCorruptionReason::MISSING_BOOKMARK_ID, /*count=*/1);
Mohamed Amir Yoseffb7986d882018-10-12 05:42:17536
Mohamed Amir Yosefb1117f742018-11-12 13:29:01537 // The entry for the Other bookmarks is having a wrong node id.
538 bookmark_metadata->set_id(model->other_node()->id() + 1000);
Mohamed Amir Yoseffb7986d882018-10-12 05:42:17539 EXPECT_FALSE(SyncedBookmarkTracker::BookmarkModelMatchesMetadata(
540 model.get(), model_metadata));
Mohamed Amir Yosef05fa2162018-11-09 22:42:20541 histogram_tester.ExpectBucketCount(
542 "Sync.BookmarksModelMetadataCorruptionReason",
543 /*sample=*/ExpectedCorruptionReason::IDS_MISMATCH, /*count=*/1);
Mohamed Amir Yoseffb7986d882018-10-12 05:42:17544
545 // A tombstone shouldn't have a node id.
546 sync_pb::BookmarkMetadata* tombstone =
547 model_metadata.add_bookmarks_metadata();
548 tombstone->mutable_metadata()->set_server_id("tombstoneId");
549 tombstone->mutable_metadata()->set_is_deleted(true);
550 tombstone->set_id(10);
551 EXPECT_FALSE(SyncedBookmarkTracker::BookmarkModelMatchesMetadata(
552 model.get(), model_metadata));
Mohamed Amir Yosef05fa2162018-11-09 22:42:20553 histogram_tester.ExpectBucketCount(
554 "Sync.BookmarksModelMetadataCorruptionReason",
555 /*sample=*/ExpectedCorruptionReason::BOOKMARK_ID_IN_TOMBSTONE,
556 /*count=*/1);
Mohamed Amir Yoseffb7986d882018-10-12 05:42:17557}
558
Mohamed Amir Yosefb6a54aa72018-11-09 13:34:03559TEST(SyncedBookmarkTrackerTest,
560 ShouldMatchModelWithUnsyncableNodesAndMetadata) {
561 // Add a managed node with an arbitrary id 100.
562 const int64_t kManagedNodeId = 100;
563 bookmarks::BookmarkPermanentNodeList extra_nodes;
564 extra_nodes.push_back(
565 std::make_unique<bookmarks::BookmarkPermanentNode>(kManagedNodeId));
566 bookmarks::BookmarkPermanentNode* extra_node = extra_nodes.back().get();
567 auto client = std::make_unique<bookmarks::TestBookmarkClient>();
568 client->SetExtraNodesToLoad(std::move(extra_nodes));
569
570 std::unique_ptr<bookmarks::BookmarkModel> model =
571 bookmarks::TestBookmarkClient::CreateModelWithClient(std::move(client));
572
573 // The model should contain the managed node now.
574 ASSERT_THAT(GetBookmarkNodeByID(model.get(), kManagedNodeId), Eq(extra_node));
575
576 sync_pb::BookmarkModelMetadata model_metadata;
577 model_metadata.mutable_model_type_state()->set_initial_sync_done(true);
578 // Add entries for all the permanent nodes. TestBookmarkClient creates all the
579 // 3 permanent nodes.
580 sync_pb::BookmarkMetadata* bookmark_metadata =
581 model_metadata.add_bookmarks_metadata();
582 bookmark_metadata->set_id(model->bookmark_bar_node()->id());
583 bookmark_metadata->mutable_metadata()->set_server_id("BookmarkBarId");
584
585 bookmark_metadata = model_metadata.add_bookmarks_metadata();
586 bookmark_metadata->set_id(model->other_node()->id());
587 bookmark_metadata->mutable_metadata()->set_server_id("OtherBookmarksId");
588
589 bookmark_metadata = model_metadata.add_bookmarks_metadata();
590 bookmark_metadata->set_id(model->mobile_node()->id());
591 bookmark_metadata->mutable_metadata()->set_server_id("MobileBookmarksId");
592
Mohamed Amir Yosef05fa2162018-11-09 22:42:20593 base::HistogramTester histogram_tester;
Mohamed Amir Yosefb6a54aa72018-11-09 13:34:03594 EXPECT_TRUE(SyncedBookmarkTracker::BookmarkModelMatchesMetadata(
595 model.get(), model_metadata));
Mohamed Amir Yosef05fa2162018-11-09 22:42:20596 histogram_tester.ExpectUniqueSample(
597 "Sync.BookmarksModelMetadataCorruptionReason",
598 /*sample=*/ExpectedCorruptionReason::NO_CORRUPTION, /*count=*/1);
Mohamed Amir Yosefb6a54aa72018-11-09 13:34:03599}
600
Mohamed Amir Yosefb0664a82018-05-09 12:19:25601} // namespace
602
603} // namespace sync_bookmarks