Home | History | Annotate | Download | only in glue
      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/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"
     36 
     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;
     43 using testing::_;
     44 using testing::DoAll;
     45 using testing::InvokeWithoutArgs;
     46 using testing::Return;
     47 using testing::SetArgumentPointee;
     48 
     49 namespace {
     50 
     51 class HistoryMock : public HistoryService {
     52  public:
     53   explicit HistoryMock(history::HistoryClient* client, Profile* profile)
     54       : HistoryService(client, profile) {}
     55   MOCK_METHOD0(BackendLoaded, bool(void));
     56 
     57  protected:
     58   virtual ~HistoryMock() {}
     59 };
     60 
     61 KeyedService* BuildChromeBookmarkClient(content::BrowserContext* context) {
     62   return new ChromeBookmarkClient(static_cast<Profile*>(context));
     63 }
     64 
     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);
     71   bookmark_client->Init(bookmark_model);
     72   return bookmark_model;
     73 }
     74 
     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),
     81                        profile->GetPath(),
     82                        profile->GetIOTaskRunner(),
     83                        content::BrowserThread::GetMessageLoopProxyForThread(
     84                            content::BrowserThread::UI));
     85   return bookmark_model;
     86 }
     87 
     88 KeyedService* BuildHistoryService(content::BrowserContext* profile) {
     89   return new HistoryMock(NULL, static_cast<Profile*>(profile));
     90 }
     91 
     92 }  // namespace
     93 
     94 class SyncBookmarkDataTypeControllerTest : public testing::Test {
     95  public:
     96   SyncBookmarkDataTypeControllerTest()
     97       : thread_bundle_(content::TestBrowserThreadBundle::DEFAULT),
     98         service_(&profile_) {}
     99 
    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_,
    108                                              change_processor_));
    109     bookmark_dtc_ = new BookmarkDataTypeController(profile_sync_factory_.get(),
    110                                                    &profile_,
    111                                                    &service_);
    112   }
    113 
    114  protected:
    115   enum BookmarkLoadPolicy {
    116     DONT_LOAD_MODEL,
    117     LOAD_MODEL,
    118   };
    119 
    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_);
    128     } else {
    129       bookmark_model_ = static_cast<BookmarkModel*>(
    130           BookmarkModelFactory::GetInstance()->SetTestingFactoryAndUse(
    131               &profile_, BuildBookmarkModelWithoutLoading));
    132     }
    133   }
    134 
    135   void SetStartExpectations() {
    136     EXPECT_CALL(*history_service_,
    137                 BackendLoaded()).WillRepeatedly(Return(true));
    138     EXPECT_CALL(model_load_callback_, Run(_, _));
    139   }
    140 
    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()));
    149   }
    150 
    151   void SetStopExpectations() {
    152     EXPECT_CALL(service_, DeactivateDataType(_));
    153     EXPECT_CALL(*model_associator_, DisassociateModels()).
    154                 WillOnce(Return(syncer::SyncError()));
    155   }
    156 
    157   void Start() {
    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_)));
    164   }
    165 
    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_;
    177 };
    178 
    179 TEST_F(SyncBookmarkDataTypeControllerTest, StartDependentsReady) {
    180   CreateBookmarkModel(LOAD_MODEL);
    181   SetStartExpectations();
    182   SetAssociateExpectations();
    183 
    184   EXPECT_EQ(DataTypeController::NOT_RUNNING, bookmark_dtc_->state());
    185 
    186   EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _, _));
    187   Start();
    188   EXPECT_EQ(DataTypeController::RUNNING, bookmark_dtc_->state());
    189 }
    190 
    191 TEST_F(SyncBookmarkDataTypeControllerTest, StartBookmarkModelNotReady) {
    192   CreateBookmarkModel(DONT_LOAD_MODEL);
    193   SetStartExpectations();
    194   SetAssociateExpectations();
    195 
    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());
    201 
    202   bookmark_model_->Load(profile_.GetPrefs(),
    203                         profile_.GetPrefs()->GetString(prefs::kAcceptLanguages),
    204                         profile_.GetPath(),
    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());
    210 
    211   bookmark_dtc_->StartAssociating(
    212       base::Bind(&StartCallbackMock::Run,
    213                  base::Unretained(&start_callback_)));
    214 
    215   EXPECT_EQ(DataTypeController::RUNNING, bookmark_dtc_->state());
    216 }
    217 
    218 TEST_F(SyncBookmarkDataTypeControllerTest, StartHistoryServiceNotReady) {
    219   CreateBookmarkModel(LOAD_MODEL);
    220   SetStartExpectations();
    221   EXPECT_CALL(*history_service_,
    222               BackendLoaded()).WillRepeatedly(Return(false));
    223 
    224   bookmark_dtc_->LoadModels(
    225       base::Bind(&ModelLoadCallbackMock::Run,
    226                  base::Unretained(&model_load_callback_)));
    227 
    228   EXPECT_EQ(DataTypeController::MODEL_STARTING, bookmark_dtc_->state());
    229   testing::Mock::VerifyAndClearExpectations(history_service_);
    230   EXPECT_CALL(*history_service_, BackendLoaded()).WillRepeatedly(Return(true));
    231 
    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());
    238 }
    239 
    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, _, _));
    247   Start();
    248 }
    249 
    250 TEST_F(SyncBookmarkDataTypeControllerTest, StartBusy) {
    251   CreateBookmarkModel(LOAD_MODEL);
    252   EXPECT_CALL(*history_service_, BackendLoaded()).WillRepeatedly(Return(false));
    253 
    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_)));
    261 }
    262 
    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)));
    269 
    270   EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _, _));
    271   Start();
    272 }
    273 
    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,
    286                                               "error",
    287                                               syncer::BOOKMARKS)));
    288 
    289   EXPECT_CALL(start_callback_,
    290               Run(DataTypeController::ASSOCIATION_FAILED, _, _));
    291   Start();
    292   EXPECT_EQ(DataTypeController::DISABLED, bookmark_dtc_->state());
    293 }
    294 
    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, _, _));
    307   Start();
    308   EXPECT_EQ(DataTypeController::NOT_RUNNING, bookmark_dtc_->state());
    309 }
    310 
    311 TEST_F(SyncBookmarkDataTypeControllerTest, StartAborted) {
    312   CreateBookmarkModel(LOAD_MODEL);
    313   EXPECT_CALL(*history_service_, BackendLoaded()).WillRepeatedly(Return(false));
    314 
    315   bookmark_dtc_->LoadModels(
    316       base::Bind(&ModelLoadCallbackMock::Run,
    317                  base::Unretained(&model_load_callback_)));
    318 
    319   bookmark_dtc_->Stop();
    320   EXPECT_EQ(DataTypeController::NOT_RUNNING, bookmark_dtc_->state());
    321 }
    322 
    323 TEST_F(SyncBookmarkDataTypeControllerTest, Stop) {
    324   CreateBookmarkModel(LOAD_MODEL);
    325   SetStartExpectations();
    326   SetAssociateExpectations();
    327   SetStopExpectations();
    328 
    329   EXPECT_EQ(DataTypeController::NOT_RUNNING, bookmark_dtc_->state());
    330 
    331   EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _, _));
    332   Start();
    333   EXPECT_EQ(DataTypeController::RUNNING, bookmark_dtc_->state());
    334   bookmark_dtc_->Stop();
    335   EXPECT_EQ(DataTypeController::NOT_RUNNING, bookmark_dtc_->state());
    336 }
    337