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