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/non_ui_data_type_controller.h" 6 7 #include "base/bind.h" 8 #include "base/bind_helpers.h" 9 #include "base/callback.h" 10 #include "base/compiler_specific.h" 11 #include "base/memory/scoped_ptr.h" 12 #include "base/message_loop/message_loop.h" 13 #include "base/synchronization/waitable_event.h" 14 #include "base/test/test_timeouts.h" 15 #include "base/threading/thread.h" 16 #include "base/tracked_objects.h" 17 #include "components/sync_driver/data_type_controller_mock.h" 18 #include "components/sync_driver/generic_change_processor_factory.h" 19 #include "components/sync_driver/non_ui_data_type_controller_mock.h" 20 #include "sync/api/fake_syncable_service.h" 21 #include "sync/api/sync_change.h" 22 #include "sync/internal_api/public/engine/model_safe_worker.h" 23 #include "testing/gmock/include/gmock/gmock.h" 24 #include "testing/gtest/include/gtest/gtest.h" 25 26 namespace browser_sync { 27 28 namespace { 29 30 using base::WaitableEvent; 31 using syncer::AUTOFILL_PROFILE; 32 using testing::_; 33 using testing::AtLeast; 34 using testing::DoAll; 35 using testing::InvokeWithoutArgs; 36 using testing::Mock; 37 using testing::Return; 38 using testing::SetArgumentPointee; 39 using testing::StrictMock; 40 41 ACTION_P(WaitOnEvent, event) { 42 event->Wait(); 43 } 44 45 ACTION_P(SignalEvent, event) { 46 event->Signal(); 47 } 48 49 ACTION_P(SaveChangeProcessor, scoped_change_processor) { 50 scoped_change_processor->reset(arg2); 51 } 52 53 ACTION_P(GetWeakPtrToSyncableService, syncable_service) { 54 // Have to do this within an Action to ensure it's not evaluated on the wrong 55 // thread. 56 return syncable_service->AsWeakPtr(); 57 } 58 59 class SharedChangeProcessorMock : public SharedChangeProcessor { 60 public: 61 SharedChangeProcessorMock() {} 62 63 MOCK_METHOD6(Connect, base::WeakPtr<syncer::SyncableService>( 64 browser_sync::SyncApiComponentFactory*, 65 GenericChangeProcessorFactory*, 66 syncer::UserShare*, 67 DataTypeErrorHandler*, 68 syncer::ModelType, 69 const base::WeakPtr<syncer::SyncMergeResult>&)); 70 MOCK_METHOD0(Disconnect, bool()); 71 MOCK_METHOD2(ProcessSyncChanges, 72 syncer::SyncError(const tracked_objects::Location&, 73 const syncer::SyncChangeList&)); 74 MOCK_CONST_METHOD2(GetAllSyncDataReturnError, 75 syncer::SyncError(syncer::ModelType, 76 syncer::SyncDataList*)); 77 MOCK_METHOD0(GetSyncCount, int()); 78 MOCK_METHOD1(SyncModelHasUserCreatedNodes, 79 bool(bool*)); 80 MOCK_METHOD0(CryptoReadyIfNecessary, bool()); 81 MOCK_CONST_METHOD1(GetDataTypeContext, bool(std::string*)); 82 83 protected: 84 virtual ~SharedChangeProcessorMock() {} 85 MOCK_METHOD2(OnUnrecoverableError, void(const tracked_objects::Location&, 86 const std::string&)); 87 88 private: 89 DISALLOW_COPY_AND_ASSIGN(SharedChangeProcessorMock); 90 }; 91 92 class NonUIDataTypeControllerFake 93 : public NonUIDataTypeController { 94 public: 95 NonUIDataTypeControllerFake( 96 browser_sync::SyncApiComponentFactory* sync_factory, 97 NonUIDataTypeControllerMock* mock, 98 SharedChangeProcessor* change_processor, 99 const DisableTypeCallback& disable_callback, 100 scoped_refptr<base::MessageLoopProxy> backend_loop) 101 : NonUIDataTypeController( 102 base::MessageLoopProxy::current(), 103 base::Closure(), 104 disable_callback, 105 sync_factory), 106 blocked_(false), 107 mock_(mock), 108 change_processor_(change_processor), 109 backend_loop_(backend_loop) {} 110 111 virtual syncer::ModelType type() const OVERRIDE { 112 return AUTOFILL_PROFILE; 113 } 114 virtual syncer::ModelSafeGroup model_safe_group() const OVERRIDE { 115 return syncer::GROUP_DB; 116 } 117 118 // Prevent tasks from being posted on the backend thread until 119 // UnblockBackendTasks() is called. 120 void BlockBackendTasks() { 121 blocked_ = true; 122 } 123 124 // Post pending tasks on the backend thread and start allowing tasks 125 // to be posted on the backend thread again. 126 void UnblockBackendTasks() { 127 blocked_ = false; 128 for (std::vector<PendingTask>::const_iterator it = pending_tasks_.begin(); 129 it != pending_tasks_.end(); ++it) { 130 PostTaskOnBackendThread(it->from_here, it->task); 131 } 132 pending_tasks_.clear(); 133 } 134 135 virtual SharedChangeProcessor* CreateSharedChangeProcessor() OVERRIDE { 136 return change_processor_; 137 } 138 139 protected: 140 virtual bool PostTaskOnBackendThread( 141 const tracked_objects::Location& from_here, 142 const base::Closure& task) OVERRIDE { 143 if (blocked_) { 144 pending_tasks_.push_back(PendingTask(from_here, task)); 145 return true; 146 } else { 147 return backend_loop_->PostTask(from_here, task); 148 } 149 } 150 151 // We mock the following methods because their default implementations do 152 // nothing, but we still want to make sure they're called appropriately. 153 virtual bool StartModels() OVERRIDE { 154 return mock_->StartModels(); 155 } 156 virtual void StopModels() OVERRIDE { 157 mock_->StopModels(); 158 } 159 virtual void RecordAssociationTime(base::TimeDelta time) OVERRIDE { 160 mock_->RecordAssociationTime(time); 161 } 162 virtual void RecordStartFailure(DataTypeController::StartResult result) 163 OVERRIDE { 164 mock_->RecordStartFailure(result); 165 } 166 167 private: 168 virtual ~NonUIDataTypeControllerFake() {} 169 170 DISALLOW_COPY_AND_ASSIGN(NonUIDataTypeControllerFake); 171 172 struct PendingTask { 173 PendingTask(const tracked_objects::Location& from_here, 174 const base::Closure& task) 175 : from_here(from_here), task(task) {} 176 177 tracked_objects::Location from_here; 178 base::Closure task; 179 }; 180 181 bool blocked_; 182 std::vector<PendingTask> pending_tasks_; 183 NonUIDataTypeControllerMock* mock_; 184 scoped_refptr<SharedChangeProcessor> change_processor_; 185 scoped_refptr<base::MessageLoopProxy> backend_loop_; 186 }; 187 188 class SyncNonUIDataTypeControllerTest : public testing::Test { 189 public: 190 SyncNonUIDataTypeControllerTest() 191 : backend_thread_("dbthread"), 192 disable_callback_invoked_(false) {} 193 194 virtual void SetUp() OVERRIDE { 195 backend_thread_.Start(); 196 change_processor_ = new SharedChangeProcessorMock(); 197 // All of these are refcounted, so don't need to be released. 198 dtc_mock_ = new StrictMock<NonUIDataTypeControllerMock>(); 199 DataTypeController::DisableTypeCallback disable_callback = 200 base::Bind(&SyncNonUIDataTypeControllerTest::DisableTypeCallback, 201 base::Unretained(this)); 202 non_ui_dtc_ = 203 new NonUIDataTypeControllerFake(NULL, 204 dtc_mock_.get(), 205 change_processor_, 206 disable_callback, 207 backend_thread_.message_loop_proxy()); 208 } 209 210 virtual void TearDown() OVERRIDE { 211 backend_thread_.Stop(); 212 } 213 214 void WaitForDTC() { 215 WaitableEvent done(true, false); 216 backend_thread_.message_loop_proxy()->PostTask( 217 FROM_HERE, 218 base::Bind(&SyncNonUIDataTypeControllerTest::SignalDone, 219 &done)); 220 done.TimedWait(TestTimeouts::action_timeout()); 221 if (!done.IsSignaled()) { 222 ADD_FAILURE() << "Timed out waiting for DB thread to finish."; 223 } 224 base::MessageLoop::current()->RunUntilIdle(); 225 } 226 227 protected: 228 void SetStartExpectations() { 229 EXPECT_CALL(*dtc_mock_.get(), StartModels()).WillOnce(Return(true)); 230 EXPECT_CALL(model_load_callback_, Run(_, _)); 231 } 232 233 void SetAssociateExpectations() { 234 EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _, _)) 235 .WillOnce(GetWeakPtrToSyncableService(&syncable_service_)); 236 EXPECT_CALL(*change_processor_.get(), CryptoReadyIfNecessary()) 237 .WillOnce(Return(true)); 238 EXPECT_CALL(*change_processor_.get(), SyncModelHasUserCreatedNodes(_)) 239 .WillOnce(DoAll(SetArgumentPointee<0>(true), Return(true))); 240 EXPECT_CALL(*change_processor_.get(), GetAllSyncDataReturnError(_,_)) 241 .WillOnce(Return(syncer::SyncError())); 242 EXPECT_CALL(*change_processor_.get(), GetSyncCount()).WillOnce(Return(0)); 243 EXPECT_CALL(*dtc_mock_.get(), RecordAssociationTime(_)); 244 } 245 246 void SetActivateExpectations(DataTypeController::StartResult result) { 247 EXPECT_CALL(start_callback_, Run(result,_,_)); 248 } 249 250 void SetStopExpectations() { 251 EXPECT_CALL(*dtc_mock_.get(), StopModels()); 252 EXPECT_CALL(*change_processor_.get(), Disconnect()).WillOnce(Return(true)); 253 } 254 255 void SetStartFailExpectations(DataTypeController::StartResult result) { 256 EXPECT_CALL(*dtc_mock_.get(), StopModels()).Times(AtLeast(1)); 257 EXPECT_CALL(*dtc_mock_.get(), RecordStartFailure(result)); 258 EXPECT_CALL(start_callback_, Run(result, _, _)); 259 } 260 261 void Start() { 262 non_ui_dtc_->LoadModels( 263 base::Bind(&ModelLoadCallbackMock::Run, 264 base::Unretained(&model_load_callback_))); 265 non_ui_dtc_->StartAssociating( 266 base::Bind(&StartCallbackMock::Run, 267 base::Unretained(&start_callback_))); 268 } 269 270 static void SignalDone(WaitableEvent* done) { 271 done->Signal(); 272 } 273 274 void DisableTypeCallback(const tracked_objects::Location& location, 275 const std::string& message) { 276 disable_callback_invoked_ = true; 277 non_ui_dtc_->Stop(); 278 } 279 280 base::MessageLoopForUI message_loop_; 281 base::Thread backend_thread_; 282 283 StartCallbackMock start_callback_; 284 ModelLoadCallbackMock model_load_callback_; 285 // Must be destroyed after non_ui_dtc_. 286 syncer::FakeSyncableService syncable_service_; 287 scoped_refptr<NonUIDataTypeControllerFake> non_ui_dtc_; 288 scoped_refptr<NonUIDataTypeControllerMock> dtc_mock_; 289 scoped_refptr<SharedChangeProcessorMock> change_processor_; 290 scoped_ptr<syncer::SyncChangeProcessor> saved_change_processor_; 291 292 bool disable_callback_invoked_; 293 }; 294 295 TEST_F(SyncNonUIDataTypeControllerTest, StartOk) { 296 SetStartExpectations(); 297 SetAssociateExpectations(); 298 SetActivateExpectations(DataTypeController::OK); 299 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state()); 300 Start(); 301 WaitForDTC(); 302 EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state()); 303 } 304 305 TEST_F(SyncNonUIDataTypeControllerTest, StartFirstRun) { 306 SetStartExpectations(); 307 EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _, _)) 308 .WillOnce(GetWeakPtrToSyncableService(&syncable_service_)); 309 EXPECT_CALL(*change_processor_.get(), CryptoReadyIfNecessary()) 310 .WillOnce(Return(true)); 311 EXPECT_CALL(*change_processor_.get(), SyncModelHasUserCreatedNodes(_)) 312 .WillOnce(DoAll(SetArgumentPointee<0>(false), Return(true))); 313 EXPECT_CALL(*change_processor_.get(), GetAllSyncDataReturnError(_,_)) 314 .WillOnce(Return(syncer::SyncError())); 315 EXPECT_CALL(*dtc_mock_.get(), RecordAssociationTime(_)); 316 SetActivateExpectations(DataTypeController::OK_FIRST_RUN); 317 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state()); 318 Start(); 319 WaitForDTC(); 320 EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state()); 321 } 322 323 // Start the DTC and have StartModels() return false. Then, stop the 324 // DTC without finishing model startup. It should stop cleanly. 325 TEST_F(SyncNonUIDataTypeControllerTest, AbortDuringStartModels) { 326 EXPECT_CALL(*dtc_mock_.get(), StartModels()).WillOnce(Return(false)); 327 EXPECT_CALL(*dtc_mock_.get(), StopModels()); 328 EXPECT_CALL(model_load_callback_, Run(_, _)); 329 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state()); 330 non_ui_dtc_->LoadModels( 331 base::Bind(&ModelLoadCallbackMock::Run, 332 base::Unretained(&model_load_callback_))); 333 WaitForDTC(); 334 EXPECT_EQ(DataTypeController::MODEL_STARTING, non_ui_dtc_->state()); 335 non_ui_dtc_->Stop(); 336 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state()); 337 } 338 339 // Start the DTC and have MergeDataAndStartSyncing() return an error. 340 // The DTC should become disabled, and the DTC should still stop 341 // cleanly. 342 TEST_F(SyncNonUIDataTypeControllerTest, StartAssociationFailed) { 343 SetStartExpectations(); 344 EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _, _)) 345 .WillOnce(GetWeakPtrToSyncableService(&syncable_service_)); 346 EXPECT_CALL(*change_processor_.get(), CryptoReadyIfNecessary()) 347 .WillOnce(Return(true)); 348 EXPECT_CALL(*change_processor_.get(), SyncModelHasUserCreatedNodes(_)) 349 .WillOnce(DoAll(SetArgumentPointee<0>(true), Return(true))); 350 EXPECT_CALL(*change_processor_.get(), GetAllSyncDataReturnError(_,_)) 351 .WillOnce(Return(syncer::SyncError())); 352 EXPECT_CALL(*dtc_mock_.get(), RecordAssociationTime(_)); 353 SetStartFailExpectations(DataTypeController::ASSOCIATION_FAILED); 354 // Set up association to fail with an association failed error. 355 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state()); 356 syncable_service_.set_merge_data_and_start_syncing_error( 357 syncer::SyncError(FROM_HERE, 358 syncer::SyncError::DATATYPE_ERROR, 359 "Sync Error", 360 non_ui_dtc_->type())); 361 Start(); 362 WaitForDTC(); 363 EXPECT_EQ(DataTypeController::DISABLED, non_ui_dtc_->state()); 364 non_ui_dtc_->Stop(); 365 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state()); 366 } 367 368 TEST_F(SyncNonUIDataTypeControllerTest, 369 StartAssociationTriggersUnrecoverableError) { 370 SetStartExpectations(); 371 SetStartFailExpectations(DataTypeController::UNRECOVERABLE_ERROR); 372 // Set up association to fail with an unrecoverable error. 373 EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _, _)) 374 .WillOnce(GetWeakPtrToSyncableService(&syncable_service_)); 375 EXPECT_CALL(*change_processor_.get(), CryptoReadyIfNecessary()) 376 .WillRepeatedly(Return(true)); 377 EXPECT_CALL(*change_processor_.get(), SyncModelHasUserCreatedNodes(_)) 378 .WillRepeatedly(DoAll(SetArgumentPointee<0>(false), Return(false))); 379 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state()); 380 Start(); 381 WaitForDTC(); 382 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state()); 383 } 384 385 TEST_F(SyncNonUIDataTypeControllerTest, 386 StartAssociationCryptoNotReady) { 387 SetStartExpectations(); 388 SetStartFailExpectations(DataTypeController::NEEDS_CRYPTO); 389 // Set up association to fail with a NEEDS_CRYPTO error. 390 EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _, _)) 391 .WillOnce(GetWeakPtrToSyncableService(&syncable_service_)); 392 EXPECT_CALL(*change_processor_.get(), CryptoReadyIfNecessary()) 393 .WillRepeatedly(Return(false)); 394 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state()); 395 Start(); 396 WaitForDTC(); 397 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state()); 398 } 399 400 // Trigger a Stop() call when we check if the model associator has user created 401 // nodes. 402 TEST_F(SyncNonUIDataTypeControllerTest, AbortDuringAssociation) { 403 WaitableEvent wait_for_db_thread_pause(false, false); 404 WaitableEvent pause_db_thread(false, false); 405 406 SetStartExpectations(); 407 SetStartFailExpectations(DataTypeController::ABORTED); 408 EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _, _)) 409 .WillOnce(GetWeakPtrToSyncableService(&syncable_service_)); 410 EXPECT_CALL(*change_processor_.get(), CryptoReadyIfNecessary()) 411 .WillOnce(Return(true)); 412 EXPECT_CALL(*change_processor_.get(), SyncModelHasUserCreatedNodes(_)) 413 .WillOnce(DoAll(SignalEvent(&wait_for_db_thread_pause), 414 WaitOnEvent(&pause_db_thread), 415 SetArgumentPointee<0>(true), 416 Return(true))); 417 EXPECT_CALL(*change_processor_.get(), GetAllSyncDataReturnError(_,_)) 418 .WillOnce( 419 Return(syncer::SyncError(FROM_HERE, 420 syncer::SyncError::DATATYPE_ERROR, 421 "Disconnected.", 422 AUTOFILL_PROFILE))); 423 EXPECT_CALL(*change_processor_.get(), Disconnect()) 424 .WillOnce(DoAll(SignalEvent(&pause_db_thread), Return(true))); 425 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state()); 426 Start(); 427 wait_for_db_thread_pause.Wait(); 428 non_ui_dtc_->Stop(); 429 WaitForDTC(); 430 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state()); 431 } 432 433 // Start the DTC while the backend tasks are blocked. Then stop the DTC before 434 // the backend tasks get a chance to run. 435 TEST_F(SyncNonUIDataTypeControllerTest, StartAfterSyncShutdown) { 436 non_ui_dtc_->BlockBackendTasks(); 437 438 SetStartExpectations(); 439 // We don't expect StopSyncing to be called because local_service_ will never 440 // have been set. 441 EXPECT_CALL(*change_processor_.get(), Disconnect()).WillOnce(Return(true)); 442 EXPECT_CALL(*dtc_mock_.get(), StopModels()); 443 EXPECT_CALL(*dtc_mock_.get(), 444 RecordStartFailure(DataTypeController::ABORTED)); 445 EXPECT_CALL(start_callback_, Run(DataTypeController::ABORTED, _, _)); 446 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state()); 447 Start(); 448 non_ui_dtc_->Stop(); 449 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state()); 450 Mock::VerifyAndClearExpectations(change_processor_.get()); 451 Mock::VerifyAndClearExpectations(dtc_mock_.get()); 452 453 EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _, _)) 454 .WillOnce(Return(base::WeakPtr<syncer::SyncableService>())); 455 non_ui_dtc_->UnblockBackendTasks(); 456 WaitForDTC(); 457 } 458 459 TEST_F(SyncNonUIDataTypeControllerTest, Stop) { 460 SetStartExpectations(); 461 SetAssociateExpectations(); 462 SetActivateExpectations(DataTypeController::OK); 463 SetStopExpectations(); 464 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state()); 465 Start(); 466 WaitForDTC(); 467 EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state()); 468 non_ui_dtc_->Stop(); 469 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state()); 470 } 471 472 // Start the DTC then block its backend tasks. While its backend 473 // tasks are blocked, stop and start it again, then unblock its 474 // backend tasks. The (delayed) running of the backend tasks from the 475 // stop after the restart shouldn't cause any problems. 476 TEST_F(SyncNonUIDataTypeControllerTest, StopStart) { 477 SetStartExpectations(); 478 SetAssociateExpectations(); 479 SetActivateExpectations(DataTypeController::OK); 480 SetStopExpectations(); 481 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state()); 482 Start(); 483 WaitForDTC(); 484 EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state()); 485 486 non_ui_dtc_->BlockBackendTasks(); 487 non_ui_dtc_->Stop(); 488 SetStartExpectations(); 489 SetAssociateExpectations(); 490 SetActivateExpectations(DataTypeController::OK); 491 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state()); 492 Start(); 493 non_ui_dtc_->UnblockBackendTasks(); 494 495 WaitForDTC(); 496 EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state()); 497 } 498 499 TEST_F(SyncNonUIDataTypeControllerTest, 500 OnSingleDatatypeUnrecoverableError) { 501 SetStartExpectations(); 502 SetAssociateExpectations(); 503 SetActivateExpectations(DataTypeController::OK); 504 SetStopExpectations(); 505 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state()); 506 Start(); 507 WaitForDTC(); 508 EXPECT_EQ(DataTypeController::RUNNING, non_ui_dtc_->state()); 509 // This should cause non_ui_dtc_->Stop() to be called. 510 backend_thread_.message_loop_proxy()->PostTask(FROM_HERE, base::Bind( 511 &NonUIDataTypeControllerFake:: 512 OnSingleDatatypeUnrecoverableError, 513 non_ui_dtc_.get(), 514 FROM_HERE, 515 std::string("Test"))); 516 WaitForDTC(); 517 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_ui_dtc_->state()); 518 EXPECT_TRUE(disable_callback_invoked_); 519 } 520 521 } // namespace 522 523 } // namespace browser_sync 524