Try to work around that clang/win bug in another file.
[chromium-blink-merge.git] / components / sync_driver / generic_change_processor_unittest.cc
blobf7ed4321ee5a199411751c39eb2e9b3770ac3dda
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.
5 #include "components/sync_driver/generic_change_processor.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/memory/weak_ptr.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/run_loop.h"
11 #include "base/strings/stringprintf.h"
12 #include "components/sync_driver/data_type_error_handler_mock.h"
13 #include "components/sync_driver/sync_api_component_factory.h"
14 #include "sync/api/attachments/attachment_id.h"
15 #include "sync/api/attachments/attachment_store.h"
16 #include "sync/api/fake_syncable_service.h"
17 #include "sync/api/sync_change.h"
18 #include "sync/api/sync_merge_result.h"
19 #include "sync/internal_api/public/attachments/attachment_service_impl.h"
20 #include "sync/internal_api/public/attachments/fake_attachment_downloader.h"
21 #include "sync/internal_api/public/attachments/fake_attachment_uploader.h"
22 #include "sync/internal_api/public/base/model_type.h"
23 #include "sync/internal_api/public/read_node.h"
24 #include "sync/internal_api/public/read_transaction.h"
25 #include "sync/internal_api/public/sync_encryption_handler.h"
26 #include "sync/internal_api/public/test/test_user_share.h"
27 #include "sync/internal_api/public/user_share.h"
28 #include "sync/internal_api/public/write_node.h"
29 #include "sync/internal_api/public/write_transaction.h"
30 #include "testing/gmock/include/gmock/gmock-matchers.h"
31 #include "testing/gtest/include/gtest/gtest.h"
33 namespace sync_driver {
35 namespace {
37 // A mock that keeps track of attachments passed to UploadAttachments.
38 class MockAttachmentService : public syncer::AttachmentServiceImpl {
39 public:
40 MockAttachmentService(
41 scoped_ptr<syncer::AttachmentStoreForSync> attachment_store);
42 ~MockAttachmentService() override;
43 void UploadAttachments(
44 const syncer::AttachmentIdList& attachment_ids) override;
45 std::vector<syncer::AttachmentIdList>* attachment_id_lists();
47 private:
48 std::vector<syncer::AttachmentIdList> attachment_id_lists_;
51 MockAttachmentService::MockAttachmentService(
52 scoped_ptr<syncer::AttachmentStoreForSync> attachment_store)
53 : AttachmentServiceImpl(attachment_store.Pass(),
54 scoped_ptr<syncer::AttachmentUploader>(
55 new syncer::FakeAttachmentUploader),
56 scoped_ptr<syncer::AttachmentDownloader>(
57 new syncer::FakeAttachmentDownloader),
58 NULL,
59 base::TimeDelta(),
60 base::TimeDelta()) {
63 MockAttachmentService::~MockAttachmentService() {
66 void MockAttachmentService::UploadAttachments(
67 const syncer::AttachmentIdList& attachment_ids) {
68 attachment_id_lists_.push_back(attachment_ids);
69 AttachmentServiceImpl::UploadAttachments(attachment_ids);
72 std::vector<syncer::AttachmentIdList>*
73 MockAttachmentService::attachment_id_lists() {
74 return &attachment_id_lists_;
77 // MockSyncApiComponentFactory needed to initialize GenericChangeProcessor and
78 // pass MockAttachmentService to it.
79 class MockSyncApiComponentFactory : public SyncApiComponentFactory {
80 public:
81 MockSyncApiComponentFactory() {}
83 base::WeakPtr<syncer::SyncableService> GetSyncableServiceForType(
84 syncer::ModelType type) override {
85 // Shouldn't be called for this test.
86 NOTREACHED();
87 return base::WeakPtr<syncer::SyncableService>();
90 scoped_ptr<syncer::AttachmentService> CreateAttachmentService(
91 scoped_ptr<syncer::AttachmentStoreForSync> attachment_store,
92 const syncer::UserShare& user_share,
93 const std::string& store_birthday,
94 syncer::ModelType model_type,
95 syncer::AttachmentService::Delegate* delegate) override {
96 scoped_ptr<MockAttachmentService> attachment_service(
97 new MockAttachmentService(attachment_store.Pass()));
98 // GenericChangeProcessor takes ownership of the AttachmentService, but we
99 // need to have a pointer to it so we can see that it was used properly.
100 // Take a pointer and trust that GenericChangeProcessor does not prematurely
101 // destroy it.
102 mock_attachment_service_ = attachment_service.get();
103 return attachment_service.Pass();
106 MockAttachmentService* GetMockAttachmentService() {
107 return mock_attachment_service_;
110 private:
111 MockAttachmentService* mock_attachment_service_;
114 class SyncGenericChangeProcessorTest : public testing::Test {
115 public:
116 // Most test cases will use this type. For those that need a
117 // GenericChangeProcessor for a different type, use |InitializeForType|.
118 static const syncer::ModelType kType = syncer::PREFERENCES;
120 SyncGenericChangeProcessorTest()
121 : syncable_service_ptr_factory_(&fake_syncable_service_),
122 mock_attachment_service_(NULL) {}
124 void SetUp() override {
125 // Use kType by default, but allow test cases to re-initialize with whatever
126 // type they choose. Therefore, it's important that all type dependent
127 // initialization occurs in InitializeForType.
128 InitializeForType(kType);
131 void TearDown() override {
132 mock_attachment_service_ = NULL;
133 if (test_user_share_) {
134 test_user_share_->TearDown();
138 // Initialize GenericChangeProcessor and related classes for testing with
139 // model type |type|.
140 void InitializeForType(syncer::ModelType type) {
141 TearDown();
142 test_user_share_.reset(new syncer::TestUserShare);
143 test_user_share_->SetUp();
144 sync_merge_result_.reset(new syncer::SyncMergeResult(type));
145 merge_result_ptr_factory_.reset(
146 new base::WeakPtrFactory<syncer::SyncMergeResult>(
147 sync_merge_result_.get()));
149 syncer::ModelTypeSet types = syncer::ProtocolTypes();
150 for (syncer::ModelTypeSet::Iterator iter = types.First(); iter.Good();
151 iter.Inc()) {
152 syncer::TestUserShare::CreateRoot(iter.Get(),
153 test_user_share_->user_share());
155 test_user_share_->encryption_handler()->Init();
156 ConstructGenericChangeProcessor(type);
159 void ConstructGenericChangeProcessor(syncer::ModelType type) {
160 MockSyncApiComponentFactory sync_factory;
161 scoped_ptr<syncer::AttachmentStore> attachment_store =
162 syncer::AttachmentStore::CreateInMemoryStore();
163 change_processor_.reset(new GenericChangeProcessor(
164 type, &data_type_error_handler_,
165 syncable_service_ptr_factory_.GetWeakPtr(),
166 merge_result_ptr_factory_->GetWeakPtr(), test_user_share_->user_share(),
167 &sync_factory, attachment_store->CreateAttachmentStoreForSync()));
168 mock_attachment_service_ = sync_factory.GetMockAttachmentService();
171 void BuildChildNodes(syncer::ModelType type, int n) {
172 syncer::WriteTransaction trans(FROM_HERE, user_share());
173 syncer::ReadNode root(&trans);
174 ASSERT_EQ(syncer::BaseNode::INIT_OK, root.InitTypeRoot(type));
175 for (int i = 0; i < n; ++i) {
176 syncer::WriteNode node(&trans);
177 node.InitUniqueByCreation(type, root, base::StringPrintf("node%05d", i));
181 GenericChangeProcessor* change_processor() {
182 return change_processor_.get();
185 syncer::UserShare* user_share() {
186 return test_user_share_->user_share();
189 MockAttachmentService* mock_attachment_service() {
190 return mock_attachment_service_;
193 void RunLoop() {
194 base::RunLoop run_loop;
195 run_loop.RunUntilIdle();
198 private:
199 base::MessageLoopForUI loop_;
201 scoped_ptr<syncer::SyncMergeResult> sync_merge_result_;
202 scoped_ptr<base::WeakPtrFactory<syncer::SyncMergeResult> >
203 merge_result_ptr_factory_;
205 syncer::FakeSyncableService fake_syncable_service_;
206 base::WeakPtrFactory<syncer::FakeSyncableService>
207 syncable_service_ptr_factory_;
209 DataTypeErrorHandlerMock data_type_error_handler_;
210 scoped_ptr<syncer::TestUserShare> test_user_share_;
211 MockAttachmentService* mock_attachment_service_;
213 scoped_ptr<GenericChangeProcessor> change_processor_;
216 // Similar to above, but focused on the method that implements sync/api
217 // interfaces and is hence exposed to datatypes directly.
218 TEST_F(SyncGenericChangeProcessorTest, StressGetAllSyncData) {
219 const int kNumChildNodes = 1000;
220 const int kRepeatCount = 1;
222 ASSERT_NO_FATAL_FAILURE(BuildChildNodes(kType, kNumChildNodes));
224 for (int i = 0; i < kRepeatCount; ++i) {
225 syncer::SyncDataList sync_data =
226 change_processor()->GetAllSyncData(kType);
228 // Start with a simple test. We can add more in-depth testing later.
229 EXPECT_EQ(static_cast<size_t>(kNumChildNodes), sync_data.size());
233 TEST_F(SyncGenericChangeProcessorTest, SetGetPasswords) {
234 InitializeForType(syncer::PASSWORDS);
235 const int kNumPasswords = 10;
236 sync_pb::PasswordSpecificsData password_data;
237 password_data.set_username_value("user");
239 sync_pb::EntitySpecifics password_holder;
241 syncer::SyncChangeList change_list;
242 for (int i = 0; i < kNumPasswords; ++i) {
243 password_data.set_password_value(
244 base::StringPrintf("password%i", i));
245 password_holder.mutable_password()->mutable_client_only_encrypted_data()->
246 CopyFrom(password_data);
247 change_list.push_back(
248 syncer::SyncChange(FROM_HERE,
249 syncer::SyncChange::ACTION_ADD,
250 syncer::SyncData::CreateLocalData(
251 base::StringPrintf("tag%i", i),
252 base::StringPrintf("title%i", i),
253 password_holder)));
256 ASSERT_FALSE(
257 change_processor()->ProcessSyncChanges(FROM_HERE, change_list).IsSet());
259 syncer::SyncDataList password_list(
260 change_processor()->GetAllSyncData(syncer::PASSWORDS));
262 ASSERT_EQ(password_list.size(), change_list.size());
263 for (int i = 0; i < kNumPasswords; ++i) {
264 // Verify the password is returned properly.
265 ASSERT_TRUE(password_list[i].GetSpecifics().has_password());
266 ASSERT_TRUE(password_list[i].GetSpecifics().password().
267 has_client_only_encrypted_data());
268 ASSERT_FALSE(password_list[i].GetSpecifics().password().has_encrypted());
269 const sync_pb::PasswordSpecificsData& sync_password =
270 password_list[i].GetSpecifics().password().client_only_encrypted_data();
271 const sync_pb::PasswordSpecificsData& change_password =
272 change_list[i].sync_data().GetSpecifics().password().
273 client_only_encrypted_data();
274 ASSERT_EQ(sync_password.password_value(), change_password.password_value());
275 ASSERT_EQ(sync_password.username_value(), change_password.username_value());
277 // Verify the raw sync data was stored securely.
278 syncer::ReadTransaction read_transaction(FROM_HERE, user_share());
279 syncer::ReadNode node(&read_transaction);
280 ASSERT_EQ(node.InitByClientTagLookup(syncer::PASSWORDS,
281 base::StringPrintf("tag%i", i)),
282 syncer::BaseNode::INIT_OK);
283 ASSERT_EQ(node.GetTitle(), "encrypted");
284 const sync_pb::EntitySpecifics& raw_specifics = node.GetEntitySpecifics();
285 ASSERT_TRUE(raw_specifics.has_password());
286 ASSERT_TRUE(raw_specifics.password().has_encrypted());
287 ASSERT_FALSE(raw_specifics.password().has_client_only_encrypted_data());
291 TEST_F(SyncGenericChangeProcessorTest, UpdatePasswords) {
292 InitializeForType(syncer::PASSWORDS);
293 const int kNumPasswords = 10;
294 sync_pb::PasswordSpecificsData password_data;
295 password_data.set_username_value("user");
297 sync_pb::EntitySpecifics password_holder;
299 syncer::SyncChangeList change_list;
300 syncer::SyncChangeList change_list2;
301 for (int i = 0; i < kNumPasswords; ++i) {
302 password_data.set_password_value(
303 base::StringPrintf("password%i", i));
304 password_holder.mutable_password()->mutable_client_only_encrypted_data()->
305 CopyFrom(password_data);
306 change_list.push_back(
307 syncer::SyncChange(FROM_HERE,
308 syncer::SyncChange::ACTION_ADD,
309 syncer::SyncData::CreateLocalData(
310 base::StringPrintf("tag%i", i),
311 base::StringPrintf("title%i", i),
312 password_holder)));
313 password_data.set_password_value(
314 base::StringPrintf("password_m%i", i));
315 password_holder.mutable_password()->mutable_client_only_encrypted_data()->
316 CopyFrom(password_data);
317 change_list2.push_back(
318 syncer::SyncChange(FROM_HERE,
319 syncer::SyncChange::ACTION_UPDATE,
320 syncer::SyncData::CreateLocalData(
321 base::StringPrintf("tag%i", i),
322 base::StringPrintf("title_m%i", i),
323 password_holder)));
326 ASSERT_FALSE(
327 change_processor()->ProcessSyncChanges(FROM_HERE, change_list).IsSet());
328 ASSERT_FALSE(
329 change_processor()->ProcessSyncChanges(FROM_HERE, change_list2).IsSet());
331 syncer::SyncDataList password_list(
332 change_processor()->GetAllSyncData(syncer::PASSWORDS));
334 ASSERT_EQ(password_list.size(), change_list2.size());
335 for (int i = 0; i < kNumPasswords; ++i) {
336 // Verify the password is returned properly.
337 ASSERT_TRUE(password_list[i].GetSpecifics().has_password());
338 ASSERT_TRUE(password_list[i].GetSpecifics().password().
339 has_client_only_encrypted_data());
340 ASSERT_FALSE(password_list[i].GetSpecifics().password().has_encrypted());
341 const sync_pb::PasswordSpecificsData& sync_password =
342 password_list[i].GetSpecifics().password().client_only_encrypted_data();
343 const sync_pb::PasswordSpecificsData& change_password =
344 change_list2[i].sync_data().GetSpecifics().password().
345 client_only_encrypted_data();
346 ASSERT_EQ(sync_password.password_value(), change_password.password_value());
347 ASSERT_EQ(sync_password.username_value(), change_password.username_value());
349 // Verify the raw sync data was stored securely.
350 syncer::ReadTransaction read_transaction(FROM_HERE, user_share());
351 syncer::ReadNode node(&read_transaction);
352 ASSERT_EQ(node.InitByClientTagLookup(syncer::PASSWORDS,
353 base::StringPrintf("tag%i", i)),
354 syncer::BaseNode::INIT_OK);
355 ASSERT_EQ(node.GetTitle(), "encrypted");
356 const sync_pb::EntitySpecifics& raw_specifics = node.GetEntitySpecifics();
357 ASSERT_TRUE(raw_specifics.has_password());
358 ASSERT_TRUE(raw_specifics.password().has_encrypted());
359 ASSERT_FALSE(raw_specifics.password().has_client_only_encrypted_data());
363 // Verify that attachments on newly added or updated SyncData are passed to the
364 // AttachmentService.
365 TEST_F(SyncGenericChangeProcessorTest,
366 ProcessSyncChanges_AddUpdateWithAttachment) {
367 std::string tag = "client_tag";
368 std::string title = "client_title";
369 sync_pb::EntitySpecifics specifics;
370 sync_pb::PreferenceSpecifics* pref_specifics = specifics.mutable_preference();
371 pref_specifics->set_name("test");
373 syncer::AttachmentIdList attachment_ids;
374 attachment_ids.push_back(syncer::AttachmentId::Create(0, 0));
375 attachment_ids.push_back(syncer::AttachmentId::Create(0, 0));
377 // Add a SyncData with two attachments.
378 syncer::SyncChangeList change_list;
379 change_list.push_back(
380 syncer::SyncChange(FROM_HERE,
381 syncer::SyncChange::ACTION_ADD,
382 syncer::SyncData::CreateLocalDataWithAttachments(
383 tag, title, specifics, attachment_ids)));
384 ASSERT_FALSE(
385 change_processor()->ProcessSyncChanges(FROM_HERE, change_list).IsSet());
386 RunLoop();
388 // Check that the AttachmentService received the new attachments.
389 ASSERT_EQ(mock_attachment_service()->attachment_id_lists()->size(), 1U);
390 const syncer::AttachmentIdList& attachments_added =
391 mock_attachment_service()->attachment_id_lists()->front();
392 ASSERT_THAT(
393 attachments_added,
394 testing::UnorderedElementsAre(attachment_ids[0], attachment_ids[1]));
396 // Update the SyncData, replacing its two attachments with one new attachment.
397 syncer::AttachmentIdList new_attachment_ids;
398 new_attachment_ids.push_back(syncer::AttachmentId::Create(0, 0));
399 mock_attachment_service()->attachment_id_lists()->clear();
400 change_list.clear();
401 change_list.push_back(
402 syncer::SyncChange(FROM_HERE,
403 syncer::SyncChange::ACTION_UPDATE,
404 syncer::SyncData::CreateLocalDataWithAttachments(
405 tag, title, specifics, new_attachment_ids)));
406 ASSERT_FALSE(
407 change_processor()->ProcessSyncChanges(FROM_HERE, change_list).IsSet());
408 RunLoop();
410 // Check that the AttachmentService received it.
411 ASSERT_EQ(mock_attachment_service()->attachment_id_lists()->size(), 1U);
412 const syncer::AttachmentIdList& new_attachments_added =
413 mock_attachment_service()->attachment_id_lists()->front();
414 ASSERT_THAT(new_attachments_added,
415 testing::UnorderedElementsAre(new_attachment_ids[0]));
418 // Verify that after attachment is uploaded GenericChangeProcessor updates
419 // corresponding entries
420 TEST_F(SyncGenericChangeProcessorTest, AttachmentUploaded) {
421 std::string tag = "client_tag";
422 std::string title = "client_title";
423 sync_pb::EntitySpecifics specifics;
424 sync_pb::PreferenceSpecifics* pref_specifics = specifics.mutable_preference();
425 pref_specifics->set_name("test");
427 syncer::AttachmentIdList attachment_ids;
428 attachment_ids.push_back(syncer::AttachmentId::Create(0, 0));
430 // Add a SyncData with two attachments.
431 syncer::SyncChangeList change_list;
432 change_list.push_back(
433 syncer::SyncChange(FROM_HERE,
434 syncer::SyncChange::ACTION_ADD,
435 syncer::SyncData::CreateLocalDataWithAttachments(
436 tag, title, specifics, attachment_ids)));
437 ASSERT_FALSE(
438 change_processor()->ProcessSyncChanges(FROM_HERE, change_list).IsSet());
440 sync_pb::AttachmentIdProto attachment_id_proto = attachment_ids[0].GetProto();
441 syncer::AttachmentId attachment_id =
442 syncer::AttachmentId::CreateFromProto(attachment_id_proto);
444 change_processor()->OnAttachmentUploaded(attachment_id);
445 syncer::ReadTransaction read_transaction(FROM_HERE, user_share());
446 syncer::ReadNode node(&read_transaction);
447 ASSERT_EQ(node.InitByClientTagLookup(kType, tag), syncer::BaseNode::INIT_OK);
448 attachment_ids = node.GetAttachmentIds();
449 EXPECT_EQ(1U, attachment_ids.size());
452 // Verify that upon construction, all attachments not yet on the server are
453 // scheduled for upload.
454 TEST_F(SyncGenericChangeProcessorTest, UploadAllAttachmentsNotOnServer) {
455 // Create two attachment ids. id2 will be marked as "on server".
456 syncer::AttachmentId id1 = syncer::AttachmentId::Create(0, 0);
457 syncer::AttachmentId id2 = syncer::AttachmentId::Create(0, 0);
459 // Write an entry containing these two attachment ids.
460 syncer::WriteTransaction trans(FROM_HERE, user_share());
461 syncer::ReadNode root(&trans);
462 ASSERT_EQ(syncer::BaseNode::INIT_OK, root.InitTypeRoot(kType));
463 syncer::WriteNode node(&trans);
464 node.InitUniqueByCreation(kType, root, "some node");
465 sync_pb::AttachmentMetadata metadata;
466 sync_pb::AttachmentMetadataRecord* record1 = metadata.add_record();
467 *record1->mutable_id() = id1.GetProto();
468 sync_pb::AttachmentMetadataRecord* record2 = metadata.add_record();
469 *record2->mutable_id() = id2.GetProto();
470 record2->set_is_on_server(true);
471 node.SetAttachmentMetadata(metadata);
474 // Construct the GenericChangeProcessor and see that it asks the
475 // AttachmentService to upload id1 only.
476 ConstructGenericChangeProcessor(kType);
477 ASSERT_EQ(1U, mock_attachment_service()->attachment_id_lists()->size());
478 ASSERT_THAT(mock_attachment_service()->attachment_id_lists()->front(),
479 testing::UnorderedElementsAre(id1));
482 // Test that attempting to add an entry that already exists still works.
483 TEST_F(SyncGenericChangeProcessorTest, AddExistingEntry) {
484 InitializeForType(syncer::SESSIONS);
485 sync_pb::EntitySpecifics sessions_specifics;
486 sessions_specifics.mutable_session()->set_session_tag("session tag");
487 syncer::SyncChangeList changes;
489 // First add it normally.
490 changes.push_back(syncer::SyncChange(
491 FROM_HERE, syncer::SyncChange::ACTION_ADD,
492 syncer::SyncData::CreateLocalData(base::StringPrintf("tag"),
493 base::StringPrintf("title"),
494 sessions_specifics)));
495 ASSERT_FALSE(
496 change_processor()->ProcessSyncChanges(FROM_HERE, changes).IsSet());
498 // Now attempt to add it again, but with different specifics. Should not
499 // result in an error and should still update the specifics.
500 sessions_specifics.mutable_session()->set_session_tag("session tag 2");
501 changes[0] =
502 syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_ADD,
503 syncer::SyncData::CreateLocalData(
504 base::StringPrintf("tag"),
505 base::StringPrintf("title"), sessions_specifics));
506 ASSERT_FALSE(
507 change_processor()->ProcessSyncChanges(FROM_HERE, changes).IsSet());
509 // Verify the data was updated properly.
510 syncer::SyncDataList sync_data =
511 change_processor()->GetAllSyncData(syncer::SESSIONS);
512 ASSERT_EQ(sync_data.size(), 1U);
513 ASSERT_EQ("session tag 2",
514 sync_data[0].GetSpecifics().session().session_tag());
517 } // namespace
519 } // namespace sync_driver