blob: ea44438a5780a72c432151d8721a04e15292b923 [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"
Mohamed Amir Yosef74ec6ceca2018-07-20 15:21:228#include "base/strings/utf_string_conversions.h"
Mohamed Amir Yosef05fa2162018-11-09 22:42:209#include "base/test/metrics/histogram_tester.h"
Mohamed Amir Yosef74ec6ceca2018-07-20 15:21:2210#include "components/bookmarks/browser/bookmark_model.h"
Mohamed Amir Yosefb0664a82018-05-09 12:19:2511#include "components/bookmarks/browser/bookmark_node.h"
Mohamed Amir Yosefb6a54aa72018-11-09 13:34:0312#include "components/bookmarks/browser/bookmark_utils.h"
Mohamed Amir Yosef74ec6ceca2018-07-20 15:21:2213#include "components/bookmarks/test/test_bookmark_client.h"
Mohamed Amir Yosefc80bdd02018-06-18 12:26:3214#include "components/sync/base/time.h"
Mohamed Amir Yosefe1f51a22018-06-25 08:59:5715#include "components/sync/base/unique_position.h"
Mohamed Amir Yosefc80bdd02018-06-18 12:26:3216#include "components/sync/model/entity_data.h"
Mohamed Amir Yosefb0664a82018-05-09 12:19:2517#include "testing/gmock/include/gmock/gmock.h"
18#include "testing/gtest/include/gtest/gtest.h"
19
20using testing::Eq;
21using testing::IsNull;
22using testing::NotNull;
23
24namespace sync_bookmarks {
25
26namespace {
27
Mohamed Amir Yosef05fa2162018-11-09 22:42:2028// Redefinition of |enum CorruptionReason| in synced_bookmark_tracker.cc to be
29// used in tests.
30enum class ExpectedCorruptionReason {
31 NO_CORRUPTION = 0,
32 MISSING_SERVER_ID = 1,
33 BOOKMARK_ID_IN_TOMBSTONE = 2,
34 MISSING_BOOKMARK_ID = 3,
35 COUNT_MISMATCH = 4,
36 IDS_MISMATCH = 5,
37 kMaxValue = IDS_MISMATCH
38};
39
Mohamed Amir Yosefc80bdd02018-06-18 12:26:3240sync_pb::EntitySpecifics GenerateSpecifics(const std::string& title,
41 const std::string& url) {
42 sync_pb::EntitySpecifics specifics;
43 specifics.mutable_bookmark()->set_title(title);
44 specifics.mutable_bookmark()->set_url(url);
45 return specifics;
46}
47
Mohamed Amir Yosef74ec6ceca2018-07-20 15:21:2248std::unique_ptr<sync_pb::EntityMetadata> CreateEntityMetadata(
49 const std::string& server_id,
50 bool is_deleted) {
51 auto metadata = std::make_unique<sync_pb::EntityMetadata>();
52 metadata->set_server_id(server_id);
53 metadata->set_is_deleted(is_deleted);
54 return metadata;
55}
56
Mohamed Amir Yosefb0664a82018-05-09 12:19:2557TEST(SyncedBookmarkTrackerTest, ShouldGetAssociatedNodes) {
Mohamed Amir Yosefc80bdd02018-06-18 12:26:3258 SyncedBookmarkTracker tracker(std::vector<NodeMetadataPair>(),
59 std::make_unique<sync_pb::ModelTypeState>());
Mohamed Amir Yosefb0664a82018-05-09 12:19:2560 const std::string kSyncId = "SYNC_ID";
Mohamed Amir Yosefc80bdd02018-06-18 12:26:3261 const std::string kTitle = "Title";
62 const GURL kUrl("http://www.foo.com");
Mohamed Amir Yosefb0664a82018-05-09 12:19:2563 const int64_t kId = 1;
Mohamed Amir Yosefc80bdd02018-06-18 12:26:3264 const int64_t kServerVersion = 1000;
65 const base::Time kCreationTime(base::Time::Now() -
66 base::TimeDelta::FromSeconds(1));
Mohamed Amir Yosefe1f51a22018-06-25 08:59:5767 const syncer::UniquePosition unique_position =
68 syncer::UniquePosition::InitialPosition(
69 syncer::UniquePosition::RandomSuffix());
Mohamed Amir Yosefc80bdd02018-06-18 12:26:3270 const sync_pb::EntitySpecifics specifics =
Mohamed Amir Yosef77ac6fbe2018-06-20 10:48:4671 GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string());
Mohamed Amir Yosefc80bdd02018-06-18 12:26:3272
73 bookmarks::BookmarkNode node(kId, kUrl);
Mohamed Amir Yosefe1f51a22018-06-25 08:59:5774 tracker.Add(kSyncId, &node, kServerVersion, kCreationTime,
75 unique_position.ToProto(), specifics);
Mohamed Amir Yosefb0664a82018-05-09 12:19:2576 const SyncedBookmarkTracker::Entity* entity =
77 tracker.GetEntityForSyncId(kSyncId);
78 ASSERT_THAT(entity, NotNull());
79 EXPECT_THAT(entity->bookmark_node(), Eq(&node));
Mohamed Amir Yosefc80bdd02018-06-18 12:26:3280 EXPECT_THAT(entity->metadata()->server_id(), Eq(kSyncId));
81 EXPECT_THAT(entity->metadata()->server_version(), Eq(kServerVersion));
82 EXPECT_THAT(entity->metadata()->creation_time(),
83 Eq(syncer::TimeToProtoTime(kCreationTime)));
Mohamed Amir Yosefe1f51a22018-06-25 08:59:5784 EXPECT_TRUE(
85 syncer::UniquePosition::FromProto(entity->metadata()->unique_position())
86 .Equals(unique_position));
87
Mohamed Amir Yosefc80bdd02018-06-18 12:26:3288 syncer::EntityData data;
89 *data.specifics.mutable_bookmark() = specifics.bookmark();
Mohamed Amir Yosef812618f2018-07-26 13:25:4990 data.unique_position = unique_position.ToProto();
91 EXPECT_TRUE(entity->MatchesDataIgnoringParent(data));
Mohamed Amir Yosefb0664a82018-05-09 12:19:2592 EXPECT_THAT(tracker.GetEntityForSyncId("unknown id"), IsNull());
93}
94
Mohamed Amir Yosefb2895112018-05-18 15:32:3895TEST(SyncedBookmarkTrackerTest, ShouldReturnNullForDisassociatedNodes) {
Mohamed Amir Yosefc80bdd02018-06-18 12:26:3296 SyncedBookmarkTracker tracker(std::vector<NodeMetadataPair>(),
97 std::make_unique<sync_pb::ModelTypeState>());
Mohamed Amir Yosefb2895112018-05-18 15:32:3898 const std::string kSyncId = "SYNC_ID";
99 const int64_t kId = 1;
Mohamed Amir Yosefc80bdd02018-06-18 12:26:32100 const int64_t kServerVersion = 1000;
101 const base::Time kModificationTime(base::Time::Now() -
102 base::TimeDelta::FromSeconds(1));
Mohamed Amir Yosefe1f51a22018-06-25 08:59:57103 const sync_pb::UniquePosition unique_position;
Mohamed Amir Yosefc80bdd02018-06-18 12:26:32104 const sync_pb::EntitySpecifics specifics =
Mohamed Amir Yosef77ac6fbe2018-06-20 10:48:46105 GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string());
Mohamed Amir Yosefb2895112018-05-18 15:32:38106 bookmarks::BookmarkNode node(kId, GURL());
Mohamed Amir Yosefe1f51a22018-06-25 08:59:57107 tracker.Add(kSyncId, &node, kServerVersion, kModificationTime,
108 unique_position, specifics);
Mohamed Amir Yosefb2895112018-05-18 15:32:38109 ASSERT_THAT(tracker.GetEntityForSyncId(kSyncId), NotNull());
Mohamed Amir Yosef20451342018-06-06 08:44:17110 tracker.Remove(kSyncId);
Mohamed Amir Yosefb2895112018-05-18 15:32:38111 EXPECT_THAT(tracker.GetEntityForSyncId(kSyncId), IsNull());
112}
113
Mohamed Amir Yosefa0aa7ae82018-07-23 20:14:34114TEST(SyncedBookmarkTrackerTest, ShouldBuildBookmarkModelMetadata) {
115 SyncedBookmarkTracker tracker(std::vector<NodeMetadataPair>(),
116 std::make_unique<sync_pb::ModelTypeState>());
117 const std::string kSyncId = "SYNC_ID";
118 const std::string kTitle = "Title";
119 const GURL kUrl("http://www.foo.com");
120 const int64_t kId = 1;
121 const int64_t kServerVersion = 1000;
122 const base::Time kCreationTime(base::Time::Now() -
123 base::TimeDelta::FromSeconds(1));
124 const syncer::UniquePosition unique_position =
125 syncer::UniquePosition::InitialPosition(
126 syncer::UniquePosition::RandomSuffix());
127 const sync_pb::EntitySpecifics specifics =
128 GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string());
129
130 bookmarks::BookmarkNode node(kId, kUrl);
131 tracker.Add(kSyncId, &node, kServerVersion, kCreationTime,
132 unique_position.ToProto(), specifics);
133
134 sync_pb::BookmarkModelMetadata bookmark_model_metadata =
135 tracker.BuildBookmarkModelMetadata();
136
137 ASSERT_THAT(bookmark_model_metadata.bookmarks_metadata().size(), Eq(1));
138 EXPECT_THAT(
139 bookmark_model_metadata.bookmarks_metadata(0).metadata().server_id(),
140 Eq(kSyncId));
141}
142
Mohamed Amir Yosef77ac6fbe2018-06-20 10:48:46143TEST(SyncedBookmarkTrackerTest,
144 ShouldRequireCommitRequestWhenSequenceNumberIsIncremented) {
145 SyncedBookmarkTracker tracker(std::vector<NodeMetadataPair>(),
146 std::make_unique<sync_pb::ModelTypeState>());
147 const std::string kSyncId = "SYNC_ID";
148 const int64_t kId = 1;
149 const int64_t kServerVersion = 1000;
150 const base::Time kModificationTime(base::Time::Now() -
151 base::TimeDelta::FromSeconds(1));
Mohamed Amir Yosefe1f51a22018-06-25 08:59:57152 const sync_pb::UniquePosition unique_position;
Mohamed Amir Yosef77ac6fbe2018-06-20 10:48:46153 const sync_pb::EntitySpecifics specifics =
154 GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string());
155 bookmarks::BookmarkNode node(kId, GURL());
Mohamed Amir Yosefe1f51a22018-06-25 08:59:57156 tracker.Add(kSyncId, &node, kServerVersion, kModificationTime,
157 unique_position, specifics);
Mohamed Amir Yosef77ac6fbe2018-06-20 10:48:46158
159 EXPECT_THAT(tracker.HasLocalChanges(), Eq(false));
160 tracker.IncrementSequenceNumber(kSyncId);
161 EXPECT_THAT(tracker.HasLocalChanges(), Eq(true));
162 // TODO(crbug.com/516866): Test HasLocalChanges after submitting commit
163 // request in a separate test probably.
164}
165
Mohamed Amir Yosef88d36bf2018-08-06 18:03:48166TEST(SyncedBookmarkTrackerTest, ShouldAckSequenceNumber) {
167 SyncedBookmarkTracker tracker(std::vector<NodeMetadataPair>(),
168 std::make_unique<sync_pb::ModelTypeState>());
169 const std::string kSyncId = "SYNC_ID";
170 const int64_t kId = 1;
171 const int64_t kServerVersion = 1000;
172 const base::Time kModificationTime(base::Time::Now() -
173 base::TimeDelta::FromSeconds(1));
174 const sync_pb::UniquePosition unique_position;
175 const sync_pb::EntitySpecifics specifics =
176 GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string());
177 bookmarks::BookmarkNode node(kId, GURL());
178 tracker.Add(kSyncId, &node, kServerVersion, kModificationTime,
179 unique_position, specifics);
180
181 // Test simple scenario of ack'ing an incrememented sequence number.
182 EXPECT_THAT(tracker.HasLocalChanges(), Eq(false));
183 tracker.IncrementSequenceNumber(kSyncId);
184 EXPECT_THAT(tracker.HasLocalChanges(), Eq(true));
185 tracker.AckSequenceNumber(kSyncId);
186 EXPECT_THAT(tracker.HasLocalChanges(), Eq(false));
187
188 // Test ack'ing of a mutliple times incremented sequence number.
189 tracker.IncrementSequenceNumber(kSyncId);
190 EXPECT_THAT(tracker.HasLocalChanges(), Eq(true));
191 tracker.IncrementSequenceNumber(kSyncId);
192 tracker.IncrementSequenceNumber(kSyncId);
193 EXPECT_THAT(tracker.HasLocalChanges(), Eq(true));
194 tracker.AckSequenceNumber(kSyncId);
195 EXPECT_THAT(tracker.HasLocalChanges(), Eq(false));
196}
197
Mohamed Amir Yosefc7097a12018-07-02 18:24:16198TEST(SyncedBookmarkTrackerTest, ShouldUpdateUponCommitResponseWithNewId) {
199 SyncedBookmarkTracker tracker(std::vector<NodeMetadataPair>(),
200 std::make_unique<sync_pb::ModelTypeState>());
201 const std::string kSyncId = "SYNC_ID";
202 const std::string kNewSyncId = "NEW_SYNC_ID";
203 const int64_t kId = 1;
204 const int64_t kServerVersion = 1000;
205 const int64_t kNewServerVersion = 1001;
206 const base::Time kModificationTime(base::Time::Now() -
207 base::TimeDelta::FromSeconds(1));
208 const sync_pb::UniquePosition unique_position;
209 const sync_pb::EntitySpecifics specifics =
210 GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string());
211 bookmarks::BookmarkNode node(kId, GURL());
212 tracker.Add(kSyncId, &node, kServerVersion, kModificationTime,
213 unique_position, specifics);
214 ASSERT_THAT(tracker.GetEntityForSyncId(kSyncId), NotNull());
215 // Receive a commit response with a changed id.
216 tracker.UpdateUponCommitResponse(
217 kSyncId, kNewSyncId, /*acked_sequence_number=*/1, kNewServerVersion);
218 // Old id shouldn't be there.
219 EXPECT_THAT(tracker.GetEntityForSyncId(kSyncId), IsNull());
220
221 const SyncedBookmarkTracker::Entity* entity =
222 tracker.GetEntityForSyncId(kNewSyncId);
223 ASSERT_THAT(entity, NotNull());
224 EXPECT_THAT(entity->metadata()->server_id(), Eq(kNewSyncId));
225 EXPECT_THAT(entity->bookmark_node(), Eq(&node));
226 EXPECT_THAT(entity->metadata()->server_version(), Eq(kNewServerVersion));
227}
228
Mohamed Amir Yosefbc7cbfb2018-10-16 10:39:45229TEST(SyncedBookmarkTrackerTest, ShouldUpdateId) {
230 SyncedBookmarkTracker tracker(std::vector<NodeMetadataPair>(),
231 std::make_unique<sync_pb::ModelTypeState>());
232 const std::string kSyncId = "SYNC_ID";
233 const std::string kNewSyncId = "NEW_SYNC_ID";
234 const int64_t kServerVersion = 1000;
235 const base::Time kModificationTime(base::Time::Now() -
236 base::TimeDelta::FromSeconds(1));
237 const sync_pb::UniquePosition unique_position;
238 const sync_pb::EntitySpecifics specifics =
239 GenerateSpecifics(/*title=*/std::string(), /*url=*/std::string());
240 bookmarks::BookmarkNode node(/*id=*/1, GURL());
241 // Track a sync entity.
242 tracker.Add(kSyncId, &node, kServerVersion, kModificationTime,
243 unique_position, specifics);
244
245 ASSERT_THAT(tracker.GetEntityForSyncId(kSyncId), NotNull());
246 // Update the sync id.
247 tracker.UpdateSyncForLocalCreationIfNeeded(kSyncId, kNewSyncId);
248 // Old id shouldn't be there.
249 EXPECT_THAT(tracker.GetEntityForSyncId(kSyncId), IsNull());
250
251 const SyncedBookmarkTracker::Entity* entity =
252 tracker.GetEntityForSyncId(kNewSyncId);
253 ASSERT_THAT(entity, NotNull());
254 EXPECT_THAT(entity->metadata()->server_id(), Eq(kNewSyncId));
255 EXPECT_THAT(entity->bookmark_node(), Eq(&node));
256 EXPECT_THAT(entity->metadata()->server_version(), Eq(kServerVersion));
257}
258
Mohamed Amir Yosef3fd347d2018-07-18 13:37:51259TEST(SyncedBookmarkTrackerTest,
260 ShouldMaintainTombstoneOrderBetweenCtorAndBuildBookmarkModelMetadata) {
261 // Feed a metadata batch of 5 entries to the constructor of the tracker.
262 // First 2 are for node, and the last 4 are for tombstones.
263
264 // Server ids.
265 const std::string kId0 = "id0";
266 const std::string kId1 = "id1";
267 const std::string kId2 = "id2";
268 const std::string kId3 = "id3";
269 const std::string kId4 = "id4";
270
271 const GURL kUrl("http://www.foo.com");
272 bookmarks::BookmarkNode node0(/*id=*/0, kUrl);
273 bookmarks::BookmarkNode node1(/*id=*/1, kUrl);
274
Mohamed Amir Yosef3fd347d2018-07-18 13:37:51275 std::vector<NodeMetadataPair> node_metadata_pairs;
Mohamed Amir Yosef74ec6ceca2018-07-20 15:21:22276 node_metadata_pairs.emplace_back(
277 &node0, CreateEntityMetadata(/*server_id=*/kId0, /*is_deleted=*/false));
278 node_metadata_pairs.emplace_back(
279 &node1, CreateEntityMetadata(/*server_id=*/kId1, /*is_deleted=*/false));
280 node_metadata_pairs.emplace_back(
281 nullptr, CreateEntityMetadata(/*server_id=*/kId2, /*is_deleted=*/true));
282 node_metadata_pairs.emplace_back(
283 nullptr, CreateEntityMetadata(/*server_id=*/kId3, /*is_deleted=*/true));
284 node_metadata_pairs.emplace_back(
285 nullptr, CreateEntityMetadata(/*server_id=*/kId4, /*is_deleted=*/true));
Mohamed Amir Yosef3fd347d2018-07-18 13:37:51286
287 SyncedBookmarkTracker tracker(std::move(node_metadata_pairs),
288 std::make_unique<sync_pb::ModelTypeState>());
289
290 sync_pb::BookmarkModelMetadata bookmark_model_metadata =
291 tracker.BuildBookmarkModelMetadata();
292
293 // Tombstones should be the last 3 entries in the metadata and in the same
294 // order as given to the constructor.
295 ASSERT_THAT(bookmark_model_metadata.bookmarks_metadata().size(), Eq(5));
296 EXPECT_THAT(
297 bookmark_model_metadata.bookmarks_metadata(2).metadata().server_id(),
298 Eq(kId2));
299 EXPECT_THAT(
300 bookmark_model_metadata.bookmarks_metadata(3).metadata().server_id(),
301 Eq(kId3));
302 EXPECT_THAT(
303 bookmark_model_metadata.bookmarks_metadata(4).metadata().server_id(),
304 Eq(kId4));
305}
306
307TEST(SyncedBookmarkTrackerTest,
308 ShouldMaintainOrderOfMarkDeletedCallsWhenBuildBookmarkModelMetadata) {
309 // Server ids.
310 const std::string kId0 = "id0";
311 const std::string kId1 = "id1";
312 const std::string kId2 = "id2";
313 const std::string kId3 = "id3";
314 const std::string kId4 = "id4";
315
316 const GURL kUrl("http://www.foo.com");
317 bookmarks::BookmarkNode node0(/*id=*/0, kUrl);
318 bookmarks::BookmarkNode node1(/*id=*/1, kUrl);
319 bookmarks::BookmarkNode node2(/*id=*/2, kUrl);
320 bookmarks::BookmarkNode node3(/*id=*/3, kUrl);
321 bookmarks::BookmarkNode node4(/*id=*/4, kUrl);
322
Mohamed Amir Yosef3fd347d2018-07-18 13:37:51323 std::vector<NodeMetadataPair> node_metadata_pairs;
Mohamed Amir Yosef74ec6ceca2018-07-20 15:21:22324 node_metadata_pairs.emplace_back(
325 &node0, CreateEntityMetadata(/*server_id=*/kId0, /*is_deleted=*/false));
326 node_metadata_pairs.emplace_back(
327 &node1, CreateEntityMetadata(/*server_id=*/kId1, /*is_deleted=*/false));
328 node_metadata_pairs.emplace_back(
329 &node2, CreateEntityMetadata(/*server_id=*/kId2, /*is_deleted=*/false));
330 node_metadata_pairs.emplace_back(
331 &node3, CreateEntityMetadata(/*server_id=*/kId3, /*is_deleted=*/false));
332 node_metadata_pairs.emplace_back(
333 &node4, CreateEntityMetadata(/*server_id=*/kId4, /*is_deleted=*/false));
Mohamed Amir Yosef3fd347d2018-07-18 13:37:51334
335 SyncedBookmarkTracker tracker(std::move(node_metadata_pairs),
336 std::make_unique<sync_pb::ModelTypeState>());
337
338 // Mark entities deleted in that order kId2, kId4, kId1
339 tracker.MarkDeleted(kId2);
340 tracker.MarkDeleted(kId4);
341 tracker.MarkDeleted(kId1);
342
343 sync_pb::BookmarkModelMetadata bookmark_model_metadata =
344 tracker.BuildBookmarkModelMetadata();
345
346 // Tombstones should be the last 3 entries in the metadata and in the same as
347 // calling MarkDeleted().
348 ASSERT_THAT(bookmark_model_metadata.bookmarks_metadata().size(), Eq(5));
349 EXPECT_THAT(
350 bookmark_model_metadata.bookmarks_metadata(2).metadata().server_id(),
351 Eq(kId2));
352 EXPECT_THAT(
353 bookmark_model_metadata.bookmarks_metadata(3).metadata().server_id(),
354 Eq(kId4));
355 EXPECT_THAT(
356 bookmark_model_metadata.bookmarks_metadata(4).metadata().server_id(),
357 Eq(kId1));
358}
359
Mohamed Amir Yosef74ec6ceca2018-07-20 15:21:22360TEST(SyncedBookmarkTrackerTest,
361 ShouldOrderParentUpdatesBeforeChildUpdatesAndDeletionsComeLast) {
362 const size_t kMaxEntries = 1000;
363
364 // Construct this structure:
365 // bookmark_bar
366 // |- node0
367 // |- node1
368 // |- node2
369
370 std::unique_ptr<bookmarks::BookmarkModel> bookmark_model =
371 bookmarks::TestBookmarkClient::CreateModel();
372
373 const bookmarks::BookmarkNode* bookmark_bar_node =
374 bookmark_model->bookmark_bar_node();
375 const bookmarks::BookmarkNode* node0 = bookmark_model->AddFolder(
376 /*parent=*/bookmark_bar_node, /*index=*/0, base::UTF8ToUTF16("node0"));
377 const bookmarks::BookmarkNode* node1 = bookmark_model->AddFolder(
378 /*parent=*/node0, /*index=*/0, base::UTF8ToUTF16("node1"));
379 const bookmarks::BookmarkNode* node2 = bookmark_model->AddFolder(
380 /*parent=*/node1, /*index=*/0, base::UTF8ToUTF16("node2"));
381
382 // Server ids.
383 const std::string kId0 = "id0";
384 const std::string kId1 = "id1";
385 const std::string kId2 = "id2";
386 const std::string kId3 = "id3";
387
388 // Prepare the metadata with shuffled order.
389 std::vector<NodeMetadataPair> node_metadata_pairs;
390 node_metadata_pairs.emplace_back(
391 node1, CreateEntityMetadata(/*server_id=*/kId1, /*is_deleted=*/false));
392 node_metadata_pairs.emplace_back(
393 nullptr, CreateEntityMetadata(/*server_id=*/kId3, /*is_deleted=*/true));
394 node_metadata_pairs.emplace_back(
395 node2, CreateEntityMetadata(/*server_id=*/kId2, /*is_deleted=*/false));
396 node_metadata_pairs.emplace_back(
397 node0, CreateEntityMetadata(/*server_id=*/kId0, /*is_deleted=*/false));
398
399 SyncedBookmarkTracker tracker(std::move(node_metadata_pairs),
400 std::make_unique<sync_pb::ModelTypeState>());
401
402 // Mark the entities that they have local changes. (in shuffled order just to
403 // verify the tracker doesn't simply maintain the order of updates similar to
404 // with deletions).
405 tracker.IncrementSequenceNumber(kId3);
406 tracker.IncrementSequenceNumber(kId1);
407 tracker.IncrementSequenceNumber(kId2);
408 tracker.IncrementSequenceNumber(kId0);
409
410 std::vector<const SyncedBookmarkTracker::Entity*> entities_with_local_change =
411 tracker.GetEntitiesWithLocalChanges(kMaxEntries);
412
413 ASSERT_THAT(entities_with_local_change.size(), Eq(4U));
414 // Verify updates are in parent before child order node0 --> node1 --> node2.
415 EXPECT_THAT(entities_with_local_change[0]->metadata()->server_id(), Eq(kId0));
416 EXPECT_THAT(entities_with_local_change[1]->metadata()->server_id(), Eq(kId1));
417 EXPECT_THAT(entities_with_local_change[2]->metadata()->server_id(), Eq(kId2));
418 // Verify that deletion is the last entry.
419 EXPECT_THAT(entities_with_local_change[3]->metadata()->server_id(), Eq(kId3));
420}
421
Mohamed Amir Yoseffb7986d882018-10-12 05:42:17422TEST(SyncedBookmarkTrackerTest, ShouldMatchModelAndMetadata) {
423 std::unique_ptr<bookmarks::BookmarkModel> model =
424 bookmarks::TestBookmarkClient::CreateModel();
425
426 const bookmarks::BookmarkNode* bookmark_bar_node = model->bookmark_bar_node();
427 const bookmarks::BookmarkNode* node = model->AddFolder(
428 /*parent=*/bookmark_bar_node, /*index=*/0, base::UTF8ToUTF16("node0"));
429
430 sync_pb::BookmarkModelMetadata model_metadata;
431 model_metadata.mutable_model_type_state()->set_initial_sync_done(true);
432 // Add entries for all the permanent nodes. TestBookmarkClient creates all the
433 // 3 permanent nodes.
434 sync_pb::BookmarkMetadata* bookmark_metadata =
435 model_metadata.add_bookmarks_metadata();
436 bookmark_metadata->set_id(model->bookmark_bar_node()->id());
437 bookmark_metadata->mutable_metadata()->set_server_id("BookmarkBarId");
438
439 bookmark_metadata = model_metadata.add_bookmarks_metadata();
440 bookmark_metadata->set_id(model->other_node()->id());
441 bookmark_metadata->mutable_metadata()->set_server_id("OtherBookmarksId");
442
443 bookmark_metadata = model_metadata.add_bookmarks_metadata();
444 bookmark_metadata->set_id(model->mobile_node()->id());
445 bookmark_metadata->mutable_metadata()->set_server_id("MobileBookmarksId");
446
Mohamed Amir Yoseffb617fde2019-07-16 09:08:54447 // Add entry for the managed node.
Mohamed Amir Yoseffb7986d882018-10-12 05:42:17448 bookmark_metadata = model_metadata.add_bookmarks_metadata();
449 bookmark_metadata->set_id(node->id());
450 bookmark_metadata->mutable_metadata()->set_server_id("NodeId");
451
452 // Add a tombstone entry.
453 sync_pb::BookmarkMetadata* tombstone =
454 model_metadata.add_bookmarks_metadata();
455 tombstone->mutable_metadata()->set_server_id("tombstoneId");
456 tombstone->mutable_metadata()->set_is_deleted(true);
457
Mohamed Amir Yosef05fa2162018-11-09 22:42:20458 base::HistogramTester histogram_tester;
Mohamed Amir Yoseffb7986d882018-10-12 05:42:17459 EXPECT_TRUE(SyncedBookmarkTracker::BookmarkModelMatchesMetadata(
460 model.get(), model_metadata));
Mohamed Amir Yosef05fa2162018-11-09 22:42:20461 histogram_tester.ExpectUniqueSample(
462 "Sync.BookmarksModelMetadataCorruptionReason",
463 /*sample=*/ExpectedCorruptionReason::NO_CORRUPTION, /*count=*/1);
Mohamed Amir Yoseffb7986d882018-10-12 05:42:17464}
465
Mohamed Amir Yosefb1117f742018-11-12 13:29:01466TEST(SyncedBookmarkTrackerTest,
Mikel Astiz113dc1e2018-12-18 16:58:47467 ShouldNotMatchModelAndMetadataIfMissingMobileFolder) {
Mohamed Amir Yosefb1117f742018-11-12 13:29:01468 std::unique_ptr<bookmarks::BookmarkModel> model =
469 bookmarks::TestBookmarkClient::CreateModel();
470
471 sync_pb::BookmarkModelMetadata model_metadata;
472 model_metadata.mutable_model_type_state()->set_initial_sync_done(true);
473 // Add entries for all the permanent nodes except for the Mobile bookmarks
Mikel Astiz113dc1e2018-12-18 16:58:47474 // folder.
Mohamed Amir Yosefb1117f742018-11-12 13:29:01475 sync_pb::BookmarkMetadata* bookmark_metadata =
476 model_metadata.add_bookmarks_metadata();
477 bookmark_metadata->set_id(model->bookmark_bar_node()->id());
478 bookmark_metadata->mutable_metadata()->set_server_id("BookmarkBarId");
479
480 bookmark_metadata = model_metadata.add_bookmarks_metadata();
481 bookmark_metadata->set_id(model->other_node()->id());
482 bookmark_metadata->mutable_metadata()->set_server_id("OtherBookmarksId");
483
484 base::HistogramTester histogram_tester;
Mikel Astiz113dc1e2018-12-18 16:58:47485 EXPECT_FALSE(SyncedBookmarkTracker::BookmarkModelMatchesMetadata(
Mohamed Amir Yosefb1117f742018-11-12 13:29:01486 model.get(), model_metadata));
487 histogram_tester.ExpectUniqueSample(
488 "Sync.BookmarksModelMetadataCorruptionReason",
Mikel Astiz113dc1e2018-12-18 16:58:47489 /*sample=*/ExpectedCorruptionReason::COUNT_MISMATCH, /*count=*/1);
Mohamed Amir Yosefb1117f742018-11-12 13:29:01490}
491
Mohamed Amir Yoseffb7986d882018-10-12 05:42:17492TEST(SyncedBookmarkTrackerTest, ShouldNotMatchModelAndCorruptedMetadata) {
493 std::unique_ptr<bookmarks::BookmarkModel> model =
494 bookmarks::TestBookmarkClient::CreateModel();
495
496 sync_pb::BookmarkModelMetadata model_metadata;
497 model_metadata.mutable_model_type_state()->set_initial_sync_done(true);
Mikel Astiz113dc1e2018-12-18 16:58:47498 // Add entries for 3 permanent nodes only. TestBookmarkClient creates all the
499 // 4 permanent nodes.
Mohamed Amir Yoseffb7986d882018-10-12 05:42:17500 sync_pb::BookmarkMetadata* bookmark_metadata =
501 model_metadata.add_bookmarks_metadata();
502 bookmark_metadata->set_id(model->bookmark_bar_node()->id());
503 bookmark_metadata->mutable_metadata()->set_server_id("BookmarkBarId");
504
Mikel Astiz113dc1e2018-12-18 16:58:47505 bookmark_metadata = model_metadata.add_bookmarks_metadata();
506 bookmark_metadata->set_id(model->mobile_node()->id());
507 bookmark_metadata->mutable_metadata()->set_server_id("MobileBookmarksId");
508
Mohamed Amir Yosef05fa2162018-11-09 22:42:20509 base::HistogramTester histogram_tester;
Mohamed Amir Yosefb1117f742018-11-12 13:29:01510 // The entry for the Other bookmarks is missing.
Mohamed Amir Yoseffb7986d882018-10-12 05:42:17511 EXPECT_FALSE(SyncedBookmarkTracker::BookmarkModelMatchesMetadata(
512 model.get(), model_metadata));
Mohamed Amir Yosef05fa2162018-11-09 22:42:20513 histogram_tester.ExpectBucketCount(
514 "Sync.BookmarksModelMetadataCorruptionReason",
515 /*sample=*/ExpectedCorruptionReason::COUNT_MISMATCH, /*count=*/1);
Mohamed Amir Yoseffb7986d882018-10-12 05:42:17516
Mohamed Amir Yosefb1117f742018-11-12 13:29:01517 // The entry for the Other bookmarks is missing a server id.
Mohamed Amir Yoseffb7986d882018-10-12 05:42:17518 bookmark_metadata = model_metadata.add_bookmarks_metadata();
Mohamed Amir Yosefb1117f742018-11-12 13:29:01519 bookmark_metadata->set_id(model->other_node()->id());
Mohamed Amir Yoseffb7986d882018-10-12 05:42:17520 EXPECT_FALSE(SyncedBookmarkTracker::BookmarkModelMatchesMetadata(
521 model.get(), model_metadata));
522
Mohamed Amir Yosef05fa2162018-11-09 22:42:20523 histogram_tester.ExpectBucketCount(
524 "Sync.BookmarksModelMetadataCorruptionReason",
525 /*sample=*/ExpectedCorruptionReason::MISSING_SERVER_ID, /*count=*/1);
526
Mohamed Amir Yosefb1117f742018-11-12 13:29:01527 // The entry for the Other bookmarks is missing a node id.
Mohamed Amir Yoseffb7986d882018-10-12 05:42:17528 bookmark_metadata->clear_id();
529 bookmark_metadata->mutable_metadata()->set_server_id("OtherBookmarksId");
530 EXPECT_FALSE(SyncedBookmarkTracker::BookmarkModelMatchesMetadata(
531 model.get(), model_metadata));
Mohamed Amir Yosef05fa2162018-11-09 22:42:20532 histogram_tester.ExpectBucketCount(
533 "Sync.BookmarksModelMetadataCorruptionReason",
534 /*sample=*/ExpectedCorruptionReason::MISSING_BOOKMARK_ID, /*count=*/1);
Mohamed Amir Yoseffb7986d882018-10-12 05:42:17535
Mohamed Amir Yosefb1117f742018-11-12 13:29:01536 // The entry for the Other bookmarks is having a wrong node id.
537 bookmark_metadata->set_id(model->other_node()->id() + 1000);
Mohamed Amir Yoseffb7986d882018-10-12 05:42:17538 EXPECT_FALSE(SyncedBookmarkTracker::BookmarkModelMatchesMetadata(
539 model.get(), model_metadata));
Mohamed Amir Yosef05fa2162018-11-09 22:42:20540 histogram_tester.ExpectBucketCount(
541 "Sync.BookmarksModelMetadataCorruptionReason",
542 /*sample=*/ExpectedCorruptionReason::IDS_MISMATCH, /*count=*/1);
Mohamed Amir Yoseffb7986d882018-10-12 05:42:17543
544 // A tombstone shouldn't have a node id.
545 sync_pb::BookmarkMetadata* tombstone =
546 model_metadata.add_bookmarks_metadata();
547 tombstone->mutable_metadata()->set_server_id("tombstoneId");
548 tombstone->mutable_metadata()->set_is_deleted(true);
549 tombstone->set_id(10);
550 EXPECT_FALSE(SyncedBookmarkTracker::BookmarkModelMatchesMetadata(
551 model.get(), model_metadata));
Mohamed Amir Yosef05fa2162018-11-09 22:42:20552 histogram_tester.ExpectBucketCount(
553 "Sync.BookmarksModelMetadataCorruptionReason",
554 /*sample=*/ExpectedCorruptionReason::BOOKMARK_ID_IN_TOMBSTONE,
555 /*count=*/1);
Mohamed Amir Yoseffb7986d882018-10-12 05:42:17556}
557
Mohamed Amir Yosefb6a54aa72018-11-09 13:34:03558TEST(SyncedBookmarkTrackerTest,
559 ShouldMatchModelWithUnsyncableNodesAndMetadata) {
560 // Add a managed node with an arbitrary id 100.
561 const int64_t kManagedNodeId = 100;
Mohamed Amir Yoseffb617fde2019-07-16 09:08:54562 auto owned_managed_node = std::make_unique<bookmarks::BookmarkPermanentNode>(
Pauline Leitao91f0b53a2019-07-09 10:13:54563 kManagedNodeId, bookmarks::BookmarkNode::FOLDER);
Mohamed Amir Yoseffb617fde2019-07-16 09:08:54564 bookmarks::BookmarkPermanentNode* managed_node = owned_managed_node.get();
Mohamed Amir Yosefb6a54aa72018-11-09 13:34:03565 auto client = std::make_unique<bookmarks::TestBookmarkClient>();
Mohamed Amir Yoseffb617fde2019-07-16 09:08:54566 client->SetManagedNodeToLoad(std::move(owned_managed_node));
Mohamed Amir Yosefb6a54aa72018-11-09 13:34:03567
568 std::unique_ptr<bookmarks::BookmarkModel> model =
569 bookmarks::TestBookmarkClient::CreateModelWithClient(std::move(client));
570
571 // The model should contain the managed node now.
Mohamed Amir Yoseffb617fde2019-07-16 09:08:54572 ASSERT_THAT(GetBookmarkNodeByID(model.get(), kManagedNodeId),
573 Eq(managed_node));
Mohamed Amir Yosefb6a54aa72018-11-09 13:34:03574
575 sync_pb::BookmarkModelMetadata model_metadata;
576 model_metadata.mutable_model_type_state()->set_initial_sync_done(true);
577 // Add entries for all the permanent nodes. TestBookmarkClient creates all the
578 // 3 permanent nodes.
579 sync_pb::BookmarkMetadata* bookmark_metadata =
580 model_metadata.add_bookmarks_metadata();
581 bookmark_metadata->set_id(model->bookmark_bar_node()->id());
582 bookmark_metadata->mutable_metadata()->set_server_id("BookmarkBarId");
583
584 bookmark_metadata = model_metadata.add_bookmarks_metadata();
585 bookmark_metadata->set_id(model->other_node()->id());
586 bookmark_metadata->mutable_metadata()->set_server_id("OtherBookmarksId");
587
588 bookmark_metadata = model_metadata.add_bookmarks_metadata();
589 bookmark_metadata->set_id(model->mobile_node()->id());
590 bookmark_metadata->mutable_metadata()->set_server_id("MobileBookmarksId");
591
Mohamed Amir Yosef05fa2162018-11-09 22:42:20592 base::HistogramTester histogram_tester;
Mohamed Amir Yosefb6a54aa72018-11-09 13:34:03593 EXPECT_TRUE(SyncedBookmarkTracker::BookmarkModelMatchesMetadata(
594 model.get(), model_metadata));
Mohamed Amir Yosef05fa2162018-11-09 22:42:20595 histogram_tester.ExpectUniqueSample(
596 "Sync.BookmarksModelMetadataCorruptionReason",
597 /*sample=*/ExpectedCorruptionReason::NO_CORRUPTION, /*count=*/1);
Mohamed Amir Yosefb6a54aa72018-11-09 13:34:03598}
599
Mohamed Amir Yosefb0664a82018-05-09 12:19:25600} // namespace
601
602} // namespace sync_bookmarks