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/glue/shared_change_processor_mock.h"
14 #include "chrome/browser/sync/profile_sync_components_factory_mock.h"
15 #include "chrome/browser/sync/profile_sync_service_factory.h"
16 #include "chrome/browser/sync/profile_sync_service_mock.h"
17 #include "chrome/browser/webdata/autocomplete_syncable_service.h"
18 #include "chrome/browser/webdata/web_data_service_factory.h"
19 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
20 #include "components/sync_driver/data_type_controller_mock.h"
21 #include "components/webdata/common/web_data_service_test_util.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/notification_service.h"
24 #include "content/public/browser/notification_source.h"
25 #include "content/public/browser/notification_types.h"
26 #include "content/public/test/test_browser_thread_bundle.h"
27 #include "sync/api/sync_error.h"
28 #include "testing/gmock/include/gmock/gmock.h"
29 #include "testing/gtest/include/gtest/gtest.h"
31 using autofill::AutofillWebDataService;
32 using autofill::AutofillWebDataBackend;
34 namespace browser_sync {
38 using content::BrowserThread;
40 using testing::NiceMock;
41 using testing::Return;
43 class NoOpAutofillBackend : public AutofillWebDataBackend {
45 NoOpAutofillBackend() {}
46 virtual ~NoOpAutofillBackend() {}
47 virtual WebDatabase* GetDatabase() OVERRIDE { return NULL; }
48 virtual void AddObserver(
49 autofill::AutofillWebDataServiceObserverOnDBThread* observer) OVERRIDE {}
50 virtual void RemoveObserver(
51 autofill::AutofillWebDataServiceObserverOnDBThread* observer) OVERRIDE {}
52 virtual void RemoveExpiredFormElements() OVERRIDE {}
53 virtual void NotifyOfMultipleAutofillChanges() OVERRIDE {}
56 // Fake WebDataService implementation that stubs out the database loading.
57 class FakeWebDataService : public AutofillWebDataService {
60 : AutofillWebDataService(
61 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
62 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB)),
63 is_database_loaded_(false),
64 db_loaded_callback_(base::Callback<void(void)>()){}
66 // Mark the database as loaded and send out the appropriate notification.
68 StartSyncableService();
69 is_database_loaded_ = true;
71 if (!db_loaded_callback_.is_null())
72 db_loaded_callback_.Run();
75 virtual bool IsDatabaseLoaded() OVERRIDE {
76 return is_database_loaded_;
79 virtual void RegisterDBLoadedCallback(
80 const base::Callback<void(void)>& callback) OVERRIDE {
81 db_loaded_callback_ = callback;
84 void StartSyncableService() {
85 // The |autofill_profile_syncable_service_| must be constructed on the DB
87 base::RunLoop run_loop;
88 BrowserThread::PostTaskAndReply(BrowserThread::DB, FROM_HERE,
89 base::Bind(&FakeWebDataService::CreateSyncableService,
90 base::Unretained(this)), run_loop.QuitClosure());
95 virtual ~FakeWebDataService() {
98 void CreateSyncableService() {
99 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::DB));
100 // These services are deleted in DestroySyncableService().
101 AutocompleteSyncableService::CreateForWebDataServiceAndBackend(
106 bool is_database_loaded_;
107 NoOpAutofillBackend autofill_backend_;
108 base::Callback<void(void)> db_loaded_callback_;
110 DISALLOW_COPY_AND_ASSIGN(FakeWebDataService);
113 class MockWebDataServiceWrapperSyncable : public MockWebDataServiceWrapper {
115 static BrowserContextKeyedService* Build(content::BrowserContext* profile) {
116 return new MockWebDataServiceWrapperSyncable();
119 MockWebDataServiceWrapperSyncable()
120 : MockWebDataServiceWrapper(NULL, new FakeWebDataService(), NULL) {
123 virtual void Shutdown() OVERRIDE {
124 static_cast<FakeWebDataService*>(
125 fake_autofill_web_data_.get())->ShutdownOnUIThread();
126 // Make sure WebDataService is shutdown properly on DB thread before we
128 base::RunLoop run_loop;
129 ASSERT_TRUE(BrowserThread::PostTaskAndReply(BrowserThread::DB, FROM_HERE,
130 base::Bind(&base::DoNothing), run_loop.QuitClosure()));
135 DISALLOW_COPY_AND_ASSIGN(MockWebDataServiceWrapperSyncable);
138 class SyncAutofillDataTypeControllerTest : public testing::Test {
140 SyncAutofillDataTypeControllerTest()
141 : thread_bundle_(content::TestBrowserThreadBundle::REAL_DB_THREAD),
143 last_start_result_(DataTypeController::OK),
144 weak_ptr_factory_(this) {}
146 virtual ~SyncAutofillDataTypeControllerTest() {}
148 virtual void SetUp() {
149 change_processor_ = new NiceMock<SharedChangeProcessorMock>();
151 EXPECT_CALL(profile_sync_factory_,
152 CreateSharedChangeProcessor()).
153 WillRepeatedly(Return(change_processor_.get()));
155 WebDataServiceFactory::GetInstance()->SetTestingFactory(
156 &profile_, MockWebDataServiceWrapperSyncable::Build);
159 new AutofillDataTypeController(&profile_sync_factory_,
164 // Passed to AutofillDTC::Start().
165 void OnStartFinished(DataTypeController::StartResult result,
166 const syncer::SyncMergeResult& local_merge_result,
167 const syncer::SyncMergeResult& syncer_merge_result) {
168 last_start_result_ = result;
169 last_start_error_ = local_merge_result.error();
172 void OnLoadFinished(syncer::ModelType type, syncer::SyncError error) {
173 EXPECT_FALSE(error.IsSet());
174 EXPECT_EQ(type, syncer::AUTOFILL);
177 virtual void TearDown() {
178 autofill_dtc_ = NULL;
179 change_processor_ = NULL;
182 void BlockForDBThread() {
183 base::RunLoop run_loop;
184 ASSERT_TRUE(BrowserThread::PostTaskAndReply(BrowserThread::DB, FROM_HERE,
185 base::Bind(&base::DoNothing), run_loop.QuitClosure()));
190 content::TestBrowserThreadBundle thread_bundle_;
192 scoped_refptr<NiceMock<SharedChangeProcessorMock> > change_processor_;
193 ProfileSyncComponentsFactoryMock profile_sync_factory_;
194 TestingProfile profile_;
195 ProfileSyncServiceMock service_;
196 scoped_refptr<AutofillDataTypeController> autofill_dtc_;
198 // Stores arguments of most recent call of OnStartFinished().
199 DataTypeController::StartResult last_start_result_;
200 syncer::SyncError last_start_error_;
201 base::WeakPtrFactory<SyncAutofillDataTypeControllerTest> weak_ptr_factory_;
204 // Load the WDS's database, then start the Autofill DTC. It should
205 // immediately try to start association and fail (due to missing DB
207 TEST_F(SyncAutofillDataTypeControllerTest, StartWDSReady) {
208 FakeWebDataService* web_db =
209 static_cast<FakeWebDataService*>(
210 WebDataServiceFactory::GetAutofillWebDataForProfile(
211 &profile_, Profile::EXPLICIT_ACCESS).get());
212 web_db->LoadDatabase();
213 autofill_dtc_->LoadModels(
214 base::Bind(&SyncAutofillDataTypeControllerTest::OnLoadFinished,
215 weak_ptr_factory_.GetWeakPtr()));
217 EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _))
218 .WillOnce(Return(base::WeakPtr<syncer::SyncableService>()));
219 autofill_dtc_->StartAssociating(
220 base::Bind(&SyncAutofillDataTypeControllerTest::OnStartFinished,
221 weak_ptr_factory_.GetWeakPtr()));
224 EXPECT_EQ(DataTypeController::ASSOCIATION_FAILED, last_start_result_);
225 EXPECT_TRUE(last_start_error_.IsSet());
226 EXPECT_EQ(DataTypeController::DISABLED, autofill_dtc_->state());
229 // Start the autofill DTC without the WDS's database loaded, then
230 // start the DB. The Autofill DTC should be in the MODEL_STARTING
231 // state until the database in loaded, when it should try to start
232 // association and fail (due to missing DB thread).
233 TEST_F(SyncAutofillDataTypeControllerTest, StartWDSNotReady) {
234 autofill_dtc_->LoadModels(
235 base::Bind(&SyncAutofillDataTypeControllerTest::OnLoadFinished,
236 weak_ptr_factory_.GetWeakPtr()));
238 EXPECT_EQ(DataTypeController::OK, last_start_result_);
239 EXPECT_FALSE(last_start_error_.IsSet());
240 EXPECT_EQ(DataTypeController::MODEL_STARTING, autofill_dtc_->state());
242 FakeWebDataService* web_db =
243 static_cast<FakeWebDataService*>(
244 WebDataServiceFactory::GetAutofillWebDataForProfile(
245 &profile_, Profile::EXPLICIT_ACCESS).get());
246 web_db->LoadDatabase();
248 EXPECT_CALL(*change_processor_.get(), Connect(_, _, _, _, _))
249 .WillOnce(Return(base::WeakPtr<syncer::SyncableService>()));
250 autofill_dtc_->StartAssociating(
251 base::Bind(&SyncAutofillDataTypeControllerTest::OnStartFinished,
252 weak_ptr_factory_.GetWeakPtr()));
255 EXPECT_EQ(DataTypeController::ASSOCIATION_FAILED, last_start_result_);
256 EXPECT_TRUE(last_start_error_.IsSet());
258 EXPECT_EQ(DataTypeController::DISABLED, autofill_dtc_->state());
263 } // namespace browser_sync