bookmark_data_type_controller_unittest.cc revision 9ab5563a3196760eb381d102cbb2bc0f7abc6a50
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 "chrome/browser/sync/glue/bookmark_data_type_controller.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/run_loop.h" 13#include "chrome/browser/bookmarks/bookmark_model.h" 14#include "chrome/browser/bookmarks/bookmark_model_factory.h" 15#include "chrome/browser/chrome_notification_types.h" 16#include "chrome/browser/history/history_service.h" 17#include "chrome/browser/history/history_service_factory.h" 18#include "chrome/browser/profiles/profile.h" 19#include "chrome/browser/sync/glue/change_processor_mock.h" 20#include "chrome/browser/sync/glue/data_type_controller_mock.h" 21#include "chrome/browser/sync/glue/model_associator_mock.h" 22#include "chrome/browser/sync/profile_sync_components_factory_mock.h" 23#include "chrome/browser/sync/profile_sync_service_mock.h" 24#include "chrome/test/base/profile_mock.h" 25#include "chrome/test/base/ui_test_utils.h" 26#include "components/browser_context_keyed_service/refcounted_browser_context_keyed_service.h" 27#include "content/public/browser/notification_service.h" 28#include "content/public/test/test_browser_thread.h" 29#include "sync/api/sync_error.h" 30#include "testing/gmock/include/gmock/gmock.h" 31#include "testing/gtest/include/gtest/gtest.h" 32 33using browser_sync::BookmarkDataTypeController; 34using browser_sync::ChangeProcessorMock; 35using browser_sync::DataTypeController; 36using browser_sync::ModelAssociatorMock; 37using browser_sync::ModelLoadCallbackMock; 38using browser_sync::StartCallbackMock; 39using content::BrowserThread; 40using testing::_; 41using testing::DoAll; 42using testing::InvokeWithoutArgs; 43using testing::Return; 44using testing::SetArgumentPointee; 45 46namespace { 47 48class HistoryMock : public HistoryService { 49 public: 50 explicit HistoryMock(Profile* profile) : HistoryService(profile) {} 51 MOCK_METHOD0(BackendLoaded, bool(void)); 52 53 protected: 54 virtual ~HistoryMock() {} 55}; 56 57BrowserContextKeyedService* BuildBookmarkModel( 58 content::BrowserContext* context) { 59 Profile* profile = static_cast<Profile*>(context); 60 BookmarkModel* bookmark_model = new BookmarkModel(profile); 61 bookmark_model->Load(profile->GetIOTaskRunner()); 62 return bookmark_model; 63} 64 65BrowserContextKeyedService* BuildBookmarkModelWithoutLoading( 66 content::BrowserContext* profile) { 67 return new BookmarkModel(static_cast<Profile*>(profile)); 68} 69 70BrowserContextKeyedService* BuildHistoryService( 71 content::BrowserContext* profile) { 72 return new HistoryMock(static_cast<Profile*>(profile)); 73} 74 75} // namespace 76 77class SyncBookmarkDataTypeControllerTest : public testing::Test { 78 public: 79 SyncBookmarkDataTypeControllerTest() 80 : ui_thread_(BrowserThread::UI, &message_loop_) {} 81 82 virtual void SetUp() { 83 model_associator_ = new ModelAssociatorMock(); 84 change_processor_ = new ChangeProcessorMock(); 85 history_service_ = static_cast<HistoryMock*>( 86 HistoryServiceFactory::GetInstance()->SetTestingFactoryAndUse( 87 &profile_, BuildHistoryService)); 88 profile_sync_factory_.reset( 89 new ProfileSyncComponentsFactoryMock(model_associator_, 90 change_processor_)); 91 bookmark_dtc_ = new BookmarkDataTypeController(profile_sync_factory_.get(), 92 &profile_, 93 &service_); 94 } 95 96 protected: 97 enum BookmarkLoadPolicy { 98 DONT_LOAD_MODEL, 99 LOAD_MODEL, 100 }; 101 102 void CreateBookmarkModel(BookmarkLoadPolicy bookmark_load_policy) { 103 if (bookmark_load_policy == LOAD_MODEL) { 104 bookmark_model_ = static_cast<BookmarkModel*>( 105 BookmarkModelFactory::GetInstance()->SetTestingFactoryAndUse( 106 &profile_, BuildBookmarkModel)); 107 ui_test_utils::WaitForBookmarkModelToLoad(bookmark_model_); 108 } else { 109 bookmark_model_ = static_cast<BookmarkModel*>( 110 BookmarkModelFactory::GetInstance()->SetTestingFactoryAndUse( 111 &profile_, BuildBookmarkModelWithoutLoading)); 112 } 113 } 114 115 void SetStartExpectations() { 116 EXPECT_CALL(*history_service_, 117 BackendLoaded()).WillRepeatedly(Return(true)); 118 EXPECT_CALL(model_load_callback_, Run(_, _)); 119 } 120 121 void SetAssociateExpectations() { 122 EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()). 123 WillRepeatedly(Return(true)); 124 EXPECT_CALL(*profile_sync_factory_, CreateBookmarkSyncComponents(_, _)); 125 EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)). 126 WillRepeatedly(DoAll(SetArgumentPointee<0>(true), Return(true))); 127 EXPECT_CALL(*model_associator_, AssociateModels(_, _)). 128 WillRepeatedly(Return(syncer::SyncError())); 129 EXPECT_CALL(service_, ActivateDataType(_, _, _)); 130 } 131 132 void SetStopExpectations() { 133 EXPECT_CALL(service_, DeactivateDataType(_)); 134 EXPECT_CALL(*model_associator_, DisassociateModels()). 135 WillOnce(Return(syncer::SyncError())); 136 } 137 138 void Start() { 139 bookmark_dtc_->LoadModels( 140 base::Bind(&ModelLoadCallbackMock::Run, 141 base::Unretained(&model_load_callback_))); 142 bookmark_dtc_->StartAssociating( 143 base::Bind(&StartCallbackMock::Run, 144 base::Unretained(&start_callback_))); 145 } 146 147 base::MessageLoopForUI message_loop_; 148 content::TestBrowserThread ui_thread_; 149 scoped_refptr<BookmarkDataTypeController> bookmark_dtc_; 150 scoped_ptr<ProfileSyncComponentsFactoryMock> profile_sync_factory_; 151 ProfileMock profile_; 152 BookmarkModel* bookmark_model_; 153 HistoryMock* history_service_; 154 ProfileSyncServiceMock service_; 155 ModelAssociatorMock* model_associator_; 156 ChangeProcessorMock* change_processor_; 157 StartCallbackMock start_callback_; 158 ModelLoadCallbackMock model_load_callback_; 159}; 160 161TEST_F(SyncBookmarkDataTypeControllerTest, StartDependentsReady) { 162 CreateBookmarkModel(LOAD_MODEL); 163 SetStartExpectations(); 164 SetAssociateExpectations(); 165 166 EXPECT_EQ(DataTypeController::NOT_RUNNING, bookmark_dtc_->state()); 167 168 EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _, _)); 169 Start(); 170 EXPECT_EQ(DataTypeController::RUNNING, bookmark_dtc_->state()); 171} 172 173TEST_F(SyncBookmarkDataTypeControllerTest, StartBookmarkModelNotReady) { 174 CreateBookmarkModel(DONT_LOAD_MODEL); 175 SetStartExpectations(); 176 SetAssociateExpectations(); 177 178 EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _, _)); 179 bookmark_dtc_->LoadModels( 180 base::Bind(&ModelLoadCallbackMock::Run, 181 base::Unretained(&model_load_callback_))); 182 EXPECT_EQ(DataTypeController::MODEL_STARTING, bookmark_dtc_->state()); 183 184 bookmark_model_->Load(profile_.GetIOTaskRunner()); 185 ui_test_utils::WaitForBookmarkModelToLoad(bookmark_model_); 186 EXPECT_EQ(DataTypeController::MODEL_LOADED, bookmark_dtc_->state()); 187 188 bookmark_dtc_->StartAssociating( 189 base::Bind(&StartCallbackMock::Run, 190 base::Unretained(&start_callback_))); 191 192 EXPECT_EQ(DataTypeController::RUNNING, bookmark_dtc_->state()); 193} 194 195TEST_F(SyncBookmarkDataTypeControllerTest, StartHistoryServiceNotReady) { 196 CreateBookmarkModel(LOAD_MODEL); 197 SetStartExpectations(); 198 EXPECT_CALL(*history_service_, 199 BackendLoaded()).WillRepeatedly(Return(false)); 200 201 bookmark_dtc_->LoadModels( 202 base::Bind(&ModelLoadCallbackMock::Run, 203 base::Unretained(&model_load_callback_))); 204 205 EXPECT_EQ(DataTypeController::MODEL_STARTING, bookmark_dtc_->state()); 206 testing::Mock::VerifyAndClearExpectations(history_service_); 207 EXPECT_CALL(*history_service_, BackendLoaded()).WillRepeatedly(Return(true)); 208 209 // Send the notification that the history service has finished loading the db. 210 content::NotificationService::current()->Notify( 211 chrome::NOTIFICATION_HISTORY_LOADED, 212 content::Source<Profile>(&profile_), 213 content::NotificationService::NoDetails()); 214 EXPECT_EQ(DataTypeController::MODEL_LOADED, bookmark_dtc_->state()); 215} 216 217TEST_F(SyncBookmarkDataTypeControllerTest, StartFirstRun) { 218 CreateBookmarkModel(LOAD_MODEL); 219 SetStartExpectations(); 220 SetAssociateExpectations(); 221 EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)). 222 WillRepeatedly(DoAll(SetArgumentPointee<0>(false), Return(true))); 223 EXPECT_CALL(start_callback_, Run(DataTypeController::OK_FIRST_RUN, _, _)); 224 Start(); 225} 226 227TEST_F(SyncBookmarkDataTypeControllerTest, StartBusy) { 228 CreateBookmarkModel(LOAD_MODEL); 229 EXPECT_CALL(*history_service_, BackendLoaded()).WillRepeatedly(Return(false)); 230 231 EXPECT_CALL(model_load_callback_, Run(_, _)); 232 bookmark_dtc_->LoadModels( 233 base::Bind(&ModelLoadCallbackMock::Run, 234 base::Unretained(&model_load_callback_))); 235 bookmark_dtc_->LoadModels( 236 base::Bind(&ModelLoadCallbackMock::Run, 237 base::Unretained(&model_load_callback_))); 238} 239 240TEST_F(SyncBookmarkDataTypeControllerTest, StartOk) { 241 CreateBookmarkModel(LOAD_MODEL); 242 SetStartExpectations(); 243 SetAssociateExpectations(); 244 EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)). 245 WillRepeatedly(DoAll(SetArgumentPointee<0>(true), Return(true))); 246 247 EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _, _)); 248 Start(); 249} 250 251TEST_F(SyncBookmarkDataTypeControllerTest, StartAssociationFailed) { 252 CreateBookmarkModel(LOAD_MODEL); 253 SetStartExpectations(); 254 // Set up association to fail. 255 EXPECT_CALL(*profile_sync_factory_, CreateBookmarkSyncComponents(_, _)); 256 EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()). 257 WillRepeatedly(Return(true)); 258 EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)). 259 WillRepeatedly(DoAll(SetArgumentPointee<0>(true), Return(true))); 260 EXPECT_CALL(*model_associator_, AssociateModels(_, _)). 261 WillRepeatedly(Return(syncer::SyncError(FROM_HERE, 262 syncer::SyncError::DATATYPE_ERROR, 263 "error", 264 syncer::BOOKMARKS))); 265 266 EXPECT_CALL(start_callback_, 267 Run(DataTypeController::ASSOCIATION_FAILED, _, _)); 268 Start(); 269 EXPECT_EQ(DataTypeController::DISABLED, bookmark_dtc_->state()); 270} 271 272TEST_F(SyncBookmarkDataTypeControllerTest, 273 StartAssociationTriggersUnrecoverableError) { 274 CreateBookmarkModel(LOAD_MODEL); 275 SetStartExpectations(); 276 // Set up association to fail with an unrecoverable error. 277 EXPECT_CALL(*profile_sync_factory_, CreateBookmarkSyncComponents(_, _)); 278 EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()). 279 WillRepeatedly(Return(true)); 280 EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)). 281 WillRepeatedly(DoAll(SetArgumentPointee<0>(false), Return(false))); 282 EXPECT_CALL(start_callback_, 283 Run(DataTypeController::UNRECOVERABLE_ERROR, _, _)); 284 Start(); 285 EXPECT_EQ(DataTypeController::NOT_RUNNING, bookmark_dtc_->state()); 286} 287 288TEST_F(SyncBookmarkDataTypeControllerTest, StartAborted) { 289 CreateBookmarkModel(LOAD_MODEL); 290 EXPECT_CALL(*history_service_, BackendLoaded()).WillRepeatedly(Return(false)); 291 292 EXPECT_CALL(model_load_callback_, Run(_, _)); 293 bookmark_dtc_->LoadModels( 294 base::Bind(&ModelLoadCallbackMock::Run, 295 base::Unretained(&model_load_callback_))); 296 297 bookmark_dtc_->Stop(); 298 EXPECT_EQ(DataTypeController::NOT_RUNNING, bookmark_dtc_->state()); 299} 300 301TEST_F(SyncBookmarkDataTypeControllerTest, Stop) { 302 CreateBookmarkModel(LOAD_MODEL); 303 SetStartExpectations(); 304 SetAssociateExpectations(); 305 SetStopExpectations(); 306 307 EXPECT_EQ(DataTypeController::NOT_RUNNING, bookmark_dtc_->state()); 308 309 EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _, _)); 310 Start(); 311 EXPECT_EQ(DataTypeController::RUNNING, bookmark_dtc_->state()); 312 bookmark_dtc_->Stop(); 313 EXPECT_EQ(DataTypeController::NOT_RUNNING, bookmark_dtc_->state()); 314} 315 316TEST_F(SyncBookmarkDataTypeControllerTest, OnSingleDatatypeUnrecoverableError) { 317 CreateBookmarkModel(LOAD_MODEL); 318 SetStartExpectations(); 319 SetAssociateExpectations(); 320 EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)). 321 WillRepeatedly(DoAll(SetArgumentPointee<0>(true), Return(true))); 322 EXPECT_CALL(service_, DisableBrokenDatatype(_,_,_)). 323 WillOnce(InvokeWithoutArgs(bookmark_dtc_.get(), 324 &BookmarkDataTypeController::Stop)); 325 SetStopExpectations(); 326 327 EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _, _)); 328 Start(); 329 // This should cause bookmark_dtc_->Stop() to be called. 330 bookmark_dtc_->OnSingleDatatypeUnrecoverableError(FROM_HERE, "Test"); 331 base::RunLoop().RunUntilIdle(); 332} 333