GN + Android: extract android_standalone_library rule.
[chromium-blink-merge.git] / components / sync_driver / generic_change_processor_unittest.cc
blob922031b52fea407038ed9c247dae1251854a9684
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 const scoped_refptr<syncer::AttachmentStore>& attachment_store);
42 ~MockAttachmentService() override;
43 void UploadAttachments(
44 const syncer::AttachmentIdSet& attachment_ids) override;
45 std::vector<syncer::AttachmentIdSet>* attachment_id_sets();
47 private:
48 std::vector<syncer::AttachmentIdSet> attachment_id_sets_;
51 MockAttachmentService::MockAttachmentService(
52 const scoped_refptr<syncer::AttachmentStore>& attachment_store)
53 : AttachmentServiceImpl(attachment_store,
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::AttachmentIdSet& attachment_ids) {
68 attachment_id_sets_.push_back(attachment_ids);
69 AttachmentServiceImpl::UploadAttachments(attachment_ids);
72 std::vector<syncer::AttachmentIdSet>*
73 MockAttachmentService::attachment_id_sets() {
74 return &attachment_id_sets_;
77 // MockSyncApiComponentFactory needed to initialize GenericChangeProcessor and
78 // pass MockAttachmentService to it.
79 class MockSyncApiComponentFactory : public SyncApiComponentFactory {
80 public:
81 MockSyncApiComponentFactory(
82 scoped_ptr<syncer::AttachmentService> attachment_service)
83 : attachment_service_(attachment_service.Pass()) {}
85 base::WeakPtr<syncer::SyncableService> GetSyncableServiceForType(
86 syncer::ModelType type) override {
87 // Shouldn't be called for this test.
88 NOTREACHED();
89 return base::WeakPtr<syncer::SyncableService>();
92 scoped_ptr<syncer::AttachmentService> CreateAttachmentService(
93 const scoped_refptr<syncer::AttachmentStore>& attachment_store,
94 const syncer::UserShare& user_share,
95 const std::string& store_birthday,
96 syncer::AttachmentService::Delegate* delegate) override {
97 EXPECT_TRUE(attachment_service_ != NULL);
98 return attachment_service_.Pass();
101 private:
102 scoped_ptr<syncer::AttachmentService> attachment_service_;
105 class SyncGenericChangeProcessorTest : public testing::Test {
106 public:
107 // Most test cases will use this type. For those that need a
108 // GenericChangeProcessor for a different type, use |InitializeForType|.
109 static const syncer::ModelType kType = syncer::PREFERENCES;
111 SyncGenericChangeProcessorTest()
112 : syncable_service_ptr_factory_(&fake_syncable_service_),
113 mock_attachment_service_(NULL) {}
115 void SetUp() override {
116 // Use kType by default, but allow test cases to re-initialize with whatever
117 // type they choose. Therefore, it's important that all type dependent
118 // initialization occurs in InitializeForType.
119 InitializeForType(kType);
122 void TearDown() override {
123 mock_attachment_service_ = NULL;
124 if (test_user_share_) {
125 test_user_share_->TearDown();
129 // Initialize GenericChangeProcessor and related classes for testing with
130 // model type |type|.
131 void InitializeForType(syncer::ModelType type) {
132 TearDown();
133 test_user_share_.reset(new syncer::TestUserShare);
134 test_user_share_->SetUp();
135 sync_merge_result_.reset(new syncer::SyncMergeResult(type));
136 merge_result_ptr_factory_.reset(
137 new base::WeakPtrFactory<syncer::SyncMergeResult>(
138 sync_merge_result_.get()));
140 syncer::ModelTypeSet types = syncer::ProtocolTypes();
141 for (syncer::ModelTypeSet::Iterator iter = types.First(); iter.Good();
142 iter.Inc()) {
143 syncer::TestUserShare::CreateRoot(iter.Get(),
144 test_user_share_->user_share());
146 test_user_share_->encryption_handler()->Init();
147 ConstructGenericChangeProcessor(type);
150 void ConstructGenericChangeProcessor(syncer::ModelType type) {
151 scoped_refptr<syncer::AttachmentStore> attachment_store =
152 syncer::AttachmentStore::CreateInMemoryStore();
153 scoped_ptr<MockAttachmentService> mock_attachment_service(
154 new MockAttachmentService(attachment_store));
155 // GenericChangeProcessor takes ownership of the AttachmentService, but we
156 // need to have a pointer to it so we can see that it was used properly.
157 // Take a pointer and trust that GenericChangeProcessor does not prematurely
158 // destroy it.
159 mock_attachment_service_ = mock_attachment_service.get();
160 sync_factory_.reset(
161 new MockSyncApiComponentFactory(mock_attachment_service.Pass()));
162 change_processor_.reset(
163 new GenericChangeProcessor(type,
164 &data_type_error_handler_,
165 syncable_service_ptr_factory_.GetWeakPtr(),
166 merge_result_ptr_factory_->GetWeakPtr(),
167 test_user_share_->user_share(),
168 sync_factory_.get(),
169 attachment_store));
172 void BuildChildNodes(syncer::ModelType type, int n) {
173 syncer::WriteTransaction trans(FROM_HERE, user_share());
174 syncer::ReadNode root(&trans);
175 ASSERT_EQ(syncer::BaseNode::INIT_OK, root.InitTypeRoot(type));
176 for (int i = 0; i < n; ++i) {
177 syncer::WriteNode node(&trans);
178 node.InitUniqueByCreation(type, root, base::StringPrintf("node%05d", i));
182 GenericChangeProcessor* change_processor() {
183 return change_processor_.get();
186 syncer::UserShare* user_share() {
187 return test_user_share_->user_share();
190 MockAttachmentService* mock_attachment_service() {
191 return mock_attachment_service_;
194 void RunLoop() {
195 base::RunLoop run_loop;
196 run_loop.RunUntilIdle();
199 private:
200 base::MessageLoopForUI loop_;
202 scoped_ptr<syncer::SyncMergeResult> sync_merge_result_;
203 scoped_ptr<base::WeakPtrFactory<syncer::SyncMergeResult> >
204 merge_result_ptr_factory_;
206 syncer::FakeSyncableService fake_syncable_service_;
207 base::WeakPtrFactory<syncer::FakeSyncableService>
208 syncable_service_ptr_factory_;
210 DataTypeErrorHandlerMock data_type_error_handler_;
211 scoped_ptr<syncer::TestUserShare> test_user_share_;
212 MockAttachmentService* mock_attachment_service_;
213 scoped_ptr<SyncApiComponentFactory> sync_factory_;
215 scoped_ptr<GenericChangeProcessor> change_processor_;
218 // Similar to above, but focused on the method that implements sync/api
219 // interfaces and is hence exposed to datatypes directly.
220 TEST_F(SyncGenericChangeProcessorTest, StressGetAllSyncData) {
221 const int kNumChildNodes = 1000;
222 const int kRepeatCount = 1;
224 ASSERT_NO_FATAL_FAILURE(BuildChildNodes(kType, kNumChildNodes));
226 for (int i = 0; i < kRepeatCount; ++i) {
227 syncer::SyncDataList sync_data =
228 change_processor()->GetAllSyncData(kType);
230 // Start with a simple test. We can add more in-depth testing later.
231 EXPECT_EQ(static_cast<size_t>(kNumChildNodes), sync_data.size());
235 TEST_F(SyncGenericChangeProcessorTest, SetGetPasswords) {
236 InitializeForType(syncer::PASSWORDS);
237 const int kNumPasswords = 10;
238 sync_pb::PasswordSpecificsData password_data;
239 password_data.set_username_value("user");
241 sync_pb::EntitySpecifics password_holder;
243 syncer::SyncChangeList change_list;
244 for (int i = 0; i < kNumPasswords; ++i) {
245 password_data.set_password_value(
246 base::StringPrintf("password%i", i));
247 password_holder.mutable_password()->mutable_client_only_encrypted_data()->
248 CopyFrom(password_data);
249 change_list.push_back(
250 syncer::SyncChange(FROM_HERE,
251 syncer::SyncChange::ACTION_ADD,
252 syncer::SyncData::CreateLocalData(
253 base::StringPrintf("tag%i", i),
254 base::StringPrintf("title%i", i),
255 password_holder)));
258 ASSERT_FALSE(
259 change_processor()->ProcessSyncChanges(FROM_HERE, change_list).IsSet());
261 syncer::SyncDataList password_list(
262 change_processor()->GetAllSyncData(syncer::PASSWORDS));
264 ASSERT_EQ(password_list.size(), change_list.size());
265 for (int i = 0; i < kNumPasswords; ++i) {
266 // Verify the password is returned properly.
267 ASSERT_TRUE(password_list[i].GetSpecifics().has_password());
268 ASSERT_TRUE(password_list[i].GetSpecifics().password().
269 has_client_only_encrypted_data());
270 ASSERT_FALSE(password_list[i].GetSpecifics().password().has_encrypted());
271 const sync_pb::PasswordSpecificsData& sync_password =
272 password_list[i].GetSpecifics().password().client_only_encrypted_data();
273 const sync_pb::PasswordSpecificsData& change_password =
274 change_list[i].sync_data().GetSpecifics().password().
275 client_only_encrypted_data();
276 ASSERT_EQ(sync_password.password_value(), change_password.password_value());
277 ASSERT_EQ(sync_password.username_value(), change_password.username_value());
279 // Verify the raw sync data was stored securely.
280 syncer::ReadTransaction read_transaction(FROM_HERE, user_share());
281 syncer::ReadNode node(&read_transaction);
282 ASSERT_EQ(node.InitByClientTagLookup(syncer::PASSWORDS,
283 base::StringPrintf("tag%i", i)),
284 syncer::BaseNode::INIT_OK);
285 ASSERT_EQ(node.GetTitle(), "encrypted");
286 const sync_pb::EntitySpecifics& raw_specifics = node.GetEntitySpecifics();
287 ASSERT_TRUE(raw_specifics.has_password());
288 ASSERT_TRUE(raw_specifics.password().has_encrypted());
289 ASSERT_FALSE(raw_specifics.password().has_client_only_encrypted_data());
293 TEST_F(SyncGenericChangeProcessorTest, UpdatePasswords) {
294 InitializeForType(syncer::PASSWORDS);
295 const int kNumPasswords = 10;
296 sync_pb::PasswordSpecificsData password_data;
297 password_data.set_username_value("user");
299 sync_pb::EntitySpecifics password_holder;
301 syncer::SyncChangeList change_list;
302 syncer::SyncChangeList change_list2;
303 for (int i = 0; i < kNumPasswords; ++i) {
304 password_data.set_password_value(
305 base::StringPrintf("password%i", i));
306 password_holder.mutable_password()->mutable_client_only_encrypted_data()->
307 CopyFrom(password_data);
308 change_list.push_back(
309 syncer::SyncChange(FROM_HERE,
310 syncer::SyncChange::ACTION_ADD,
311 syncer::SyncData::CreateLocalData(
312 base::StringPrintf("tag%i", i),
313 base::StringPrintf("title%i", i),
314 password_holder)));
315 password_data.set_password_value(
316 base::StringPrintf("password_m%i", i));
317 password_holder.mutable_password()->mutable_client_only_encrypted_data()->
318 CopyFrom(password_data);
319 change_list2.push_back(
320 syncer::SyncChange(FROM_HERE,
321 syncer::SyncChange::ACTION_UPDATE,
322 syncer::SyncData::CreateLocalData(
323 base::StringPrintf("tag%i", i),
324 base::StringPrintf("title_m%i", i),
325 password_holder)));
328 ASSERT_FALSE(
329 change_processor()->ProcessSyncChanges(FROM_HERE, change_list).IsSet());
330 ASSERT_FALSE(
331 change_processor()->ProcessSyncChanges(FROM_HERE, change_list2).IsSet());
333 syncer::SyncDataList password_list(
334 change_processor()->GetAllSyncData(syncer::PASSWORDS));
336 ASSERT_EQ(password_list.size(), change_list2.size());
337 for (int i = 0; i < kNumPasswords; ++i) {
338 // Verify the password is returned properly.
339 ASSERT_TRUE(password_list[i].GetSpecifics().has_password());
340 ASSERT_TRUE(password_list[i].GetSpecifics().password().
341 has_client_only_encrypted_data());
342 ASSERT_FALSE(password_list[i].GetSpecifics().password().has_encrypted());
343 const sync_pb::PasswordSpecificsData& sync_password =
344 password_list[i].GetSpecifics().password().client_only_encrypted_data();
345 const sync_pb::PasswordSpecificsData& change_password =
346 change_list2[i].sync_data().GetSpecifics().password().
347 client_only_encrypted_data();
348 ASSERT_EQ(sync_password.password_value(), change_password.password_value());
349 ASSERT_EQ(sync_password.username_value(), change_password.username_value());
351 // Verify the raw sync data was stored securely.
352 syncer::ReadTransaction read_transaction(FROM_HERE, user_share());
353 syncer::ReadNode node(&read_transaction);
354 ASSERT_EQ(node.InitByClientTagLookup(syncer::PASSWORDS,
355 base::StringPrintf("tag%i", i)),
356 syncer::BaseNode::INIT_OK);
357 ASSERT_EQ(node.GetTitle(), "encrypted");
358 const sync_pb::EntitySpecifics& raw_specifics = node.GetEntitySpecifics();
359 ASSERT_TRUE(raw_specifics.has_password());
360 ASSERT_TRUE(raw_specifics.password().has_encrypted());
361 ASSERT_FALSE(raw_specifics.password().has_client_only_encrypted_data());
365 // Verify that attachments on newly added or updated SyncData are passed to the
366 // AttachmentService.
367 TEST_F(SyncGenericChangeProcessorTest,
368 ProcessSyncChanges_AddUpdateWithAttachment) {
369 std::string tag = "client_tag";
370 std::string title = "client_title";
371 sync_pb::EntitySpecifics specifics;
372 sync_pb::PreferenceSpecifics* pref_specifics = specifics.mutable_preference();
373 pref_specifics->set_name("test");
375 syncer::AttachmentIdList attachment_ids;
376 attachment_ids.push_back(syncer::AttachmentId::Create());
377 attachment_ids.push_back(syncer::AttachmentId::Create());
379 // Add a SyncData with two attachments.
380 syncer::SyncChangeList change_list;
381 change_list.push_back(
382 syncer::SyncChange(FROM_HERE,
383 syncer::SyncChange::ACTION_ADD,
384 syncer::SyncData::CreateLocalDataWithAttachments(
385 tag, title, specifics, attachment_ids)));
386 ASSERT_FALSE(
387 change_processor()->ProcessSyncChanges(FROM_HERE, change_list).IsSet());
388 RunLoop();
390 // Check that the AttachmentService received the new attachments.
391 ASSERT_EQ(mock_attachment_service()->attachment_id_sets()->size(), 1U);
392 const syncer::AttachmentIdSet& attachments_added =
393 mock_attachment_service()->attachment_id_sets()->front();
394 ASSERT_THAT(
395 attachments_added,
396 testing::UnorderedElementsAre(attachment_ids[0], attachment_ids[1]));
398 // Update the SyncData, replacing its two attachments with one new attachment.
399 syncer::AttachmentIdList new_attachment_ids;
400 new_attachment_ids.push_back(syncer::AttachmentId::Create());
401 mock_attachment_service()->attachment_id_sets()->clear();
402 change_list.clear();
403 change_list.push_back(
404 syncer::SyncChange(FROM_HERE,
405 syncer::SyncChange::ACTION_UPDATE,
406 syncer::SyncData::CreateLocalDataWithAttachments(
407 tag, title, specifics, new_attachment_ids)));
408 ASSERT_FALSE(
409 change_processor()->ProcessSyncChanges(FROM_HERE, change_list).IsSet());
410 RunLoop();
412 // Check that the AttachmentService received it.
413 ASSERT_EQ(mock_attachment_service()->attachment_id_sets()->size(), 1U);
414 const syncer::AttachmentIdSet& new_attachments_added =
415 mock_attachment_service()->attachment_id_sets()->front();
416 ASSERT_THAT(new_attachments_added,
417 testing::UnorderedElementsAre(new_attachment_ids[0]));
420 // Verify that after attachment is uploaded GenericChangeProcessor updates
421 // corresponding entries
422 TEST_F(SyncGenericChangeProcessorTest, AttachmentUploaded) {
423 std::string tag = "client_tag";
424 std::string title = "client_title";
425 sync_pb::EntitySpecifics specifics;
426 sync_pb::PreferenceSpecifics* pref_specifics = specifics.mutable_preference();
427 pref_specifics->set_name("test");
429 syncer::AttachmentIdList attachment_ids;
430 attachment_ids.push_back(syncer::AttachmentId::Create());
432 // Add a SyncData with two attachments.
433 syncer::SyncChangeList change_list;
434 change_list.push_back(
435 syncer::SyncChange(FROM_HERE,
436 syncer::SyncChange::ACTION_ADD,
437 syncer::SyncData::CreateLocalDataWithAttachments(
438 tag, title, specifics, attachment_ids)));
439 ASSERT_FALSE(
440 change_processor()->ProcessSyncChanges(FROM_HERE, change_list).IsSet());
442 sync_pb::AttachmentIdProto attachment_id_proto = attachment_ids[0].GetProto();
443 syncer::AttachmentId attachment_id =
444 syncer::AttachmentId::CreateFromProto(attachment_id_proto);
446 change_processor()->OnAttachmentUploaded(attachment_id);
447 syncer::ReadTransaction read_transaction(FROM_HERE, user_share());
448 syncer::ReadNode node(&read_transaction);
449 ASSERT_EQ(node.InitByClientTagLookup(kType, tag), syncer::BaseNode::INIT_OK);
450 attachment_ids = node.GetAttachmentIds();
451 EXPECT_EQ(1U, attachment_ids.size());
454 // Verify that upon construction, all attachments not yet on the server are
455 // scheduled for upload.
456 TEST_F(SyncGenericChangeProcessorTest, UploadAllAttachmentsNotOnServer) {
457 // Create two attachment ids. id2 will be marked as "on server".
458 syncer::AttachmentId id1 = syncer::AttachmentId::Create();
459 syncer::AttachmentId id2 = syncer::AttachmentId::Create();
461 // Write an entry containing these two attachment ids.
462 syncer::WriteTransaction trans(FROM_HERE, user_share());
463 syncer::ReadNode root(&trans);
464 ASSERT_EQ(syncer::BaseNode::INIT_OK, root.InitTypeRoot(kType));
465 syncer::WriteNode node(&trans);
466 node.InitUniqueByCreation(kType, root, "some node");
467 sync_pb::AttachmentMetadata metadata;
468 sync_pb::AttachmentMetadataRecord* record1 = metadata.add_record();
469 *record1->mutable_id() = id1.GetProto();
470 sync_pb::AttachmentMetadataRecord* record2 = metadata.add_record();
471 *record2->mutable_id() = id2.GetProto();
472 record2->set_is_on_server(true);
473 node.SetAttachmentMetadata(metadata);
476 // Construct the GenericChangeProcessor and see that it asks the
477 // AttachmentService to upload id1 only.
478 ConstructGenericChangeProcessor(kType);
479 ASSERT_EQ(1U, mock_attachment_service()->attachment_id_sets()->size());
480 ASSERT_THAT(mock_attachment_service()->attachment_id_sets()->front(),
481 testing::UnorderedElementsAre(id1));
484 } // namespace
486 } // namespace sync_driver