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