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