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 "base/callback.h"
      6 #include "base/message_loop/message_loop.h"
      7 #include "chrome/browser/sync/glue/fake_data_type_controller.h"
      8 #include "chrome/browser/sync/glue/model_association_manager.h"
      9 #include "content/public/test/test_browser_thread.h"
     10 #include "testing/gmock/include/gmock/gmock.h"
     11 #include "testing/gtest/include/gtest/gtest.h"
     12 
     13 using ::testing::_;
     14 namespace browser_sync {
     15 class MockModelAssociationResultProcessor :
     16     public ModelAssociationResultProcessor {
     17  public:
     18   MockModelAssociationResultProcessor() {}
     19   ~MockModelAssociationResultProcessor() {}
     20   MOCK_METHOD2(OnSingleDataTypeAssociationDone,
     21                void(syncer::ModelType type,
     22                     const syncer::DataTypeAssociationStats& association_stats));
     23   MOCK_METHOD1(OnModelAssociationDone, void(
     24       const DataTypeManager::ConfigureResult& result));
     25   MOCK_METHOD0(OnTypesLoaded, void());
     26 };
     27 
     28 FakeDataTypeController* GetController(
     29     const DataTypeController::TypeMap& controllers,
     30     syncer::ModelType model_type) {
     31   DataTypeController::TypeMap::const_iterator it =
     32       controllers.find(model_type);
     33   if (it == controllers.end()) {
     34     return NULL;
     35   }
     36   return (FakeDataTypeController*)(it->second.get());
     37 }
     38 
     39 ACTION_P(VerifyResult, expected_result) {
     40   EXPECT_EQ(arg0.status, expected_result.status);
     41   EXPECT_TRUE(arg0.requested_types.Equals(expected_result.requested_types));
     42   EXPECT_EQ(arg0.failed_data_types.size(),
     43             expected_result.failed_data_types.size());
     44 
     45   if (arg0.failed_data_types.size() ==
     46           expected_result.failed_data_types.size()) {
     47     std::map<syncer::ModelType, syncer::SyncError>::const_iterator it1, it2;
     48     for (it1 = arg0.failed_data_types.begin(),
     49          it2 = expected_result.failed_data_types.begin();
     50          it1 != arg0.failed_data_types.end();
     51          ++it1, ++it2) {
     52       EXPECT_EQ((*it1).first, (*it2).first);
     53     }
     54   }
     55 
     56   EXPECT_TRUE(arg0.waiting_to_start.Equals(expected_result.waiting_to_start));
     57 }
     58 
     59 class SyncModelAssociationManagerTest : public testing::Test {
     60  public:
     61   SyncModelAssociationManagerTest() :
     62       ui_thread_(content::BrowserThread::UI, &ui_loop_) {
     63   }
     64 
     65  protected:
     66   base::MessageLoopForUI ui_loop_;
     67   content::TestBrowserThread ui_thread_;
     68   MockModelAssociationResultProcessor result_processor_;
     69   DataTypeController::TypeMap controllers_;
     70 };
     71 
     72 // Start a type and make sure ModelAssociationManager callst the |Start|
     73 // method and calls the callback when it is done.
     74 TEST_F(SyncModelAssociationManagerTest, SimpleModelStart) {
     75   controllers_[syncer::BOOKMARKS] =
     76       new FakeDataTypeController(syncer::BOOKMARKS);
     77   ModelAssociationManager model_association_manager(&controllers_,
     78                                                     &result_processor_);
     79   syncer::ModelTypeSet types;
     80   types.Put(syncer::BOOKMARKS);
     81   DataTypeManager::ConfigureResult expected_result(
     82       DataTypeManager::OK,
     83       types,
     84       std::map<syncer::ModelType, syncer::SyncError>(),
     85       syncer::ModelTypeSet(),
     86       syncer::ModelTypeSet());
     87   EXPECT_CALL(result_processor_, OnModelAssociationDone(_)).
     88               WillOnce(VerifyResult(expected_result));
     89 
     90   model_association_manager.Initialize(types);
     91   model_association_manager.StopDisabledTypes();
     92   model_association_manager.StartAssociationAsync(types);
     93 
     94   EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
     95             DataTypeController::ASSOCIATING);
     96   GetController(controllers_, syncer::BOOKMARKS)->FinishStart(
     97       DataTypeController::OK);
     98 }
     99 
    100 // Start a type and call stop before it finishes associating.
    101 TEST_F(SyncModelAssociationManagerTest, StopModelBeforeFinish) {
    102   controllers_[syncer::BOOKMARKS] =
    103       new FakeDataTypeController(syncer::BOOKMARKS);
    104   ModelAssociationManager model_association_manager(
    105       &controllers_,
    106       &result_processor_);
    107 
    108   syncer::ModelTypeSet types;
    109   types.Put(syncer::BOOKMARKS);
    110 
    111   DataTypeManager::ConfigureResult expected_result(
    112       DataTypeManager::ABORTED,
    113       types,
    114       std::map<syncer::ModelType, syncer::SyncError>(),
    115       syncer::ModelTypeSet(),
    116       syncer::ModelTypeSet());
    117 
    118   EXPECT_CALL(result_processor_, OnModelAssociationDone(_)).
    119               WillOnce(VerifyResult(expected_result));
    120 
    121   model_association_manager.Initialize(types);
    122   model_association_manager.StopDisabledTypes();
    123   model_association_manager.StartAssociationAsync(types);
    124 
    125   EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
    126             DataTypeController::ASSOCIATING);
    127   model_association_manager.Stop();
    128   EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
    129             DataTypeController::NOT_RUNNING);
    130 }
    131 
    132 // Start a type, let it finish and then call stop.
    133 TEST_F(SyncModelAssociationManagerTest, StopAfterFinish) {
    134   controllers_[syncer::BOOKMARKS] =
    135       new FakeDataTypeController(syncer::BOOKMARKS);
    136   ModelAssociationManager model_association_manager(
    137       &controllers_,
    138       &result_processor_);
    139   syncer::ModelTypeSet types;
    140   types.Put(syncer::BOOKMARKS);
    141   DataTypeManager::ConfigureResult expected_result(
    142       DataTypeManager::OK,
    143       types,
    144       std::map<syncer::ModelType, syncer::SyncError>(),
    145       syncer::ModelTypeSet(),
    146       syncer::ModelTypeSet());
    147   EXPECT_CALL(result_processor_, OnModelAssociationDone(_)).
    148               WillOnce(VerifyResult(expected_result));
    149 
    150   model_association_manager.Initialize(types);
    151   model_association_manager.StopDisabledTypes();
    152   model_association_manager.StartAssociationAsync(types);
    153 
    154   EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
    155             DataTypeController::ASSOCIATING);
    156   GetController(controllers_, syncer::BOOKMARKS)->FinishStart(
    157       DataTypeController::OK);
    158 
    159   model_association_manager.Stop();
    160   EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
    161             DataTypeController::NOT_RUNNING);
    162 }
    163 
    164 // Make a type fail model association and verify correctness.
    165 TEST_F(SyncModelAssociationManagerTest, TypeFailModelAssociation) {
    166   controllers_[syncer::BOOKMARKS] =
    167       new FakeDataTypeController(syncer::BOOKMARKS);
    168   ModelAssociationManager model_association_manager(
    169       &controllers_,
    170       &result_processor_);
    171   syncer::ModelTypeSet types;
    172   types.Put(syncer::BOOKMARKS);
    173   std::map<syncer::ModelType, syncer::SyncError> errors;
    174   syncer::SyncError error(FROM_HERE,
    175                           syncer::SyncError::DATATYPE_ERROR,
    176                           "Failed",
    177                           syncer::BOOKMARKS);
    178   errors[syncer::BOOKMARKS] = error;
    179   DataTypeManager::ConfigureResult expected_result(
    180       DataTypeManager::PARTIAL_SUCCESS,
    181       types,
    182       errors,
    183       syncer::ModelTypeSet(),
    184       syncer::ModelTypeSet());
    185   EXPECT_CALL(result_processor_, OnModelAssociationDone(_)).
    186               WillOnce(VerifyResult(expected_result));
    187 
    188   model_association_manager.Initialize(types);
    189   model_association_manager.StopDisabledTypes();
    190   model_association_manager.StartAssociationAsync(types);
    191 
    192   EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
    193             DataTypeController::ASSOCIATING);
    194   GetController(controllers_, syncer::BOOKMARKS)->FinishStart(
    195       DataTypeController::ASSOCIATION_FAILED);
    196   EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
    197             DataTypeController::NOT_RUNNING);
    198 }
    199 
    200 // Ensure configuring stops when a type returns a unrecoverable error.
    201 TEST_F(SyncModelAssociationManagerTest, TypeReturnUnrecoverableError) {
    202   controllers_[syncer::BOOKMARKS] =
    203       new FakeDataTypeController(syncer::BOOKMARKS);
    204   ModelAssociationManager model_association_manager(
    205       &controllers_,
    206       &result_processor_);
    207   syncer::ModelTypeSet types;
    208   types.Put(syncer::BOOKMARKS);
    209   std::map<syncer::ModelType, syncer::SyncError> errors;
    210   syncer::SyncError error(FROM_HERE,
    211                           syncer::SyncError::DATATYPE_ERROR,
    212                           "Failed",
    213                           syncer::BOOKMARKS);
    214   errors[syncer::BOOKMARKS] = error;
    215   DataTypeManager::ConfigureResult expected_result(
    216       DataTypeManager::UNRECOVERABLE_ERROR,
    217       types,
    218       errors,
    219       syncer::ModelTypeSet(),
    220       syncer::ModelTypeSet());
    221   EXPECT_CALL(result_processor_, OnModelAssociationDone(_)).
    222               WillOnce(VerifyResult(expected_result));
    223 
    224   model_association_manager.Initialize(types);
    225   model_association_manager.StopDisabledTypes();
    226   model_association_manager.StartAssociationAsync(types);
    227 
    228   EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
    229             DataTypeController::ASSOCIATING);
    230   GetController(controllers_, syncer::BOOKMARKS)->FinishStart(
    231       DataTypeController::UNRECOVERABLE_ERROR);
    232 }
    233 
    234 TEST_F(SyncModelAssociationManagerTest, InitializeAbortsLoad) {
    235   controllers_[syncer::BOOKMARKS] =
    236       new FakeDataTypeController(syncer::BOOKMARKS);
    237   controllers_[syncer::THEMES] =
    238       new FakeDataTypeController(syncer::THEMES);
    239 
    240   GetController(controllers_, syncer::BOOKMARKS)->SetDelayModelLoad();
    241   ModelAssociationManager model_association_manager(&controllers_,
    242                                                     &result_processor_);
    243   syncer::ModelTypeSet types(syncer::BOOKMARKS, syncer::THEMES);
    244 
    245   syncer::ModelTypeSet expected_types_waiting_to_load;
    246   expected_types_waiting_to_load.Put(syncer::BOOKMARKS);
    247   DataTypeManager::ConfigureResult expected_result_partially_done(
    248       DataTypeManager::PARTIAL_SUCCESS,
    249       types,
    250       std::map<syncer::ModelType, syncer::SyncError>(),
    251       expected_types_waiting_to_load,
    252       syncer::ModelTypeSet());
    253 
    254   model_association_manager.Initialize(types);
    255   model_association_manager.StopDisabledTypes();
    256 
    257   model_association_manager.StartAssociationAsync(types);
    258 
    259   EXPECT_CALL(result_processor_, OnModelAssociationDone(_)).
    260               WillOnce(VerifyResult(expected_result_partially_done));
    261 
    262   base::OneShotTimer<ModelAssociationManager>* timer =
    263       model_association_manager.GetTimerForTesting();
    264 
    265   base::Closure task = timer->user_task();
    266   timer->Stop();
    267   task.Run();  // Bookmark load times out here.
    268 
    269   // Apps finishes associating here.
    270   GetController(controllers_, syncer::THEMES)->FinishStart(
    271       DataTypeController::OK);
    272 
    273   // At this point, BOOKMARKS is still waiting to load (as evidenced by
    274   // expected_result_partially_done). If we schedule another Initialize (which
    275   // could happen in practice due to reconfiguration), this should abort
    276   // BOOKMARKS. Aborting will call ModelLoadCallback, but the
    277   // ModelAssociationManager should be smart enough to know that this is not due
    278   // to the type having completed loading.
    279   EXPECT_CALL(result_processor_, OnTypesLoaded()).Times(0);
    280 
    281   EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
    282             DataTypeController::MODEL_STARTING);
    283 
    284   model_association_manager.Initialize(types);
    285   EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
    286             DataTypeController::NOT_RUNNING);
    287 
    288   DataTypeManager::ConfigureResult expected_result_done(
    289       DataTypeManager::OK,
    290       types,
    291       std::map<syncer::ModelType, syncer::SyncError>(),
    292       syncer::ModelTypeSet(),
    293       syncer::ModelTypeSet());
    294   EXPECT_CALL(result_processor_, OnModelAssociationDone(_)).
    295               WillOnce(VerifyResult(expected_result_done));
    296 
    297   model_association_manager.StopDisabledTypes();
    298   model_association_manager.StartAssociationAsync(types);
    299 
    300   GetController(controllers_,
    301                 syncer::BOOKMARKS)->SimulateModelLoadFinishing();
    302   GetController(controllers_, syncer::BOOKMARKS)->FinishStart(
    303       DataTypeController::OK);
    304 }
    305 
    306 // Start 2 types. One of which timeout loading. Ensure that type is
    307 // fully configured eventually.
    308 TEST_F(SyncModelAssociationManagerTest, ModelStartWithSlowLoadingType) {
    309   controllers_[syncer::BOOKMARKS] =
    310       new FakeDataTypeController(syncer::BOOKMARKS);
    311   controllers_[syncer::APPS] =
    312       new FakeDataTypeController(syncer::APPS);
    313   GetController(controllers_, syncer::BOOKMARKS)->SetDelayModelLoad();
    314   ModelAssociationManager model_association_manager(&controllers_,
    315                                                     &result_processor_);
    316   syncer::ModelTypeSet types;
    317   types.Put(syncer::BOOKMARKS);
    318   types.Put(syncer::APPS);
    319 
    320   syncer::ModelTypeSet expected_types_waiting_to_load;
    321   expected_types_waiting_to_load.Put(syncer::BOOKMARKS);
    322   DataTypeManager::ConfigureResult expected_result_partially_done(
    323       DataTypeManager::PARTIAL_SUCCESS,
    324       types,
    325       std::map<syncer::ModelType, syncer::SyncError>(),
    326       expected_types_waiting_to_load,
    327       syncer::ModelTypeSet());
    328 
    329   DataTypeManager::ConfigureResult expected_result_done(
    330       DataTypeManager::OK,
    331       types,
    332       std::map<syncer::ModelType, syncer::SyncError>(),
    333       syncer::ModelTypeSet(),
    334       syncer::ModelTypeSet());
    335 
    336   EXPECT_CALL(result_processor_, OnModelAssociationDone(_)).
    337               WillOnce(VerifyResult(expected_result_partially_done));
    338   EXPECT_CALL(result_processor_, OnTypesLoaded());
    339 
    340   model_association_manager.Initialize(types);
    341   model_association_manager.StopDisabledTypes();
    342   model_association_manager.StartAssociationAsync(types);
    343 
    344   base::OneShotTimer<ModelAssociationManager>* timer =
    345       model_association_manager.GetTimerForTesting();
    346 
    347   // Note: Independent of the timeout value this test is not flaky.
    348   // The reason is timer posts a task which would never be executed
    349   // as we dont let the message loop run.
    350   base::Closure task = timer->user_task();
    351   timer->Stop();
    352   task.Run();
    353 
    354   // Simulate delayed loading of bookmark model.
    355   GetController(controllers_, syncer::APPS)->FinishStart(
    356       DataTypeController::OK);
    357 
    358   GetController(controllers_,
    359                 syncer::BOOKMARKS)->SimulateModelLoadFinishing();
    360 
    361   EXPECT_CALL(result_processor_, OnModelAssociationDone(_)).
    362               WillOnce(VerifyResult(expected_result_done));
    363 
    364   // Do it once more to associate bookmarks.
    365   model_association_manager.Initialize(types);
    366   model_association_manager.StopDisabledTypes();
    367   model_association_manager.StartAssociationAsync(types);
    368 
    369   GetController(controllers_,
    370                 syncer::BOOKMARKS)->SimulateModelLoadFinishing();
    371 
    372   GetController(controllers_, syncer::BOOKMARKS)->FinishStart(
    373       DataTypeController::OK);
    374 }
    375 
    376 TEST_F(SyncModelAssociationManagerTest, StartMultipleTimes) {
    377   controllers_[syncer::BOOKMARKS] =
    378       new FakeDataTypeController(syncer::BOOKMARKS);
    379   controllers_[syncer::APPS] =
    380       new FakeDataTypeController(syncer::APPS);
    381   ModelAssociationManager model_association_manager(&controllers_,
    382                                                     &result_processor_);
    383   syncer::ModelTypeSet types;
    384   types.Put(syncer::BOOKMARKS);
    385   types.Put(syncer::APPS);
    386 
    387   DataTypeManager::ConfigureResult result_1st(
    388       DataTypeManager::OK,
    389       syncer::ModelTypeSet(syncer::BOOKMARKS),
    390       std::map<syncer::ModelType, syncer::SyncError>(),
    391       syncer::ModelTypeSet(),
    392       syncer::ModelTypeSet());
    393   DataTypeManager::ConfigureResult result_2nd(
    394       DataTypeManager::OK,
    395       syncer::ModelTypeSet(syncer::APPS),
    396       std::map<syncer::ModelType, syncer::SyncError>(),
    397       syncer::ModelTypeSet(),
    398       syncer::ModelTypeSet());
    399   EXPECT_CALL(result_processor_, OnModelAssociationDone(_)).
    400       Times(2).
    401       WillOnce(VerifyResult(result_1st)).
    402       WillOnce(VerifyResult(result_2nd));
    403 
    404   model_association_manager.Initialize(types);
    405   model_association_manager.StopDisabledTypes();
    406 
    407   // Start BOOKMARKS first.
    408   model_association_manager.StartAssociationAsync(
    409       syncer::ModelTypeSet(syncer::BOOKMARKS));
    410   EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
    411             DataTypeController::ASSOCIATING);
    412   EXPECT_EQ(GetController(controllers_, syncer::APPS)->state(),
    413             DataTypeController::NOT_RUNNING);
    414 
    415   // Finish BOOKMARKS association.
    416   GetController(controllers_, syncer::BOOKMARKS)->FinishStart(
    417       DataTypeController::OK);
    418   EXPECT_EQ(GetController(controllers_, syncer::BOOKMARKS)->state(),
    419             DataTypeController::RUNNING);
    420   EXPECT_EQ(GetController(controllers_, syncer::APPS)->state(),
    421             DataTypeController::NOT_RUNNING);
    422 
    423   // Start APPS next.
    424   model_association_manager.StartAssociationAsync(
    425       syncer::ModelTypeSet(syncer::APPS));
    426   EXPECT_EQ(GetController(controllers_, syncer::APPS)->state(),
    427             DataTypeController::ASSOCIATING);
    428   GetController(controllers_, syncer::APPS)->FinishStart(
    429       DataTypeController::OK);
    430   EXPECT_EQ(GetController(controllers_, syncer::APPS)->state(),
    431             DataTypeController::RUNNING);
    432 }
    433 
    434 }  // namespace browser_sync
    435