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