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 "testing/gtest/include/gtest/gtest.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/bind_helpers.h"
      9 #include "base/callback.h"
     10 #include "base/compiler_specific.h"
     11 #include "base/memory/scoped_ptr.h"
     12 #include "base/message_loop/message_loop.h"
     13 #include "base/synchronization/waitable_event.h"
     14 #include "base/test/test_timeouts.h"
     15 #include "base/tracked_objects.h"
     16 #include "chrome/browser/sync/glue/non_frontend_data_type_controller.h"
     17 #include "chrome/browser/sync/glue/non_frontend_data_type_controller_mock.h"
     18 #include "chrome/browser/sync/profile_sync_components_factory_mock.h"
     19 #include "chrome/browser/sync/profile_sync_service_mock.h"
     20 #include "chrome/test/base/profile_mock.h"
     21 #include "components/sync_driver/change_processor_mock.h"
     22 #include "components/sync_driver/data_type_controller_mock.h"
     23 #include "components/sync_driver/model_associator_mock.h"
     24 #include "content/public/test/test_browser_thread.h"
     25 #include "sync/internal_api/public/engine/model_safe_worker.h"
     26 
     27 using base::WaitableEvent;
     28 using syncer::GROUP_DB;
     29 using browser_sync::NonFrontendDataTypeController;
     30 using browser_sync::NonFrontendDataTypeControllerMock;
     31 using sync_driver::ChangeProcessorMock;
     32 using sync_driver::DataTypeController;
     33 using sync_driver::ModelAssociatorMock;
     34 using sync_driver::ModelLoadCallbackMock;
     35 using sync_driver::StartCallbackMock;
     36 using content::BrowserThread;
     37 using testing::_;
     38 using testing::DoAll;
     39 using testing::InvokeWithoutArgs;
     40 using testing::Return;
     41 using testing::SetArgumentPointee;
     42 using testing::StrictMock;
     43 
     44 ACTION_P(WaitOnEvent, event) {
     45   event->Wait();
     46 }
     47 
     48 ACTION_P(SignalEvent, event) {
     49   event->Signal();
     50 }
     51 
     52 class NonFrontendDataTypeControllerFake : public NonFrontendDataTypeController {
     53  public:
     54   NonFrontendDataTypeControllerFake(
     55       ProfileSyncComponentsFactory* profile_sync_factory,
     56       Profile* profile,
     57       ProfileSyncService* sync_service,
     58       NonFrontendDataTypeControllerMock* mock)
     59       : NonFrontendDataTypeController(base::MessageLoopProxy::current(),
     60                                       base::Closure(),
     61                                       profile_sync_factory,
     62                                       profile,
     63                                       sync_service),
     64         mock_(mock) {}
     65 
     66   virtual syncer::ModelType type() const OVERRIDE { return syncer::BOOKMARKS; }
     67   virtual syncer::ModelSafeGroup model_safe_group() const OVERRIDE {
     68     return syncer::GROUP_DB;
     69   }
     70 
     71  private:
     72   virtual ~NonFrontendDataTypeControllerFake() {}
     73 
     74   virtual ProfileSyncComponentsFactory::SyncComponents
     75   CreateSyncComponents() OVERRIDE {
     76     return profile_sync_factory()->
     77             CreateBookmarkSyncComponents(profile_sync_service(), this);
     78   }
     79 
     80   virtual bool PostTaskOnBackendThread(
     81       const tracked_objects::Location& from_here,
     82       const base::Closure& task) OVERRIDE {
     83     return BrowserThread::PostTask(BrowserThread::DB, from_here, task);
     84   }
     85 
     86   // We mock the following methods because their default implementations do
     87   // nothing, but we still want to make sure they're called appropriately.
     88   virtual bool StartModels() OVERRIDE {
     89     return mock_->StartModels();
     90   }
     91   virtual void RecordUnrecoverableError(
     92       const tracked_objects::Location& from_here,
     93       const std::string& message) OVERRIDE {
     94     mock_->RecordUnrecoverableError(from_here, message);
     95   }
     96   virtual void RecordAssociationTime(base::TimeDelta time) OVERRIDE {
     97     mock_->RecordAssociationTime(time);
     98   }
     99   virtual void RecordStartFailure(
    100       DataTypeController::ConfigureResult result) OVERRIDE {
    101     mock_->RecordStartFailure(result);
    102   }
    103   virtual void DisconnectProcessor(
    104       sync_driver::ChangeProcessor* processor) OVERRIDE{
    105     mock_->DisconnectProcessor(processor);
    106   }
    107 
    108  private:
    109   NonFrontendDataTypeControllerMock* mock_;
    110 };
    111 
    112 class SyncNonFrontendDataTypeControllerTest : public testing::Test {
    113  public:
    114   SyncNonFrontendDataTypeControllerTest()
    115       : ui_thread_(BrowserThread::UI, &message_loop_),
    116         db_thread_(BrowserThread::DB),
    117         service_(&profile_),
    118         model_associator_(NULL),
    119         change_processor_(NULL) {}
    120 
    121   virtual void SetUp() {
    122     db_thread_.Start();
    123     profile_sync_factory_.reset(new ProfileSyncComponentsFactoryMock());
    124 
    125     // All of these are refcounted, so don't need to be released.
    126     dtc_mock_ = new StrictMock<NonFrontendDataTypeControllerMock>();
    127     non_frontend_dtc_ =
    128         new NonFrontendDataTypeControllerFake(profile_sync_factory_.get(),
    129                                               &profile_,
    130                                               &service_,
    131                                               dtc_mock_.get());
    132   }
    133 
    134   virtual void TearDown() {
    135     if (non_frontend_dtc_->state() !=
    136         NonFrontendDataTypeController::NOT_RUNNING) {
    137       non_frontend_dtc_->Stop();
    138     }
    139     db_thread_.Stop();
    140   }
    141 
    142  protected:
    143   void SetStartExpectations() {
    144     EXPECT_CALL(*dtc_mock_.get(), StartModels()).WillOnce(Return(true));
    145     EXPECT_CALL(model_load_callback_, Run(_, _));
    146     model_associator_ = new ModelAssociatorMock();
    147     change_processor_ = new ChangeProcessorMock();
    148     EXPECT_CALL(*profile_sync_factory_, CreateBookmarkSyncComponents(_, _)).
    149         WillOnce(Return(ProfileSyncComponentsFactory::SyncComponents(
    150             model_associator_, change_processor_)));
    151   }
    152 
    153   void SetAssociateExpectations() {
    154     EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
    155         WillOnce(Return(true));
    156     EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
    157         WillOnce(DoAll(SetArgumentPointee<0>(true), Return(true)));
    158     EXPECT_CALL(*model_associator_, AssociateModels(_, _)).
    159         WillOnce(Return(syncer::SyncError()));
    160     EXPECT_CALL(*dtc_mock_.get(), RecordAssociationTime(_));
    161   }
    162 
    163   void SetActivateExpectations(DataTypeController::ConfigureResult result) {
    164     EXPECT_CALL(start_callback_, Run(result, _, _));
    165   }
    166 
    167   void SetStopExpectations() {
    168     EXPECT_CALL(*dtc_mock_.get(), DisconnectProcessor(_));
    169     EXPECT_CALL(service_, DeactivateDataType(_));
    170     EXPECT_CALL(*model_associator_, DisassociateModels()).
    171                 WillOnce(Return(syncer::SyncError()));
    172   }
    173 
    174   void SetStartFailExpectations(DataTypeController::ConfigureResult result) {
    175     if (DataTypeController::IsUnrecoverableResult(result))
    176       EXPECT_CALL(*dtc_mock_.get(), RecordUnrecoverableError(_, _));
    177     if (model_associator_) {
    178       EXPECT_CALL(*model_associator_, DisassociateModels()).
    179                   WillOnce(Return(syncer::SyncError()));
    180     }
    181     EXPECT_CALL(*dtc_mock_.get(), RecordStartFailure(result));
    182     EXPECT_CALL(start_callback_, Run(result, _, _));
    183   }
    184 
    185   static void SignalDone(WaitableEvent* done) {
    186     done->Signal();
    187   }
    188 
    189   void WaitForDTC() {
    190     WaitableEvent done(true, false);
    191     BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
    192         base::Bind(&SyncNonFrontendDataTypeControllerTest::SignalDone, &done));
    193     done.TimedWait(TestTimeouts::action_timeout());
    194     if (!done.IsSignaled()) {
    195       ADD_FAILURE() << "Timed out waiting for DB thread to finish.";
    196     }
    197     base::MessageLoop::current()->RunUntilIdle();
    198   }
    199 
    200   void Start() {
    201     non_frontend_dtc_->LoadModels(
    202         base::Bind(&ModelLoadCallbackMock::Run,
    203                    base::Unretained(&model_load_callback_)));
    204     non_frontend_dtc_->StartAssociating(
    205         base::Bind(&StartCallbackMock::Run,
    206                    base::Unretained(&start_callback_)));
    207   }
    208 
    209   base::MessageLoopForUI message_loop_;
    210   content::TestBrowserThread ui_thread_;
    211   content::TestBrowserThread db_thread_;
    212   scoped_refptr<NonFrontendDataTypeControllerFake> non_frontend_dtc_;
    213   scoped_ptr<ProfileSyncComponentsFactoryMock> profile_sync_factory_;
    214   scoped_refptr<NonFrontendDataTypeControllerMock> dtc_mock_;
    215   ProfileMock profile_;
    216   ProfileSyncServiceMock service_;
    217   ModelAssociatorMock* model_associator_;
    218   ChangeProcessorMock* change_processor_;
    219   StartCallbackMock start_callback_;
    220   ModelLoadCallbackMock model_load_callback_;
    221 };
    222 
    223 TEST_F(SyncNonFrontendDataTypeControllerTest, StartOk) {
    224   SetStartExpectations();
    225   SetAssociateExpectations();
    226   SetActivateExpectations(DataTypeController::OK);
    227   SetStopExpectations();
    228   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
    229   Start();
    230   WaitForDTC();
    231   EXPECT_EQ(DataTypeController::RUNNING, non_frontend_dtc_->state());
    232 }
    233 
    234 TEST_F(SyncNonFrontendDataTypeControllerTest, StartFirstRun) {
    235   SetStartExpectations();
    236   EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
    237       WillOnce(Return(true));
    238   EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
    239       WillOnce(DoAll(SetArgumentPointee<0>(false), Return(true)));
    240   EXPECT_CALL(*model_associator_, AssociateModels(_, _)).
    241       WillOnce(Return(syncer::SyncError()));
    242   EXPECT_CALL(*dtc_mock_.get(), RecordAssociationTime(_));
    243   SetActivateExpectations(DataTypeController::OK_FIRST_RUN);
    244   SetStopExpectations();
    245   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
    246   Start();
    247   WaitForDTC();
    248   EXPECT_EQ(DataTypeController::RUNNING, non_frontend_dtc_->state());
    249 }
    250 
    251 TEST_F(SyncNonFrontendDataTypeControllerTest, StartAssociationFailed) {
    252   SetStartExpectations();
    253   EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
    254       WillOnce(Return(true));
    255   EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
    256       WillOnce(DoAll(SetArgumentPointee<0>(true), Return(true)));
    257   EXPECT_CALL(*model_associator_, AssociateModels(_, _)).
    258       WillOnce(
    259           Return(syncer::SyncError(FROM_HERE,
    260                                    syncer::SyncError::DATATYPE_ERROR,
    261                                    "Error",
    262                                    syncer::BOOKMARKS)));
    263   EXPECT_CALL(*dtc_mock_.get(), RecordAssociationTime(_));
    264   SetStartFailExpectations(DataTypeController::ASSOCIATION_FAILED);
    265   // Set up association to fail with an association failed error.
    266   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
    267   Start();
    268   WaitForDTC();
    269   EXPECT_EQ(DataTypeController::DISABLED, non_frontend_dtc_->state());
    270 }
    271 
    272 TEST_F(SyncNonFrontendDataTypeControllerTest,
    273        StartAssociationTriggersUnrecoverableError) {
    274   SetStartExpectations();
    275   SetStartFailExpectations(DataTypeController::UNRECOVERABLE_ERROR);
    276   // Set up association to fail with an unrecoverable error.
    277   EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
    278       WillRepeatedly(Return(true));
    279   EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
    280       WillRepeatedly(DoAll(SetArgumentPointee<0>(false), Return(false)));
    281   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
    282   Start();
    283   WaitForDTC();
    284   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
    285 }
    286 
    287 TEST_F(SyncNonFrontendDataTypeControllerTest, StartAssociationCryptoNotReady) {
    288   SetStartExpectations();
    289   SetStartFailExpectations(DataTypeController::NEEDS_CRYPTO);
    290   // Set up association to fail with a NEEDS_CRYPTO error.
    291   EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
    292       WillRepeatedly(Return(false));
    293   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
    294   Start();
    295   WaitForDTC();
    296   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
    297 }
    298 
    299 // Trigger a Stop() call when we check if the model associator has user created
    300 // nodes.
    301 TEST_F(SyncNonFrontendDataTypeControllerTest, AbortDuringAssociationInactive) {
    302   WaitableEvent wait_for_db_thread_pause(false, false);
    303   WaitableEvent pause_db_thread(false, false);
    304 
    305   SetStartExpectations();
    306   EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
    307       WillOnce(Return(true));
    308   EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
    309       WillOnce(DoAll(
    310           SignalEvent(&wait_for_db_thread_pause),
    311           WaitOnEvent(&pause_db_thread),
    312           SetArgumentPointee<0>(true),
    313           Return(true)));
    314   EXPECT_CALL(*model_associator_, AbortAssociation()).WillOnce(
    315       SignalEvent(&pause_db_thread));
    316   EXPECT_CALL(*model_associator_, AssociateModels(_, _)).
    317               WillOnce(Return(syncer::SyncError()));
    318   SetStopExpectations();
    319   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
    320   Start();
    321   wait_for_db_thread_pause.Wait();
    322   non_frontend_dtc_->Stop();
    323   WaitForDTC();
    324   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
    325 }
    326 
    327 // Same as above but abort during the Activate call.
    328 TEST_F(SyncNonFrontendDataTypeControllerTest, AbortDuringAssociationActivated) {
    329   WaitableEvent wait_for_association_starts(false, false);
    330   WaitableEvent wait_for_dtc_stop(false, false);
    331 
    332   SetStartExpectations();
    333   EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
    334       WillOnce(Return(true));
    335   EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
    336       WillOnce(DoAll(
    337           SetArgumentPointee<0>(true),
    338           Return(true)));
    339   EXPECT_CALL(*model_associator_, AbortAssociation());
    340   EXPECT_CALL(*model_associator_, AssociateModels(_, _)).
    341       WillOnce(DoAll(
    342           SignalEvent(&wait_for_association_starts),
    343           WaitOnEvent(&wait_for_dtc_stop),
    344           Return(syncer::SyncError())));
    345   SetStopExpectations();
    346   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
    347   Start();
    348   wait_for_association_starts.Wait();
    349   non_frontend_dtc_->Stop();
    350   wait_for_dtc_stop.Signal();
    351   WaitForDTC();
    352   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
    353 }
    354 
    355 TEST_F(SyncNonFrontendDataTypeControllerTest, Stop) {
    356   SetStartExpectations();
    357   SetAssociateExpectations();
    358   SetActivateExpectations(DataTypeController::OK);
    359   SetStopExpectations();
    360   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
    361   Start();
    362   WaitForDTC();
    363   EXPECT_EQ(DataTypeController::RUNNING, non_frontend_dtc_->state());
    364   non_frontend_dtc_->Stop();
    365   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
    366 }
    367 
    368 // Disabled due to http://crbug.com/388367
    369 TEST_F(SyncNonFrontendDataTypeControllerTest,
    370        DISABLED_OnSingleDataTypeUnrecoverableError) {
    371   SetStartExpectations();
    372   SetAssociateExpectations();
    373   SetActivateExpectations(DataTypeController::OK);
    374   EXPECT_CALL(*dtc_mock_.get(), RecordUnrecoverableError(_, "Test"));
    375   EXPECT_CALL(service_, DisableDatatype(_))
    376       .WillOnce(InvokeWithoutArgs(non_frontend_dtc_.get(),
    377                                   &NonFrontendDataTypeController::Stop));
    378   SetStopExpectations();
    379   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
    380   Start();
    381   WaitForDTC();
    382   EXPECT_EQ(DataTypeController::RUNNING, non_frontend_dtc_->state());
    383   // This should cause non_frontend_dtc_->Stop() to be called.
    384   syncer::SyncError error(FROM_HERE,
    385                           syncer::SyncError::DATATYPE_ERROR,
    386                           "error",
    387                           non_frontend_dtc_->type());
    388   BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, base::Bind(
    389       &NonFrontendDataTypeControllerFake::OnSingleDataTypeUnrecoverableError,
    390       non_frontend_dtc_.get(),
    391       error));
    392   WaitForDTC();
    393   EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
    394 }
    395