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.
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"
30 using autofill::AutofillWebDataService;
31 using autofill::AutofillWebDataBackend;
33 namespace browser_sync {
37 using content::BrowserThread;
39 using testing::Return;
41 class NoOpAutofillBackend : public AutofillWebDataBackend {
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 {}
54 // Fake WebDataService implementation that stubs out the database loading.
55 class FakeWebDataService : public AutofillWebDataService {
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)>()){}
64 // Mark the database as loaded and send out the appropriate notification.
66 StartSyncableService();
67 is_database_loaded_ = true;
69 if (!db_loaded_callback_.is_null())
70 db_loaded_callback_.Run();
73 virtual bool IsDatabaseLoaded() OVERRIDE {
74 return is_database_loaded_;
77 virtual void RegisterDBLoadedCallback(
78 const base::Callback<void(void)>& callback) OVERRIDE {
79 db_loaded_callback_ = callback;
82 void StartSyncableService() {
83 // The |autofill_profile_syncable_service_| must be constructed on the DB
85 base::RunLoop run_loop;
86 BrowserThread::PostTaskAndReply(BrowserThread::DB, FROM_HERE,
87 base::Bind(&FakeWebDataService::CreateSyncableService,
88 base::Unretained(this)), run_loop.QuitClosure());
93 virtual ~FakeWebDataService() {
96 void CreateSyncableService() {
97 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::DB));
98 // These services are deleted in DestroySyncableService().
99 AutocompleteSyncableService::CreateForWebDataServiceAndBackend(
104 bool is_database_loaded_;
105 NoOpAutofillBackend autofill_backend_;
106 base::Callback<void(void)> db_loaded_callback_;
108 DISALLOW_COPY_AND_ASSIGN(FakeWebDataService);
111 class MockWebDataServiceWrapperSyncable : public MockWebDataServiceWrapper {
113 static KeyedService* Build(content::BrowserContext* profile) {
114 return new MockWebDataServiceWrapperSyncable();
117 MockWebDataServiceWrapperSyncable()
118 : MockWebDataServiceWrapper(NULL, new FakeWebDataService(), NULL) {
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
126 base::RunLoop run_loop;
127 ASSERT_TRUE(BrowserThread::PostTaskAndReply(BrowserThread::DB, FROM_HERE,
128 base::Bind(&base::DoNothing), run_loop.QuitClosure()));
133 DISALLOW_COPY_AND_ASSIGN(MockWebDataServiceWrapperSyncable);
136 class SyncAutofillDataTypeControllerTest : public testing::Test {
138 SyncAutofillDataTypeControllerTest()
139 : thread_bundle_(content::TestBrowserThreadBundle::REAL_DB_THREAD),
141 last_start_result_(DataTypeController::OK),
142 weak_ptr_factory_(this) {}
144 virtual ~SyncAutofillDataTypeControllerTest() {}
146 virtual void SetUp() {
147 EXPECT_CALL(profile_sync_factory_,
148 GetSyncableServiceForType(_)).
149 WillRepeatedly(Return(base::WeakPtr<syncer::SyncableService>()));
151 WebDataServiceFactory::GetInstance()->SetTestingFactory(
152 &profile_, MockWebDataServiceWrapperSyncable::Build);
155 new AutofillDataTypeController(&profile_sync_factory_,
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();
168 void OnLoadFinished(syncer::ModelType type, syncer::SyncError error) {
169 EXPECT_FALSE(error.IsSet());
170 EXPECT_EQ(type, syncer::AUTOFILL);
173 virtual void TearDown() {
174 autofill_dtc_ = NULL;
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()));
185 content::TestBrowserThreadBundle thread_bundle_;
186 ProfileSyncComponentsFactoryMock profile_sync_factory_;
187 TestingProfile profile_;
188 ProfileSyncServiceMock service_;
189 scoped_refptr<AutofillDataTypeController> autofill_dtc_;
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_;
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
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()));
210 autofill_dtc_->StartAssociating(
211 base::Bind(&SyncAutofillDataTypeControllerTest::OnStartFinished,
212 weak_ptr_factory_.GetWeakPtr()));
215 EXPECT_EQ(DataTypeController::ASSOCIATION_FAILED, last_start_result_);
216 EXPECT_TRUE(last_start_error_.IsSet());
217 EXPECT_EQ(DataTypeController::DISABLED, autofill_dtc_->state());
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()));
229 EXPECT_EQ(DataTypeController::OK, last_start_result_);
230 EXPECT_FALSE(last_start_error_.IsSet());
231 EXPECT_EQ(DataTypeController::MODEL_STARTING, autofill_dtc_->state());
233 FakeWebDataService* web_db =
234 static_cast<FakeWebDataService*>(
235 WebDataServiceFactory::GetAutofillWebDataForProfile(
236 &profile_, Profile::EXPLICIT_ACCESS).get());
237 web_db->LoadDatabase();
239 autofill_dtc_->StartAssociating(
240 base::Bind(&SyncAutofillDataTypeControllerTest::OnStartFinished,
241 weak_ptr_factory_.GetWeakPtr()));
244 EXPECT_EQ(DataTypeController::ASSOCIATION_FAILED, last_start_result_);
245 EXPECT_TRUE(last_start_error_.IsSet());
247 EXPECT_EQ(DataTypeController::DISABLED, autofill_dtc_->state());
252 } // namespace browser_sync