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/ui_data_type_controller.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "base/message_loop/message_loop.h"
     10 #include "base/tracked_objects.h"
     11 #include "chrome/browser/sync/glue/data_type_controller_mock.h"
     12 #include "chrome/browser/sync/glue/fake_generic_change_processor.h"
     13 #include "chrome/browser/sync/profile_sync_components_factory_mock.h"
     14 #include "chrome/browser/sync/profile_sync_service_mock.h"
     15 #include "chrome/test/base/profile_mock.h"
     16 #include "content/public/test/test_browser_thread.h"
     17 #include "sync/api/fake_syncable_service.h"
     18 #include "testing/gtest/include/gtest/gtest.h"
     19 
     20 using content::BrowserThread;
     21 using testing::_;
     22 using testing::InvokeWithoutArgs;
     23 using testing::Return;
     24 
     25 namespace browser_sync {
     26 namespace {
     27 
     28 ACTION(MakeSharedChangeProcessor) {
     29   return new SharedChangeProcessor();
     30 }
     31 
     32 ACTION_P(ReturnAndRelease, change_processor) {
     33   return change_processor->release();
     34 }
     35 
     36 // TODO(zea): Expand this to make the dtc type paramterizable. This will let us
     37 // test the basic functionality of all UIDataTypeControllers. We'll need to have
     38 // intelligent default values for the methods queried in the dependent services
     39 // (e.g. those queried in StartModels).
     40 class SyncUIDataTypeControllerTest : public testing::Test {
     41  public:
     42   SyncUIDataTypeControllerTest()
     43       : ui_thread_(BrowserThread::UI, &message_loop_),
     44         type_(syncer::PREFERENCES),
     45         change_processor_(new FakeGenericChangeProcessor()) {}
     46 
     47   virtual void SetUp() {
     48     profile_sync_factory_.reset(new ProfileSyncComponentsFactoryMock());
     49     preference_dtc_ =
     50         new UIDataTypeController(type_,
     51                                  profile_sync_factory_.get(),
     52                                  &profile_,
     53                                  &profile_sync_service_);
     54     SetStartExpectations();
     55   }
     56 
     57   virtual void TearDown() {
     58     // Must be done before we pump the loop.
     59     syncable_service_.StopSyncing(type_);
     60     preference_dtc_ = NULL;
     61     PumpLoop();
     62   }
     63 
     64  protected:
     65   void SetStartExpectations() {
     66     // Ownership gets passed to caller of CreateGenericChangeProcessor.
     67     change_processor_.reset(new FakeGenericChangeProcessor());
     68     EXPECT_CALL(model_load_callback_, Run(_, _));
     69     EXPECT_CALL(*profile_sync_factory_, GetSyncableServiceForType(type_)).
     70         WillOnce(Return(syncable_service_.AsWeakPtr()));
     71     EXPECT_CALL(*profile_sync_factory_, CreateSharedChangeProcessor()).
     72         WillOnce(MakeSharedChangeProcessor());
     73     EXPECT_CALL(*profile_sync_factory_,
     74                 CreateGenericChangeProcessor(_, _, _, _)).
     75         WillOnce(ReturnAndRelease(&change_processor_));
     76   }
     77 
     78   void SetActivateExpectations() {
     79     EXPECT_CALL(profile_sync_service_, ActivateDataType(type_, _, _));
     80   }
     81 
     82   void SetStopExpectations() {
     83     EXPECT_CALL(profile_sync_service_, DeactivateDataType(type_));
     84   }
     85 
     86   void Start() {
     87     preference_dtc_->LoadModels(
     88         base::Bind(&ModelLoadCallbackMock::Run,
     89                    base::Unretained(&model_load_callback_)));
     90     preference_dtc_->StartAssociating(
     91         base::Bind(&StartCallbackMock::Run,
     92                    base::Unretained(&start_callback_)));
     93   }
     94 
     95   void PumpLoop() {
     96     message_loop_.RunUntilIdle();
     97   }
     98 
     99   base::MessageLoopForUI message_loop_;
    100   content::TestBrowserThread ui_thread_;
    101   ProfileMock profile_;
    102   scoped_ptr<ProfileSyncComponentsFactoryMock> profile_sync_factory_;
    103   ProfileSyncServiceMock profile_sync_service_;
    104   const syncer::ModelType type_;
    105   StartCallbackMock start_callback_;
    106   ModelLoadCallbackMock model_load_callback_;
    107   scoped_refptr<UIDataTypeController> preference_dtc_;
    108   scoped_ptr<FakeGenericChangeProcessor> change_processor_;
    109   syncer::FakeSyncableService syncable_service_;
    110 };
    111 
    112 // Start the DTC. Verify that the callback is called with OK, the
    113 // service has been told to start syncing and that the DTC is now in RUNNING
    114 // state.
    115 TEST_F(SyncUIDataTypeControllerTest, Start) {
    116   SetActivateExpectations();
    117   EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _, _));
    118 
    119   EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
    120   EXPECT_FALSE(syncable_service_.syncing());
    121   Start();
    122   EXPECT_EQ(DataTypeController::RUNNING, preference_dtc_->state());
    123   EXPECT_TRUE(syncable_service_.syncing());
    124 }
    125 
    126 // Start and then stop the DTC. Verify that the service started and stopped
    127 // syncing, and that the DTC went from RUNNING to NOT_RUNNING.
    128 TEST_F(SyncUIDataTypeControllerTest, StartStop) {
    129   SetActivateExpectations();
    130   SetStopExpectations();
    131   EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _, _));
    132 
    133   EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
    134   EXPECT_FALSE(syncable_service_.syncing());
    135   Start();
    136   EXPECT_EQ(DataTypeController::RUNNING, preference_dtc_->state());
    137   EXPECT_TRUE(syncable_service_.syncing());
    138   preference_dtc_->Stop();
    139   EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
    140   EXPECT_FALSE(syncable_service_.syncing());
    141 }
    142 
    143 // Start the DTC when no user nodes are created. Verify that the callback
    144 // is called with OK_FIRST_RUN. Stop the DTC.
    145 TEST_F(SyncUIDataTypeControllerTest, StartStopFirstRun) {
    146   SetActivateExpectations();
    147   SetStopExpectations();
    148   EXPECT_CALL(start_callback_, Run(DataTypeController::OK_FIRST_RUN, _, _));
    149   change_processor_->set_sync_model_has_user_created_nodes(false);
    150 
    151   EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
    152   EXPECT_FALSE(syncable_service_.syncing());
    153   Start();
    154   EXPECT_EQ(DataTypeController::RUNNING, preference_dtc_->state());
    155   EXPECT_TRUE(syncable_service_.syncing());
    156   preference_dtc_->Stop();
    157   EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
    158   EXPECT_FALSE(syncable_service_.syncing());
    159 }
    160 
    161 // Start the DTC, but have the service fail association. Verify the callback
    162 // is called with ASSOCIATION_FAILED, the DTC goes to state DISABLED, and the
    163 // service is not syncing. Then stop the DTC.
    164 TEST_F(SyncUIDataTypeControllerTest, StartAssociationFailed) {
    165   SetStopExpectations();
    166   EXPECT_CALL(start_callback_,
    167               Run(DataTypeController::ASSOCIATION_FAILED, _, _));
    168   syncable_service_.set_merge_data_and_start_syncing_error(
    169       syncer::SyncError(FROM_HERE,
    170                         syncer::SyncError::DATATYPE_ERROR,
    171                         "Error",
    172                         type_));
    173 
    174   EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
    175   EXPECT_FALSE(syncable_service_.syncing());
    176   Start();
    177   EXPECT_EQ(DataTypeController::DISABLED, preference_dtc_->state());
    178   EXPECT_FALSE(syncable_service_.syncing());
    179   preference_dtc_->Stop();
    180   EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
    181   EXPECT_FALSE(syncable_service_.syncing());
    182 }
    183 
    184 // Start the DTC but fail to check if there are user created nodes. Verify the
    185 // DTC calls the callback with UNRECOVERABLE_ERROR and that it goes into
    186 // NOT_RUNNING state. Verify the syncable service is not syncing.
    187 TEST_F(SyncUIDataTypeControllerTest,
    188        StartAssociationTriggersUnrecoverableError) {
    189   EXPECT_CALL(start_callback_,
    190               Run(DataTypeController::UNRECOVERABLE_ERROR, _, _));
    191   change_processor_->set_sync_model_has_user_created_nodes_success(false);
    192 
    193   EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
    194   EXPECT_FALSE(syncable_service_.syncing());
    195   Start();
    196   EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
    197   EXPECT_FALSE(syncable_service_.syncing());
    198 }
    199 
    200 // Start the DTC, but then trigger an unrecoverable error. Verify the syncer
    201 // gets stopped and the DTC is in NOT_RUNNING state.
    202 TEST_F(SyncUIDataTypeControllerTest, OnSingleDatatypeUnrecoverableError) {
    203   SetActivateExpectations();
    204   EXPECT_CALL(profile_sync_service_, DisableBrokenDatatype(_,_,_)).
    205       WillOnce(InvokeWithoutArgs(preference_dtc_.get(),
    206                                  &UIDataTypeController::Stop));
    207   SetStopExpectations();
    208   EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _, _));
    209 
    210   EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
    211   EXPECT_FALSE(syncable_service_.syncing());
    212   Start();
    213   EXPECT_TRUE(syncable_service_.syncing());
    214   preference_dtc_->OnSingleDatatypeUnrecoverableError(FROM_HERE, "Test");
    215   PumpLoop();
    216   EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
    217   EXPECT_FALSE(syncable_service_.syncing());
    218 }
    219 
    220 }  // namespace
    221 }  // namespace browser_sync
    222