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