diff options
author | zork@google.com <zork@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-01 22:06:21 +0000 |
---|---|---|
committer | zork@google.com <zork@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-01 22:06:21 +0000 |
commit | 8b3b23abcf91b7573c6fcf230240395118c04580 (patch) | |
tree | 3c4dc9c354662a6d9ecff8443f4620fa017c7718 /chrome/browser/webdata | |
parent | 3950400350f7f8494f09a3568acb6d40592701f5 (diff) | |
download | chromium_src-8b3b23abcf91b7573c6fcf230240395118c04580.zip chromium_src-8b3b23abcf91b7573c6fcf230240395118c04580.tar.gz chromium_src-8b3b23abcf91b7573c6fcf230240395118c04580.tar.bz2 |
Add autofill Change Processor and Model Associator
BUG=29926
TEST=none
Review URL: http://codereview.chromium.org/628003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@40304 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/webdata')
-rw-r--r-- | chrome/browser/webdata/autofill_entry.cc | 15 | ||||
-rw-r--r-- | chrome/browser/webdata/autofill_entry.h | 3 | ||||
-rw-r--r-- | chrome/browser/webdata/web_data_service.cc | 49 | ||||
-rw-r--r-- | chrome/browser/webdata/web_data_service.h | 3 | ||||
-rw-r--r-- | chrome/browser/webdata/web_data_service_unittest.cc | 147 | ||||
-rw-r--r-- | chrome/browser/webdata/web_database.cc | 29 | ||||
-rw-r--r-- | chrome/browser/webdata/web_database.h | 9 | ||||
-rw-r--r-- | chrome/browser/webdata/web_database_unittest.cc | 18 |
8 files changed, 212 insertions, 61 deletions
diff --git a/chrome/browser/webdata/autofill_entry.cc b/chrome/browser/webdata/autofill_entry.cc index 08f7557..d0f8913 100644 --- a/chrome/browser/webdata/autofill_entry.cc +++ b/chrome/browser/webdata/autofill_entry.cc @@ -9,6 +9,17 @@ bool AutofillKey::operator==(const AutofillKey& key) const { return name_ == key.name() && value_ == key.value(); } +bool AutofillKey::operator<(const AutofillKey& key) const { + int diff = name_.compare(key.name()); + if (diff < 0) { + return true; + } else if (diff == 0) { + return value_.compare(key.value()) < 0; + } else { + return false; + } +} + bool AutofillEntry::operator==(const AutofillEntry& entry) const { if (!(key_ == entry.key())) return false; @@ -25,3 +36,7 @@ bool AutofillEntry::operator==(const AutofillEntry& entry) const { return true; } + +bool AutofillEntry::operator<(const AutofillEntry& entry) const { + return key_ < entry.key(); +} diff --git a/chrome/browser/webdata/autofill_entry.h b/chrome/browser/webdata/autofill_entry.h index 850f93b..d67a090 100644 --- a/chrome/browser/webdata/autofill_entry.h +++ b/chrome/browser/webdata/autofill_entry.h @@ -11,6 +11,7 @@ class AutofillKey { public: + AutofillKey() {} AutofillKey(const string16& name, const string16& value) : name_(name), value_(value) {} @@ -23,6 +24,7 @@ class AutofillKey { const string16& value() const { return value_; } bool operator==(const AutofillKey& key) const; + bool operator<(const AutofillKey& key) const; private: string16 name_; @@ -40,6 +42,7 @@ class AutofillEntry { const std::vector<base::Time>& timestamps() const { return timestamps_; } bool operator==(const AutofillEntry& entry) const; + bool operator<(const AutofillEntry& entry) const; private: AutofillKey key_; diff --git a/chrome/browser/webdata/web_data_service.cc b/chrome/browser/webdata/web_data_service.cc index 197b859..68c330c 100644 --- a/chrome/browser/webdata/web_data_service.cc +++ b/chrome/browser/webdata/web_data_service.cc @@ -225,6 +225,15 @@ WebDataService::Handle WebDataService::GetCreditCards( return request->GetHandle(); } +bool WebDataService::IsDatabaseLoaded() { + return db_ != NULL; +} + +WebDatabase* WebDataService::GetDatabase() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB)); + return db_; +} + void WebDataService::RequestCompleted(Handle h) { pending_lock_.Acquire(); RequestMap::iterator i = pending_requests_.find(h); @@ -245,20 +254,6 @@ void WebDataService::RequestCompleted(Handle h) { consumer->OnWebDataServiceRequestDone(request->GetHandle(), request->GetResult()); } - - // If this is an autofill change request, post the notifications - // including the list of affected keys. - const WDTypedResult* result = request->GetResult(); - if (!request->IsCancelled() && result) { - if (result->GetType() == AUTOFILL_CHANGES) { - AutofillChangeList changes = - static_cast<const WDResult<AutofillChangeList>*>(result)->GetValue(); - NotificationService::current()->Notify( - NotificationType::AUTOFILL_ENTRIES_CHANGED, - NotificationService::AllSources(), - Details<AutofillChangeList>(&changes)); - } - } } ////////////////////////////////////////////////////////////////////////////// @@ -708,7 +703,16 @@ void WebDataService::AddFormFieldValuesImpl( request->SetResult( new WDResult<AutofillChangeList>(AUTOFILL_CHANGES, changes)); ScheduleCommit(); + + // Post the notifications including the list of affected keys. + // This is sent here so that work resulting from this notification will be + // done on the DB thread, and not the UI thread. + NotificationService::current()->Notify( + NotificationType::AUTOFILL_ENTRIES_CHANGED, + NotificationService::AllSources(), + Details<AutofillChangeList>(&changes)); } + request->RequestComplete(); } @@ -719,8 +723,7 @@ void WebDataService::GetFormValuesForElementNameImpl(WebDataRequest* request, std::vector<string16> values; db_->GetFormValuesForElementName(name, prefix, &values, limit); request->SetResult( - new WDResult<std::vector<string16> >(AUTOFILL_VALUE_RESULT, - values)); + new WDResult<std::vector<string16> >(AUTOFILL_VALUE_RESULT, values)); } request->RequestComplete(); } @@ -736,6 +739,14 @@ void WebDataService::RemoveFormElementsAddedBetweenImpl( if (changes.size() > 0) { request->SetResult( new WDResult<AutofillChangeList>(AUTOFILL_CHANGES, changes)); + + // Post the notifications including the list of affected keys. + // This is sent here so that work resulting from this notification + // will be done on the DB thread, and not the UI thread. + NotificationService::current()->Notify( + NotificationType::AUTOFILL_ENTRIES_CHANGED, + NotificationService::AllSources(), + Details<AutofillChangeList>(&changes)); } ScheduleCommit(); } @@ -757,6 +768,12 @@ void WebDataService::RemoveFormValueForElementNameImpl( request->SetResult( new WDResult<AutofillChangeList>(AUTOFILL_CHANGES, changes)); ScheduleCommit(); + + // Post the notifications including the list of affected keys. + NotificationService::current()->Notify( + NotificationType::AUTOFILL_ENTRIES_CHANGED, + NotificationService::AllSources(), + Details<AutofillChangeList>(&changes)); } } request->RequestComplete(); diff --git a/chrome/browser/webdata/web_data_service.h b/chrome/browser/webdata/web_data_service.h index c81061d..c6887f4 100644 --- a/chrome/browser/webdata/web_data_service.h +++ b/chrome/browser/webdata/web_data_service.h @@ -448,6 +448,9 @@ class WebDataService void set_failed_init(bool value) { failed_init_ = value; } #endif + bool IsDatabaseLoaded(); + WebDatabase* GetDatabase(); + protected: friend class TemplateURLModelTest; friend class TemplateURLModelTestingProfile; diff --git a/chrome/browser/webdata/web_data_service_unittest.cc b/chrome/browser/webdata/web_data_service_unittest.cc index 34092b8..96f2b6e 100644 --- a/chrome/browser/webdata/web_data_service_unittest.cc +++ b/chrome/browser/webdata/web_data_service_unittest.cc @@ -8,10 +8,12 @@ #include "base/file_util.h" #include "base/message_loop.h" #include "base/path_service.h" +#include "base/ref_counted.h" #include "base/scoped_ptr.h" #include "base/string16.h" #include "base/string_util.h" #include "base/time.h" +#include "base/waitable_event.h" #include "chrome/browser/chrome_thread.h" #include "chrome/browser/webdata/autofill_change.h" #include "chrome/browser/webdata/autofill_entry.h" @@ -29,6 +31,7 @@ using base::Time; using base::TimeDelta; +using base::WaitableEvent; using testing::_; using testing::ElementsAreArray; using testing::Pointee; @@ -36,9 +39,8 @@ using testing::Property; typedef std::vector<AutofillChange> AutofillChangeList; -ACTION(QuitUIMessageLoop) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); - MessageLoop::current()->Quit(); +ACTION_P(SignalEvent, event) { + event->Signal(); } class AutofillWebDataServiceConsumer: public WebDataServiceConsumer { @@ -69,6 +71,49 @@ class AutofillWebDataServiceConsumer: public WebDataServiceConsumer { DISALLOW_COPY_AND_ASSIGN(AutofillWebDataServiceConsumer); }; +// This class will add and remove a mock notification observer from +// the DB thread. +class DBThreadObserverHelper : + public base::RefCountedThreadSafe<DBThreadObserverHelper, + ChromeThread::DeleteOnDBThread> { + public: + DBThreadObserverHelper() : done_event_(true, false) {} + + void Init() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + ChromeThread::PostTask( + ChromeThread::DB, + FROM_HERE, + NewRunnableMethod(this, &DBThreadObserverHelper::AddObserverTask)); + done_event_.Wait(); + } + + virtual ~DBThreadObserverHelper() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB)); + registrar_.Remove(&observer_, + NotificationType::AUTOFILL_ENTRIES_CHANGED, + NotificationService::AllSources()); + } + + NotificationObserverMock* observer() { + return &observer_; + } + + private: + friend class base::RefCountedThreadSafe<DBThreadObserverHelper>; + + void AddObserverTask() { + registrar_.Add(&observer_, + NotificationType::AUTOFILL_ENTRIES_CHANGED, + NotificationService::AllSources()); + done_event_.Signal(); + } + + WaitableEvent done_event_; + NotificationRegistrar registrar_; + NotificationObserverMock observer_; +}; + class WebDataServiceTest : public testing::Test { public: WebDataServiceTest() @@ -78,10 +123,6 @@ class WebDataServiceTest : public testing::Test { protected: virtual void SetUp() { db_thread_.Start(); - name1_ = ASCIIToUTF16("name1"); - name2_ = ASCIIToUTF16("name2"); - value1_ = ASCIIToUTF16("value1"); - value2_ = ASCIIToUTF16("value2"); PathService::Get(chrome::DIR_TEST_DATA, &profile_dir_); const std::string test_profile = "WebDataServiceTest"; @@ -102,6 +143,35 @@ class WebDataServiceTest : public testing::Test { MessageLoop::current()->Run(); } + MessageLoopForUI message_loop_; + ChromeThread ui_thread_; + ChromeThread db_thread_; + FilePath profile_dir_; + scoped_refptr<WebDataService> wds_; +}; + +class WebDataServiceAutofillTest : public WebDataServiceTest { + public: + WebDataServiceAutofillTest() + : WebDataServiceTest(), done_event_(true, false) {} + + protected: + virtual void SetUp() { + WebDataServiceTest::SetUp(); + name1_ = ASCIIToUTF16("name1"); + name2_ = ASCIIToUTF16("name2"); + value1_ = ASCIIToUTF16("value1"); + value2_ = ASCIIToUTF16("value2"); + observer_helper_ = new DBThreadObserverHelper(); + observer_helper_->Init(); + } + + virtual void TearDown() { + // Release this first so it can get destructed on the db thread. + observer_helper_ = NULL; + WebDataServiceTest::TearDown(); + } + void AppendFormField(const string16& name, const string16& value, std::vector<webkit_glue::FormField>* form_fields) { @@ -113,20 +183,15 @@ class WebDataServiceTest : public testing::Test { WebKit::WebInputElement::Text)); } - MessageLoopForUI message_loop_; - ChromeThread ui_thread_; - ChromeThread db_thread_; string16 name1_; string16 name2_; string16 value1_; string16 value2_; - FilePath profile_dir_; - scoped_refptr<WebDataService> wds_; - NotificationRegistrar registrar_; - NotificationObserverMock observer_; + scoped_refptr<DBThreadObserverHelper> observer_helper_; + WaitableEvent done_event_; }; -TEST_F(WebDataServiceTest, AutofillAdd) { +TEST_F(WebDataServiceAutofillTest, Add) { const AutofillChange expected_changes[] = { AutofillChange(AutofillChange::ADD, AutofillKey(name1_, value1_)), AutofillChange(AutofillChange::ADD, AutofillKey(name2_, value2_)) @@ -135,24 +200,20 @@ TEST_F(WebDataServiceTest, AutofillAdd) { // This will verify that the correct notification is triggered, // passing the correct list of autofill keys in the details. EXPECT_CALL( - observer_, + *observer_helper_->observer(), Observe(NotificationType(NotificationType::AUTOFILL_ENTRIES_CHANGED), NotificationService::AllSources(), Property(&Details<const AutofillChangeList>::ptr, Pointee(ElementsAreArray(expected_changes))))). - WillOnce(QuitUIMessageLoop()); - - registrar_.Add(&observer_, - NotificationType::AUTOFILL_ENTRIES_CHANGED, - NotificationService::AllSources()); + WillOnce(SignalEvent(&done_event_)); std::vector<webkit_glue::FormField> form_fields; AppendFormField(name1_, value1_, &form_fields); AppendFormField(name2_, value2_, &form_fields); wds_->AddFormFieldValues(form_fields); - // The message loop will exit when the mock observer is notified. - MessageLoop::current()->Run(); + // The event will be signaled when the mock observer is notified. + done_event_.Wait(); AutofillWebDataServiceConsumer consumer; WebDataService::Handle handle; @@ -168,18 +229,16 @@ TEST_F(WebDataServiceTest, AutofillAdd) { EXPECT_EQ(value1_, consumer.values()[0]); } -TEST_F(WebDataServiceTest, AutofillRemoveOne) { +TEST_F(WebDataServiceAutofillTest, RemoveOne) { // First add some values to autofill. - EXPECT_CALL(observer_, Observe(_, _, _)).WillOnce(QuitUIMessageLoop()); - registrar_.Add(&observer_, - NotificationType::AUTOFILL_ENTRIES_CHANGED, - NotificationService::AllSources()); + EXPECT_CALL(*observer_helper_->observer(), Observe(_, _, _)). + WillOnce(SignalEvent(&done_event_)); std::vector<webkit_glue::FormField> form_fields; AppendFormField(name1_, value1_, &form_fields); wds_->AddFormFieldValues(form_fields); - // The message loop will exit when the mock observer is notified. - MessageLoop::current()->Run(); + // The event will be signaled when the mock observer is notified. + done_event_.Wait(); // This will verify that the correct notification is triggered, // passing the correct list of autofill keys in the details. @@ -187,33 +246,31 @@ TEST_F(WebDataServiceTest, AutofillRemoveOne) { AutofillChange(AutofillChange::REMOVE, AutofillKey(name1_, value1_)) }; EXPECT_CALL( - observer_, + *observer_helper_->observer(), Observe(NotificationType(NotificationType::AUTOFILL_ENTRIES_CHANGED), NotificationService::AllSources(), Property(&Details<const AutofillChangeList>::ptr, Pointee(ElementsAreArray(expected_changes))))). - WillOnce(QuitUIMessageLoop()); + WillOnce(SignalEvent(&done_event_)); wds_->RemoveFormValueForElementName(name1_, value1_); - // The message loop will exit when the mock observer is notified. - MessageLoop::current()->Run(); + // The event will be signaled when the mock observer is notified. + done_event_.Wait(); } -TEST_F(WebDataServiceTest, AutofillRemoveMany) { +TEST_F(WebDataServiceAutofillTest,RemoveMany) { TimeDelta one_day(TimeDelta::FromDays(1)); Time t = Time::Now(); - EXPECT_CALL(observer_, Observe(_, _, _)).WillOnce(QuitUIMessageLoop()); - registrar_.Add(&observer_, - NotificationType::AUTOFILL_ENTRIES_CHANGED, - NotificationService::AllSources()); + EXPECT_CALL(*observer_helper_->observer(), Observe(_, _, _)). + WillOnce(SignalEvent(&done_event_)); std::vector<webkit_glue::FormField> form_fields; AppendFormField(name1_, value1_, &form_fields); AppendFormField(name2_, value2_, &form_fields); wds_->AddFormFieldValues(form_fields); - // The message loop will exit when the mock observer is notified. - MessageLoop::current()->Run(); + // The event will be signaled when the mock observer is notified. + done_event_.Wait(); // This will verify that the correct notification is triggered, // passing the correct list of autofill keys in the details. @@ -222,14 +279,14 @@ TEST_F(WebDataServiceTest, AutofillRemoveMany) { AutofillChange(AutofillChange::REMOVE, AutofillKey(name2_, value2_)) }; EXPECT_CALL( - observer_, + *observer_helper_->observer(), Observe(NotificationType(NotificationType::AUTOFILL_ENTRIES_CHANGED), NotificationService::AllSources(), Property(&Details<const AutofillChangeList>::ptr, Pointee(ElementsAreArray(expected_changes))))). - WillOnce(QuitUIMessageLoop()); + WillOnce(SignalEvent(&done_event_)); wds_->RemoveFormElementsAddedBetween(t, t + one_day); - // The message loop will exit when the mock observer is notified. - MessageLoop::current()->Run(); + // The event will be signaled when the mock observer is notified. + done_event_.Wait(); } diff --git a/chrome/browser/webdata/web_database.cc b/chrome/browser/webdata/web_database.cc index 7f8c3c7..d87ef0b 100644 --- a/chrome/browser/webdata/web_database.cc +++ b/chrome/browser/webdata/web_database.cc @@ -21,6 +21,7 @@ #include "chrome/browser/diagnostics/sqlite_diagnostics.h" #include "chrome/browser/history/history_database.h" #include "chrome/browser/webdata/autofill_change.h" +#include "chrome/common/notification_service.h" #include "webkit/glue/password_form.h" // Encryptor is the *wrong* way of doing things; we need to turn it into a @@ -180,6 +181,11 @@ void WebDatabase::CommitTransaction() { } sql::InitStatus WebDatabase::Init(const FilePath& db_name) { + // When running in unit tests, there is already a NotificationService object. + // Since only one can exist at a time per thread, check first. + if (!NotificationService::current()) + notification_service_.reset(new NotificationService); + // Set the exceptional sqlite error handler. db_.set_error_delegate(GetErrorHandlerForWebDb()); @@ -1041,6 +1047,29 @@ bool WebDatabase::GetAllAutofillEntries(std::vector<AutofillEntry>* entries) { return s.Succeeded(); } +bool WebDatabase::GetAutofillTimestamps(const string16& name, + const string16& value, + std::vector<base::Time>* timestamps) { + DCHECK(timestamps); + sql::Statement s(db_.GetUniqueStatement( + "SELECT date_created FROM autofill a JOIN " + "autofill_dates ad ON a.pair_id=ad.pair_id " + "WHERE a.name = ? AND a.value = ?")); + + if (!s) { + NOTREACHED() << "Statement prepare failed"; + return false; + } + + s.BindString(0, UTF16ToUTF8(name)); + s.BindString(1, UTF16ToUTF8(value)); + while (s.Step()) { + timestamps->push_back(Time::FromTimeT(s.ColumnInt64(0))); + } + + return s.Succeeded(); +} + bool WebDatabase::UpdateAutofillEntries( const std::vector<AutofillEntry>& entries) { if (!entries.size()) diff --git a/chrome/browser/webdata/web_database.h b/chrome/browser/webdata/web_database.h index 6745503..6d1a99d 100644 --- a/chrome/browser/webdata/web_database.h +++ b/chrome/browser/webdata/web_database.h @@ -10,6 +10,7 @@ #include "app/sql/connection.h" #include "app/sql/init_status.h" #include "app/sql/meta_table.h" +#include "base/scoped_ptr.h" #include "chrome/browser/search_engines/template_url.h" #include "third_party/skia/include/core/SkBitmap.h" #include "testing/gtest/include/gtest/gtest_prod.h" @@ -20,6 +21,7 @@ class AutofillEntry; class AutoFillProfile; class CreditCard; class FilePath; +class NotificationService; class WebDatabaseTest; namespace base { @@ -204,6 +206,11 @@ class WebDatabase { // Retrieves all of the entries in the autofill table. bool GetAllAutofillEntries(std::vector<AutofillEntry>* entries); + // Retrieves a single entry from the autofill table. + bool GetAutofillTimestamps(const string16& name, + const string16& value, + std::vector<base::Time>* timestamps); + // Replaces existing autofill entries with the entries supplied in // the argument. If the entry does not already exist, it will be // added. @@ -298,6 +305,8 @@ class WebDatabase { sql::Connection db_; sql::MetaTable meta_table_; + scoped_ptr<NotificationService> notification_service_; + DISALLOW_COPY_AND_ASSIGN(WebDatabase); }; diff --git a/chrome/browser/webdata/web_database_unittest.cc b/chrome/browser/webdata/web_database_unittest.cc index 52d6f41..9a84816 100644 --- a/chrome/browser/webdata/web_database_unittest.cc +++ b/chrome/browser/webdata/web_database_unittest.cc @@ -791,6 +791,24 @@ TEST_F(WebDatabaseTest, Autofill_UpdateOneWithTwoTimestamps) { EXPECT_TRUE(entry == all_entries[0]); } +TEST_F(WebDatabaseTest, Autofill_GetAutofillTimestamps) { + WebDatabase db; + ASSERT_EQ(sql::INIT_OK, db.Init(file_)); + + AutofillEntry entry(MakeAutofillEntry("foo", "bar", 1, 2)); + std::vector<AutofillEntry> entries; + entries.push_back(entry); + ASSERT_TRUE(db.UpdateAutofillEntries(entries)); + + std::vector<base::Time> timestamps; + ASSERT_TRUE(db.GetAutofillTimestamps(ASCIIToUTF16("foo"), + ASCIIToUTF16("bar"), + ×tamps)); + ASSERT_EQ(2U, timestamps.size()); + EXPECT_TRUE(Time::FromTimeT(1) == timestamps[0]); + EXPECT_TRUE(Time::FromTimeT(2) == timestamps[1]); +} + TEST_F(WebDatabaseTest, Autofill_UpdateTwo) { WebDatabase db; ASSERT_EQ(sql::INIT_OK, db.Init(file_)); |