| OLD | NEW |
| (Empty) |
| 1 // Copyright 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 "components/sync_driver/glue/sync_backend_registrar.h" | |
| 6 | |
| 7 #include "base/location.h" | |
| 8 #include "base/run_loop.h" | |
| 9 #include "base/single_thread_task_runner.h" | |
| 10 #include "components/sync/base/model_type.h" | |
| 11 #include "components/sync/core/test/test_user_share.h" | |
| 12 #include "components/sync/engine/passive_model_worker.h" | |
| 13 #include "components/sync_driver/change_processor_mock.h" | |
| 14 #include "components/sync_driver/fake_sync_client.h" | |
| 15 #include "components/sync_driver/glue/browser_thread_model_worker.h" | |
| 16 #include "components/sync_driver/sync_api_component_factory_mock.h" | |
| 17 #include "testing/gmock/include/gmock/gmock.h" | |
| 18 #include "testing/gtest/include/gtest/gtest.h" | |
| 19 | |
| 20 namespace browser_sync { | |
| 21 | |
| 22 namespace { | |
| 23 | |
| 24 using ::testing::_; | |
| 25 using ::testing::InSequence; | |
| 26 using ::testing::Return; | |
| 27 using ::testing::StrictMock; | |
| 28 using syncer::FIRST_REAL_MODEL_TYPE; | |
| 29 using syncer::AUTOFILL; | |
| 30 using syncer::BOOKMARKS; | |
| 31 using syncer::PREFERENCES; | |
| 32 using syncer::THEMES; | |
| 33 using syncer::NIGORI; | |
| 34 using syncer::PASSWORDS; | |
| 35 using syncer::MODEL_TYPE_COUNT; | |
| 36 using syncer::ModelTypeSet; | |
| 37 using syncer::ModelType; | |
| 38 using syncer::ModelTypeFromInt; | |
| 39 | |
| 40 void TriggerChanges(SyncBackendRegistrar* registrar, ModelType type) { | |
| 41 registrar->OnChangesApplied(type, 0, NULL, | |
| 42 syncer::ImmutableChangeRecordList()); | |
| 43 registrar->OnChangesComplete(type); | |
| 44 } | |
| 45 | |
| 46 class RegistrarSyncClient : public sync_driver::FakeSyncClient { | |
| 47 public: | |
| 48 RegistrarSyncClient( | |
| 49 const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner, | |
| 50 const scoped_refptr<base::SingleThreadTaskRunner>& db_task_runner, | |
| 51 const scoped_refptr<base::SingleThreadTaskRunner>& file_task_runner) | |
| 52 : ui_task_runner_(ui_task_runner), | |
| 53 db_task_runner_(db_task_runner), | |
| 54 file_task_runner_(file_task_runner) {} | |
| 55 | |
| 56 scoped_refptr<syncer::ModelSafeWorker> CreateModelWorkerForGroup( | |
| 57 syncer::ModelSafeGroup group, | |
| 58 syncer::WorkerLoopDestructionObserver* observer) override { | |
| 59 switch (group) { | |
| 60 case syncer::GROUP_UI: | |
| 61 return new BrowserThreadModelWorker(ui_task_runner_, group, observer); | |
| 62 case syncer::GROUP_DB: | |
| 63 return new BrowserThreadModelWorker(db_task_runner_, group, observer); | |
| 64 case syncer::GROUP_FILE: | |
| 65 return new BrowserThreadModelWorker(file_task_runner_, group, observer); | |
| 66 case syncer::GROUP_PASSIVE: | |
| 67 return new syncer::PassiveModelWorker(observer); | |
| 68 default: | |
| 69 return nullptr; | |
| 70 } | |
| 71 } | |
| 72 | |
| 73 private: | |
| 74 const scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_; | |
| 75 const scoped_refptr<base::SingleThreadTaskRunner> db_task_runner_; | |
| 76 const scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_; | |
| 77 }; | |
| 78 | |
| 79 // Flaky: https://crbug.com/498238 | |
| 80 class SyncBackendRegistrarTest : public testing::Test { | |
| 81 public: | |
| 82 void TestNonUIDataTypeActivationAsync(sync_driver::ChangeProcessor* processor, | |
| 83 base::WaitableEvent* done) { | |
| 84 registrar_->ActivateDataType(AUTOFILL, | |
| 85 syncer::GROUP_DB, | |
| 86 processor, | |
| 87 test_user_share_.user_share()); | |
| 88 syncer::ModelSafeRoutingInfo expected_routing_info; | |
| 89 expected_routing_info[AUTOFILL] = syncer::GROUP_DB; | |
| 90 ExpectRoutingInfo(registrar_.get(), expected_routing_info); | |
| 91 ExpectHasProcessorsForTypes(*registrar_, ModelTypeSet(AUTOFILL)); | |
| 92 TriggerChanges(registrar_.get(), AUTOFILL); | |
| 93 done->Signal(); | |
| 94 } | |
| 95 | |
| 96 protected: | |
| 97 SyncBackendRegistrarTest() | |
| 98 : db_thread_("DBThreadForTest"), | |
| 99 file_thread_("FileThreadForTest"), | |
| 100 sync_thread_(NULL) {} | |
| 101 | |
| 102 ~SyncBackendRegistrarTest() override {} | |
| 103 | |
| 104 void SetUp() override { | |
| 105 db_thread_.StartAndWaitForTesting(); | |
| 106 file_thread_.StartAndWaitForTesting(); | |
| 107 test_user_share_.SetUp(); | |
| 108 sync_client_.reset(new RegistrarSyncClient( | |
| 109 ui_task_runner(), db_task_runner(), file_task_runner())); | |
| 110 registrar_.reset(new SyncBackendRegistrar( | |
| 111 "test", sync_client_.get(), std::unique_ptr<base::Thread>(), | |
| 112 ui_task_runner(), db_task_runner(), file_task_runner())); | |
| 113 sync_thread_ = registrar_->sync_thread(); | |
| 114 } | |
| 115 | |
| 116 void TearDown() override { | |
| 117 registrar_->RequestWorkerStopOnUIThread(); | |
| 118 test_user_share_.TearDown(); | |
| 119 sync_thread_->task_runner()->PostTask( | |
| 120 FROM_HERE, base::Bind(&SyncBackendRegistrar::Shutdown, | |
| 121 base::Unretained(registrar_.release()))); | |
| 122 sync_thread_->WaitUntilThreadStarted(); | |
| 123 base::RunLoop().RunUntilIdle(); | |
| 124 } | |
| 125 | |
| 126 void ExpectRoutingInfo( | |
| 127 SyncBackendRegistrar* registrar, | |
| 128 const syncer::ModelSafeRoutingInfo& expected_routing_info) { | |
| 129 syncer::ModelSafeRoutingInfo routing_info; | |
| 130 registrar->GetModelSafeRoutingInfo(&routing_info); | |
| 131 EXPECT_EQ(expected_routing_info, routing_info); | |
| 132 } | |
| 133 | |
| 134 void ExpectHasProcessorsForTypes(const SyncBackendRegistrar& registrar, | |
| 135 ModelTypeSet types) { | |
| 136 for (int i = FIRST_REAL_MODEL_TYPE; i < MODEL_TYPE_COUNT; ++i) { | |
| 137 ModelType model_type = ModelTypeFromInt(i); | |
| 138 EXPECT_EQ(types.Has(model_type), | |
| 139 registrar_->IsTypeActivatedForTest(model_type)); | |
| 140 } | |
| 141 } | |
| 142 | |
| 143 const scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner() { | |
| 144 return message_loop_.task_runner(); | |
| 145 } | |
| 146 | |
| 147 const scoped_refptr<base::SingleThreadTaskRunner> db_task_runner() { | |
| 148 return db_thread_.task_runner(); | |
| 149 } | |
| 150 | |
| 151 const scoped_refptr<base::SingleThreadTaskRunner> file_task_runner() { | |
| 152 return db_thread_.task_runner(); | |
| 153 } | |
| 154 | |
| 155 base::MessageLoop message_loop_; | |
| 156 base::Thread db_thread_; | |
| 157 base::Thread file_thread_; | |
| 158 | |
| 159 syncer::TestUserShare test_user_share_; | |
| 160 std::unique_ptr<RegistrarSyncClient> sync_client_; | |
| 161 std::unique_ptr<SyncBackendRegistrar> registrar_; | |
| 162 | |
| 163 base::Thread* sync_thread_; | |
| 164 }; | |
| 165 | |
| 166 TEST_F(SyncBackendRegistrarTest, ConstructorEmpty) { | |
| 167 registrar_->SetInitialTypes(ModelTypeSet()); | |
| 168 EXPECT_FALSE(registrar_->IsNigoriEnabled()); | |
| 169 { | |
| 170 std::vector<scoped_refptr<syncer::ModelSafeWorker> > workers; | |
| 171 registrar_->GetWorkers(&workers); | |
| 172 EXPECT_EQ(4u, workers.size()); | |
| 173 } | |
| 174 ExpectRoutingInfo(registrar_.get(), syncer::ModelSafeRoutingInfo()); | |
| 175 ExpectHasProcessorsForTypes(*registrar_, ModelTypeSet()); | |
| 176 } | |
| 177 | |
| 178 TEST_F(SyncBackendRegistrarTest, ConstructorNonEmpty) { | |
| 179 const ModelTypeSet initial_types(BOOKMARKS, NIGORI, PASSWORDS); | |
| 180 registrar_->RegisterNonBlockingType(BOOKMARKS); | |
| 181 registrar_->SetInitialTypes(initial_types); | |
| 182 EXPECT_TRUE(registrar_->IsNigoriEnabled()); | |
| 183 { | |
| 184 std::vector<scoped_refptr<syncer::ModelSafeWorker> > workers; | |
| 185 registrar_->GetWorkers(&workers); | |
| 186 EXPECT_EQ(4u, workers.size()); | |
| 187 } | |
| 188 { | |
| 189 syncer::ModelSafeRoutingInfo expected_routing_info; | |
| 190 expected_routing_info[BOOKMARKS] = syncer::GROUP_NON_BLOCKING; | |
| 191 expected_routing_info[NIGORI] = syncer::GROUP_PASSIVE; | |
| 192 // Passwords dropped because of no password store. | |
| 193 ExpectRoutingInfo(registrar_.get(), expected_routing_info); | |
| 194 } | |
| 195 ExpectHasProcessorsForTypes(*registrar_, ModelTypeSet()); | |
| 196 } | |
| 197 | |
| 198 TEST_F(SyncBackendRegistrarTest, ConfigureDataTypes) { | |
| 199 registrar_->RegisterNonBlockingType(BOOKMARKS); | |
| 200 registrar_->SetInitialTypes(ModelTypeSet()); | |
| 201 | |
| 202 // Add. | |
| 203 const ModelTypeSet types1(BOOKMARKS, NIGORI, AUTOFILL); | |
| 204 EXPECT_EQ(types1, registrar_->ConfigureDataTypes(types1, ModelTypeSet())); | |
| 205 { | |
| 206 syncer::ModelSafeRoutingInfo expected_routing_info; | |
| 207 expected_routing_info[BOOKMARKS] = syncer::GROUP_NON_BLOCKING; | |
| 208 expected_routing_info[NIGORI] = syncer::GROUP_PASSIVE; | |
| 209 expected_routing_info[AUTOFILL] = syncer::GROUP_PASSIVE; | |
| 210 ExpectRoutingInfo(registrar_.get(), expected_routing_info); | |
| 211 } | |
| 212 ExpectHasProcessorsForTypes(*registrar_, ModelTypeSet()); | |
| 213 EXPECT_EQ(types1, registrar_->GetLastConfiguredTypes()); | |
| 214 | |
| 215 // Add and remove. | |
| 216 const ModelTypeSet types2(PREFERENCES, THEMES); | |
| 217 EXPECT_EQ(types2, registrar_->ConfigureDataTypes(types2, types1)); | |
| 218 { | |
| 219 syncer::ModelSafeRoutingInfo expected_routing_info; | |
| 220 expected_routing_info[PREFERENCES] = syncer::GROUP_PASSIVE; | |
| 221 expected_routing_info[THEMES] = syncer::GROUP_PASSIVE; | |
| 222 ExpectRoutingInfo(registrar_.get(), expected_routing_info); | |
| 223 } | |
| 224 ExpectHasProcessorsForTypes(*registrar_, ModelTypeSet()); | |
| 225 EXPECT_EQ(types2, registrar_->GetLastConfiguredTypes()); | |
| 226 | |
| 227 // Remove. | |
| 228 EXPECT_TRUE(registrar_->ConfigureDataTypes(ModelTypeSet(), types2).Empty()); | |
| 229 ExpectRoutingInfo(registrar_.get(), syncer::ModelSafeRoutingInfo()); | |
| 230 ExpectHasProcessorsForTypes(*registrar_, ModelTypeSet()); | |
| 231 EXPECT_EQ(ModelTypeSet(), registrar_->GetLastConfiguredTypes()); | |
| 232 } | |
| 233 | |
| 234 TEST_F(SyncBackendRegistrarTest, ActivateDeactivateUIDataType) { | |
| 235 InSequence in_sequence; | |
| 236 registrar_->SetInitialTypes(ModelTypeSet()); | |
| 237 | |
| 238 // Should do nothing. | |
| 239 TriggerChanges(registrar_.get(), BOOKMARKS); | |
| 240 | |
| 241 StrictMock<sync_driver::ChangeProcessorMock> change_processor_mock; | |
| 242 EXPECT_CALL(change_processor_mock, StartImpl()); | |
| 243 EXPECT_CALL(change_processor_mock, IsRunning()) | |
| 244 .WillRepeatedly(Return(true)); | |
| 245 EXPECT_CALL(change_processor_mock, ApplyChangesFromSyncModel(NULL, _, _)); | |
| 246 EXPECT_CALL(change_processor_mock, IsRunning()) | |
| 247 .WillRepeatedly(Return(true)); | |
| 248 EXPECT_CALL(change_processor_mock, CommitChangesFromSyncModel()); | |
| 249 EXPECT_CALL(change_processor_mock, IsRunning()) | |
| 250 .WillRepeatedly(Return(false)); | |
| 251 | |
| 252 const ModelTypeSet types(BOOKMARKS); | |
| 253 EXPECT_EQ(types, registrar_->ConfigureDataTypes(types, ModelTypeSet())); | |
| 254 registrar_->ActivateDataType(BOOKMARKS, syncer::GROUP_UI, | |
| 255 &change_processor_mock, | |
| 256 test_user_share_.user_share()); | |
| 257 { | |
| 258 syncer::ModelSafeRoutingInfo expected_routing_info; | |
| 259 expected_routing_info[BOOKMARKS] = syncer::GROUP_UI; | |
| 260 ExpectRoutingInfo(registrar_.get(), expected_routing_info); | |
| 261 } | |
| 262 ExpectHasProcessorsForTypes(*registrar_, types); | |
| 263 | |
| 264 TriggerChanges(registrar_.get(), BOOKMARKS); | |
| 265 | |
| 266 registrar_->DeactivateDataType(BOOKMARKS); | |
| 267 ExpectRoutingInfo(registrar_.get(), syncer::ModelSafeRoutingInfo()); | |
| 268 ExpectHasProcessorsForTypes(*registrar_, ModelTypeSet()); | |
| 269 | |
| 270 // Should do nothing. | |
| 271 TriggerChanges(registrar_.get(), BOOKMARKS); | |
| 272 } | |
| 273 | |
| 274 TEST_F(SyncBackendRegistrarTest, ActivateDeactivateNonUIDataType) { | |
| 275 InSequence in_sequence; | |
| 276 registrar_->SetInitialTypes(ModelTypeSet()); | |
| 277 | |
| 278 // Should do nothing. | |
| 279 TriggerChanges(registrar_.get(), AUTOFILL); | |
| 280 | |
| 281 StrictMock<sync_driver::ChangeProcessorMock> change_processor_mock; | |
| 282 EXPECT_CALL(change_processor_mock, StartImpl()); | |
| 283 EXPECT_CALL(change_processor_mock, IsRunning()) | |
| 284 .WillRepeatedly(Return(true)); | |
| 285 EXPECT_CALL(change_processor_mock, ApplyChangesFromSyncModel(NULL, _, _)); | |
| 286 EXPECT_CALL(change_processor_mock, IsRunning()) | |
| 287 .WillRepeatedly(Return(true)); | |
| 288 EXPECT_CALL(change_processor_mock, CommitChangesFromSyncModel()); | |
| 289 EXPECT_CALL(change_processor_mock, IsRunning()) | |
| 290 .WillRepeatedly(Return(false)); | |
| 291 | |
| 292 const ModelTypeSet types(AUTOFILL); | |
| 293 EXPECT_EQ(types, registrar_->ConfigureDataTypes(types, ModelTypeSet())); | |
| 294 | |
| 295 base::WaitableEvent done(base::WaitableEvent::ResetPolicy::AUTOMATIC, | |
| 296 base::WaitableEvent::InitialState::NOT_SIGNALED); | |
| 297 db_task_runner()->PostTask( | |
| 298 FROM_HERE, | |
| 299 base::Bind(&SyncBackendRegistrarTest::TestNonUIDataTypeActivationAsync, | |
| 300 base::Unretained(this), &change_processor_mock, &done)); | |
| 301 done.Wait(); | |
| 302 | |
| 303 registrar_->DeactivateDataType(AUTOFILL); | |
| 304 ExpectRoutingInfo(registrar_.get(), syncer::ModelSafeRoutingInfo()); | |
| 305 ExpectHasProcessorsForTypes(*registrar_, ModelTypeSet()); | |
| 306 | |
| 307 // Should do nothing. | |
| 308 TriggerChanges(registrar_.get(), AUTOFILL); | |
| 309 } | |
| 310 | |
| 311 // Tests that registration and configuration of non-blocking data types is | |
| 312 // handled correctly in SyncBackendRegistrar. | |
| 313 TEST_F(SyncBackendRegistrarTest, ConfigureNonBlockingDataType) { | |
| 314 registrar_->RegisterNonBlockingType(AUTOFILL); | |
| 315 registrar_->RegisterNonBlockingType(BOOKMARKS); | |
| 316 | |
| 317 ExpectRoutingInfo(registrar_.get(), syncer::ModelSafeRoutingInfo()); | |
| 318 // Simulate that initial sync was already done for AUTOFILL. | |
| 319 registrar_->AddRestoredNonBlockingType(AUTOFILL); | |
| 320 // It should be added to routing info and set of configured types. | |
| 321 EXPECT_EQ(ModelTypeSet(AUTOFILL), registrar_->GetLastConfiguredTypes()); | |
| 322 { | |
| 323 syncer::ModelSafeRoutingInfo expected_routing_info; | |
| 324 expected_routing_info[AUTOFILL] = syncer::GROUP_NON_BLOCKING; | |
| 325 ExpectRoutingInfo(registrar_.get(), expected_routing_info); | |
| 326 } | |
| 327 | |
| 328 // Configure two non-blocking types. Initial sync wasn't done for BOOKMARKS so | |
| 329 // it should be included in types to be downloaded. | |
| 330 ModelTypeSet types_to_add(AUTOFILL, BOOKMARKS); | |
| 331 ModelTypeSet newly_added_types = | |
| 332 registrar_->ConfigureDataTypes(types_to_add, ModelTypeSet()); | |
| 333 EXPECT_EQ(ModelTypeSet(BOOKMARKS), newly_added_types); | |
| 334 EXPECT_EQ(types_to_add, registrar_->GetLastConfiguredTypes()); | |
| 335 { | |
| 336 syncer::ModelSafeRoutingInfo expected_routing_info; | |
| 337 expected_routing_info[AUTOFILL] = syncer::GROUP_NON_BLOCKING; | |
| 338 expected_routing_info[BOOKMARKS] = syncer::GROUP_NON_BLOCKING; | |
| 339 ExpectRoutingInfo(registrar_.get(), expected_routing_info); | |
| 340 } | |
| 341 } | |
| 342 | |
| 343 class SyncBackendRegistrarShutdownTest : public testing::Test { | |
| 344 public: | |
| 345 void BlockDBThread() { | |
| 346 EXPECT_FALSE(db_thread_lock_.Try()); | |
| 347 | |
| 348 db_thread_blocked_.Signal(); | |
| 349 base::AutoLock l(db_thread_lock_); | |
| 350 } | |
| 351 | |
| 352 protected: | |
| 353 friend class TestRegistrar; | |
| 354 | |
| 355 SyncBackendRegistrarShutdownTest() | |
| 356 : db_thread_("DBThreadForTest"), | |
| 357 file_thread_("FileThreadForTest"), | |
| 358 db_thread_blocked_(base::WaitableEvent::ResetPolicy::AUTOMATIC, | |
| 359 base::WaitableEvent::InitialState::NOT_SIGNALED) { | |
| 360 quit_closure_ = run_loop_.QuitClosure(); | |
| 361 } | |
| 362 | |
| 363 ~SyncBackendRegistrarShutdownTest() override {} | |
| 364 | |
| 365 void SetUp() override { | |
| 366 db_thread_.StartAndWaitForTesting(); | |
| 367 file_thread_.StartAndWaitForTesting(); | |
| 368 sync_client_.reset(new RegistrarSyncClient( | |
| 369 ui_task_runner(), db_task_runner(), file_task_runner())); | |
| 370 } | |
| 371 | |
| 372 void PostQuitOnUIMessageLoop() { | |
| 373 ui_task_runner()->PostTask(FROM_HERE, quit_closure_); | |
| 374 } | |
| 375 | |
| 376 const scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner() { | |
| 377 return message_loop_.task_runner(); | |
| 378 } | |
| 379 | |
| 380 const scoped_refptr<base::SingleThreadTaskRunner> db_task_runner() { | |
| 381 return db_thread_.task_runner(); | |
| 382 } | |
| 383 | |
| 384 const scoped_refptr<base::SingleThreadTaskRunner> file_task_runner() { | |
| 385 return file_thread_.task_runner(); | |
| 386 } | |
| 387 | |
| 388 base::MessageLoop message_loop_; | |
| 389 base::Thread db_thread_; | |
| 390 base::Thread file_thread_; | |
| 391 | |
| 392 std::unique_ptr<RegistrarSyncClient> sync_client_; | |
| 393 base::WaitableEvent db_thread_blocked_; | |
| 394 | |
| 395 base::Lock db_thread_lock_; | |
| 396 base::RunLoop run_loop_; | |
| 397 base::Closure quit_closure_; | |
| 398 }; | |
| 399 | |
| 400 // Wrap SyncBackendRegistrar so that we can monitor its lifetime. | |
| 401 class TestRegistrar : public SyncBackendRegistrar { | |
| 402 public: | |
| 403 explicit TestRegistrar( | |
| 404 sync_driver::SyncClient* sync_client, | |
| 405 const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread, | |
| 406 const scoped_refptr<base::SingleThreadTaskRunner>& db_thread, | |
| 407 const scoped_refptr<base::SingleThreadTaskRunner>& file_thread, | |
| 408 SyncBackendRegistrarShutdownTest* test) | |
| 409 : SyncBackendRegistrar("test", | |
| 410 sync_client, | |
| 411 std::unique_ptr<base::Thread>(), | |
| 412 ui_thread, | |
| 413 db_thread, | |
| 414 file_thread), | |
| 415 test_(test) {} | |
| 416 | |
| 417 ~TestRegistrar() override { test_->PostQuitOnUIMessageLoop(); } | |
| 418 | |
| 419 private: | |
| 420 SyncBackendRegistrarShutdownTest* test_; | |
| 421 }; | |
| 422 | |
| 423 TEST_F(SyncBackendRegistrarShutdownTest, BlockingShutdown) { | |
| 424 // Take ownership of |db_thread_lock_| so that the DB thread can't acquire it. | |
| 425 db_thread_lock_.Acquire(); | |
| 426 | |
| 427 // This will block the DB thread by waiting on |db_thread_lock_|. | |
| 428 db_task_runner()->PostTask( | |
| 429 FROM_HERE, base::Bind(&SyncBackendRegistrarShutdownTest::BlockDBThread, | |
| 430 base::Unretained(this))); | |
| 431 | |
| 432 std::unique_ptr<TestRegistrar> registrar( | |
| 433 new TestRegistrar(sync_client_.get(), ui_task_runner(), db_task_runner(), | |
| 434 file_task_runner(), this)); | |
| 435 base::Thread* sync_thread = registrar->sync_thread(); | |
| 436 | |
| 437 // Stop here until the DB thread gets a chance to run and block on the lock. | |
| 438 // Please note that since the task above didn't finish, the task to | |
| 439 // initialize the worker on the DB thread hasn't had a chance to run yet too. | |
| 440 // Which means ModelSafeWorker::SetWorkingLoopToCurrent hasn't been called | |
| 441 // for the DB worker. | |
| 442 db_thread_blocked_.Wait(); | |
| 443 | |
| 444 registrar->SetInitialTypes(ModelTypeSet()); | |
| 445 | |
| 446 // Start the shutdown. | |
| 447 registrar->RequestWorkerStopOnUIThread(); | |
| 448 | |
| 449 sync_thread->task_runner()->PostTask( | |
| 450 FROM_HERE, base::Bind(&SyncBackendRegistrar::Shutdown, | |
| 451 base::Unretained(registrar.release()))); | |
| 452 | |
| 453 // Make sure the thread starts running. | |
| 454 sync_thread->WaitUntilThreadStarted(); | |
| 455 | |
| 456 // The test verifies that the sync thread doesn't block because | |
| 457 // of the blocked DB thread and can finish the shutdown. | |
| 458 base::RunLoop().RunUntilIdle(); | |
| 459 | |
| 460 db_thread_lock_.Release(); | |
| 461 | |
| 462 // Run the main thread loop until all workers have been removed and the | |
| 463 // registrar destroyed. | |
| 464 run_loop_.Run(); | |
| 465 } | |
| 466 | |
| 467 } // namespace | |
| 468 | |
| 469 } // namespace browser_sync | |
| OLD | NEW |