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/sync_backend_registrar.h"
      6 
      7 #include "base/run_loop.h"
      8 #include "chrome/browser/sync/glue/ui_model_worker.h"
      9 #include "chrome/test/base/testing_profile.h"
     10 #include "components/sync_driver/change_processor_mock.h"
     11 #include "content/public/browser/browser_thread.h"
     12 #include "content/public/test/test_browser_thread_bundle.h"
     13 #include "sync/internal_api/public/base/model_type.h"
     14 #include "sync/internal_api/public/test/test_user_share.h"
     15 #include "testing/gmock/include/gmock/gmock.h"
     16 #include "testing/gtest/include/gtest/gtest.h"
     17 
     18 namespace browser_sync {
     19 
     20 namespace {
     21 
     22 using ::testing::_;
     23 using ::testing::InSequence;
     24 using ::testing::Return;
     25 using ::testing::StrictMock;
     26 using content::BrowserThread;
     27 using syncer::FIRST_REAL_MODEL_TYPE;
     28 using syncer::AUTOFILL;
     29 using syncer::BOOKMARKS;
     30 using syncer::PREFERENCES;
     31 using syncer::THEMES;
     32 using syncer::NIGORI;
     33 using syncer::PASSWORDS;
     34 using syncer::MODEL_TYPE_COUNT;
     35 using syncer::ModelTypeSet;
     36 using syncer::ModelType;
     37 using syncer::ModelTypeFromInt;
     38 
     39 void TriggerChanges(SyncBackendRegistrar* registrar, ModelType type) {
     40   registrar->OnChangesApplied(type, 0, NULL,
     41                               syncer::ImmutableChangeRecordList());
     42   registrar->OnChangesComplete(type);
     43 }
     44 
     45 class SyncBackendRegistrarTest : public testing::Test {
     46  public:
     47   void TestNonUIDataTypeActivationAsync(sync_driver::ChangeProcessor* processor,
     48                                         base::WaitableEvent* done) {
     49     registrar_->ActivateDataType(AUTOFILL,
     50                                  syncer::GROUP_DB,
     51                                  processor,
     52                                  test_user_share_.user_share());
     53     syncer::ModelSafeRoutingInfo expected_routing_info;
     54     expected_routing_info[AUTOFILL] = syncer::GROUP_DB;
     55     ExpectRoutingInfo(registrar_.get(), expected_routing_info);
     56     ExpectHasProcessorsForTypes(*registrar_, ModelTypeSet(AUTOFILL));
     57     TriggerChanges(registrar_.get(), AUTOFILL);
     58     done->Signal();
     59   }
     60 
     61  protected:
     62   SyncBackendRegistrarTest()
     63       : sync_thread_(NULL),
     64         thread_bundle_(content::TestBrowserThreadBundle::REAL_DB_THREAD |
     65                        content::TestBrowserThreadBundle::REAL_FILE_THREAD |
     66                        content::TestBrowserThreadBundle::REAL_IO_THREAD) {}
     67 
     68   virtual ~SyncBackendRegistrarTest() {}
     69 
     70   virtual void SetUp() {
     71     test_user_share_.SetUp();
     72     registrar_.reset(new SyncBackendRegistrar("test", &profile_,
     73                                               scoped_ptr<base::Thread>()));
     74     sync_thread_ = registrar_->sync_thread();
     75   }
     76 
     77   virtual void TearDown() {
     78     registrar_->RequestWorkerStopOnUIThread();
     79     test_user_share_.TearDown();
     80     sync_thread_->message_loop()->PostTask(
     81         FROM_HERE,
     82         base::Bind(&SyncBackendRegistrar::Shutdown,
     83                    base::Unretained(registrar_.release())));
     84     sync_thread_->message_loop()->RunUntilIdle();
     85   }
     86 
     87   void ExpectRoutingInfo(
     88       SyncBackendRegistrar* registrar,
     89       const syncer::ModelSafeRoutingInfo& expected_routing_info) {
     90     syncer::ModelSafeRoutingInfo routing_info;
     91     registrar->GetModelSafeRoutingInfo(&routing_info);
     92     EXPECT_EQ(expected_routing_info, routing_info);
     93   }
     94 
     95   void ExpectHasProcessorsForTypes(const SyncBackendRegistrar& registrar,
     96                                    ModelTypeSet types) {
     97     for (int i = FIRST_REAL_MODEL_TYPE; i < MODEL_TYPE_COUNT; ++i) {
     98       ModelType model_type = ModelTypeFromInt(i);
     99       EXPECT_EQ(types.Has(model_type),
    100                 registrar_->IsTypeActivatedForTest(model_type));
    101     }
    102   }
    103 
    104   syncer::TestUserShare test_user_share_;
    105   TestingProfile profile_;
    106   scoped_ptr<SyncBackendRegistrar> registrar_;
    107 
    108   base::Thread* sync_thread_;
    109   content::TestBrowserThreadBundle thread_bundle_;
    110 };
    111 
    112 TEST_F(SyncBackendRegistrarTest, ConstructorEmpty) {
    113   registrar_->SetInitialTypes(ModelTypeSet());
    114   EXPECT_FALSE(registrar_->IsNigoriEnabled());
    115   {
    116     std::vector<scoped_refptr<syncer::ModelSafeWorker> > workers;
    117     registrar_->GetWorkers(&workers);
    118     EXPECT_EQ(4u, workers.size());
    119   }
    120   ExpectRoutingInfo(registrar_.get(), syncer::ModelSafeRoutingInfo());
    121   ExpectHasProcessorsForTypes(*registrar_, ModelTypeSet());
    122 }
    123 
    124 TEST_F(SyncBackendRegistrarTest, ConstructorNonEmpty) {
    125   const ModelTypeSet initial_types(BOOKMARKS, NIGORI, PASSWORDS);
    126   registrar_->SetInitialTypes(initial_types);
    127   EXPECT_TRUE(registrar_->IsNigoriEnabled());
    128   {
    129     std::vector<scoped_refptr<syncer::ModelSafeWorker> > workers;
    130     registrar_->GetWorkers(&workers);
    131     EXPECT_EQ(4u, workers.size());
    132   }
    133   {
    134     syncer::ModelSafeRoutingInfo expected_routing_info;
    135     expected_routing_info[BOOKMARKS] = syncer::GROUP_PASSIVE;
    136     expected_routing_info[NIGORI] = syncer::GROUP_PASSIVE;
    137     // Passwords dropped because of no password store.
    138     ExpectRoutingInfo(registrar_.get(), expected_routing_info);
    139   }
    140   ExpectHasProcessorsForTypes(*registrar_, ModelTypeSet());
    141 }
    142 
    143 TEST_F(SyncBackendRegistrarTest, ConfigureDataTypes) {
    144   registrar_->SetInitialTypes(ModelTypeSet());
    145 
    146   // Add.
    147   const ModelTypeSet types1(BOOKMARKS, NIGORI, AUTOFILL);
    148   EXPECT_TRUE(
    149       registrar_->ConfigureDataTypes(types1, ModelTypeSet()).Equals(types1));
    150   {
    151     syncer::ModelSafeRoutingInfo expected_routing_info;
    152     expected_routing_info[BOOKMARKS] = syncer::GROUP_PASSIVE;
    153     expected_routing_info[NIGORI] = syncer::GROUP_PASSIVE;
    154     expected_routing_info[AUTOFILL] = syncer::GROUP_PASSIVE;
    155     ExpectRoutingInfo(registrar_.get(), expected_routing_info);
    156   }
    157   ExpectHasProcessorsForTypes(*registrar_, ModelTypeSet());
    158   EXPECT_TRUE(types1.Equals(registrar_->GetLastConfiguredTypes()));
    159 
    160   // Add and remove.
    161   const ModelTypeSet types2(PREFERENCES, THEMES);
    162   EXPECT_TRUE(registrar_->ConfigureDataTypes(types2, types1).Equals(types2));
    163   {
    164     syncer::ModelSafeRoutingInfo expected_routing_info;
    165     expected_routing_info[PREFERENCES] = syncer::GROUP_PASSIVE;
    166     expected_routing_info[THEMES] = syncer::GROUP_PASSIVE;
    167     ExpectRoutingInfo(registrar_.get(), expected_routing_info);
    168   }
    169   ExpectHasProcessorsForTypes(*registrar_, ModelTypeSet());
    170   EXPECT_TRUE(types2.Equals(registrar_->GetLastConfiguredTypes()));
    171 
    172   // Remove.
    173   EXPECT_TRUE(registrar_->ConfigureDataTypes(ModelTypeSet(), types2).Empty());
    174   ExpectRoutingInfo(registrar_.get(), syncer::ModelSafeRoutingInfo());
    175   ExpectHasProcessorsForTypes(*registrar_, ModelTypeSet());
    176   EXPECT_TRUE(ModelTypeSet().Equals(registrar_->GetLastConfiguredTypes()));
    177 }
    178 
    179 TEST_F(SyncBackendRegistrarTest, ActivateDeactivateUIDataType) {
    180   InSequence in_sequence;
    181   registrar_->SetInitialTypes(ModelTypeSet());
    182 
    183   // Should do nothing.
    184   TriggerChanges(registrar_.get(), BOOKMARKS);
    185 
    186   StrictMock<sync_driver::ChangeProcessorMock> change_processor_mock;
    187   EXPECT_CALL(change_processor_mock, StartImpl());
    188   EXPECT_CALL(change_processor_mock, IsRunning())
    189       .WillRepeatedly(Return(true));
    190   EXPECT_CALL(change_processor_mock, ApplyChangesFromSyncModel(NULL, _, _));
    191   EXPECT_CALL(change_processor_mock, IsRunning())
    192       .WillRepeatedly(Return(true));
    193   EXPECT_CALL(change_processor_mock, CommitChangesFromSyncModel());
    194   EXPECT_CALL(change_processor_mock, IsRunning())
    195       .WillRepeatedly(Return(false));
    196 
    197   const ModelTypeSet types(BOOKMARKS);
    198   EXPECT_TRUE(
    199       registrar_->ConfigureDataTypes(types, ModelTypeSet()).Equals(types));
    200   registrar_->ActivateDataType(BOOKMARKS, syncer::GROUP_UI,
    201                              &change_processor_mock,
    202                              test_user_share_.user_share());
    203   {
    204     syncer::ModelSafeRoutingInfo expected_routing_info;
    205     expected_routing_info[BOOKMARKS] = syncer::GROUP_UI;
    206     ExpectRoutingInfo(registrar_.get(), expected_routing_info);
    207   }
    208   ExpectHasProcessorsForTypes(*registrar_, types);
    209 
    210   TriggerChanges(registrar_.get(), BOOKMARKS);
    211 
    212   registrar_->DeactivateDataType(BOOKMARKS);
    213   ExpectRoutingInfo(registrar_.get(), syncer::ModelSafeRoutingInfo());
    214   ExpectHasProcessorsForTypes(*registrar_, ModelTypeSet());
    215 
    216   // Should do nothing.
    217   TriggerChanges(registrar_.get(), BOOKMARKS);
    218 }
    219 
    220 TEST_F(SyncBackendRegistrarTest, ActivateDeactivateNonUIDataType) {
    221   InSequence in_sequence;
    222   registrar_->SetInitialTypes(ModelTypeSet());
    223 
    224   // Should do nothing.
    225   TriggerChanges(registrar_.get(), AUTOFILL);
    226 
    227   StrictMock<sync_driver::ChangeProcessorMock> change_processor_mock;
    228   EXPECT_CALL(change_processor_mock, StartImpl());
    229   EXPECT_CALL(change_processor_mock, IsRunning())
    230       .WillRepeatedly(Return(true));
    231   EXPECT_CALL(change_processor_mock, ApplyChangesFromSyncModel(NULL, _, _));
    232   EXPECT_CALL(change_processor_mock, IsRunning())
    233       .WillRepeatedly(Return(true));
    234   EXPECT_CALL(change_processor_mock, CommitChangesFromSyncModel());
    235   EXPECT_CALL(change_processor_mock, IsRunning())
    236       .WillRepeatedly(Return(false));
    237 
    238   const ModelTypeSet types(AUTOFILL);
    239   EXPECT_TRUE(
    240       registrar_->ConfigureDataTypes(types, ModelTypeSet()).Equals(types));
    241 
    242   base::WaitableEvent done(false, false);
    243   BrowserThread::PostTask(
    244       BrowserThread::DB,
    245       FROM_HERE,
    246       base::Bind(&SyncBackendRegistrarTest::TestNonUIDataTypeActivationAsync,
    247                  base::Unretained(this),
    248                  &change_processor_mock,
    249                  &done));
    250   done.Wait();
    251 
    252   registrar_->DeactivateDataType(AUTOFILL);
    253   ExpectRoutingInfo(registrar_.get(), syncer::ModelSafeRoutingInfo());
    254   ExpectHasProcessorsForTypes(*registrar_, ModelTypeSet());
    255 
    256   // Should do nothing.
    257   TriggerChanges(registrar_.get(), AUTOFILL);
    258 }
    259 
    260 class SyncBackendRegistrarShutdownTest : public testing::Test {
    261  public:
    262   void BlockDBThread() {
    263     EXPECT_FALSE(db_thread_lock_.Try());
    264 
    265     db_thread_blocked_.Signal();
    266     base::AutoLock l(db_thread_lock_);
    267   }
    268 
    269  protected:
    270   friend class TestRegistrar;
    271 
    272   SyncBackendRegistrarShutdownTest()
    273       : thread_bundle_(content::TestBrowserThreadBundle::REAL_DB_THREAD |
    274                        content::TestBrowserThreadBundle::REAL_FILE_THREAD |
    275                        content::TestBrowserThreadBundle::REAL_IO_THREAD),
    276         db_thread_blocked_(false, false) {
    277     quit_closure_ = run_loop_.QuitClosure();
    278   }
    279 
    280   virtual ~SyncBackendRegistrarShutdownTest() {}
    281 
    282   void PostQuitOnUIMessageLoop() {
    283     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, quit_closure_);
    284   }
    285 
    286   content::TestBrowserThreadBundle thread_bundle_;
    287   TestingProfile profile_;
    288   base::WaitableEvent db_thread_blocked_;
    289   base::Lock db_thread_lock_;
    290   base::RunLoop run_loop_;
    291   base::Closure quit_closure_;
    292 };
    293 
    294 // Wrap SyncBackendRegistrar so that we can monitor its lifetime.
    295 class TestRegistrar : public SyncBackendRegistrar {
    296  public:
    297   explicit TestRegistrar(Profile* profile,
    298                          SyncBackendRegistrarShutdownTest* test)
    299       : SyncBackendRegistrar("test", profile, scoped_ptr<base::Thread>()),
    300         test_(test) {}
    301 
    302   virtual ~TestRegistrar() { test_->PostQuitOnUIMessageLoop(); }
    303 
    304  private:
    305   SyncBackendRegistrarShutdownTest* test_;
    306 };
    307 
    308 TEST_F(SyncBackendRegistrarShutdownTest, BlockingShutdown) {
    309   // Take ownership of |db_thread_lock_| so that the DB thread can't acquire it.
    310   db_thread_lock_.Acquire();
    311 
    312   // This will block the DB thread by waiting on |db_thread_lock_|.
    313   BrowserThread::PostTask(
    314       BrowserThread::DB,
    315       FROM_HERE,
    316       base::Bind(&SyncBackendRegistrarShutdownTest::BlockDBThread,
    317                  base::Unretained(this)));
    318 
    319   scoped_ptr<TestRegistrar> registrar(new TestRegistrar(&profile_, this));
    320   base::Thread* sync_thread = registrar->sync_thread();
    321 
    322   // Stop here until the DB thread gets a chance to run and block on the lock.
    323   // Please note that since the task above didn't finish, the task to
    324   // initialize the worker on the DB thread hasn't had a chance to run yet too.
    325   // Which means ModelSafeWorker::SetWorkingLoopToCurrent hasn't been called
    326   // for the DB worker.
    327   db_thread_blocked_.Wait();
    328 
    329   registrar->SetInitialTypes(ModelTypeSet());
    330 
    331   // Start the shutdown.
    332   registrar->RequestWorkerStopOnUIThread();
    333 
    334   sync_thread->message_loop()->PostTask(
    335       FROM_HERE,
    336       base::Bind(&SyncBackendRegistrar::Shutdown,
    337                  base::Unretained(registrar.release())));
    338 
    339   // The test verifies that the sync thread doesn't block because
    340   // of the blocked DB thread and can finish the shutdown.
    341   sync_thread->message_loop()->RunUntilIdle();
    342 
    343   db_thread_lock_.Release();
    344 
    345   // Run the main thread loop until all workers have been removed and the
    346   // registrar destroyed.
    347   run_loop_.Run();
    348 }
    349 
    350 }  // namespace
    351 
    352 }  // namespace browser_sync
    353