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 "testing/gtest/include/gtest/gtest.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/tracked_objects.h" 16 #include "chrome/browser/sync/glue/non_frontend_data_type_controller.h" 17 #include "chrome/browser/sync/glue/non_frontend_data_type_controller_mock.h" 18 #include "chrome/browser/sync/profile_sync_components_factory_mock.h" 19 #include "chrome/browser/sync/profile_sync_service_mock.h" 20 #include "chrome/test/base/profile_mock.h" 21 #include "components/sync_driver/change_processor_mock.h" 22 #include "components/sync_driver/data_type_controller_mock.h" 23 #include "components/sync_driver/model_associator_mock.h" 24 #include "content/public/test/test_browser_thread.h" 25 #include "sync/internal_api/public/engine/model_safe_worker.h" 26 27 using base::WaitableEvent; 28 using syncer::GROUP_DB; 29 using browser_sync::NonFrontendDataTypeController; 30 using browser_sync::NonFrontendDataTypeControllerMock; 31 using sync_driver::ChangeProcessorMock; 32 using sync_driver::DataTypeController; 33 using sync_driver::ModelAssociatorMock; 34 using sync_driver::ModelLoadCallbackMock; 35 using sync_driver::StartCallbackMock; 36 using content::BrowserThread; 37 using testing::_; 38 using testing::DoAll; 39 using testing::InvokeWithoutArgs; 40 using testing::Return; 41 using testing::SetArgumentPointee; 42 using testing::StrictMock; 43 44 ACTION_P(WaitOnEvent, event) { 45 event->Wait(); 46 } 47 48 ACTION_P(SignalEvent, event) { 49 event->Signal(); 50 } 51 52 class NonFrontendDataTypeControllerFake : public NonFrontendDataTypeController { 53 public: 54 NonFrontendDataTypeControllerFake( 55 ProfileSyncComponentsFactory* profile_sync_factory, 56 Profile* profile, 57 ProfileSyncService* sync_service, 58 NonFrontendDataTypeControllerMock* mock) 59 : NonFrontendDataTypeController(base::MessageLoopProxy::current(), 60 base::Closure(), 61 profile_sync_factory, 62 profile, 63 sync_service), 64 mock_(mock) {} 65 66 virtual syncer::ModelType type() const OVERRIDE { return syncer::BOOKMARKS; } 67 virtual syncer::ModelSafeGroup model_safe_group() const OVERRIDE { 68 return syncer::GROUP_DB; 69 } 70 71 private: 72 virtual ~NonFrontendDataTypeControllerFake() {} 73 74 virtual ProfileSyncComponentsFactory::SyncComponents 75 CreateSyncComponents() OVERRIDE { 76 return profile_sync_factory()-> 77 CreateBookmarkSyncComponents(profile_sync_service(), this); 78 } 79 80 virtual bool PostTaskOnBackendThread( 81 const tracked_objects::Location& from_here, 82 const base::Closure& task) OVERRIDE { 83 return BrowserThread::PostTask(BrowserThread::DB, from_here, task); 84 } 85 86 // We mock the following methods because their default implementations do 87 // nothing, but we still want to make sure they're called appropriately. 88 virtual bool StartModels() OVERRIDE { 89 return mock_->StartModels(); 90 } 91 virtual void RecordUnrecoverableError( 92 const tracked_objects::Location& from_here, 93 const std::string& message) OVERRIDE { 94 mock_->RecordUnrecoverableError(from_here, message); 95 } 96 virtual void RecordAssociationTime(base::TimeDelta time) OVERRIDE { 97 mock_->RecordAssociationTime(time); 98 } 99 virtual void RecordStartFailure( 100 DataTypeController::ConfigureResult result) OVERRIDE { 101 mock_->RecordStartFailure(result); 102 } 103 virtual void DisconnectProcessor( 104 sync_driver::ChangeProcessor* processor) OVERRIDE{ 105 mock_->DisconnectProcessor(processor); 106 } 107 108 private: 109 NonFrontendDataTypeControllerMock* mock_; 110 }; 111 112 class SyncNonFrontendDataTypeControllerTest : public testing::Test { 113 public: 114 SyncNonFrontendDataTypeControllerTest() 115 : ui_thread_(BrowserThread::UI, &message_loop_), 116 db_thread_(BrowserThread::DB), 117 service_(&profile_), 118 model_associator_(NULL), 119 change_processor_(NULL) {} 120 121 virtual void SetUp() { 122 db_thread_.Start(); 123 profile_sync_factory_.reset(new ProfileSyncComponentsFactoryMock()); 124 125 // All of these are refcounted, so don't need to be released. 126 dtc_mock_ = new StrictMock<NonFrontendDataTypeControllerMock>(); 127 non_frontend_dtc_ = 128 new NonFrontendDataTypeControllerFake(profile_sync_factory_.get(), 129 &profile_, 130 &service_, 131 dtc_mock_.get()); 132 } 133 134 virtual void TearDown() { 135 if (non_frontend_dtc_->state() != 136 NonFrontendDataTypeController::NOT_RUNNING) { 137 non_frontend_dtc_->Stop(); 138 } 139 db_thread_.Stop(); 140 } 141 142 protected: 143 void SetStartExpectations() { 144 EXPECT_CALL(*dtc_mock_.get(), StartModels()).WillOnce(Return(true)); 145 EXPECT_CALL(model_load_callback_, Run(_, _)); 146 model_associator_ = new ModelAssociatorMock(); 147 change_processor_ = new ChangeProcessorMock(); 148 EXPECT_CALL(*profile_sync_factory_, CreateBookmarkSyncComponents(_, _)). 149 WillOnce(Return(ProfileSyncComponentsFactory::SyncComponents( 150 model_associator_, change_processor_))); 151 } 152 153 void SetAssociateExpectations() { 154 EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()). 155 WillOnce(Return(true)); 156 EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)). 157 WillOnce(DoAll(SetArgumentPointee<0>(true), Return(true))); 158 EXPECT_CALL(*model_associator_, AssociateModels(_, _)). 159 WillOnce(Return(syncer::SyncError())); 160 EXPECT_CALL(*dtc_mock_.get(), RecordAssociationTime(_)); 161 } 162 163 void SetActivateExpectations(DataTypeController::ConfigureResult result) { 164 EXPECT_CALL(start_callback_, Run(result, _, _)); 165 } 166 167 void SetStopExpectations() { 168 EXPECT_CALL(*dtc_mock_.get(), DisconnectProcessor(_)); 169 EXPECT_CALL(service_, DeactivateDataType(_)); 170 EXPECT_CALL(*model_associator_, DisassociateModels()). 171 WillOnce(Return(syncer::SyncError())); 172 } 173 174 void SetStartFailExpectations(DataTypeController::ConfigureResult result) { 175 if (DataTypeController::IsUnrecoverableResult(result)) 176 EXPECT_CALL(*dtc_mock_.get(), RecordUnrecoverableError(_, _)); 177 if (model_associator_) { 178 EXPECT_CALL(*model_associator_, DisassociateModels()). 179 WillOnce(Return(syncer::SyncError())); 180 } 181 EXPECT_CALL(*dtc_mock_.get(), RecordStartFailure(result)); 182 EXPECT_CALL(start_callback_, Run(result, _, _)); 183 } 184 185 static void SignalDone(WaitableEvent* done) { 186 done->Signal(); 187 } 188 189 void WaitForDTC() { 190 WaitableEvent done(true, false); 191 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, 192 base::Bind(&SyncNonFrontendDataTypeControllerTest::SignalDone, &done)); 193 done.TimedWait(TestTimeouts::action_timeout()); 194 if (!done.IsSignaled()) { 195 ADD_FAILURE() << "Timed out waiting for DB thread to finish."; 196 } 197 base::MessageLoop::current()->RunUntilIdle(); 198 } 199 200 void Start() { 201 non_frontend_dtc_->LoadModels( 202 base::Bind(&ModelLoadCallbackMock::Run, 203 base::Unretained(&model_load_callback_))); 204 non_frontend_dtc_->StartAssociating( 205 base::Bind(&StartCallbackMock::Run, 206 base::Unretained(&start_callback_))); 207 } 208 209 base::MessageLoopForUI message_loop_; 210 content::TestBrowserThread ui_thread_; 211 content::TestBrowserThread db_thread_; 212 scoped_refptr<NonFrontendDataTypeControllerFake> non_frontend_dtc_; 213 scoped_ptr<ProfileSyncComponentsFactoryMock> profile_sync_factory_; 214 scoped_refptr<NonFrontendDataTypeControllerMock> dtc_mock_; 215 ProfileMock profile_; 216 ProfileSyncServiceMock service_; 217 ModelAssociatorMock* model_associator_; 218 ChangeProcessorMock* change_processor_; 219 StartCallbackMock start_callback_; 220 ModelLoadCallbackMock model_load_callback_; 221 }; 222 223 TEST_F(SyncNonFrontendDataTypeControllerTest, StartOk) { 224 SetStartExpectations(); 225 SetAssociateExpectations(); 226 SetActivateExpectations(DataTypeController::OK); 227 SetStopExpectations(); 228 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state()); 229 Start(); 230 WaitForDTC(); 231 EXPECT_EQ(DataTypeController::RUNNING, non_frontend_dtc_->state()); 232 } 233 234 TEST_F(SyncNonFrontendDataTypeControllerTest, StartFirstRun) { 235 SetStartExpectations(); 236 EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()). 237 WillOnce(Return(true)); 238 EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)). 239 WillOnce(DoAll(SetArgumentPointee<0>(false), Return(true))); 240 EXPECT_CALL(*model_associator_, AssociateModels(_, _)). 241 WillOnce(Return(syncer::SyncError())); 242 EXPECT_CALL(*dtc_mock_.get(), RecordAssociationTime(_)); 243 SetActivateExpectations(DataTypeController::OK_FIRST_RUN); 244 SetStopExpectations(); 245 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state()); 246 Start(); 247 WaitForDTC(); 248 EXPECT_EQ(DataTypeController::RUNNING, non_frontend_dtc_->state()); 249 } 250 251 TEST_F(SyncNonFrontendDataTypeControllerTest, StartAssociationFailed) { 252 SetStartExpectations(); 253 EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()). 254 WillOnce(Return(true)); 255 EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)). 256 WillOnce(DoAll(SetArgumentPointee<0>(true), Return(true))); 257 EXPECT_CALL(*model_associator_, AssociateModels(_, _)). 258 WillOnce( 259 Return(syncer::SyncError(FROM_HERE, 260 syncer::SyncError::DATATYPE_ERROR, 261 "Error", 262 syncer::BOOKMARKS))); 263 EXPECT_CALL(*dtc_mock_.get(), RecordAssociationTime(_)); 264 SetStartFailExpectations(DataTypeController::ASSOCIATION_FAILED); 265 // Set up association to fail with an association failed error. 266 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state()); 267 Start(); 268 WaitForDTC(); 269 EXPECT_EQ(DataTypeController::DISABLED, non_frontend_dtc_->state()); 270 } 271 272 TEST_F(SyncNonFrontendDataTypeControllerTest, 273 StartAssociationTriggersUnrecoverableError) { 274 SetStartExpectations(); 275 SetStartFailExpectations(DataTypeController::UNRECOVERABLE_ERROR); 276 // Set up association to fail with an unrecoverable error. 277 EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()). 278 WillRepeatedly(Return(true)); 279 EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)). 280 WillRepeatedly(DoAll(SetArgumentPointee<0>(false), Return(false))); 281 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state()); 282 Start(); 283 WaitForDTC(); 284 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state()); 285 } 286 287 TEST_F(SyncNonFrontendDataTypeControllerTest, StartAssociationCryptoNotReady) { 288 SetStartExpectations(); 289 SetStartFailExpectations(DataTypeController::NEEDS_CRYPTO); 290 // Set up association to fail with a NEEDS_CRYPTO error. 291 EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()). 292 WillRepeatedly(Return(false)); 293 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state()); 294 Start(); 295 WaitForDTC(); 296 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state()); 297 } 298 299 // Trigger a Stop() call when we check if the model associator has user created 300 // nodes. 301 TEST_F(SyncNonFrontendDataTypeControllerTest, AbortDuringAssociationInactive) { 302 WaitableEvent wait_for_db_thread_pause(false, false); 303 WaitableEvent pause_db_thread(false, false); 304 305 SetStartExpectations(); 306 EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()). 307 WillOnce(Return(true)); 308 EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)). 309 WillOnce(DoAll( 310 SignalEvent(&wait_for_db_thread_pause), 311 WaitOnEvent(&pause_db_thread), 312 SetArgumentPointee<0>(true), 313 Return(true))); 314 EXPECT_CALL(*model_associator_, AbortAssociation()).WillOnce( 315 SignalEvent(&pause_db_thread)); 316 EXPECT_CALL(*model_associator_, AssociateModels(_, _)). 317 WillOnce(Return(syncer::SyncError())); 318 SetStopExpectations(); 319 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state()); 320 Start(); 321 wait_for_db_thread_pause.Wait(); 322 non_frontend_dtc_->Stop(); 323 WaitForDTC(); 324 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state()); 325 } 326 327 // Same as above but abort during the Activate call. 328 TEST_F(SyncNonFrontendDataTypeControllerTest, AbortDuringAssociationActivated) { 329 WaitableEvent wait_for_association_starts(false, false); 330 WaitableEvent wait_for_dtc_stop(false, false); 331 332 SetStartExpectations(); 333 EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()). 334 WillOnce(Return(true)); 335 EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)). 336 WillOnce(DoAll( 337 SetArgumentPointee<0>(true), 338 Return(true))); 339 EXPECT_CALL(*model_associator_, AbortAssociation()); 340 EXPECT_CALL(*model_associator_, AssociateModels(_, _)). 341 WillOnce(DoAll( 342 SignalEvent(&wait_for_association_starts), 343 WaitOnEvent(&wait_for_dtc_stop), 344 Return(syncer::SyncError()))); 345 SetStopExpectations(); 346 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state()); 347 Start(); 348 wait_for_association_starts.Wait(); 349 non_frontend_dtc_->Stop(); 350 wait_for_dtc_stop.Signal(); 351 WaitForDTC(); 352 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state()); 353 } 354 355 TEST_F(SyncNonFrontendDataTypeControllerTest, Stop) { 356 SetStartExpectations(); 357 SetAssociateExpectations(); 358 SetActivateExpectations(DataTypeController::OK); 359 SetStopExpectations(); 360 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state()); 361 Start(); 362 WaitForDTC(); 363 EXPECT_EQ(DataTypeController::RUNNING, non_frontend_dtc_->state()); 364 non_frontend_dtc_->Stop(); 365 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state()); 366 } 367 368 // Disabled due to http://crbug.com/388367 369 TEST_F(SyncNonFrontendDataTypeControllerTest, 370 DISABLED_OnSingleDataTypeUnrecoverableError) { 371 SetStartExpectations(); 372 SetAssociateExpectations(); 373 SetActivateExpectations(DataTypeController::OK); 374 EXPECT_CALL(*dtc_mock_.get(), RecordUnrecoverableError(_, "Test")); 375 EXPECT_CALL(service_, DisableDatatype(_)) 376 .WillOnce(InvokeWithoutArgs(non_frontend_dtc_.get(), 377 &NonFrontendDataTypeController::Stop)); 378 SetStopExpectations(); 379 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state()); 380 Start(); 381 WaitForDTC(); 382 EXPECT_EQ(DataTypeController::RUNNING, non_frontend_dtc_->state()); 383 // This should cause non_frontend_dtc_->Stop() to be called. 384 syncer::SyncError error(FROM_HERE, 385 syncer::SyncError::DATATYPE_ERROR, 386 "error", 387 non_frontend_dtc_->type()); 388 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, base::Bind( 389 &NonFrontendDataTypeControllerFake::OnSingleDataTypeUnrecoverableError, 390 non_frontend_dtc_.get(), 391 error)); 392 WaitForDTC(); 393 EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state()); 394 } 395