blob: 68e8dd0d259d5f684cc7539a722f9b0125ff9694 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <memory>
#include <string>
#include <vector>
#include "base/bind.h"
#include "base/files/scoped_temp_dir.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string16.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h"
#include "base/test/scoped_task_environment.h"
#include "base/threading/thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "components/autofill/core/browser/autofill_country.h"
#include "components/autofill/core/browser/autofill_profile.h"
#include "components/autofill/core/browser/credit_card.h"
#include "components/autofill/core/browser/webdata/autofill_change.h"
#include "components/autofill/core/browser/webdata/autofill_entry.h"
#include "components/autofill/core/browser/webdata/autofill_table.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service_observer.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/webdata/common/web_data_results.h"
#include "components/webdata/common/web_data_service_base.h"
#include "components/webdata/common/web_data_service_consumer.h"
#include "components/webdata/common/web_database_service.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::ASCIIToUTF16;
using base::Time;
using base::TimeDelta;
using base::WaitableEvent;
using testing::_;
using testing::DoDefault;
using testing::ElementsAreArray;
namespace {
template <class T>
class AutofillWebDataServiceConsumer: public WebDataServiceConsumer {
public:
AutofillWebDataServiceConsumer() : handle_(0) {}
virtual ~AutofillWebDataServiceConsumer() {}
virtual void OnWebDataServiceRequestDone(
WebDataServiceBase::Handle handle,
std::unique_ptr<WDTypedResult> result) {
handle_ = handle;
result_ = std::move(static_cast<WDResult<T>*>(result.get())->GetValue());
base::MessageLoop::current()->QuitWhenIdle();
}
WebDataServiceBase::Handle handle() { return handle_; }
T& result() { return result_; }
private:
WebDataServiceBase::Handle handle_;
T result_;
DISALLOW_COPY_AND_ASSIGN(AutofillWebDataServiceConsumer);
};
const int kWebDataServiceTimeoutSeconds = 8;
} // namespace
namespace autofill {
ACTION_P(SignalEvent, event) {
event->Signal();
}
class MockAutofillWebDataServiceObserver
: public AutofillWebDataServiceObserverOnDBThread {
public:
MOCK_METHOD1(AutofillEntriesChanged,
void(const AutofillChangeList& changes));
MOCK_METHOD1(AutofillProfileChanged,
void(const AutofillProfileChange& change));
};
class WebDataServiceTest : public testing::Test {
public:
WebDataServiceTest()
: scoped_task_environment_(
base::test::ScopedTaskEnvironment::MainThreadType::UI),
db_thread_("DBThread") {}
protected:
void SetUp() override {
db_thread_.Start();
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
base::FilePath path = temp_dir_.GetPath().AppendASCII("TestWebDB");
wdbs_ = new WebDatabaseService(path, base::ThreadTaskRunnerHandle::Get(),
db_thread_.task_runner());
wdbs_->AddTable(base::WrapUnique(new AutofillTable));
wdbs_->LoadDatabase();
wds_ = new AutofillWebDataService(
wdbs_, base::ThreadTaskRunnerHandle::Get(), db_thread_.task_runner(),
WebDataServiceBase::ProfileErrorCallback());
wds_->Init();
}
void TearDown() override {
wds_->ShutdownOnUIThread();
wdbs_->ShutdownDatabase();
wds_ = NULL;
wdbs_ = NULL;
WaitForDatabaseThread();
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
base::RunLoop().Run();
db_thread_.Stop();
}
void WaitForDatabaseThread() {
base::WaitableEvent done(base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED);
db_thread_.task_runner()->PostTask(
FROM_HERE,
base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done)));
done.Wait();
}
base::test::ScopedTaskEnvironment scoped_task_environment_;
base::Thread db_thread_;
base::FilePath profile_dir_;
scoped_refptr<AutofillWebDataService> wds_;
scoped_refptr<WebDatabaseService> wdbs_;
base::ScopedTempDir temp_dir_;
};
class WebDataServiceAutofillTest : public WebDataServiceTest {
public:
WebDataServiceAutofillTest()
: WebDataServiceTest(),
unique_id1_(1),
unique_id2_(2),
test_timeout_(TimeDelta::FromSeconds(kWebDataServiceTimeoutSeconds)),
done_event_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED) {}
protected:
virtual void SetUp() {
WebDataServiceTest::SetUp();
name1_ = ASCIIToUTF16("name1");
name2_ = ASCIIToUTF16("name2");
value1_ = ASCIIToUTF16("value1");
value2_ = ASCIIToUTF16("value2");
void(AutofillWebDataService::*add_observer_func)(
AutofillWebDataServiceObserverOnDBThread*) =
&AutofillWebDataService::AddObserver;
db_thread_.task_runner()->PostTask(
FROM_HERE, base::Bind(add_observer_func, wds_, &observer_));
WaitForDatabaseThread();
}
virtual void TearDown() {
void(AutofillWebDataService::*remove_observer_func)(
AutofillWebDataServiceObserverOnDBThread*) =
&AutofillWebDataService::RemoveObserver;
db_thread_.task_runner()->PostTask(
FROM_HERE, base::Bind(remove_observer_func, wds_, &observer_));
WaitForDatabaseThread();
WebDataServiceTest::TearDown();
}
void AppendFormField(const base::string16& name,
const base::string16& value,
std::vector<FormFieldData>* form_fields) {
FormFieldData field;
field.name = name;
field.value = value;
form_fields->push_back(field);
}
base::string16 name1_;
base::string16 name2_;
base::string16 value1_;
base::string16 value2_;
int unique_id1_, unique_id2_;
const TimeDelta test_timeout_;
testing::NiceMock<MockAutofillWebDataServiceObserver> observer_;
WaitableEvent done_event_;
};
TEST_F(WebDataServiceAutofillTest, FormFillAdd) {
const AutofillChange expected_changes[] = {
AutofillChange(AutofillChange::ADD, AutofillKey(name1_, value1_)),
AutofillChange(AutofillChange::ADD, AutofillKey(name2_, value2_))
};
// This will verify that the correct notification is triggered,
// passing the correct list of autofill keys in the details.
EXPECT_CALL(observer_,
AutofillEntriesChanged(ElementsAreArray(expected_changes)))
.WillOnce(SignalEvent(&done_event_));
std::vector<FormFieldData> form_fields;
AppendFormField(name1_, value1_, &form_fields);
AppendFormField(name2_, value2_, &form_fields);
wds_->AddFormFields(form_fields);
// The event will be signaled when the mock observer is notified.
done_event_.TimedWait(test_timeout_);
AutofillWebDataServiceConsumer<std::vector<base::string16>> consumer;
WebDataServiceBase::Handle handle;
static const int limit = 10;
handle = wds_->GetFormValuesForElementName(
name1_, base::string16(), limit, &consumer);
// The message loop will exit when the consumer is called.
base::RunLoop().Run();
EXPECT_EQ(handle, consumer.handle());
ASSERT_EQ(1U, consumer.result().size());
EXPECT_EQ(value1_, consumer.result()[0]);
}
TEST_F(WebDataServiceAutofillTest, FormFillRemoveOne) {
// First add some values to autofill.
EXPECT_CALL(observer_, AutofillEntriesChanged(_))
.WillOnce(SignalEvent(&done_event_));
std::vector<FormFieldData> form_fields;
AppendFormField(name1_, value1_, &form_fields);
wds_->AddFormFields(form_fields);
// The event will be signaled when the mock observer is notified.
done_event_.TimedWait(test_timeout_);
// This will verify that the correct notification is triggered,
// passing the correct list of autofill keys in the details.
const AutofillChange expected_changes[] = {
AutofillChange(AutofillChange::REMOVE, AutofillKey(name1_, value1_))
};
EXPECT_CALL(observer_,
AutofillEntriesChanged(ElementsAreArray(expected_changes)))
.WillOnce(SignalEvent(&done_event_));
wds_->RemoveFormValueForElementName(name1_, value1_);
// The event will be signaled when the mock observer is notified.
done_event_.TimedWait(test_timeout_);
}
TEST_F(WebDataServiceAutofillTest, FormFillRemoveMany) {
TimeDelta one_day(TimeDelta::FromDays(1));
Time t = Time::Now();
EXPECT_CALL(observer_, AutofillEntriesChanged(_))
.WillOnce(SignalEvent(&done_event_));
std::vector<FormFieldData> form_fields;
AppendFormField(name1_, value1_, &form_fields);
AppendFormField(name2_, value2_, &form_fields);
wds_->AddFormFields(form_fields);
// The event will be signaled when the mock observer is notified.
done_event_.TimedWait(test_timeout_);
// This will verify that the correct notification is triggered,
// passing the correct list of autofill keys in the details.
const AutofillChange expected_changes[] = {
AutofillChange(AutofillChange::REMOVE, AutofillKey(name1_, value1_)),
AutofillChange(AutofillChange::REMOVE, AutofillKey(name2_, value2_))
};
EXPECT_CALL(observer_,
AutofillEntriesChanged(ElementsAreArray(expected_changes)))
.WillOnce(SignalEvent(&done_event_));
wds_->RemoveFormElementsAddedBetween(t, t + one_day);
// The event will be signaled when the mock observer is notified.
done_event_.TimedWait(test_timeout_);
}
TEST_F(WebDataServiceAutofillTest, ProfileAdd) {
AutofillProfile profile;
// Check that GUID-based notification was sent.
const AutofillProfileChange expected_change(
AutofillProfileChange::ADD, profile.guid(), &profile);
EXPECT_CALL(observer_, AutofillProfileChanged(expected_change))
.WillOnce(SignalEvent(&done_event_));
wds_->AddAutofillProfile(profile);
done_event_.TimedWait(test_timeout_);
// Check that it was added.
AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<AutofillProfile>>>
consumer;
WebDataServiceBase::Handle handle = wds_->GetAutofillProfiles(&consumer);
base::RunLoop().Run();
EXPECT_EQ(handle, consumer.handle());
ASSERT_EQ(1U, consumer.result().size());
EXPECT_EQ(profile, *consumer.result()[0]);
}
TEST_F(WebDataServiceAutofillTest, ProfileRemove) {
AutofillProfile profile;
// Add a profile.
EXPECT_CALL(observer_, AutofillProfileChanged(_))
.WillOnce(SignalEvent(&done_event_));
wds_->AddAutofillProfile(profile);
done_event_.TimedWait(test_timeout_);
// Check that it was added.
AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<AutofillProfile>>>
consumer;
WebDataServiceBase::Handle handle = wds_->GetAutofillProfiles(&consumer);
base::RunLoop().Run();
EXPECT_EQ(handle, consumer.handle());
ASSERT_EQ(1U, consumer.result().size());
EXPECT_EQ(profile, *consumer.result()[0]);
// Check that GUID-based notification was sent.
const AutofillProfileChange expected_change(
AutofillProfileChange::REMOVE, profile.guid(), NULL);
EXPECT_CALL(observer_, AutofillProfileChanged(expected_change))
.WillOnce(SignalEvent(&done_event_));
// Remove the profile.
wds_->RemoveAutofillProfile(profile.guid());
done_event_.TimedWait(test_timeout_);
// Check that it was removed.
AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<AutofillProfile>>>
consumer2;
WebDataServiceBase::Handle handle2 = wds_->GetAutofillProfiles(&consumer2);
base::RunLoop().Run();
EXPECT_EQ(handle2, consumer2.handle());
ASSERT_EQ(0U, consumer2.result().size());
}
TEST_F(WebDataServiceAutofillTest, ProfileUpdate) {
// The GUIDs are alphabetical for easier testing.
AutofillProfile profile1("6141084B-72D7-4B73-90CF-3D6AC154673B",
"http://example.com");
profile1.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Abe"));
AutofillProfile profile2("087151C8-6AB1-487C-9095-28E80BE5DA15",
"http://example.com");
profile2.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Alice"));
EXPECT_CALL(observer_, AutofillProfileChanged(_))
.WillOnce(DoDefault())
.WillOnce(SignalEvent(&done_event_));
wds_->AddAutofillProfile(profile1);
wds_->AddAutofillProfile(profile2);
done_event_.TimedWait(test_timeout_);
// Check that they were added.
AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<AutofillProfile>>>
consumer;
WebDataServiceBase::Handle handle = wds_->GetAutofillProfiles(&consumer);
base::RunLoop().Run();
EXPECT_EQ(handle, consumer.handle());
ASSERT_EQ(2U, consumer.result().size());
EXPECT_EQ(profile2, *consumer.result()[0]);
EXPECT_EQ(profile1, *consumer.result()[1]);
AutofillProfile profile2_changed(profile2);
profile2_changed.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Bill"));
const AutofillProfileChange expected_change(
AutofillProfileChange::UPDATE, profile2.guid(), &profile2_changed);
EXPECT_CALL(observer_, AutofillProfileChanged(expected_change))
.WillOnce(SignalEvent(&done_event_));
// Update the profile.
wds_->UpdateAutofillProfile(profile2_changed);
done_event_.TimedWait(test_timeout_);
// Check that the updates were made.
AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<AutofillProfile>>>
consumer2;
WebDataServiceBase::Handle handle2 = wds_->GetAutofillProfiles(&consumer2);
base::RunLoop().Run();
EXPECT_EQ(handle2, consumer2.handle());
ASSERT_EQ(2U, consumer2.result().size());
EXPECT_EQ(profile2_changed, *consumer2.result()[0]);
EXPECT_NE(profile2, *consumer2.result()[0]);
EXPECT_EQ(profile1, *consumer2.result()[1]);
}
TEST_F(WebDataServiceAutofillTest, CreditAdd) {
CreditCard card;
wds_->AddCreditCard(card);
WaitForDatabaseThread();
// Check that it was added.
AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<CreditCard>>>
consumer;
WebDataServiceBase::Handle handle = wds_->GetCreditCards(&consumer);
base::RunLoop().Run();
EXPECT_EQ(handle, consumer.handle());
ASSERT_EQ(1U, consumer.result().size());
EXPECT_EQ(card, *consumer.result()[0]);
}
TEST_F(WebDataServiceAutofillTest, CreditCardRemove) {
CreditCard credit_card;
// Add a credit card.
wds_->AddCreditCard(credit_card);
WaitForDatabaseThread();
// Check that it was added.
AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<CreditCard>>>
consumer;
WebDataServiceBase::Handle handle = wds_->GetCreditCards(&consumer);
base::RunLoop().Run();
EXPECT_EQ(handle, consumer.handle());
ASSERT_EQ(1U, consumer.result().size());
EXPECT_EQ(credit_card, *consumer.result()[0]);
// Remove the credit card.
wds_->RemoveCreditCard(credit_card.guid());
WaitForDatabaseThread();
// Check that it was removed.
AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<CreditCard>>>
consumer2;
WebDataServiceBase::Handle handle2 = wds_->GetCreditCards(&consumer2);
base::RunLoop().Run();
EXPECT_EQ(handle2, consumer2.handle());
ASSERT_EQ(0U, consumer2.result().size());
}
TEST_F(WebDataServiceAutofillTest, CreditUpdate) {
CreditCard card1("E4D2662E-5E16-44F3-AF5A-5A77FAE4A6F3",
"https://ejemplo.mx");
card1.SetRawInfo(CREDIT_CARD_NAME_FULL, ASCIIToUTF16("Abe"));
CreditCard card2("B9C52112-BD5F-4080-84E1-C651D2CB90E2",
"https://example.com");
card2.SetRawInfo(CREDIT_CARD_NAME_FULL, ASCIIToUTF16("Alice"));
wds_->AddCreditCard(card1);
wds_->AddCreditCard(card2);
WaitForDatabaseThread();
// Check that they got added.
AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<CreditCard>>>
consumer;
WebDataServiceBase::Handle handle = wds_->GetCreditCards(&consumer);
base::RunLoop().Run();
EXPECT_EQ(handle, consumer.handle());
ASSERT_EQ(2U, consumer.result().size());
EXPECT_EQ(card2, *consumer.result()[0]);
EXPECT_EQ(card1, *consumer.result()[1]);
CreditCard card2_changed(card2);
card2_changed.SetRawInfo(CREDIT_CARD_NAME_FULL, ASCIIToUTF16("Bill"));
wds_->UpdateCreditCard(card2_changed);
WaitForDatabaseThread();
// Check that the updates were made.
AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<CreditCard>>>
consumer2;
WebDataServiceBase::Handle handle2 = wds_->GetCreditCards(&consumer2);
base::RunLoop().Run();
EXPECT_EQ(handle2, consumer2.handle());
ASSERT_EQ(2U, consumer2.result().size());
EXPECT_NE(card2, *consumer2.result()[0]);
EXPECT_EQ(card2_changed, *consumer2.result()[0]);
EXPECT_EQ(card1, *consumer2.result()[1]);
}
TEST_F(WebDataServiceAutofillTest, AutofillRemoveModifiedBetween) {
// Add a profile.
EXPECT_CALL(observer_, AutofillProfileChanged(_))
.WillOnce(SignalEvent(&done_event_));
AutofillProfile profile;
wds_->AddAutofillProfile(profile);
done_event_.TimedWait(test_timeout_);
// Check that it was added.
AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<AutofillProfile>>>
profile_consumer;
WebDataServiceBase::Handle handle =
wds_->GetAutofillProfiles(&profile_consumer);
base::RunLoop().Run();
EXPECT_EQ(handle, profile_consumer.handle());
ASSERT_EQ(1U, profile_consumer.result().size());
EXPECT_EQ(profile, *profile_consumer.result()[0]);
// Add a credit card.
CreditCard credit_card;
wds_->AddCreditCard(credit_card);
WaitForDatabaseThread();
// Check that it was added.
AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<CreditCard>>>
card_consumer;
handle = wds_->GetCreditCards(&card_consumer);
base::RunLoop().Run();
EXPECT_EQ(handle, card_consumer.handle());
ASSERT_EQ(1U, card_consumer.result().size());
EXPECT_EQ(credit_card, *card_consumer.result()[0]);
// Check that GUID-based notification was sent for the profile.
const AutofillProfileChange expected_profile_change(
AutofillProfileChange::REMOVE, profile.guid(), NULL);
EXPECT_CALL(observer_, AutofillProfileChanged(expected_profile_change))
.WillOnce(SignalEvent(&done_event_));
// Remove the profile using time range of "all time".
wds_->RemoveAutofillDataModifiedBetween(Time(), Time());
done_event_.TimedWait(test_timeout_);
WaitForDatabaseThread();
// Check that the profile was removed.
AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<AutofillProfile>>>
profile_consumer2;
WebDataServiceBase::Handle handle2 =
wds_->GetAutofillProfiles(&profile_consumer2);
base::RunLoop().Run();
EXPECT_EQ(handle2, profile_consumer2.handle());
ASSERT_EQ(0U, profile_consumer2.result().size());
// Check that the credit card was removed.
AutofillWebDataServiceConsumer<std::vector<std::unique_ptr<CreditCard>>>
card_consumer2;
handle2 = wds_->GetCreditCards(&card_consumer2);
base::RunLoop().Run();
EXPECT_EQ(handle2, card_consumer2.handle());
ASSERT_EQ(0U, card_consumer2.result().size());
}
} // namespace autofill