1 // Copyright (c) 2012 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/sync_backend_registrar.h" 6 7 #include "base/run_loop.h" 8 #include "chrome/browser/sync/glue/ui_model_worker.h" 9 #include "chrome/test/base/testing_profile.h" 10 #include "components/sync_driver/change_processor_mock.h" 11 #include "content/public/browser/browser_thread.h" 12 #include "content/public/test/test_browser_thread_bundle.h" 13 #include "sync/internal_api/public/base/model_type.h" 14 #include "sync/internal_api/public/test/test_user_share.h" 15 #include "testing/gmock/include/gmock/gmock.h" 16 #include "testing/gtest/include/gtest/gtest.h" 17 18 namespace browser_sync { 19 20 namespace { 21 22 using ::testing::_; 23 using ::testing::InSequence; 24 using ::testing::Return; 25 using ::testing::StrictMock; 26 using content::BrowserThread; 27 using syncer::FIRST_REAL_MODEL_TYPE; 28 using syncer::AUTOFILL; 29 using syncer::BOOKMARKS; 30 using syncer::PREFERENCES; 31 using syncer::THEMES; 32 using syncer::NIGORI; 33 using syncer::PASSWORDS; 34 using syncer::MODEL_TYPE_COUNT; 35 using syncer::ModelTypeSet; 36 using syncer::ModelType; 37 using syncer::ModelTypeFromInt; 38 39 void TriggerChanges(SyncBackendRegistrar* registrar, ModelType type) { 40 registrar->OnChangesApplied(type, 0, NULL, 41 syncer::ImmutableChangeRecordList()); 42 registrar->OnChangesComplete(type); 43 } 44 45 class SyncBackendRegistrarTest : public testing::Test { 46 public: 47 void TestNonUIDataTypeActivationAsync(sync_driver::ChangeProcessor* processor, 48 base::WaitableEvent* done) { 49 registrar_->ActivateDataType(AUTOFILL, 50 syncer::GROUP_DB, 51 processor, 52 test_user_share_.user_share()); 53 syncer::ModelSafeRoutingInfo expected_routing_info; 54 expected_routing_info[AUTOFILL] = syncer::GROUP_DB; 55 ExpectRoutingInfo(registrar_.get(), expected_routing_info); 56 ExpectHasProcessorsForTypes(*registrar_, ModelTypeSet(AUTOFILL)); 57 TriggerChanges(registrar_.get(), AUTOFILL); 58 done->Signal(); 59 } 60 61 protected: 62 SyncBackendRegistrarTest() 63 : sync_thread_(NULL), 64 thread_bundle_(content::TestBrowserThreadBundle::REAL_DB_THREAD | 65 content::TestBrowserThreadBundle::REAL_FILE_THREAD | 66 content::TestBrowserThreadBundle::REAL_IO_THREAD) {} 67 68 virtual ~SyncBackendRegistrarTest() {} 69 70 virtual void SetUp() { 71 test_user_share_.SetUp(); 72 registrar_.reset(new SyncBackendRegistrar("test", &profile_, 73 scoped_ptr<base::Thread>())); 74 sync_thread_ = registrar_->sync_thread(); 75 } 76 77 virtual void TearDown() { 78 registrar_->RequestWorkerStopOnUIThread(); 79 test_user_share_.TearDown(); 80 sync_thread_->message_loop()->PostTask( 81 FROM_HERE, 82 base::Bind(&SyncBackendRegistrar::Shutdown, 83 base::Unretained(registrar_.release()))); 84 sync_thread_->message_loop()->RunUntilIdle(); 85 } 86 87 void ExpectRoutingInfo( 88 SyncBackendRegistrar* registrar, 89 const syncer::ModelSafeRoutingInfo& expected_routing_info) { 90 syncer::ModelSafeRoutingInfo routing_info; 91 registrar->GetModelSafeRoutingInfo(&routing_info); 92 EXPECT_EQ(expected_routing_info, routing_info); 93 } 94 95 void ExpectHasProcessorsForTypes(const SyncBackendRegistrar& registrar, 96 ModelTypeSet types) { 97 for (int i = FIRST_REAL_MODEL_TYPE; i < MODEL_TYPE_COUNT; ++i) { 98 ModelType model_type = ModelTypeFromInt(i); 99 EXPECT_EQ(types.Has(model_type), 100 registrar_->IsTypeActivatedForTest(model_type)); 101 } 102 } 103 104 syncer::TestUserShare test_user_share_; 105 TestingProfile profile_; 106 scoped_ptr<SyncBackendRegistrar> registrar_; 107 108 base::Thread* sync_thread_; 109 content::TestBrowserThreadBundle thread_bundle_; 110 }; 111 112 TEST_F(SyncBackendRegistrarTest, ConstructorEmpty) { 113 registrar_->SetInitialTypes(ModelTypeSet()); 114 EXPECT_FALSE(registrar_->IsNigoriEnabled()); 115 { 116 std::vector<scoped_refptr<syncer::ModelSafeWorker> > workers; 117 registrar_->GetWorkers(&workers); 118 EXPECT_EQ(4u, workers.size()); 119 } 120 ExpectRoutingInfo(registrar_.get(), syncer::ModelSafeRoutingInfo()); 121 ExpectHasProcessorsForTypes(*registrar_, ModelTypeSet()); 122 } 123 124 TEST_F(SyncBackendRegistrarTest, ConstructorNonEmpty) { 125 const ModelTypeSet initial_types(BOOKMARKS, NIGORI, PASSWORDS); 126 registrar_->SetInitialTypes(initial_types); 127 EXPECT_TRUE(registrar_->IsNigoriEnabled()); 128 { 129 std::vector<scoped_refptr<syncer::ModelSafeWorker> > workers; 130 registrar_->GetWorkers(&workers); 131 EXPECT_EQ(4u, workers.size()); 132 } 133 { 134 syncer::ModelSafeRoutingInfo expected_routing_info; 135 expected_routing_info[BOOKMARKS] = syncer::GROUP_PASSIVE; 136 expected_routing_info[NIGORI] = syncer::GROUP_PASSIVE; 137 // Passwords dropped because of no password store. 138 ExpectRoutingInfo(registrar_.get(), expected_routing_info); 139 } 140 ExpectHasProcessorsForTypes(*registrar_, ModelTypeSet()); 141 } 142 143 TEST_F(SyncBackendRegistrarTest, ConfigureDataTypes) { 144 registrar_->SetInitialTypes(ModelTypeSet()); 145 146 // Add. 147 const ModelTypeSet types1(BOOKMARKS, NIGORI, AUTOFILL); 148 EXPECT_TRUE( 149 registrar_->ConfigureDataTypes(types1, ModelTypeSet()).Equals(types1)); 150 { 151 syncer::ModelSafeRoutingInfo expected_routing_info; 152 expected_routing_info[BOOKMARKS] = syncer::GROUP_PASSIVE; 153 expected_routing_info[NIGORI] = syncer::GROUP_PASSIVE; 154 expected_routing_info[AUTOFILL] = syncer::GROUP_PASSIVE; 155 ExpectRoutingInfo(registrar_.get(), expected_routing_info); 156 } 157 ExpectHasProcessorsForTypes(*registrar_, ModelTypeSet()); 158 EXPECT_TRUE(types1.Equals(registrar_->GetLastConfiguredTypes())); 159 160 // Add and remove. 161 const ModelTypeSet types2(PREFERENCES, THEMES); 162 EXPECT_TRUE(registrar_->ConfigureDataTypes(types2, types1).Equals(types2)); 163 { 164 syncer::ModelSafeRoutingInfo expected_routing_info; 165 expected_routing_info[PREFERENCES] = syncer::GROUP_PASSIVE; 166 expected_routing_info[THEMES] = syncer::GROUP_PASSIVE; 167 ExpectRoutingInfo(registrar_.get(), expected_routing_info); 168 } 169 ExpectHasProcessorsForTypes(*registrar_, ModelTypeSet()); 170 EXPECT_TRUE(types2.Equals(registrar_->GetLastConfiguredTypes())); 171 172 // Remove. 173 EXPECT_TRUE(registrar_->ConfigureDataTypes(ModelTypeSet(), types2).Empty()); 174 ExpectRoutingInfo(registrar_.get(), syncer::ModelSafeRoutingInfo()); 175 ExpectHasProcessorsForTypes(*registrar_, ModelTypeSet()); 176 EXPECT_TRUE(ModelTypeSet().Equals(registrar_->GetLastConfiguredTypes())); 177 } 178 179 TEST_F(SyncBackendRegistrarTest, ActivateDeactivateUIDataType) { 180 InSequence in_sequence; 181 registrar_->SetInitialTypes(ModelTypeSet()); 182 183 // Should do nothing. 184 TriggerChanges(registrar_.get(), BOOKMARKS); 185 186 StrictMock<sync_driver::ChangeProcessorMock> change_processor_mock; 187 EXPECT_CALL(change_processor_mock, StartImpl()); 188 EXPECT_CALL(change_processor_mock, IsRunning()) 189 .WillRepeatedly(Return(true)); 190 EXPECT_CALL(change_processor_mock, ApplyChangesFromSyncModel(NULL, _, _)); 191 EXPECT_CALL(change_processor_mock, IsRunning()) 192 .WillRepeatedly(Return(true)); 193 EXPECT_CALL(change_processor_mock, CommitChangesFromSyncModel()); 194 EXPECT_CALL(change_processor_mock, IsRunning()) 195 .WillRepeatedly(Return(false)); 196 197 const ModelTypeSet types(BOOKMARKS); 198 EXPECT_TRUE( 199 registrar_->ConfigureDataTypes(types, ModelTypeSet()).Equals(types)); 200 registrar_->ActivateDataType(BOOKMARKS, syncer::GROUP_UI, 201 &change_processor_mock, 202 test_user_share_.user_share()); 203 { 204 syncer::ModelSafeRoutingInfo expected_routing_info; 205 expected_routing_info[BOOKMARKS] = syncer::GROUP_UI; 206 ExpectRoutingInfo(registrar_.get(), expected_routing_info); 207 } 208 ExpectHasProcessorsForTypes(*registrar_, types); 209 210 TriggerChanges(registrar_.get(), BOOKMARKS); 211 212 registrar_->DeactivateDataType(BOOKMARKS); 213 ExpectRoutingInfo(registrar_.get(), syncer::ModelSafeRoutingInfo()); 214 ExpectHasProcessorsForTypes(*registrar_, ModelTypeSet()); 215 216 // Should do nothing. 217 TriggerChanges(registrar_.get(), BOOKMARKS); 218 } 219 220 TEST_F(SyncBackendRegistrarTest, ActivateDeactivateNonUIDataType) { 221 InSequence in_sequence; 222 registrar_->SetInitialTypes(ModelTypeSet()); 223 224 // Should do nothing. 225 TriggerChanges(registrar_.get(), AUTOFILL); 226 227 StrictMock<sync_driver::ChangeProcessorMock> change_processor_mock; 228 EXPECT_CALL(change_processor_mock, StartImpl()); 229 EXPECT_CALL(change_processor_mock, IsRunning()) 230 .WillRepeatedly(Return(true)); 231 EXPECT_CALL(change_processor_mock, ApplyChangesFromSyncModel(NULL, _, _)); 232 EXPECT_CALL(change_processor_mock, IsRunning()) 233 .WillRepeatedly(Return(true)); 234 EXPECT_CALL(change_processor_mock, CommitChangesFromSyncModel()); 235 EXPECT_CALL(change_processor_mock, IsRunning()) 236 .WillRepeatedly(Return(false)); 237 238 const ModelTypeSet types(AUTOFILL); 239 EXPECT_TRUE( 240 registrar_->ConfigureDataTypes(types, ModelTypeSet()).Equals(types)); 241 242 base::WaitableEvent done(false, false); 243 BrowserThread::PostTask( 244 BrowserThread::DB, 245 FROM_HERE, 246 base::Bind(&SyncBackendRegistrarTest::TestNonUIDataTypeActivationAsync, 247 base::Unretained(this), 248 &change_processor_mock, 249 &done)); 250 done.Wait(); 251 252 registrar_->DeactivateDataType(AUTOFILL); 253 ExpectRoutingInfo(registrar_.get(), syncer::ModelSafeRoutingInfo()); 254 ExpectHasProcessorsForTypes(*registrar_, ModelTypeSet()); 255 256 // Should do nothing. 257 TriggerChanges(registrar_.get(), AUTOFILL); 258 } 259 260 class SyncBackendRegistrarShutdownTest : public testing::Test { 261 public: 262 void BlockDBThread() { 263 EXPECT_FALSE(db_thread_lock_.Try()); 264 265 db_thread_blocked_.Signal(); 266 base::AutoLock l(db_thread_lock_); 267 } 268 269 protected: 270 friend class TestRegistrar; 271 272 SyncBackendRegistrarShutdownTest() 273 : thread_bundle_(content::TestBrowserThreadBundle::REAL_DB_THREAD | 274 content::TestBrowserThreadBundle::REAL_FILE_THREAD | 275 content::TestBrowserThreadBundle::REAL_IO_THREAD), 276 db_thread_blocked_(false, false) { 277 quit_closure_ = run_loop_.QuitClosure(); 278 } 279 280 virtual ~SyncBackendRegistrarShutdownTest() {} 281 282 void PostQuitOnUIMessageLoop() { 283 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, quit_closure_); 284 } 285 286 content::TestBrowserThreadBundle thread_bundle_; 287 TestingProfile profile_; 288 base::WaitableEvent db_thread_blocked_; 289 base::Lock db_thread_lock_; 290 base::RunLoop run_loop_; 291 base::Closure quit_closure_; 292 }; 293 294 // Wrap SyncBackendRegistrar so that we can monitor its lifetime. 295 class TestRegistrar : public SyncBackendRegistrar { 296 public: 297 explicit TestRegistrar(Profile* profile, 298 SyncBackendRegistrarShutdownTest* test) 299 : SyncBackendRegistrar("test", profile, scoped_ptr<base::Thread>()), 300 test_(test) {} 301 302 virtual ~TestRegistrar() { test_->PostQuitOnUIMessageLoop(); } 303 304 private: 305 SyncBackendRegistrarShutdownTest* test_; 306 }; 307 308 TEST_F(SyncBackendRegistrarShutdownTest, BlockingShutdown) { 309 // Take ownership of |db_thread_lock_| so that the DB thread can't acquire it. 310 db_thread_lock_.Acquire(); 311 312 // This will block the DB thread by waiting on |db_thread_lock_|. 313 BrowserThread::PostTask( 314 BrowserThread::DB, 315 FROM_HERE, 316 base::Bind(&SyncBackendRegistrarShutdownTest::BlockDBThread, 317 base::Unretained(this))); 318 319 scoped_ptr<TestRegistrar> registrar(new TestRegistrar(&profile_, this)); 320 base::Thread* sync_thread = registrar->sync_thread(); 321 322 // Stop here until the DB thread gets a chance to run and block on the lock. 323 // Please note that since the task above didn't finish, the task to 324 // initialize the worker on the DB thread hasn't had a chance to run yet too. 325 // Which means ModelSafeWorker::SetWorkingLoopToCurrent hasn't been called 326 // for the DB worker. 327 db_thread_blocked_.Wait(); 328 329 registrar->SetInitialTypes(ModelTypeSet()); 330 331 // Start the shutdown. 332 registrar->RequestWorkerStopOnUIThread(); 333 334 sync_thread->message_loop()->PostTask( 335 FROM_HERE, 336 base::Bind(&SyncBackendRegistrar::Shutdown, 337 base::Unretained(registrar.release()))); 338 339 // The test verifies that the sync thread doesn't block because 340 // of the blocked DB thread and can finish the shutdown. 341 sync_thread->message_loop()->RunUntilIdle(); 342 343 db_thread_lock_.Release(); 344 345 // Run the main thread loop until all workers have been removed and the 346 // registrar destroyed. 347 run_loop_.Run(); 348 } 349 350 } // namespace 351 352 } // namespace browser_sync 353