Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: sync/syncable/parent_child_index_unittest.cc

Issue 2130453004: [Sync] Move //sync to //components/sync. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase. Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « sync/syncable/parent_child_index.cc ('k') | sync/syncable/scoped_kernel_lock.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2013 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 "sync/syncable/parent_child_index.h"
6
7 #include <list>
8 #include <string>
9
10 #include "base/stl_util.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "sync/syncable/entry_kernel.h"
13 #include "sync/syncable/syncable_util.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 namespace syncer {
17 namespace syncable {
18
19 namespace {
20
21 static const std::string kCacheGuid = "8HhNIHlEOCGQbIAALr9QEg==";
22
23 } // namespace
24
25 class ParentChildIndexTest : public testing::Test {
26 public:
27 void TearDown() override {
28 // To make memory management easier, we take ownership of all EntryKernels
29 // returned by our factory methods and delete them here.
30 STLDeleteElements(&owned_entry_kernels_);
31 }
32
33 // Unfortunately, we can't use the regular Entry factory methods, because the
34 // ParentChildIndex deals in EntryKernels.
35
36 static syncable::Id GetBookmarkRootId() {
37 return syncable::Id::CreateFromServerId("bookmark_folder");
38 }
39
40 static syncable::Id GetBookmarkId(int n) {
41 return syncable::Id::CreateFromServerId("b" + base::IntToString(n));
42 }
43
44 static syncable::Id GetClientUniqueId(int n) {
45 return syncable::Id::CreateFromServerId("c" + base::IntToString(n));
46 }
47
48 EntryKernel* MakeRoot() {
49 // Mimics the root node.
50 EntryKernel* root = new EntryKernel();
51 root->put(META_HANDLE, 1);
52 root->put(BASE_VERSION, -1);
53 root->put(SERVER_VERSION, 0);
54 root->put(IS_DIR, true);
55 root->put(ID, syncable::Id::GetRoot());
56 root->put(PARENT_ID, syncable::Id::GetRoot());
57
58 owned_entry_kernels_.push_back(root);
59 return root;
60 }
61
62 EntryKernel* MakeTypeRoot(ModelType model_type, const syncable::Id& id) {
63 // Mimics a server-created bookmark folder.
64 EntryKernel* folder = new EntryKernel;
65 folder->put(META_HANDLE, 1);
66 folder->put(BASE_VERSION, 9);
67 folder->put(SERVER_VERSION, 9);
68 folder->put(IS_DIR, true);
69 folder->put(ID, id);
70 folder->put(PARENT_ID, syncable::Id::GetRoot());
71 folder->put(UNIQUE_SERVER_TAG, ModelTypeToRootTag(model_type));
72
73 // Ensure that GetModelType() returns a correct value.
74 sync_pb::EntitySpecifics specifics;
75 AddDefaultFieldValue(model_type, &specifics);
76 folder->put(SPECIFICS, specifics);
77
78 owned_entry_kernels_.push_back(folder);
79 return folder;
80 }
81
82 EntryKernel* MakeBookmarkRoot() {
83 return MakeTypeRoot(BOOKMARKS, GetBookmarkRootId());
84 }
85
86 EntryKernel* MakeBookmark(int n, int pos, bool is_dir) {
87 // Mimics a regular bookmark or folder.
88 EntryKernel* bm = new EntryKernel();
89 bm->put(META_HANDLE, n);
90 bm->put(BASE_VERSION, 10);
91 bm->put(SERVER_VERSION, 10);
92 bm->put(IS_DIR, is_dir);
93 bm->put(ID, GetBookmarkId(n));
94 bm->put(PARENT_ID, GetBookmarkRootId());
95
96 bm->put(UNIQUE_BOOKMARK_TAG,
97 syncable::GenerateSyncableBookmarkHash(kCacheGuid,
98 bm->ref(ID).GetServerId()));
99
100 UniquePosition unique_pos =
101 UniquePosition::FromInt64(pos, bm->ref(UNIQUE_BOOKMARK_TAG));
102 bm->put(UNIQUE_POSITION, unique_pos);
103 bm->put(SERVER_UNIQUE_POSITION, unique_pos);
104
105 owned_entry_kernels_.push_back(bm);
106 return bm;
107 }
108
109 EntryKernel* MakeUniqueClientItem(ModelType model_type,
110 int n,
111 const syncable::Id& parent_id) {
112 EntryKernel* item = new EntryKernel();
113 item->put(META_HANDLE, n);
114 item->put(BASE_VERSION, 10);
115 item->put(SERVER_VERSION, 10);
116 item->put(IS_DIR, false);
117 item->put(ID, GetClientUniqueId(n));
118 item->put(UNIQUE_CLIENT_TAG, base::IntToString(n));
119
120 if (!parent_id.IsNull()) {
121 item->put(PARENT_ID, parent_id);
122 }
123
124 if (model_type != UNSPECIFIED) {
125 // Ensure that GetModelType() returns a correct value.
126 sync_pb::EntitySpecifics specifics;
127 AddDefaultFieldValue(model_type, &specifics);
128 item->put(SPECIFICS, specifics);
129 }
130
131 owned_entry_kernels_.push_back(item);
132 return item;
133 }
134
135 EntryKernel* MakeUniqueClientItem(int n, const syncable::Id& parent_id) {
136 return MakeUniqueClientItem(UNSPECIFIED, n, parent_id);
137 }
138
139 EntryKernel* MakeUniqueClientItem(ModelType model_type, int n) {
140 return MakeUniqueClientItem(model_type, n, Id());
141 }
142
143 const syncable::Id& IndexKnownModelTypeRootId(ModelType model_type) const {
144 return index_.GetModelTypeRootId(model_type);
145 }
146
147 ParentChildIndex index_;
148
149 private:
150 std::list<EntryKernel*> owned_entry_kernels_;
151 };
152
153 TEST_F(ParentChildIndexTest, TestRootNode) {
154 EntryKernel* root = MakeRoot();
155 EXPECT_FALSE(ParentChildIndex::ShouldInclude(root));
156 }
157
158 TEST_F(ParentChildIndexTest, TestBookmarkRootFolder) {
159 EntryKernel* bm_folder = MakeBookmarkRoot();
160 EXPECT_TRUE(ParentChildIndex::ShouldInclude(bm_folder));
161
162 index_.Insert(bm_folder);
163 // Since BOOKMARKS is a hierarchical type, its type root folder shouldn't be
164 // tracked by ParentChildIndex.
165 EXPECT_EQ(Id(), IndexKnownModelTypeRootId(BOOKMARKS));
166 }
167
168 // Tests iteration over a set of siblings.
169 TEST_F(ParentChildIndexTest, ChildInsertionAndIteration) {
170 EntryKernel* bm_folder = MakeBookmarkRoot();
171 index_.Insert(bm_folder);
172
173 // Make some folder and non-folder entries.
174 EntryKernel* b1 = MakeBookmark(1, 1, false);
175 EntryKernel* b2 = MakeBookmark(2, 2, false);
176 EntryKernel* b3 = MakeBookmark(3, 3, true);
177 EntryKernel* b4 = MakeBookmark(4, 4, false);
178
179 // Insert them out-of-order to test different cases.
180 index_.Insert(b3); // Only child.
181 index_.Insert(b4); // Right-most child.
182 index_.Insert(b1); // Left-most child.
183 index_.Insert(b2); // Between existing items.
184
185 // Double-check they've been added.
186 EXPECT_TRUE(index_.Contains(b1));
187 EXPECT_TRUE(index_.Contains(b2));
188 EXPECT_TRUE(index_.Contains(b3));
189 EXPECT_TRUE(index_.Contains(b4));
190
191 // Check the ordering.
192 const OrderedChildSet* children = index_.GetChildren(GetBookmarkRootId());
193 ASSERT_TRUE(children);
194 ASSERT_EQ(children->size(), 4UL);
195 OrderedChildSet::const_iterator it = children->begin();
196 EXPECT_EQ(*it, b1);
197 it++;
198 EXPECT_EQ(*it, b2);
199 it++;
200 EXPECT_EQ(*it, b3);
201 it++;
202 EXPECT_EQ(*it, b4);
203 it++;
204 EXPECT_TRUE(it == children->end());
205 }
206
207 // Tests iteration when hierarchy is involved.
208 TEST_F(ParentChildIndexTest, ChildInsertionAndIterationWithHierarchy) {
209 EntryKernel* bm_folder = MakeBookmarkRoot();
210 index_.Insert(bm_folder);
211
212 // Just below the root, we have folders f1 and f2.
213 EntryKernel* f1 = MakeBookmark(1, 1, false);
214 EntryKernel* f2 = MakeBookmark(2, 2, false);
215 EntryKernel* f3 = MakeBookmark(3, 3, false);
216
217 // Under folder f1, we have two bookmarks.
218 EntryKernel* f1_b1 = MakeBookmark(101, 1, false);
219 f1_b1->put(PARENT_ID, GetBookmarkId(1));
220 EntryKernel* f1_b2 = MakeBookmark(102, 2, false);
221 f1_b2->put(PARENT_ID, GetBookmarkId(1));
222
223 // Under folder f2, there is one bookmark.
224 EntryKernel* f2_b1 = MakeBookmark(201, 1, false);
225 f2_b1->put(PARENT_ID, GetBookmarkId(2));
226
227 // Under folder f3, there is nothing.
228
229 // Insert in a strange order, because we can.
230 index_.Insert(f1_b2);
231 index_.Insert(f2);
232 index_.Insert(f2_b1);
233 index_.Insert(f1);
234 index_.Insert(f1_b1);
235 index_.Insert(f3);
236
237 OrderedChildSet::const_iterator it;
238
239 // Iterate over children of the bookmark root.
240 const OrderedChildSet* top_children = index_.GetChildren(GetBookmarkRootId());
241 ASSERT_TRUE(top_children);
242 ASSERT_EQ(top_children->size(), 3UL);
243 it = top_children->begin();
244 EXPECT_EQ(*it, f1);
245 it++;
246 EXPECT_EQ(*it, f2);
247 it++;
248 EXPECT_EQ(*it, f3);
249 it++;
250 EXPECT_TRUE(it == top_children->end());
251
252 // Iterate over children of the first folder.
253 const OrderedChildSet* f1_children = index_.GetChildren(GetBookmarkId(1));
254 ASSERT_TRUE(f1_children);
255 ASSERT_EQ(f1_children->size(), 2UL);
256 it = f1_children->begin();
257 EXPECT_EQ(*it, f1_b1);
258 it++;
259 EXPECT_EQ(*it, f1_b2);
260 it++;
261 EXPECT_TRUE(it == f1_children->end());
262
263 // Iterate over children of the second folder.
264 const OrderedChildSet* f2_children = index_.GetChildren(GetBookmarkId(2));
265 ASSERT_TRUE(f2_children);
266 ASSERT_EQ(f2_children->size(), 1UL);
267 it = f2_children->begin();
268 EXPECT_EQ(*it, f2_b1);
269 it++;
270 EXPECT_TRUE(it == f2_children->end());
271
272 // Check for children of the third folder.
273 const OrderedChildSet* f3_children = index_.GetChildren(GetBookmarkId(3));
274 EXPECT_FALSE(f3_children);
275 }
276
277 // Tests removing items.
278 TEST_F(ParentChildIndexTest, RemoveWithHierarchy) {
279 EntryKernel* bm_folder = MakeBookmarkRoot();
280 index_.Insert(bm_folder);
281
282 // Just below the root, we have folders f1 and f2.
283 EntryKernel* f1 = MakeBookmark(1, 1, false);
284 EntryKernel* f2 = MakeBookmark(2, 2, false);
285 EntryKernel* f3 = MakeBookmark(3, 3, false);
286
287 // Under folder f1, we have two bookmarks.
288 EntryKernel* f1_b1 = MakeBookmark(101, 1, false);
289 f1_b1->put(PARENT_ID, GetBookmarkId(1));
290 EntryKernel* f1_b2 = MakeBookmark(102, 2, false);
291 f1_b2->put(PARENT_ID, GetBookmarkId(1));
292
293 // Under folder f2, there is one bookmark.
294 EntryKernel* f2_b1 = MakeBookmark(201, 1, false);
295 f2_b1->put(PARENT_ID, GetBookmarkId(2));
296
297 // Under folder f3, there is nothing.
298
299 // Insert in any order.
300 index_.Insert(f2_b1);
301 index_.Insert(f3);
302 index_.Insert(f1_b2);
303 index_.Insert(f1);
304 index_.Insert(f2);
305 index_.Insert(f1_b1);
306
307 // Check that all are in the index.
308 EXPECT_TRUE(index_.Contains(f1));
309 EXPECT_TRUE(index_.Contains(f2));
310 EXPECT_TRUE(index_.Contains(f3));
311 EXPECT_TRUE(index_.Contains(f1_b1));
312 EXPECT_TRUE(index_.Contains(f1_b2));
313 EXPECT_TRUE(index_.Contains(f2_b1));
314
315 // Remove them all in any order.
316 index_.Remove(f3);
317 EXPECT_FALSE(index_.Contains(f3));
318 index_.Remove(f1_b2);
319 EXPECT_FALSE(index_.Contains(f1_b2));
320 index_.Remove(f2_b1);
321 EXPECT_FALSE(index_.Contains(f2_b1));
322 index_.Remove(f1);
323 EXPECT_FALSE(index_.Contains(f1));
324 index_.Remove(f2);
325 EXPECT_FALSE(index_.Contains(f2));
326 index_.Remove(f1_b1);
327 EXPECT_FALSE(index_.Contains(f1_b1));
328 }
329
330 // Test that involves two non-ordered items.
331 TEST_F(ParentChildIndexTest, UnorderedChildren) {
332 // Make two unique client tag items under the root node.
333 EntryKernel* u1 = MakeUniqueClientItem(1, syncable::Id::GetRoot());
334 EntryKernel* u2 = MakeUniqueClientItem(2, syncable::Id::GetRoot());
335
336 EXPECT_FALSE(u1->ShouldMaintainPosition());
337 EXPECT_FALSE(u2->ShouldMaintainPosition());
338
339 index_.Insert(u1);
340 index_.Insert(u2);
341
342 const OrderedChildSet* children = index_.GetChildren(syncable::Id::GetRoot());
343 EXPECT_EQ(children->count(u1), 1UL);
344 EXPECT_EQ(children->count(u2), 1UL);
345 EXPECT_EQ(children->size(), 2UL);
346 }
347
348 // Test ordered and non-ordered entries under the same parent.
349 // TODO(rlarocque): We should not need to support this.
350 TEST_F(ParentChildIndexTest, OrderedAndUnorderedChildren) {
351 EntryKernel* bm_folder = MakeBookmarkRoot();
352 index_.Insert(bm_folder);
353
354 EntryKernel* b1 = MakeBookmark(1, 1, false);
355 EntryKernel* b2 = MakeBookmark(2, 2, false);
356 EntryKernel* u1 = MakeUniqueClientItem(1, GetBookmarkRootId());
357
358 index_.Insert(b1);
359 index_.Insert(u1);
360 index_.Insert(b2);
361
362 const OrderedChildSet* children = index_.GetChildren(GetBookmarkRootId());
363 ASSERT_TRUE(children);
364 EXPECT_EQ(3UL, children->size());
365
366 // Ensure that the non-positionable item is moved to the far right.
367 OrderedChildSet::const_iterator it = children->begin();
368 EXPECT_EQ(*it, b1);
369 it++;
370 EXPECT_EQ(*it, b2);
371 it++;
372 EXPECT_EQ(*it, u1);
373 it++;
374 EXPECT_TRUE(it == children->end());
375 }
376
377 TEST_F(ParentChildIndexTest, NodesWithImplicitParentId) {
378 syncable::Id type_root_id = syncable::Id::CreateFromServerId("type_root");
379 EntryKernel* type_root = MakeTypeRoot(PREFERENCES, type_root_id);
380 index_.Insert(type_root);
381 EXPECT_EQ(type_root_id, IndexKnownModelTypeRootId(PREFERENCES));
382
383 // Create entries without parent ID
384 EntryKernel* p1 = MakeUniqueClientItem(PREFERENCES, 1);
385 EntryKernel* p2 = MakeUniqueClientItem(PREFERENCES, 2);
386
387 index_.Insert(p1);
388 index_.Insert(p2);
389
390 EXPECT_TRUE(index_.Contains(p1));
391 EXPECT_TRUE(index_.Contains(p2));
392
393 // Items should appear under the type root
394 const OrderedChildSet* children = index_.GetChildren(type_root);
395 ASSERT_TRUE(children);
396 EXPECT_EQ(2UL, children->size());
397
398 EXPECT_EQ(2UL, index_.GetSiblings(p1)->size());
399 EXPECT_EQ(2UL, index_.GetSiblings(p2)->size());
400
401 index_.Remove(p1);
402
403 EXPECT_FALSE(index_.Contains(p1));
404 EXPECT_TRUE(index_.Contains(p2));
405 children = index_.GetChildren(type_root_id);
406 ASSERT_TRUE(children);
407 EXPECT_EQ(1UL, children->size());
408
409 index_.Remove(p2);
410
411 EXPECT_FALSE(index_.Contains(p2));
412 children = index_.GetChildren(type_root);
413 ASSERT_EQ(nullptr, children);
414 }
415
416 // Test that the removal isn't sensitive to the order (PurgeEntriesWithTypeIn
417 // removes items in arbitrary order).
418 TEST_F(ParentChildIndexTest, RemoveOutOfOrder) {
419 // Insert a type root and two items (with implicit parent ID).
420 syncable::Id type_root_id = syncable::Id::CreateFromServerId("type_root");
421 EntryKernel* type_root = MakeTypeRoot(PREFERENCES, type_root_id);
422 index_.Insert(type_root);
423 EntryKernel* p1 = MakeUniqueClientItem(PREFERENCES, 1);
424 EntryKernel* p2 = MakeUniqueClientItem(PREFERENCES, 2);
425 index_.Insert(p1);
426 index_.Insert(p2);
427
428 // Two items expected under the type root.
429 const OrderedChildSet* children = index_.GetChildren(type_root);
430 ASSERT_TRUE(children);
431 EXPECT_EQ(2UL, children->size());
432
433 // Remove all 3 items in arbitrary order.
434 index_.Remove(p2);
435 index_.Remove(type_root);
436 index_.Remove(p1);
437
438 EXPECT_EQ(nullptr, index_.GetChildren(type_root));
439
440 // Add a new root and another two items again.
441 type_root = MakeTypeRoot(PREFERENCES, type_root_id);
442 index_.Insert(type_root);
443
444 index_.Insert(MakeUniqueClientItem(PREFERENCES, 3));
445 index_.Insert(MakeUniqueClientItem(PREFERENCES, 4));
446
447 children = index_.GetChildren(type_root);
448 ASSERT_TRUE(children);
449 // Should have 2 items. If the out of order removal cleared the implicit
450 // parent folder ID prematurely, the collection would have 3 items including
451 // p1.
452 EXPECT_EQ(2UL, children->size());
453 }
454
455 // Test that the insert isn't sensitive to the order (Loading entries from
456 // Sync DB is done in arbitrary order).
457 TEST_F(ParentChildIndexTest, InsertOutOfOrder) {
458 // Insert two Preferences entries with implicit parent first
459 index_.Insert(MakeUniqueClientItem(PREFERENCES, 1));
460 index_.Insert(MakeUniqueClientItem(PREFERENCES, 2));
461
462 // Then insert the Preferences type root
463 syncable::Id type_root_id = syncable::Id::CreateFromServerId("type_root");
464 index_.Insert(MakeTypeRoot(PREFERENCES, type_root_id));
465
466 // The index should still be able to associate Preferences entries
467 // with the root.
468 const OrderedChildSet* children = index_.GetChildren(type_root_id);
469 ASSERT_TRUE(children);
470 EXPECT_EQ(2UL, children->size());
471 }
472
473 // Test that if for some reason we wind up with multiple type roots, we
474 // gracefully handle it and don't allow any new entities to become invisible.
475 TEST_F(ParentChildIndexTest, MultipleTypeRoots) {
476 // Create the good Preferences type root.
477 syncable::Id type_root_id = syncable::Id::CreateFromClientString("type_root");
478 index_.Insert(MakeTypeRoot(PREFERENCES, type_root_id));
479
480 // Then insert the bad Preferences type root
481 syncable::Id bad_type_root_id = syncable::Id::CreateFromServerId("bad");
482 index_.Insert(MakeTypeRoot(PREFERENCES, bad_type_root_id));
483
484 // Insert two Preferences entries with implicit parent.
485 index_.Insert(MakeUniqueClientItem(PREFERENCES, 1));
486 index_.Insert(MakeUniqueClientItem(PREFERENCES, 2));
487
488 // The index should still be able to associate Preferences entries
489 // with the good and bad roots.
490 const OrderedChildSet* children = index_.GetChildren(type_root_id);
491 ASSERT_TRUE(children);
492 EXPECT_EQ(2UL, children->size());
493 const OrderedChildSet* children_bad = index_.GetChildren(bad_type_root_id);
494 ASSERT_TRUE(children_bad);
495 EXPECT_EQ(2UL, children_bad->size());
496 }
497
498 // Test that if for some reason we wind up with multiple type roots, we
499 // gracefully handle it and don't allow any new entities to become invisible.
500 // Same as above but with the roots created in inverse order.
501 TEST_F(ParentChildIndexTest, MultipleTypeRootsInverse) {
502 // Create the bad Preferences type root
503 syncable::Id bad_type_root_id = syncable::Id::CreateFromServerId("bad");
504 index_.Insert(MakeTypeRoot(PREFERENCES, bad_type_root_id));
505
506 // Then insert the good Preferences type root.
507 syncable::Id type_root_id = syncable::Id::CreateFromClientString("type_root");
508 index_.Insert(MakeTypeRoot(PREFERENCES, type_root_id));
509
510 // Insert two Preferences entries with implicit parent.
511 index_.Insert(MakeUniqueClientItem(PREFERENCES, 1));
512 index_.Insert(MakeUniqueClientItem(PREFERENCES, 2));
513
514 // The index should still be able to associate Preferences entries
515 // with the good root and bad roots.
516 const OrderedChildSet* children = index_.GetChildren(type_root_id);
517 ASSERT_TRUE(children);
518 EXPECT_EQ(2UL, children->size());
519 const OrderedChildSet* children_bad = index_.GetChildren(bad_type_root_id);
520 ASSERT_TRUE(children_bad);
521 EXPECT_EQ(2UL, children_bad->size());
522 }
523
524 } // namespace syncable
525 } // namespace syncer
526
OLDNEW
« no previous file with comments | « sync/syncable/parent_child_index.cc ('k') | sync/syncable/scoped_kernel_lock.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698