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

Side by Side Diff: sync/engine/directory_commit_contribution_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
OLDNEW
(Empty)
1 // Copyright 2014 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/engine/directory_commit_contribution.h"
6
7 #include <stdint.h>
8
9 #include <set>
10 #include <string>
11
12 #include "base/message_loop/message_loop.h"
13 #include "sync/internal_api/public/base/attachment_id_proto.h"
14 #include "sync/sessions/status_controller.h"
15 #include "sync/syncable/entry.h"
16 #include "sync/syncable/mutable_entry.h"
17 #include "sync/syncable/syncable_read_transaction.h"
18 #include "sync/syncable/syncable_write_transaction.h"
19 #include "sync/test/engine/test_directory_setter_upper.h"
20 #include "sync/test/engine/test_id_factory.h"
21 #include "sync/test/engine/test_syncable_utils.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23
24 namespace syncer {
25
26 class DirectoryCommitContributionTest : public ::testing::Test {
27 public:
28 void SetUp() override {
29 dir_maker_.SetUp();
30
31 syncable::WriteTransaction trans(FROM_HERE, syncable::UNITTEST, dir());
32 CreateTypeRoot(&trans, dir(), PREFERENCES);
33 CreateTypeRoot(&trans, dir(), EXTENSIONS);
34 CreateTypeRoot(&trans, dir(), ARTICLES);
35 CreateTypeRoot(&trans, dir(), BOOKMARKS);
36 }
37
38 void TearDown() override { dir_maker_.TearDown(); }
39
40 protected:
41 int64_t CreateUnsyncedItemWithAttachments(
42 syncable::WriteTransaction* trans,
43 ModelType type,
44 const std::string& tag,
45 const sync_pb::AttachmentMetadata& attachment_metadata) {
46 // For bookmarks specify the Bookmarks root folder as the parent;
47 // for other types leave the parent ID empty
48 syncable::Id parent_id;
49 if (type == BOOKMARKS) {
50 syncable::Entry parent_entry(trans, syncable::GET_TYPE_ROOT, type);
51 parent_id = parent_entry.GetId();
52 }
53
54 syncable::MutableEntry entry(trans, syncable::CREATE, type, parent_id, tag);
55 if (attachment_metadata.record_size() > 0) {
56 entry.PutAttachmentMetadata(attachment_metadata);
57 }
58 entry.PutIsUnsynced(true);
59 return entry.GetMetahandle();
60 }
61
62 int64_t CreateUnsyncedItem(syncable::WriteTransaction* trans,
63 ModelType type,
64 const std::string& tag) {
65 return CreateUnsyncedItemWithAttachments(
66 trans, type, tag, sync_pb::AttachmentMetadata());
67 }
68
69 int64_t CreateSyncedItem(syncable::WriteTransaction* trans,
70 ModelType type,
71 const std::string& tag) {
72 syncable::Entry parent_entry(trans, syncable::GET_TYPE_ROOT, type);
73 syncable::MutableEntry entry(
74 trans,
75 syncable::CREATE,
76 type,
77 parent_entry.GetId(),
78 tag);
79
80 entry.PutId(syncable::Id::CreateFromServerId(
81 id_factory_.NewServerId().GetServerId()));
82 entry.PutBaseVersion(10);
83 entry.PutServerVersion(10);
84 entry.PutIsUnappliedUpdate(false);
85 entry.PutIsUnsynced(false);
86 entry.PutIsDel(false);
87 entry.PutServerIsDel(false);
88
89 return entry.GetMetahandle();
90 }
91
92 void CreateSuccessfulCommitResponse(
93 const sync_pb::SyncEntity& entity,
94 sync_pb::CommitResponse::EntryResponse* response) {
95 response->set_response_type(sync_pb::CommitResponse::SUCCESS);
96 response->set_non_unique_name(entity.name());
97 response->set_version(entity.version() + 1);
98 response->set_parent_id_string(entity.parent_id_string());
99
100 if (entity.id_string()[0] == '-') // Look for the - in 'c-1234' style IDs.
101 response->set_id_string(id_factory_.NewServerId().GetServerId());
102 else
103 response->set_id_string(entity.id_string());
104 }
105
106 syncable::Directory* dir() {
107 return dir_maker_.directory();
108 }
109
110 TestIdFactory id_factory_;
111
112 // Used in construction of DirectoryTypeDebugInfoEmitters.
113 base::ObserverList<TypeDebugInfoObserver> type_observers_;
114
115 private:
116 base::MessageLoop loop_; // Neeed to initialize the directory.
117 TestDirectorySetterUpper dir_maker_;
118 };
119
120 // Verify that the DirectoryCommitContribution contains only entries of its
121 // specified type.
122 TEST_F(DirectoryCommitContributionTest, GatherByTypes) {
123 int64_t pref1;
124 {
125 syncable::WriteTransaction trans(FROM_HERE, syncable::UNITTEST, dir());
126 pref1 = CreateUnsyncedItem(&trans, PREFERENCES, "pref1");
127 CreateUnsyncedItem(&trans, PREFERENCES, "pref2");
128 CreateUnsyncedItem(&trans, EXTENSIONS, "extension1");
129 }
130
131 DirectoryTypeDebugInfoEmitter emitter(PREFERENCES, &type_observers_);
132 std::unique_ptr<DirectoryCommitContribution> cc(
133 DirectoryCommitContribution::Build(dir(), PREFERENCES, 5, &emitter));
134 ASSERT_EQ(2U, cc->GetNumEntries());
135
136 const std::vector<int64_t>& metahandles = cc->metahandles_;
137 EXPECT_TRUE(std::find(metahandles.begin(), metahandles.end(), pref1) !=
138 metahandles.end());
139 EXPECT_TRUE(std::find(metahandles.begin(), metahandles.end(), pref1) !=
140 metahandles.end());
141
142 cc->CleanUp();
143 }
144
145 // Verify that the DirectoryCommitContributionTest builder function
146 // truncates if necessary.
147 TEST_F(DirectoryCommitContributionTest, GatherAndTruncate) {
148 int64_t pref1;
149 int64_t pref2;
150 {
151 syncable::WriteTransaction trans(FROM_HERE, syncable::UNITTEST, dir());
152 pref1 = CreateUnsyncedItem(&trans, PREFERENCES, "pref1");
153 pref2 = CreateUnsyncedItem(&trans, PREFERENCES, "pref2");
154 CreateUnsyncedItem(&trans, EXTENSIONS, "extension1");
155 }
156
157 DirectoryTypeDebugInfoEmitter emitter(PREFERENCES, &type_observers_);
158 std::unique_ptr<DirectoryCommitContribution> cc(
159 DirectoryCommitContribution::Build(dir(), PREFERENCES, 1, &emitter));
160 ASSERT_EQ(1U, cc->GetNumEntries());
161
162 int64_t only_metahandle = cc->metahandles_[0];
163 EXPECT_TRUE(only_metahandle == pref1 || only_metahandle == pref2);
164
165 cc->CleanUp();
166 }
167
168 // Sanity check for building commits from DirectoryCommitContributions.
169 // This test makes two CommitContribution objects of different types and uses
170 // them to initialize a commit message. Then it checks that the contents of the
171 // commit message match those of the directory they came from.
172 TEST_F(DirectoryCommitContributionTest, PrepareCommit) {
173 {
174 syncable::WriteTransaction trans(FROM_HERE, syncable::UNITTEST, dir());
175 CreateUnsyncedItem(&trans, PREFERENCES, "pref1");
176 CreateUnsyncedItem(&trans, PREFERENCES, "pref2");
177 CreateUnsyncedItem(&trans, EXTENSIONS, "extension1");
178 }
179
180 DirectoryTypeDebugInfoEmitter emitter1(PREFERENCES, &type_observers_);
181 DirectoryTypeDebugInfoEmitter emitter2(EXTENSIONS, &type_observers_);
182 std::unique_ptr<DirectoryCommitContribution> pref_cc(
183 DirectoryCommitContribution::Build(dir(), PREFERENCES, 25, &emitter1));
184 std::unique_ptr<DirectoryCommitContribution> ext_cc(
185 DirectoryCommitContribution::Build(dir(), EXTENSIONS, 25, &emitter2));
186
187 sync_pb::ClientToServerMessage message;
188 pref_cc->AddToCommitMessage(&message);
189 ext_cc->AddToCommitMessage(&message);
190
191 const sync_pb::CommitMessage& commit_message = message.commit();
192
193 std::set<syncable::Id> ids_for_commit;
194 ASSERT_EQ(3, commit_message.entries_size());
195 for (int i = 0; i < commit_message.entries_size(); ++i) {
196 const sync_pb::SyncEntity& entity = commit_message.entries(i);
197 // The entities in this test have client-style IDs since they've never been
198 // committed before, so we must use CreateFromClientString to re-create them
199 // from the commit message.
200 ids_for_commit.insert(syncable::Id::CreateFromClientString(
201 entity.id_string()));
202 }
203
204 ASSERT_EQ(3U, ids_for_commit.size());
205 {
206 syncable::ReadTransaction trans(FROM_HERE, dir());
207 for (std::set<syncable::Id>::iterator it = ids_for_commit.begin();
208 it != ids_for_commit.end(); ++it) {
209 SCOPED_TRACE(it->value());
210 syncable::Entry entry(&trans, syncable::GET_BY_ID, *it);
211 ASSERT_TRUE(entry.good());
212 EXPECT_TRUE(entry.GetSyncing());
213 EXPECT_FALSE(entry.GetDirtySync());
214 }
215 }
216
217 pref_cc->CleanUp();
218 ext_cc->CleanUp();
219 }
220
221 // Check that deletion requests include a model type.
222 // This was not always the case, but was implemented to allow us to loosen some
223 // other restrictions in the protocol.
224 TEST_F(DirectoryCommitContributionTest, DeletedItemsWithSpecifics) {
225 int64_t pref1;
226 {
227 syncable::WriteTransaction trans(FROM_HERE, syncable::UNITTEST, dir());
228 pref1 = CreateSyncedItem(&trans, PREFERENCES, "pref1");
229 syncable::MutableEntry e1(&trans, syncable::GET_BY_HANDLE, pref1);
230 e1.PutIsDel(true);
231 e1.PutIsUnsynced(true);
232 }
233
234 DirectoryTypeDebugInfoEmitter emitter(PREFERENCES, &type_observers_);
235 std::unique_ptr<DirectoryCommitContribution> pref_cc(
236 DirectoryCommitContribution::Build(dir(), PREFERENCES, 25, &emitter));
237 ASSERT_TRUE(pref_cc);
238
239 sync_pb::ClientToServerMessage message;
240 pref_cc->AddToCommitMessage(&message);
241
242 const sync_pb::CommitMessage& commit_message = message.commit();
243 ASSERT_EQ(1, commit_message.entries_size());
244 EXPECT_TRUE(
245 commit_message.entries(0).specifics().has_preference());
246
247 pref_cc->CleanUp();
248 }
249
250 // As ususal, bookmarks are special. Bookmark deletion is special.
251 // Deleted bookmarks include a valid "is folder" bit and their full specifics
252 // (especially the meta info, which is what server really wants).
253 TEST_F(DirectoryCommitContributionTest, DeletedBookmarksWithSpecifics) {
254 int64_t bm1;
255 {
256 syncable::WriteTransaction trans(FROM_HERE, syncable::UNITTEST, dir());
257 bm1 = CreateSyncedItem(&trans, BOOKMARKS, "bm1");
258 syncable::MutableEntry e1(&trans, syncable::GET_BY_HANDLE, bm1);
259
260 e1.PutIsDir(true);
261 e1.PutServerIsDir(true);
262
263 sync_pb::EntitySpecifics specifics;
264 sync_pb::BookmarkSpecifics* bm_specifics = specifics.mutable_bookmark();
265 bm_specifics->set_url("http://www.chrome.com");
266 bm_specifics->set_title("Chrome");
267 sync_pb::MetaInfo* meta_info = bm_specifics->add_meta_info();
268 meta_info->set_key("K");
269 meta_info->set_value("V");
270 e1.PutSpecifics(specifics);
271
272 e1.PutIsDel(true);
273 e1.PutIsUnsynced(true);
274 }
275
276 DirectoryTypeDebugInfoEmitter emitter(BOOKMARKS, &type_observers_);
277 std::unique_ptr<DirectoryCommitContribution> bm_cc(
278 DirectoryCommitContribution::Build(dir(), BOOKMARKS, 25, &emitter));
279 ASSERT_TRUE(bm_cc);
280
281 sync_pb::ClientToServerMessage message;
282 bm_cc->AddToCommitMessage(&message);
283
284 const sync_pb::CommitMessage& commit_message = message.commit();
285 ASSERT_EQ(1, commit_message.entries_size());
286
287 const sync_pb::SyncEntity& entity = commit_message.entries(0);
288 EXPECT_TRUE(entity.has_folder());
289 ASSERT_TRUE(entity.specifics().has_bookmark());
290 ASSERT_EQ(1, entity.specifics().bookmark().meta_info_size());
291 EXPECT_EQ("K", entity.specifics().bookmark().meta_info(0).key());
292 EXPECT_EQ("V", entity.specifics().bookmark().meta_info(0).value());
293
294 bm_cc->CleanUp();
295 }
296
297 // Test that bookmarks support hierarchy.
298 TEST_F(DirectoryCommitContributionTest, HierarchySupport_Bookmark) {
299 // Create a normal-looking bookmark item.
300 int64_t bm1;
301 {
302 syncable::WriteTransaction trans(FROM_HERE, syncable::UNITTEST, dir());
303 bm1 = CreateSyncedItem(&trans, BOOKMARKS, "bm1");
304 syncable::MutableEntry e(&trans, syncable::GET_BY_HANDLE, bm1);
305
306 sync_pb::EntitySpecifics specifics;
307 sync_pb::BookmarkSpecifics* bm_specifics = specifics.mutable_bookmark();
308 bm_specifics->set_url("http://www.chrome.com");
309 bm_specifics->set_title("Chrome");
310 e.PutSpecifics(specifics);
311
312 e.PutIsDel(false);
313 e.PutIsUnsynced(true);
314
315 EXPECT_TRUE(e.ShouldMaintainHierarchy());
316 }
317
318 DirectoryTypeDebugInfoEmitter emitter(BOOKMARKS, &type_observers_);
319 std::unique_ptr<DirectoryCommitContribution> bm_cc(
320 DirectoryCommitContribution::Build(dir(), BOOKMARKS, 25, &emitter));
321
322 sync_pb::ClientToServerMessage message;
323 bm_cc->AddToCommitMessage(&message);
324 const sync_pb::CommitMessage& commit_message = message.commit();
325 bm_cc->CleanUp();
326
327 ASSERT_EQ(1, commit_message.entries_size());
328 EXPECT_TRUE(commit_message.entries(0).has_parent_id_string());
329 EXPECT_FALSE(commit_message.entries(0).parent_id_string().empty());
330 }
331
332 // Test that preferences do not support hierarchy.
333 TEST_F(DirectoryCommitContributionTest, HierarchySupport_Preferences) {
334 // Create a normal-looking prefs item.
335 int64_t pref1;
336 {
337 syncable::WriteTransaction trans(FROM_HERE, syncable::UNITTEST, dir());
338 pref1 = CreateUnsyncedItem(&trans, PREFERENCES, "pref1");
339 syncable::MutableEntry e(&trans, syncable::GET_BY_HANDLE, pref1);
340
341 EXPECT_FALSE(e.ShouldMaintainHierarchy());
342 }
343
344 DirectoryTypeDebugInfoEmitter emitter(PREFERENCES, &type_observers_);
345 std::unique_ptr<DirectoryCommitContribution> pref_cc(
346 DirectoryCommitContribution::Build(dir(), PREFERENCES, 25, &emitter));
347
348 sync_pb::ClientToServerMessage message;
349 pref_cc->AddToCommitMessage(&message);
350 const sync_pb::CommitMessage& commit_message = message.commit();
351 pref_cc->CleanUp();
352
353 ASSERT_EQ(1, commit_message.entries_size());
354 EXPECT_FALSE(commit_message.entries(0).has_parent_id_string());
355 EXPECT_TRUE(commit_message.entries(0).parent_id_string().empty());
356 }
357
358 void AddAttachment(sync_pb::AttachmentMetadata* metadata, bool is_on_server) {
359 sync_pb::AttachmentMetadataRecord record;
360 *record.mutable_id() = CreateAttachmentIdProto(0, 0);
361 record.set_is_on_server(is_on_server);
362 *metadata->add_record() = record;
363 }
364
365 // Creates some unsynced items, pretends to commit them, and hands back a
366 // specially crafted response to the syncer in order to test commit response
367 // processing. The response simulates a succesful commit scenario.
368 TEST_F(DirectoryCommitContributionTest, ProcessCommitResponse) {
369 int64_t pref1_handle;
370 int64_t pref2_handle;
371 int64_t ext1_handle;
372 {
373 syncable::WriteTransaction trans(FROM_HERE, syncable::UNITTEST, dir());
374 pref1_handle = CreateUnsyncedItem(&trans, PREFERENCES, "pref1");
375 pref2_handle = CreateUnsyncedItem(&trans, PREFERENCES, "pref2");
376 ext1_handle = CreateUnsyncedItem(&trans, EXTENSIONS, "extension1");
377 }
378
379 DirectoryTypeDebugInfoEmitter emitter1(PREFERENCES, &type_observers_);
380 DirectoryTypeDebugInfoEmitter emitter2(EXTENSIONS, &type_observers_);
381 std::unique_ptr<DirectoryCommitContribution> pref_cc(
382 DirectoryCommitContribution::Build(dir(), PREFERENCES, 25, &emitter1));
383 std::unique_ptr<DirectoryCommitContribution> ext_cc(
384 DirectoryCommitContribution::Build(dir(), EXTENSIONS, 25, &emitter2));
385
386 sync_pb::ClientToServerMessage message;
387 pref_cc->AddToCommitMessage(&message);
388 ext_cc->AddToCommitMessage(&message);
389
390 const sync_pb::CommitMessage& commit_message = message.commit();
391 ASSERT_EQ(3, commit_message.entries_size());
392
393 sync_pb::ClientToServerResponse response;
394 for (int i = 0; i < commit_message.entries_size(); ++i) {
395 sync_pb::SyncEntity entity = commit_message.entries(i);
396 sync_pb::CommitResponse_EntryResponse* entry_response =
397 response.mutable_commit()->add_entryresponse();
398 CreateSuccessfulCommitResponse(entity, entry_response);
399 }
400
401 sessions::StatusController status;
402
403 // Process these in reverse order. Just because we can.
404 ext_cc->ProcessCommitResponse(response, &status);
405 pref_cc->ProcessCommitResponse(response, &status);
406
407 {
408 syncable::ReadTransaction trans(FROM_HERE, dir());
409 syncable::Entry p1(&trans, syncable::GET_BY_HANDLE, pref1_handle);
410 EXPECT_TRUE(p1.GetId().ServerKnows());
411 EXPECT_FALSE(p1.GetSyncing());
412 EXPECT_FALSE(p1.GetDirtySync());
413 EXPECT_LT(0, p1.GetServerVersion());
414
415 syncable::Entry p2(&trans, syncable::GET_BY_HANDLE, pref2_handle);
416 EXPECT_TRUE(p2.GetId().ServerKnows());
417 EXPECT_FALSE(p2.GetSyncing());
418 EXPECT_FALSE(p2.GetDirtySync());
419 EXPECT_LT(0, p2.GetServerVersion());
420
421 syncable::Entry e1(&trans, syncable::GET_BY_HANDLE, ext1_handle);
422 EXPECT_TRUE(e1.GetId().ServerKnows());
423 EXPECT_FALSE(e1.GetSyncing());
424 EXPECT_FALSE(e1.GetDirtySync());
425 EXPECT_LT(0, e1.GetServerVersion());
426 }
427
428 pref_cc->CleanUp();
429 ext_cc->CleanUp();
430 }
431
432 // Creates some unsynced items with attachments and verifies that only items
433 // where all attachments have been uploaded to the server are eligible to be
434 // committed.
435 TEST_F(DirectoryCommitContributionTest, ProcessCommitResponseWithAttachments) {
436 int64_t art1_handle;
437 int64_t art2_handle;
438 int64_t art3_handle;
439 {
440 syncable::WriteTransaction trans(FROM_HERE, syncable::UNITTEST, dir());
441
442 // art1 has two attachments, both have been uploaded to the server. art1 is
443 // eligible to be committed.
444 sync_pb::AttachmentMetadata art1_attachments;
445 AddAttachment(&art1_attachments, true /* is_on_server */);
446 AddAttachment(&art1_attachments, true /* is_on_server */);
447 art1_handle = CreateUnsyncedItemWithAttachments(
448 &trans, ARTICLES, "art1", art1_attachments);
449
450 // art2 has two attachments, one of which has been uploaded to the
451 // server. art2 is not eligible to be committed.
452 sync_pb::AttachmentMetadata art2_attachments;
453 AddAttachment(&art2_attachments, false /* is_on_server */);
454 AddAttachment(&art2_attachments, true /* is_on_server */);
455 art2_handle = CreateUnsyncedItemWithAttachments(
456 &trans, ARTICLES, "art2", art2_attachments);
457
458 // art3 has two attachments, neither of which have been uploaded to the
459 // server. art2 is not eligible to be committed.
460 sync_pb::AttachmentMetadata art3_attachments;
461 AddAttachment(&art3_attachments, false /* is_on_server */);
462 AddAttachment(&art3_attachments, false /* is_on_server */);
463 art3_handle = CreateUnsyncedItemWithAttachments(
464 &trans, ARTICLES, "art3", art3_attachments);
465 }
466
467 DirectoryTypeDebugInfoEmitter emitter(ARTICLES, &type_observers_);
468 std::unique_ptr<DirectoryCommitContribution> art_cc(
469 DirectoryCommitContribution::Build(dir(), ARTICLES, 25, &emitter));
470
471 // Only art1 is ready.
472 EXPECT_EQ(1U, art_cc->GetNumEntries());
473
474 sync_pb::ClientToServerMessage message;
475 art_cc->AddToCommitMessage(&message);
476
477 const sync_pb::CommitMessage& commit_message = message.commit();
478 ASSERT_EQ(1, commit_message.entries_size());
479
480 sync_pb::ClientToServerResponse response;
481 for (int i = 0; i < commit_message.entries_size(); ++i) {
482 sync_pb::SyncEntity entity = commit_message.entries(i);
483 sync_pb::CommitResponse_EntryResponse* entry_response =
484 response.mutable_commit()->add_entryresponse();
485 CreateSuccessfulCommitResponse(entity, entry_response);
486 }
487
488 sessions::StatusController status;
489 art_cc->ProcessCommitResponse(response, &status);
490 {
491 syncable::ReadTransaction trans(FROM_HERE, dir());
492
493 syncable::Entry a1(&trans, syncable::GET_BY_HANDLE, art1_handle);
494 EXPECT_TRUE(a1.GetId().ServerKnows());
495 EXPECT_FALSE(a1.GetSyncing());
496 EXPECT_FALSE(a1.GetDirtySync());
497 EXPECT_LT(0, a1.GetServerVersion());
498
499 syncable::Entry a2(&trans, syncable::GET_BY_HANDLE, art2_handle);
500 EXPECT_FALSE(a2.GetId().ServerKnows());
501 EXPECT_FALSE(a2.GetSyncing());
502 EXPECT_FALSE(a2.GetDirtySync());
503 EXPECT_EQ(0, a2.GetServerVersion());
504
505 syncable::Entry a3(&trans, syncable::GET_BY_HANDLE, art3_handle);
506 EXPECT_FALSE(a3.GetId().ServerKnows());
507 EXPECT_FALSE(a3.GetSyncing());
508 EXPECT_FALSE(a3.GetDirtySync());
509 EXPECT_EQ(0, a3.GetServerVersion());
510 }
511
512 art_cc->CleanUp();
513 }
514
515 } // namespace syncer
OLDNEW
« no previous file with comments | « sync/engine/directory_commit_contribution.cc ('k') | sync/engine/directory_commit_contributor.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698