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/bind.h"
      6 #include "base/callback.h"
      7 #include "base/compiler_specific.h"
      8 #include "base/memory/ref_counted.h"
      9 #include "base/memory/weak_ptr.h"
     10 #include "base/run_loop.h"
     11 #include "chrome/browser/chrome_notification_types.h"
     12 #include "chrome/browser/sync/glue/autofill_data_type_controller.h"
     13 #include "chrome/browser/sync/profile_sync_components_factory_mock.h"
     14 #include "chrome/browser/sync/profile_sync_service_factory.h"
     15 #include "chrome/browser/sync/profile_sync_service_mock.h"
     16 #include "chrome/browser/webdata/autocomplete_syncable_service.h"
     17 #include "chrome/browser/webdata/web_data_service_factory.h"
     18 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
     19 #include "components/sync_driver/data_type_controller_mock.h"
     20 #include "components/webdata/common/web_data_service_test_util.h"
     21 #include "content/public/browser/browser_thread.h"
     22 #include "content/public/browser/notification_service.h"
     23 #include "content/public/browser/notification_source.h"
     24 #include "content/public/browser/notification_types.h"
     25 #include "content/public/test/test_browser_thread_bundle.h"
     26 #include "sync/api/sync_error.h"
     27 #include "testing/gmock/include/gmock/gmock.h"
     28 #include "testing/gtest/include/gtest/gtest.h"
     29 
     30 using autofill::AutofillWebDataService;
     31 using autofill::AutofillWebDataBackend;
     32 
     33 namespace browser_sync {
     34 
     35 namespace {
     36 
     37 using content::BrowserThread;
     38 using testing::_;
     39 using testing::Return;
     40 
     41 class NoOpAutofillBackend : public AutofillWebDataBackend {
     42  public:
     43   NoOpAutofillBackend() {}
     44   virtual ~NoOpAutofillBackend() {}
     45   virtual WebDatabase* GetDatabase() OVERRIDE { return NULL; }
     46   virtual void AddObserver(
     47       autofill::AutofillWebDataServiceObserverOnDBThread* observer) OVERRIDE {}
     48   virtual void RemoveObserver(
     49       autofill::AutofillWebDataServiceObserverOnDBThread* observer) OVERRIDE {}
     50   virtual void RemoveExpiredFormElements() OVERRIDE {}
     51   virtual void NotifyOfMultipleAutofillChanges() OVERRIDE {}
     52 };
     53 
     54 // Fake WebDataService implementation that stubs out the database loading.
     55 class FakeWebDataService : public AutofillWebDataService {
     56  public:
     57   FakeWebDataService()
     58       : AutofillWebDataService(
     59             BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
     60             BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB)),
     61         is_database_loaded_(false),
     62         db_loaded_callback_(base::Callback<void(void)>()){}
     63 
     64   // Mark the database as loaded and send out the appropriate notification.
     65   void LoadDatabase() {
     66     StartSyncableService();
     67     is_database_loaded_ = true;
     68 
     69     if (!db_loaded_callback_.is_null())
     70       db_loaded_callback_.Run();
     71   }
     72 
     73   virtual bool IsDatabaseLoaded() OVERRIDE {
     74     return is_database_loaded_;
     75   }
     76 
     77   virtual void RegisterDBLoadedCallback(
     78       const base::Callback<void(void)>& callback) OVERRIDE {
     79     db_loaded_callback_ = callback;
     80   }
     81 
     82   void StartSyncableService() {
     83     // The |autofill_profile_syncable_service_| must be constructed on the DB
     84     // thread.
     85     base::RunLoop run_loop;
     86     BrowserThread::PostTaskAndReply(BrowserThread::DB, FROM_HERE,
     87         base::Bind(&FakeWebDataService::CreateSyncableService,
     88                    base::Unretained(this)), run_loop.QuitClosure());
     89     run_loop.Run();
     90   }
     91 
     92  private:
     93   virtual ~FakeWebDataService() {
     94   }
     95 
     96   void CreateSyncableService() {
     97     ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::DB));
     98     // These services are deleted in DestroySyncableService().
     99     AutocompleteSyncableService::CreateForWebDataServiceAndBackend(
    100         this,
    101         &autofill_backend_);
    102   }
    103 
    104   bool is_database_loaded_;
    105   NoOpAutofillBackend autofill_backend_;
    106   base::Callback<void(void)> db_loaded_callback_;
    107 
    108   DISALLOW_COPY_AND_ASSIGN(FakeWebDataService);
    109 };
    110 
    111 class MockWebDataServiceWrapperSyncable : public MockWebDataServiceWrapper {
    112  public:
    113   static KeyedService* Build(content::BrowserContext* profile) {
    114     return new MockWebDataServiceWrapperSyncable();
    115   }
    116 
    117   MockWebDataServiceWrapperSyncable()
    118       : MockWebDataServiceWrapper(NULL, new FakeWebDataService(), NULL) {
    119   }
    120 
    121   virtual void Shutdown() OVERRIDE {
    122     static_cast<FakeWebDataService*>(
    123         fake_autofill_web_data_.get())->ShutdownOnUIThread();
    124     // Make sure WebDataService is shutdown properly on DB thread before we
    125     // destroy it.
    126     base::RunLoop run_loop;
    127     ASSERT_TRUE(BrowserThread::PostTaskAndReply(BrowserThread::DB, FROM_HERE,
    128         base::Bind(&base::DoNothing), run_loop.QuitClosure()));
    129     run_loop.Run();
    130   }
    131 
    132  private:
    133   DISALLOW_COPY_AND_ASSIGN(MockWebDataServiceWrapperSyncable);
    134 };
    135 
    136 class SyncAutofillDataTypeControllerTest : public testing::Test {
    137  public:
    138   SyncAutofillDataTypeControllerTest()
    139       : thread_bundle_(content::TestBrowserThreadBundle::REAL_DB_THREAD),
    140         service_(&profile_),
    141         last_start_result_(DataTypeController::OK),
    142         weak_ptr_factory_(this) {}
    143 
    144   virtual ~SyncAutofillDataTypeControllerTest() {}
    145 
    146   virtual void SetUp() {
    147     EXPECT_CALL(profile_sync_factory_,
    148                 GetSyncableServiceForType(_)).
    149         WillRepeatedly(Return(base::WeakPtr<syncer::SyncableService>()));
    150 
    151     WebDataServiceFactory::GetInstance()->SetTestingFactory(
    152         &profile_, MockWebDataServiceWrapperSyncable::Build);
    153 
    154     autofill_dtc_ =
    155         new AutofillDataTypeController(
    156             &profile_sync_factory_, &profile_,
    157             DataTypeController::DisableTypeCallback());
    158   }
    159 
    160   // Passed to AutofillDTC::Start().
    161   void OnStartFinished(DataTypeController::StartResult result,
    162                        const syncer::SyncMergeResult& local_merge_result,
    163                        const syncer::SyncMergeResult& syncer_merge_result) {
    164     last_start_result_ = result;
    165     last_start_error_ = local_merge_result.error();
    166   }
    167 
    168   void OnLoadFinished(syncer::ModelType type, syncer::SyncError error) {
    169     EXPECT_FALSE(error.IsSet());
    170     EXPECT_EQ(type, syncer::AUTOFILL);
    171   }
    172 
    173   virtual void TearDown() {
    174     autofill_dtc_ = NULL;
    175   }
    176 
    177   void BlockForDBThread() {
    178     base::RunLoop run_loop;
    179     ASSERT_TRUE(BrowserThread::PostTaskAndReply(BrowserThread::DB, FROM_HERE,
    180         base::Bind(&base::DoNothing), run_loop.QuitClosure()));
    181     run_loop.Run();
    182   }
    183 
    184  protected:
    185   content::TestBrowserThreadBundle thread_bundle_;
    186   ProfileSyncComponentsFactoryMock profile_sync_factory_;
    187   TestingProfile profile_;
    188   ProfileSyncServiceMock service_;
    189   scoped_refptr<AutofillDataTypeController> autofill_dtc_;
    190 
    191   // Stores arguments of most recent call of OnStartFinished().
    192   DataTypeController::StartResult last_start_result_;
    193   syncer::SyncError last_start_error_;
    194   base::WeakPtrFactory<SyncAutofillDataTypeControllerTest> weak_ptr_factory_;
    195 };
    196 
    197 // Load the WDS's database, then start the Autofill DTC.  It should
    198 // immediately try to start association and fail (due to missing DB
    199 // thread).
    200 TEST_F(SyncAutofillDataTypeControllerTest, StartWDSReady) {
    201   FakeWebDataService* web_db =
    202       static_cast<FakeWebDataService*>(
    203           WebDataServiceFactory::GetAutofillWebDataForProfile(
    204               &profile_, Profile::EXPLICIT_ACCESS).get());
    205   web_db->LoadDatabase();
    206   autofill_dtc_->LoadModels(
    207     base::Bind(&SyncAutofillDataTypeControllerTest::OnLoadFinished,
    208                weak_ptr_factory_.GetWeakPtr()));
    209 
    210   autofill_dtc_->StartAssociating(
    211       base::Bind(&SyncAutofillDataTypeControllerTest::OnStartFinished,
    212                  weak_ptr_factory_.GetWeakPtr()));
    213   BlockForDBThread();
    214 
    215   EXPECT_EQ(DataTypeController::ASSOCIATION_FAILED, last_start_result_);
    216   EXPECT_TRUE(last_start_error_.IsSet());
    217   EXPECT_EQ(DataTypeController::DISABLED, autofill_dtc_->state());
    218 }
    219 
    220 // Start the autofill DTC without the WDS's database loaded, then
    221 // start the DB.  The Autofill DTC should be in the MODEL_STARTING
    222 // state until the database in loaded, when it should try to start
    223 // association and fail (due to missing DB thread).
    224 TEST_F(SyncAutofillDataTypeControllerTest, StartWDSNotReady) {
    225   autofill_dtc_->LoadModels(
    226     base::Bind(&SyncAutofillDataTypeControllerTest::OnLoadFinished,
    227                weak_ptr_factory_.GetWeakPtr()));
    228 
    229   EXPECT_EQ(DataTypeController::OK, last_start_result_);
    230   EXPECT_FALSE(last_start_error_.IsSet());
    231   EXPECT_EQ(DataTypeController::MODEL_STARTING, autofill_dtc_->state());
    232 
    233   FakeWebDataService* web_db =
    234       static_cast<FakeWebDataService*>(
    235           WebDataServiceFactory::GetAutofillWebDataForProfile(
    236               &profile_, Profile::EXPLICIT_ACCESS).get());
    237   web_db->LoadDatabase();
    238 
    239   autofill_dtc_->StartAssociating(
    240       base::Bind(&SyncAutofillDataTypeControllerTest::OnStartFinished,
    241                  weak_ptr_factory_.GetWeakPtr()));
    242   BlockForDBThread();
    243 
    244   EXPECT_EQ(DataTypeController::ASSOCIATION_FAILED, last_start_result_);
    245   EXPECT_TRUE(last_start_error_.IsSet());
    246 
    247   EXPECT_EQ(DataTypeController::DISABLED, autofill_dtc_->state());
    248 }
    249 
    250 }  // namespace
    251 
    252 }  // namespace browser_sync
    253