bookmark_data_type_controller_unittest.cc revision 58537e28ecd584eab876aee8be7156509866d23a
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/bookmarks/bookmark_test_helpers.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/glue/change_processor_mock.h"
21#include "chrome/browser/sync/glue/data_type_controller_mock.h"
22#include "chrome/browser/sync/glue/model_associator_mock.h"
23#include "chrome/browser/sync/profile_sync_components_factory_mock.h"
24#include "chrome/browser/sync/profile_sync_service_mock.h"
25#include "chrome/test/base/profile_mock.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      test::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  test::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