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.
5 #include "chrome/browser/sync/glue/bookmark_data_type_controller.h"
8 #include "base/bind_helpers.h"
9 #include "base/callback.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/run_loop.h"
13 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
14 #include "chrome/browser/bookmarks/chrome_bookmark_client.h"
15 #include "chrome/browser/bookmarks/chrome_bookmark_client_factory.h"
16 #include "chrome/browser/chrome_notification_types.h"
17 #include "chrome/browser/history/history_service.h"
18 #include "chrome/browser/history/history_service_factory.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/sync/profile_sync_components_factory_mock.h"
21 #include "chrome/browser/sync/profile_sync_service_mock.h"
22 #include "chrome/common/pref_names.h"
23 #include "chrome/test/base/profile_mock.h"
24 #include "components/bookmarks/browser/bookmark_model.h"
25 #include "components/bookmarks/test/bookmark_test_helpers.h"
26 #include "components/keyed_service/content/refcounted_browser_context_keyed_service.h"
27 #include "components/sync_driver/change_processor_mock.h"
28 #include "components/sync_driver/data_type_controller_mock.h"
29 #include "components/sync_driver/model_associator_mock.h"
30 #include "content/public/browser/browser_thread.h"
31 #include "content/public/browser/notification_service.h"
32 #include "content/public/test/test_browser_thread_bundle.h"
33 #include "sync/api/sync_error.h"
34 #include "testing/gmock/include/gmock/gmock.h"
35 #include "testing/gtest/include/gtest/gtest.h"
37 using browser_sync::BookmarkDataTypeController;
38 using sync_driver::ChangeProcessorMock;
39 using sync_driver::DataTypeController;
40 using sync_driver::ModelAssociatorMock;
41 using sync_driver::ModelLoadCallbackMock;
42 using sync_driver::StartCallbackMock;
45 using testing::InvokeWithoutArgs;
46 using testing::Return;
47 using testing::SetArgumentPointee;
51 class HistoryMock : public HistoryService {
53 explicit HistoryMock(history::HistoryClient* client, Profile* profile)
54 : HistoryService(client, profile) {}
55 MOCK_METHOD0(BackendLoaded, bool(void));
58 virtual ~HistoryMock() {}
61 KeyedService* BuildChromeBookmarkClient(content::BrowserContext* context) {
62 return new ChromeBookmarkClient(static_cast<Profile*>(context));
65 KeyedService* BuildBookmarkModelWithoutLoading(
66 content::BrowserContext* context) {
67 Profile* profile = static_cast<Profile*>(context);
68 ChromeBookmarkClient* bookmark_client =
69 ChromeBookmarkClientFactory::GetForProfile(profile);
70 BookmarkModel* bookmark_model = new BookmarkModel(bookmark_client, false);
71 bookmark_client->Init(bookmark_model);
72 return bookmark_model;
75 KeyedService* BuildBookmarkModel(content::BrowserContext* context) {
76 BookmarkModel* bookmark_model = static_cast<BookmarkModel*>(
77 BuildBookmarkModelWithoutLoading(context));
78 Profile* profile = static_cast<Profile*>(context);
79 bookmark_model->Load(profile->GetPrefs(),
80 profile->GetPrefs()->GetString(prefs::kAcceptLanguages),
82 profile->GetIOTaskRunner(),
83 content::BrowserThread::GetMessageLoopProxyForThread(
84 content::BrowserThread::UI));
85 return bookmark_model;
88 KeyedService* BuildHistoryService(content::BrowserContext* profile) {
89 return new HistoryMock(NULL, static_cast<Profile*>(profile));
94 class SyncBookmarkDataTypeControllerTest : public testing::Test {
96 SyncBookmarkDataTypeControllerTest()
97 : thread_bundle_(content::TestBrowserThreadBundle::DEFAULT),
98 service_(&profile_) {}
100 virtual void SetUp() {
101 model_associator_ = new ModelAssociatorMock();
102 change_processor_ = new ChangeProcessorMock();
103 history_service_ = static_cast<HistoryMock*>(
104 HistoryServiceFactory::GetInstance()->SetTestingFactoryAndUse(
105 &profile_, BuildHistoryService));
106 profile_sync_factory_.reset(
107 new ProfileSyncComponentsFactoryMock(model_associator_,
109 bookmark_dtc_ = new BookmarkDataTypeController(profile_sync_factory_.get(),
115 enum BookmarkLoadPolicy {
120 void CreateBookmarkModel(BookmarkLoadPolicy bookmark_load_policy) {
121 ChromeBookmarkClientFactory::GetInstance()->SetTestingFactory(
122 &profile_, BuildChromeBookmarkClient);
123 if (bookmark_load_policy == LOAD_MODEL) {
124 bookmark_model_ = static_cast<BookmarkModel*>(
125 BookmarkModelFactory::GetInstance()->SetTestingFactoryAndUse(
126 &profile_, BuildBookmarkModel));
127 test::WaitForBookmarkModelToLoad(bookmark_model_);
129 bookmark_model_ = static_cast<BookmarkModel*>(
130 BookmarkModelFactory::GetInstance()->SetTestingFactoryAndUse(
131 &profile_, BuildBookmarkModelWithoutLoading));
135 void SetStartExpectations() {
136 EXPECT_CALL(*history_service_,
137 BackendLoaded()).WillRepeatedly(Return(true));
138 EXPECT_CALL(model_load_callback_, Run(_, _));
141 void SetAssociateExpectations() {
142 EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
143 WillRepeatedly(Return(true));
144 EXPECT_CALL(*profile_sync_factory_, CreateBookmarkSyncComponents(_, _));
145 EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
146 WillRepeatedly(DoAll(SetArgumentPointee<0>(true), Return(true)));
147 EXPECT_CALL(*model_associator_, AssociateModels(_, _)).
148 WillRepeatedly(Return(syncer::SyncError()));
151 void SetStopExpectations() {
152 EXPECT_CALL(service_, DeactivateDataType(_));
153 EXPECT_CALL(*model_associator_, DisassociateModels()).
154 WillOnce(Return(syncer::SyncError()));
158 bookmark_dtc_->LoadModels(
159 base::Bind(&ModelLoadCallbackMock::Run,
160 base::Unretained(&model_load_callback_)));
161 bookmark_dtc_->StartAssociating(
162 base::Bind(&StartCallbackMock::Run,
163 base::Unretained(&start_callback_)));
166 content::TestBrowserThreadBundle thread_bundle_;
167 scoped_refptr<BookmarkDataTypeController> bookmark_dtc_;
168 scoped_ptr<ProfileSyncComponentsFactoryMock> profile_sync_factory_;
169 ProfileMock profile_;
170 BookmarkModel* bookmark_model_;
171 HistoryMock* history_service_;
172 ProfileSyncServiceMock service_;
173 ModelAssociatorMock* model_associator_;
174 ChangeProcessorMock* change_processor_;
175 StartCallbackMock start_callback_;
176 ModelLoadCallbackMock model_load_callback_;
179 TEST_F(SyncBookmarkDataTypeControllerTest, StartDependentsReady) {
180 CreateBookmarkModel(LOAD_MODEL);
181 SetStartExpectations();
182 SetAssociateExpectations();
184 EXPECT_EQ(DataTypeController::NOT_RUNNING, bookmark_dtc_->state());
186 EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _, _));
188 EXPECT_EQ(DataTypeController::RUNNING, bookmark_dtc_->state());
191 TEST_F(SyncBookmarkDataTypeControllerTest, StartBookmarkModelNotReady) {
192 CreateBookmarkModel(DONT_LOAD_MODEL);
193 SetStartExpectations();
194 SetAssociateExpectations();
196 EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _, _));
197 bookmark_dtc_->LoadModels(
198 base::Bind(&ModelLoadCallbackMock::Run,
199 base::Unretained(&model_load_callback_)));
200 EXPECT_EQ(DataTypeController::MODEL_STARTING, bookmark_dtc_->state());
202 bookmark_model_->Load(profile_.GetPrefs(),
203 profile_.GetPrefs()->GetString(prefs::kAcceptLanguages),
205 profile_.GetIOTaskRunner(),
206 content::BrowserThread::GetMessageLoopProxyForThread(
207 content::BrowserThread::UI));
208 test::WaitForBookmarkModelToLoad(bookmark_model_);
209 EXPECT_EQ(DataTypeController::MODEL_LOADED, bookmark_dtc_->state());
211 bookmark_dtc_->StartAssociating(
212 base::Bind(&StartCallbackMock::Run,
213 base::Unretained(&start_callback_)));
215 EXPECT_EQ(DataTypeController::RUNNING, bookmark_dtc_->state());
218 TEST_F(SyncBookmarkDataTypeControllerTest, StartHistoryServiceNotReady) {
219 CreateBookmarkModel(LOAD_MODEL);
220 SetStartExpectations();
221 EXPECT_CALL(*history_service_,
222 BackendLoaded()).WillRepeatedly(Return(false));
224 bookmark_dtc_->LoadModels(
225 base::Bind(&ModelLoadCallbackMock::Run,
226 base::Unretained(&model_load_callback_)));
228 EXPECT_EQ(DataTypeController::MODEL_STARTING, bookmark_dtc_->state());
229 testing::Mock::VerifyAndClearExpectations(history_service_);
230 EXPECT_CALL(*history_service_, BackendLoaded()).WillRepeatedly(Return(true));
232 // Send the notification that the history service has finished loading the db.
233 content::NotificationService::current()->Notify(
234 chrome::NOTIFICATION_HISTORY_LOADED,
235 content::Source<Profile>(&profile_),
236 content::NotificationService::NoDetails());
237 EXPECT_EQ(DataTypeController::MODEL_LOADED, bookmark_dtc_->state());
240 TEST_F(SyncBookmarkDataTypeControllerTest, StartFirstRun) {
241 CreateBookmarkModel(LOAD_MODEL);
242 SetStartExpectations();
243 SetAssociateExpectations();
244 EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
245 WillRepeatedly(DoAll(SetArgumentPointee<0>(false), Return(true)));
246 EXPECT_CALL(start_callback_, Run(DataTypeController::OK_FIRST_RUN, _, _));
250 TEST_F(SyncBookmarkDataTypeControllerTest, StartBusy) {
251 CreateBookmarkModel(LOAD_MODEL);
252 EXPECT_CALL(*history_service_, BackendLoaded()).WillRepeatedly(Return(false));
254 EXPECT_CALL(model_load_callback_, Run(_, _));
255 bookmark_dtc_->LoadModels(
256 base::Bind(&ModelLoadCallbackMock::Run,
257 base::Unretained(&model_load_callback_)));
258 bookmark_dtc_->LoadModels(
259 base::Bind(&ModelLoadCallbackMock::Run,
260 base::Unretained(&model_load_callback_)));
263 TEST_F(SyncBookmarkDataTypeControllerTest, StartOk) {
264 CreateBookmarkModel(LOAD_MODEL);
265 SetStartExpectations();
266 SetAssociateExpectations();
267 EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
268 WillRepeatedly(DoAll(SetArgumentPointee<0>(true), Return(true)));
270 EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _, _));
274 TEST_F(SyncBookmarkDataTypeControllerTest, StartAssociationFailed) {
275 CreateBookmarkModel(LOAD_MODEL);
276 SetStartExpectations();
277 // Set up association to fail.
278 EXPECT_CALL(*profile_sync_factory_, CreateBookmarkSyncComponents(_, _));
279 EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
280 WillRepeatedly(Return(true));
281 EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
282 WillRepeatedly(DoAll(SetArgumentPointee<0>(true), Return(true)));
283 EXPECT_CALL(*model_associator_, AssociateModels(_, _)).
284 WillRepeatedly(Return(syncer::SyncError(FROM_HERE,
285 syncer::SyncError::DATATYPE_ERROR,
287 syncer::BOOKMARKS)));
289 EXPECT_CALL(start_callback_,
290 Run(DataTypeController::ASSOCIATION_FAILED, _, _));
292 EXPECT_EQ(DataTypeController::DISABLED, bookmark_dtc_->state());
295 TEST_F(SyncBookmarkDataTypeControllerTest,
296 StartAssociationTriggersUnrecoverableError) {
297 CreateBookmarkModel(LOAD_MODEL);
298 SetStartExpectations();
299 // Set up association to fail with an unrecoverable error.
300 EXPECT_CALL(*profile_sync_factory_, CreateBookmarkSyncComponents(_, _));
301 EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
302 WillRepeatedly(Return(true));
303 EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
304 WillRepeatedly(DoAll(SetArgumentPointee<0>(false), Return(false)));
305 EXPECT_CALL(start_callback_,
306 Run(DataTypeController::UNRECOVERABLE_ERROR, _, _));
308 EXPECT_EQ(DataTypeController::NOT_RUNNING, bookmark_dtc_->state());
311 TEST_F(SyncBookmarkDataTypeControllerTest, StartAborted) {
312 CreateBookmarkModel(LOAD_MODEL);
313 EXPECT_CALL(*history_service_, BackendLoaded()).WillRepeatedly(Return(false));
315 EXPECT_CALL(model_load_callback_, Run(_, _));
316 bookmark_dtc_->LoadModels(
317 base::Bind(&ModelLoadCallbackMock::Run,
318 base::Unretained(&model_load_callback_)));
320 bookmark_dtc_->Stop();
321 EXPECT_EQ(DataTypeController::NOT_RUNNING, bookmark_dtc_->state());
324 TEST_F(SyncBookmarkDataTypeControllerTest, Stop) {
325 CreateBookmarkModel(LOAD_MODEL);
326 SetStartExpectations();
327 SetAssociateExpectations();
328 SetStopExpectations();
330 EXPECT_EQ(DataTypeController::NOT_RUNNING, bookmark_dtc_->state());
332 EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _, _));
334 EXPECT_EQ(DataTypeController::RUNNING, bookmark_dtc_->state());
335 bookmark_dtc_->Stop();
336 EXPECT_EQ(DataTypeController::NOT_RUNNING, bookmark_dtc_->state());