Home | History | Annotate | Download | only in glue
      1 // Copyright 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 "chrome/browser/sync/glue/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/strings/stringprintf.h"
     11 #include "chrome/browser/sync/glue/data_type_error_handler_mock.h"
     12 #include "sync/api/fake_syncable_service.h"
     13 #include "sync/api/sync_change.h"
     14 #include "sync/api/sync_merge_result.h"
     15 #include "sync/internal_api/public/base/model_type.h"
     16 #include "sync/internal_api/public/read_node.h"
     17 #include "sync/internal_api/public/read_transaction.h"
     18 #include "sync/internal_api/public/test/test_user_share.h"
     19 #include "sync/internal_api/public/user_share.h"
     20 #include "sync/internal_api/public/write_node.h"
     21 #include "sync/internal_api/public/write_transaction.h"
     22 #include "testing/gtest/include/gtest/gtest.h"
     23 
     24 namespace browser_sync {
     25 
     26 namespace {
     27 
     28 class SyncGenericChangeProcessorTest : public testing::Test {
     29  public:
     30   // It doesn't matter which type we use.  Just pick one.
     31   static const syncer::ModelType kType = syncer::PREFERENCES;
     32 
     33   SyncGenericChangeProcessorTest() :
     34       loop_(base::MessageLoop::TYPE_UI),
     35       sync_merge_result_(kType),
     36       merge_result_ptr_factory_(&sync_merge_result_),
     37       syncable_service_ptr_factory_(&fake_syncable_service_) {
     38   }
     39 
     40   virtual void SetUp() OVERRIDE {
     41     test_user_share_.SetUp();
     42     syncer::ModelTypeSet types = syncer::ProtocolTypes();
     43     for (syncer::ModelTypeSet::Iterator iter = types.First(); iter.Good();
     44          iter.Inc()) {
     45       syncer::TestUserShare::CreateRoot(iter.Get(),
     46                                         test_user_share_.user_share());
     47     }
     48     test_user_share_.encryption_handler()->Init();
     49     change_processor_.reset(
     50         new GenericChangeProcessor(
     51             &data_type_error_handler_,
     52             syncable_service_ptr_factory_.GetWeakPtr(),
     53             merge_result_ptr_factory_.GetWeakPtr(),
     54             test_user_share_.user_share()));
     55   }
     56 
     57   virtual void TearDown() OVERRIDE {
     58     test_user_share_.TearDown();
     59   }
     60 
     61   void BuildChildNodes(int n) {
     62     syncer::WriteTransaction trans(FROM_HERE, user_share());
     63     syncer::ReadNode root(&trans);
     64     ASSERT_EQ(syncer::BaseNode::INIT_OK,
     65               root.InitByTagLookup(syncer::ModelTypeToRootTag(kType)));
     66     for (int i = 0; i < n; ++i) {
     67       syncer::WriteNode node(&trans);
     68       node.InitUniqueByCreation(kType, root, base::StringPrintf("node%05d", i));
     69     }
     70   }
     71 
     72   GenericChangeProcessor* change_processor() {
     73     return change_processor_.get();
     74   }
     75 
     76   syncer::UserShare* user_share() {
     77     return test_user_share_.user_share();
     78   }
     79 
     80  private:
     81   base::MessageLoop loop_;
     82 
     83   syncer::SyncMergeResult sync_merge_result_;
     84   base::WeakPtrFactory<syncer::SyncMergeResult> merge_result_ptr_factory_;
     85 
     86   syncer::FakeSyncableService fake_syncable_service_;
     87   base::WeakPtrFactory<syncer::FakeSyncableService>
     88       syncable_service_ptr_factory_;
     89 
     90   DataTypeErrorHandlerMock data_type_error_handler_;
     91   syncer::TestUserShare test_user_share_;
     92 
     93   scoped_ptr<GenericChangeProcessor> change_processor_;
     94 };
     95 
     96 // This test exercises GenericChangeProcessor's GetSyncDataForType function.
     97 // It's not a great test, but, by modifying some of the parameters, you could
     98 // turn it into a micro-benchmark for model association.
     99 TEST_F(SyncGenericChangeProcessorTest, StressGetSyncDataForType) {
    100   const int kNumChildNodes = 1000;
    101   const int kRepeatCount = 1;
    102 
    103   ASSERT_NO_FATAL_FAILURE(BuildChildNodes(kNumChildNodes));
    104 
    105   for (int i = 0; i < kRepeatCount; ++i) {
    106     syncer::SyncDataList sync_data;
    107     change_processor()->GetSyncDataForType(kType, &sync_data);
    108 
    109     // Start with a simple test.  We can add more in-depth testing later.
    110     EXPECT_EQ(static_cast<size_t>(kNumChildNodes), sync_data.size());
    111   }
    112 }
    113 
    114 TEST_F(SyncGenericChangeProcessorTest, SetGetPasswords) {
    115   const int kNumPasswords = 10;
    116   sync_pb::PasswordSpecificsData password_data;
    117   password_data.set_username_value("user");
    118 
    119   sync_pb::EntitySpecifics password_holder;
    120 
    121   syncer::SyncChangeList change_list;
    122   for (int i = 0; i < kNumPasswords; ++i) {
    123     password_data.set_password_value(
    124         base::StringPrintf("password%i", i));
    125     password_holder.mutable_password()->mutable_client_only_encrypted_data()->
    126         CopyFrom(password_data);
    127     change_list.push_back(
    128         syncer::SyncChange(FROM_HERE,
    129                            syncer::SyncChange::ACTION_ADD,
    130                            syncer::SyncData::CreateLocalData(
    131                                base::StringPrintf("tag%i", i),
    132                                base::StringPrintf("title%i", i),
    133                                password_holder)));
    134   }
    135 
    136   ASSERT_FALSE(
    137       change_processor()->ProcessSyncChanges(FROM_HERE, change_list).IsSet());
    138 
    139   syncer::SyncDataList password_list;
    140   ASSERT_FALSE(
    141       change_processor()->GetSyncDataForType(syncer::PASSWORDS, &password_list).
    142           IsSet());
    143 
    144   ASSERT_EQ(password_list.size(), change_list.size());
    145   for (int i = 0; i < kNumPasswords; ++i) {
    146     // Verify the password is returned properly.
    147     ASSERT_TRUE(password_list[i].GetSpecifics().has_password());
    148     ASSERT_TRUE(password_list[i].GetSpecifics().password().
    149                     has_client_only_encrypted_data());
    150     ASSERT_FALSE(password_list[i].GetSpecifics().password().has_encrypted());
    151     const sync_pb::PasswordSpecificsData& sync_password =
    152         password_list[i].GetSpecifics().password().client_only_encrypted_data();
    153     const sync_pb::PasswordSpecificsData& change_password =
    154         change_list[i].sync_data().GetSpecifics().password().
    155             client_only_encrypted_data();
    156     ASSERT_EQ(sync_password.password_value(), change_password.password_value());
    157     ASSERT_EQ(sync_password.username_value(), change_password.username_value());
    158 
    159     // Verify the raw sync data was stored securely.
    160     syncer::ReadTransaction read_transaction(FROM_HERE, user_share());
    161     syncer::ReadNode node(&read_transaction);
    162     ASSERT_EQ(node.InitByClientTagLookup(syncer::PASSWORDS,
    163                                          base::StringPrintf("tag%i", i)),
    164               syncer::BaseNode::INIT_OK);
    165     ASSERT_EQ(node.GetTitle(), "encrypted");
    166     const sync_pb::EntitySpecifics& raw_specifics = node.GetEntitySpecifics();
    167     ASSERT_TRUE(raw_specifics.has_password());
    168     ASSERT_TRUE(raw_specifics.password().has_encrypted());
    169     ASSERT_FALSE(raw_specifics.password().has_client_only_encrypted_data());
    170   }
    171 }
    172 
    173 TEST_F(SyncGenericChangeProcessorTest, UpdatePasswords) {
    174   const int kNumPasswords = 10;
    175   sync_pb::PasswordSpecificsData password_data;
    176   password_data.set_username_value("user");
    177 
    178   sync_pb::EntitySpecifics password_holder;
    179 
    180   syncer::SyncChangeList change_list;
    181   syncer::SyncChangeList change_list2;
    182   for (int i = 0; i < kNumPasswords; ++i) {
    183     password_data.set_password_value(
    184         base::StringPrintf("password%i", i));
    185     password_holder.mutable_password()->mutable_client_only_encrypted_data()->
    186         CopyFrom(password_data);
    187     change_list.push_back(
    188         syncer::SyncChange(FROM_HERE,
    189                            syncer::SyncChange::ACTION_ADD,
    190                            syncer::SyncData::CreateLocalData(
    191                                base::StringPrintf("tag%i", i),
    192                                base::StringPrintf("title%i", i),
    193                                password_holder)));
    194     password_data.set_password_value(
    195         base::StringPrintf("password_m%i", i));
    196     password_holder.mutable_password()->mutable_client_only_encrypted_data()->
    197         CopyFrom(password_data);
    198     change_list2.push_back(
    199         syncer::SyncChange(FROM_HERE,
    200                            syncer::SyncChange::ACTION_UPDATE,
    201                            syncer::SyncData::CreateLocalData(
    202                                base::StringPrintf("tag%i", i),
    203                                base::StringPrintf("title_m%i", i),
    204                                password_holder)));
    205   }
    206 
    207   ASSERT_FALSE(
    208       change_processor()->ProcessSyncChanges(FROM_HERE, change_list).IsSet());
    209   ASSERT_FALSE(
    210       change_processor()->ProcessSyncChanges(FROM_HERE, change_list2).IsSet());
    211 
    212   syncer::SyncDataList password_list;
    213   ASSERT_FALSE(
    214       change_processor()->GetSyncDataForType(syncer::PASSWORDS, &password_list).
    215           IsSet());
    216 
    217   ASSERT_EQ(password_list.size(), change_list2.size());
    218   for (int i = 0; i < kNumPasswords; ++i) {
    219     // Verify the password is returned properly.
    220     ASSERT_TRUE(password_list[i].GetSpecifics().has_password());
    221     ASSERT_TRUE(password_list[i].GetSpecifics().password().
    222                     has_client_only_encrypted_data());
    223     ASSERT_FALSE(password_list[i].GetSpecifics().password().has_encrypted());
    224     const sync_pb::PasswordSpecificsData& sync_password =
    225         password_list[i].GetSpecifics().password().client_only_encrypted_data();
    226     const sync_pb::PasswordSpecificsData& change_password =
    227         change_list2[i].sync_data().GetSpecifics().password().
    228             client_only_encrypted_data();
    229     ASSERT_EQ(sync_password.password_value(), change_password.password_value());
    230     ASSERT_EQ(sync_password.username_value(), change_password.username_value());
    231 
    232     // Verify the raw sync data was stored securely.
    233     syncer::ReadTransaction read_transaction(FROM_HERE, user_share());
    234     syncer::ReadNode node(&read_transaction);
    235     ASSERT_EQ(node.InitByClientTagLookup(syncer::PASSWORDS,
    236                                          base::StringPrintf("tag%i", i)),
    237               syncer::BaseNode::INIT_OK);
    238     ASSERT_EQ(node.GetTitle(), "encrypted");
    239     const sync_pb::EntitySpecifics& raw_specifics = node.GetEntitySpecifics();
    240     ASSERT_TRUE(raw_specifics.has_password());
    241     ASSERT_TRUE(raw_specifics.password().has_encrypted());
    242     ASSERT_FALSE(raw_specifics.password().has_client_only_encrypted_data());
    243   }
    244 }
    245 
    246 }  // namespace
    247 
    248 }  // namespace browser_sync
    249 
    250