summaryrefslogtreecommitdiffstats
path: root/chrome/browser/webdata
diff options
context:
space:
mode:
authorzork@google.com <zork@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-01 22:06:21 +0000
committerzork@google.com <zork@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-01 22:06:21 +0000
commit8b3b23abcf91b7573c6fcf230240395118c04580 (patch)
tree3c4dc9c354662a6d9ecff8443f4620fa017c7718 /chrome/browser/webdata
parent3950400350f7f8494f09a3568acb6d40592701f5 (diff)
downloadchromium_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.cc15
-rw-r--r--chrome/browser/webdata/autofill_entry.h3
-rw-r--r--chrome/browser/webdata/web_data_service.cc49
-rw-r--r--chrome/browser/webdata/web_data_service.h3
-rw-r--r--chrome/browser/webdata/web_data_service_unittest.cc147
-rw-r--r--chrome/browser/webdata/web_database.cc29
-rw-r--r--chrome/browser/webdata/web_database.h9
-rw-r--r--chrome/browser/webdata/web_database_unittest.cc18
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"),
+ &timestamps));
+ 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_));