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/memory/scoped_ptr.h" 11 #include "base/message_loop/message_loop.h" 12 #include "base/tracked_objects.h" 13 #include "chrome/browser/sync/glue/change_processor_mock.h" 14 #include "chrome/browser/sync/glue/data_type_controller_mock.h" 15 #include "chrome/browser/sync/glue/frontend_data_type_controller.h" 16 #include "chrome/browser/sync/glue/frontend_data_type_controller_mock.h" 17 #include "chrome/browser/sync/glue/model_associator_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 "content/public/test/test_browser_thread.h" 22 23 using browser_sync::ChangeProcessorMock; 24 using browser_sync::DataTypeController; 25 using browser_sync::FrontendDataTypeController; 26 using browser_sync::FrontendDataTypeControllerMock; 27 using browser_sync::ModelAssociatorMock; 28 using browser_sync::ModelLoadCallbackMock; 29 using browser_sync::StartCallbackMock; 30 using content::BrowserThread; 31 using testing::_; 32 using testing::DoAll; 33 using testing::InvokeWithoutArgs; 34 using testing::Return; 35 using testing::SetArgumentPointee; 36 using testing::StrictMock; 37 38 class FrontendDataTypeControllerFake : public FrontendDataTypeController { 39 public: 40 FrontendDataTypeControllerFake( 41 ProfileSyncComponentsFactory* profile_sync_factory, 42 Profile* profile, 43 ProfileSyncService* sync_service, 44 FrontendDataTypeControllerMock* mock) 45 : FrontendDataTypeController(profile_sync_factory, 46 profile, 47 sync_service), 48 mock_(mock) {} 49 virtual syncer::ModelType type() const OVERRIDE { return syncer::BOOKMARKS; } 50 51 private: 52 virtual void CreateSyncComponents() OVERRIDE { 53 ProfileSyncComponentsFactory::SyncComponents sync_components = 54 profile_sync_factory_-> 55 CreateBookmarkSyncComponents(sync_service_, this); 56 model_associator_.reset(sync_components.model_associator); 57 change_processor_.reset(sync_components.change_processor); 58 } 59 60 // We mock the following methods because their default implementations do 61 // nothing, but we still want to make sure they're called appropriately. 62 virtual bool StartModels() OVERRIDE { 63 return mock_->StartModels(); 64 } 65 virtual void CleanUpState() OVERRIDE { 66 mock_->CleanUpState(); 67 } 68 virtual void RecordUnrecoverableError( 69 const tracked_objects::Location& from_here, 70 const std::string& message) OVERRIDE { 71 mock_->RecordUnrecoverableError(from_here, message); 72 } 73 virtual void RecordAssociationTime(base::TimeDelta time) OVERRIDE { 74 mock_->RecordAssociationTime(time); 75 } 76 virtual void RecordStartFailure( 77 DataTypeController::StartResult result) OVERRIDE { 78 mock_->RecordStartFailure(result); 79 } 80 private: 81 virtual ~FrontendDataTypeControllerFake() {} 82 FrontendDataTypeControllerMock* mock_; 83 }; 84 85 class SyncFrontendDataTypeControllerTest : public testing::Test { 86 public: 87 SyncFrontendDataTypeControllerTest() 88 : ui_thread_(BrowserThread::UI, &message_loop_) {} 89 90 virtual void SetUp() { 91 profile_sync_factory_.reset(new ProfileSyncComponentsFactoryMock()); 92 dtc_mock_ = new StrictMock<FrontendDataTypeControllerMock>(); 93 frontend_dtc_ = 94 new FrontendDataTypeControllerFake(profile_sync_factory_.get(), 95 &profile_, 96 &service_, 97 dtc_mock_.get()); 98 } 99 100 protected: 101 void SetStartExpectations() { 102 EXPECT_CALL(*dtc_mock_.get(), StartModels()).WillOnce(Return(true)); 103 EXPECT_CALL(model_load_callback_, Run(_, _)); 104 model_associator_ = new ModelAssociatorMock(); 105 change_processor_ = new ChangeProcessorMock(); 106 EXPECT_CALL(*profile_sync_factory_, CreateBookmarkSyncComponents(_, _)). 107 WillOnce(Return(ProfileSyncComponentsFactory::SyncComponents( 108 model_associator_, change_processor_))); 109 } 110 111 void SetAssociateExpectations() { 112 EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()). 113 WillOnce(Return(true)); 114 EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)). 115 WillOnce(DoAll(SetArgumentPointee<0>(true), Return(true))); 116 EXPECT_CALL(*model_associator_, AssociateModels(_, _)). 117 WillOnce(Return(syncer::SyncError())); 118 EXPECT_CALL(*dtc_mock_.get(), RecordAssociationTime(_)); 119 } 120 121 void SetActivateExpectations(DataTypeController::StartResult result) { 122 EXPECT_CALL(service_, ActivateDataType(_, _, _)); 123 EXPECT_CALL(start_callback_, Run(result, _, _)); 124 } 125 126 void SetStopExpectations() { 127 EXPECT_CALL(*dtc_mock_.get(), CleanUpState()); 128 EXPECT_CALL(service_, DeactivateDataType(_)); 129 EXPECT_CALL(*model_associator_, DisassociateModels()). 130 WillOnce(Return(syncer::SyncError())); 131 } 132 133 void SetStartFailExpectations(DataTypeController::StartResult result) { 134 if (DataTypeController::IsUnrecoverableResult(result)) 135 EXPECT_CALL(*dtc_mock_.get(), RecordUnrecoverableError(_, _)); 136 EXPECT_CALL(*dtc_mock_.get(), CleanUpState()); 137 EXPECT_CALL(*dtc_mock_.get(), RecordStartFailure(result)); 138 EXPECT_CALL(start_callback_, Run(result, _, _)); 139 } 140 141 void Start() { 142 frontend_dtc_->LoadModels( 143 base::Bind(&ModelLoadCallbackMock::Run, 144 base::Unretained(&model_load_callback_))); 145 frontend_dtc_->StartAssociating( 146 base::Bind(&StartCallbackMock::Run, 147 base::Unretained(&start_callback_))); 148 } 149 150 void PumpLoop() { 151 message_loop_.RunUntilIdle(); 152 } 153 154 base::MessageLoopForUI message_loop_; 155 content::TestBrowserThread ui_thread_; 156 scoped_refptr<FrontendDataTypeControllerFake> frontend_dtc_; 157 scoped_ptr<ProfileSyncComponentsFactoryMock> profile_sync_factory_; 158 scoped_refptr<FrontendDataTypeControllerMock> dtc_mock_; 159 ProfileMock profile_; 160 ProfileSyncServiceMock service_; 161 ModelAssociatorMock* model_associator_; 162 ChangeProcessorMock* change_processor_; 163 StartCallbackMock start_callback_; 164 ModelLoadCallbackMock model_load_callback_; 165 }; 166 167 TEST_F(SyncFrontendDataTypeControllerTest, StartOk) { 168 SetStartExpectations(); 169 SetAssociateExpectations(); 170 SetActivateExpectations(DataTypeController::OK); 171 EXPECT_EQ(DataTypeController::NOT_RUNNING, frontend_dtc_->state()); 172 Start(); 173 EXPECT_EQ(DataTypeController::RUNNING, frontend_dtc_->state()); 174 } 175 176 TEST_F(SyncFrontendDataTypeControllerTest, StartFirstRun) { 177 SetStartExpectations(); 178 EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()). 179 WillOnce(Return(true)); 180 EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)). 181 WillOnce(DoAll(SetArgumentPointee<0>(false), Return(true))); 182 EXPECT_CALL(*model_associator_, AssociateModels(_, _)). 183 WillOnce(Return(syncer::SyncError())); 184 EXPECT_CALL(*dtc_mock_.get(), RecordAssociationTime(_)); 185 SetActivateExpectations(DataTypeController::OK_FIRST_RUN); 186 EXPECT_EQ(DataTypeController::NOT_RUNNING, frontend_dtc_->state()); 187 Start(); 188 EXPECT_EQ(DataTypeController::RUNNING, frontend_dtc_->state()); 189 } 190 191 TEST_F(SyncFrontendDataTypeControllerTest, AbortDuringStartModels) { 192 EXPECT_CALL(*dtc_mock_.get(), StartModels()).WillOnce(Return(false)); 193 EXPECT_CALL(*dtc_mock_.get(), CleanUpState()); 194 EXPECT_CALL(model_load_callback_, Run(_, _)); 195 EXPECT_EQ(DataTypeController::NOT_RUNNING, frontend_dtc_->state()); 196 frontend_dtc_->LoadModels( 197 base::Bind(&ModelLoadCallbackMock::Run, 198 base::Unretained(&model_load_callback_))); 199 EXPECT_EQ(DataTypeController::MODEL_STARTING, frontend_dtc_->state()); 200 frontend_dtc_->Stop(); 201 EXPECT_EQ(DataTypeController::NOT_RUNNING, frontend_dtc_->state()); 202 } 203 204 TEST_F(SyncFrontendDataTypeControllerTest, StartAssociationFailed) { 205 SetStartExpectations(); 206 EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()). 207 WillOnce(Return(true)); 208 EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)). 209 WillOnce(DoAll(SetArgumentPointee<0>(true), Return(true))); 210 EXPECT_CALL(*model_associator_, AssociateModels(_, _)). 211 WillOnce(Return(syncer::SyncError(FROM_HERE, 212 syncer::SyncError::DATATYPE_ERROR, 213 "error", 214 syncer::BOOKMARKS))); 215 216 EXPECT_CALL(*dtc_mock_.get(), RecordAssociationTime(_)); 217 SetStartFailExpectations(DataTypeController::ASSOCIATION_FAILED); 218 // Set up association to fail with an association failed error. 219 EXPECT_EQ(DataTypeController::NOT_RUNNING, frontend_dtc_->state()); 220 Start(); 221 EXPECT_EQ(DataTypeController::DISABLED, frontend_dtc_->state()); 222 } 223 224 TEST_F(SyncFrontendDataTypeControllerTest, 225 StartAssociationTriggersUnrecoverableError) { 226 SetStartExpectations(); 227 SetStartFailExpectations(DataTypeController::UNRECOVERABLE_ERROR); 228 // Set up association to fail with an unrecoverable error. 229 EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()). 230 WillRepeatedly(Return(true)); 231 EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)). 232 WillRepeatedly(DoAll(SetArgumentPointee<0>(false), Return(false))); 233 EXPECT_EQ(DataTypeController::NOT_RUNNING, frontend_dtc_->state()); 234 Start(); 235 EXPECT_EQ(DataTypeController::NOT_RUNNING, frontend_dtc_->state()); 236 } 237 238 TEST_F(SyncFrontendDataTypeControllerTest, StartAssociationCryptoNotReady) { 239 SetStartExpectations(); 240 SetStartFailExpectations(DataTypeController::NEEDS_CRYPTO); 241 // Set up association to fail with a NEEDS_CRYPTO error. 242 EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()). 243 WillRepeatedly(Return(false)); 244 EXPECT_EQ(DataTypeController::NOT_RUNNING, frontend_dtc_->state()); 245 Start(); 246 EXPECT_EQ(DataTypeController::NOT_RUNNING, frontend_dtc_->state()); 247 } 248 249 TEST_F(SyncFrontendDataTypeControllerTest, Stop) { 250 SetStartExpectations(); 251 SetAssociateExpectations(); 252 SetActivateExpectations(DataTypeController::OK); 253 SetStopExpectations(); 254 EXPECT_EQ(DataTypeController::NOT_RUNNING, frontend_dtc_->state()); 255 Start(); 256 EXPECT_EQ(DataTypeController::RUNNING, frontend_dtc_->state()); 257 frontend_dtc_->Stop(); 258 EXPECT_EQ(DataTypeController::NOT_RUNNING, frontend_dtc_->state()); 259 } 260 261 TEST_F(SyncFrontendDataTypeControllerTest, OnSingleDatatypeUnrecoverableError) { 262 SetStartExpectations(); 263 SetAssociateExpectations(); 264 SetActivateExpectations(DataTypeController::OK); 265 EXPECT_CALL(*dtc_mock_.get(), RecordUnrecoverableError(_, "Test")); 266 EXPECT_CALL(service_, DisableBrokenDatatype(_, _, _)) 267 .WillOnce(InvokeWithoutArgs(frontend_dtc_.get(), 268 &FrontendDataTypeController::Stop)); 269 SetStopExpectations(); 270 EXPECT_EQ(DataTypeController::NOT_RUNNING, frontend_dtc_->state()); 271 Start(); 272 EXPECT_EQ(DataTypeController::RUNNING, frontend_dtc_->state()); 273 // This should cause frontend_dtc_->Stop() to be called. 274 frontend_dtc_->OnSingleDatatypeUnrecoverableError(FROM_HERE, "Test"); 275 PumpLoop(); 276 EXPECT_EQ(DataTypeController::NOT_RUNNING, frontend_dtc_->state()); 277 } 278