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