diff options
author | vasilii <vasilii@chromium.org> | 2015-04-25 17:48:02 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-04-26 00:48:09 +0000 |
commit | 0ca264b8e9dc7f0713cb78c7ff75099749b4806f (patch) | |
tree | e44567d466e6131cba028d459dfd3f24410a391c /components | |
parent | 57cdc723f71b691b10ddc8f10f9a56897acb6886 (diff) | |
download | chromium_src-0ca264b8e9dc7f0713cb78c7ff75099749b4806f.zip chromium_src-0ca264b8e9dc7f0713cb78c7ff75099749b4806f.tar.gz chromium_src-0ca264b8e9dc7f0713cb78c7ff75099749b4806f.tar.bz2 |
Implement the statistics table for the passwords.
It contains information of how the user closed the "Save password?" bubble in the past. Basing on this data two different algorithms are to be implemented so the bubble isn't so annoying for the users.
BUG=431739
Review URL: https://codereview.chromium.org/1083293004
Cr-Commit-Position: refs/heads/master@{#326981}
Diffstat (limited to 'components')
18 files changed, 445 insertions, 4 deletions
diff --git a/components/components_tests.gyp b/components/components_tests.gyp index 05383f1..9c3ea50 100644 --- a/components/components_tests.gyp +++ b/components/components_tests.gyp @@ -346,6 +346,7 @@ 'password_manager/core/browser/password_store_unittest.cc', 'password_manager/core/browser/password_syncable_service_unittest.cc', 'password_manager/core/browser/psl_matching_helper_unittest.cc', + 'password_manager/core/browser/statistics_table_unittest.cc', 'password_manager/core/common/credential_manager_types_unittest.cc', ], 'policy_unittest_sources': [ diff --git a/components/password_manager.gypi b/components/password_manager.gypi index b560a66..62792ef 100644 --- a/components/password_manager.gypi +++ b/components/password_manager.gypi @@ -90,6 +90,8 @@ 'password_manager/core/browser/password_syncable_service.h', 'password_manager/core/browser/psl_matching_helper.cc', 'password_manager/core/browser/psl_matching_helper.h', + 'password_manager/core/browser/statistics_table.cc', + 'password_manager/core/browser/statistics_table.h', 'password_manager/core/browser/test_affiliation_fetcher_factory.h', 'password_manager/core/browser/webdata/logins_table.cc', 'password_manager/core/browser/webdata/logins_table.h', diff --git a/components/password_manager/core/browser/BUILD.gn b/components/password_manager/core/browser/BUILD.gn index 9880bd3..f46488d 100644 --- a/components/password_manager/core/browser/BUILD.gn +++ b/components/password_manager/core/browser/BUILD.gn @@ -72,6 +72,8 @@ static_library("browser") { "password_syncable_service.h", "psl_matching_helper.cc", "psl_matching_helper.h", + "statistics_table.cc", + "statistics_table.h", "test_affiliation_fetcher_factory.h", "webdata/logins_table.cc", "webdata/logins_table.h", diff --git a/components/password_manager/core/browser/login_database.cc b/components/password_manager/core/browser/login_database.cc index f59f8c6..91c71d0 100644 --- a/components/password_manager/core/browser/login_database.cc +++ b/components/password_manager/core/browser/login_database.cc @@ -29,7 +29,7 @@ using autofill::PasswordForm; namespace password_manager { -const int kCurrentVersionNumber = 12; +const int kCurrentVersionNumber = 13; static const int kCompatibleVersionNumber = 1; Pickle SerializeVector(const std::vector<base::string16>& vec) { @@ -233,7 +233,13 @@ bool LoginDatabase::Init() { // Initialize the tables. if (!InitLoginsTable()) { - LOG(WARNING) << "Unable to initialize the password store database."; + LOG(WARNING) << "Unable to initialize the logins table."; + db_.Close(); + return false; + } + + if (!stats_table_.Init(&db_)) { + LOG(WARNING) << "Unable to initialize the stats table."; db_.Close(); return false; } @@ -374,6 +380,9 @@ bool LoginDatabase::MigrateOldVersionsAsNeeded() { "generation_upload_status INTEGER")) return false; meta_table_.SetVersionNumber(12); + case 12: + // The stats table was added. Nothing to do really. + meta_table_.SetVersionNumber(13); case kCurrentVersionNumber: // Already up to date return true; diff --git a/components/password_manager/core/browser/login_database.h b/components/password_manager/core/browser/login_database.h index 008afa3..ca3db84 100644 --- a/components/password_manager/core/browser/login_database.h +++ b/components/password_manager/core/browser/login_database.h @@ -16,6 +16,7 @@ #include "components/password_manager/core/browser/password_store.h" #include "components/password_manager/core/browser/password_store_change.h" #include "components/password_manager/core/browser/psl_matching_helper.h" +#include "components/password_manager/core/browser/statistics_table.h" #include "sql/connection.h" #include "sql/meta_table.h" @@ -108,6 +109,8 @@ class LoginDatabase { // whether further use of this login database will succeed is unspecified. bool DeleteAndRecreateDatabaseFile(); + StatisticsTable& stats_table() { return stats_table_; } + private: // Result values for encryption/decryption actions. enum EncryptionResult { @@ -165,6 +168,7 @@ class LoginDatabase { base::FilePath db_path_; mutable sql::Connection db_; sql::MetaTable meta_table_; + StatisticsTable stats_table_; DISALLOW_COPY_AND_ASSIGN(LoginDatabase); }; diff --git a/components/password_manager/core/browser/mock_password_store.h b/components/password_manager/core/browser/mock_password_store.h index 70f54e9..7b76b91 100644 --- a/components/password_manager/core/browser/mock_password_store.h +++ b/components/password_manager/core/browser/mock_password_store.h @@ -47,6 +47,12 @@ class MockPasswordStore : public PasswordStore { MOCK_METHOD1(FillBlacklistLogins, bool(ScopedVector<autofill::PasswordForm>*)); MOCK_METHOD1(NotifyLoginsChanged, void(const PasswordStoreChangeList&)); + void AddSiteStatsImpl(const InteractionsStats& stats) override {} + void RemoveSiteStatsImpl(const GURL& origin_domain) override {} + scoped_ptr<InteractionsStats> GetSiteStatsImpl( + const GURL& origin_domain) override { + return scoped_ptr<InteractionsStats>(); + } PasswordStoreSync* GetSyncInterface() { return this; } diff --git a/components/password_manager/core/browser/password_store.cc b/components/password_manager/core/browser/password_store.cc index 5b13a3c..4a35791 100644 --- a/components/password_manager/core/browser/password_store.cc +++ b/components/password_manager/core/browser/password_store.cc @@ -59,6 +59,13 @@ void PasswordStore::GetLoginsRequest::NotifyConsumerWithResults( consumer_weak_, base::Passed(&results))); } +void PasswordStore::GetLoginsRequest::NotifyWithSiteStatistics( + scoped_ptr<InteractionsStats> stats) { + origin_loop_->PostTask(FROM_HERE, + base::Bind(&PasswordStoreConsumer::OnGetSiteStatistics, + consumer_weak_, base::Passed(&stats))); +} + PasswordStore::PasswordStore( scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner, scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner) @@ -163,6 +170,22 @@ void PasswordStore::ReportMetrics(const std::string& sync_username, } } +void PasswordStore::AddSiteStats(const InteractionsStats& stats) { + ScheduleTask(base::Bind(&PasswordStore::AddSiteStatsImpl, this, stats)); +} + +void PasswordStore::RemoveSiteStats(const GURL& origin_domain) { + ScheduleTask( + base::Bind(&PasswordStore::RemoveSiteStatsImpl, this, origin_domain)); +} + +void PasswordStore::GetSiteStats(const GURL& origin_domain, + PasswordStoreConsumer* consumer) { + scoped_ptr<GetLoginsRequest> request(new GetLoginsRequest(consumer)); + ScheduleTask(base::Bind(&PasswordStore::NotifySiteStats, this, origin_domain, + base::Passed(&request))); +} + void PasswordStore::AddObserver(Observer* observer) { observers_->AddObserver(observer); } @@ -302,6 +325,11 @@ void PasswordStore::RemoveLoginsSyncedBetweenInternal(base::Time delete_begin, NotifyLoginsChanged(changes); } +void PasswordStore::NotifySiteStats(const GURL& origin_domain, + scoped_ptr<GetLoginsRequest> request) { + request->NotifyWithSiteStatistics(GetSiteStatsImpl(origin_domain)); +} + void PasswordStore::GetLoginsWithAffiliationsImpl( const PasswordForm& form, AuthorizationPromptPolicy prompt_policy, diff --git a/components/password_manager/core/browser/password_store.h b/components/password_manager/core/browser/password_store.h index 74ff469..c1194cf 100644 --- a/components/password_manager/core/browser/password_store.h +++ b/components/password_manager/core/browser/password_store.h @@ -15,6 +15,7 @@ #include "base/time/time.h" #include "components/password_manager/core/browser/password_store_change.h" #include "components/password_manager/core/browser/password_store_sync.h" +#include "components/password_manager/core/browser/statistics_table.h" #include "sync/api/syncable_service.h" namespace autofill { @@ -128,6 +129,16 @@ class PasswordStore : protected PasswordStoreSync, virtual void ReportMetrics(const std::string& sync_username, bool custom_passphrase_sync_enabled); + // Adds or replaces the statistics for the domain |stats.origin_domain|. + void AddSiteStats(const InteractionsStats& stats); + + // Removes the statistics for |origin_domain|. + void RemoveSiteStats(const GURL& origin_domain); + + // Retrieves the statistics for |origin_domain| and notifies |consumer| on + // completion. The request will be cancelled if the consumer is destroyed. + void GetSiteStats(const GURL& origin_domain, PasswordStoreConsumer* consumer); + // Adds an observer to be notified when the password store data changes. void AddObserver(Observer* observer); @@ -162,6 +173,8 @@ class PasswordStore : protected PasswordStoreSync, void NotifyConsumerWithResults( ScopedVector<autofill::PasswordForm> results); + void NotifyWithSiteStatistics(scoped_ptr<InteractionsStats> stats); + void set_ignore_logins_cutoff(base::Time cutoff) { ignore_logins_cutoff_ = cutoff; } @@ -235,6 +248,13 @@ class PasswordStore : protected PasswordStoreSync, // Finds all blacklist PasswordForms, and notifies the consumer. virtual void GetBlacklistLoginsImpl(scoped_ptr<GetLoginsRequest> request) = 0; + // Synchronous implementation for manipulating with statistics. + virtual void AddSiteStatsImpl(const InteractionsStats& stats) = 0; + virtual void RemoveSiteStatsImpl(const GURL& origin_domain) = 0; + // Returns a raw pointer so that InteractionsStats can be forward declared. + virtual scoped_ptr<InteractionsStats> GetSiteStatsImpl( + const GURL& origin_domain) WARN_UNUSED_RESULT = 0; + // Log UMA stats for number of bulk deletions. void LogStatsForBulkDeletion(int num_deletions); @@ -288,6 +308,10 @@ class PasswordStore : protected PasswordStoreSync, void RemoveLoginsSyncedBetweenInternal(base::Time delete_begin, base::Time delete_end); + // Notifies |request| about the stats for |origin_domain|. + void NotifySiteStats(const GURL& origin_domain, + scoped_ptr<GetLoginsRequest> request); + // Extended version of GetLoginsImpl that also returns credentials stored for // the specified affiliated Android applications. That is, it finds all // PasswordForms with a signon_realm that is either: diff --git a/components/password_manager/core/browser/password_store_consumer.cc b/components/password_manager/core/browser/password_store_consumer.cc index da62aed..8347f2b 100644 --- a/components/password_manager/core/browser/password_store_consumer.cc +++ b/components/password_manager/core/browser/password_store_consumer.cc @@ -4,6 +4,8 @@ #include "components/password_manager/core/browser/password_store_consumer.h" +#include "components/password_manager/core/browser/statistics_table.h" + namespace password_manager { PasswordStoreConsumer::PasswordStoreConsumer() : weak_ptr_factory_(this) { @@ -12,4 +14,8 @@ PasswordStoreConsumer::PasswordStoreConsumer() : weak_ptr_factory_(this) { PasswordStoreConsumer::~PasswordStoreConsumer() { } +void PasswordStoreConsumer::OnGetSiteStatistics( + scoped_ptr<InteractionsStats> stats) { +} + } // namespace password_manager diff --git a/components/password_manager/core/browser/password_store_consumer.h b/components/password_manager/core/browser/password_store_consumer.h index 1ffdae3..b8934995 100644 --- a/components/password_manager/core/browser/password_store_consumer.h +++ b/components/password_manager/core/browser/password_store_consumer.h @@ -16,6 +16,8 @@ struct PasswordForm; namespace password_manager { +struct InteractionsStats; + // Reads from the PasswordStore are done asynchronously on a separate // thread. PasswordStoreConsumer provides the virtual callback method, which is // guaranteed to be executed on this (the UI) thread. It also provides the @@ -25,10 +27,13 @@ class PasswordStoreConsumer { public: PasswordStoreConsumer(); - // Called when the request is finished, with the associated |results|. + // Called when the GetLogins() request is finished, with the associated + // |results|. virtual void OnGetPasswordStoreResults( ScopedVector<autofill::PasswordForm> results) = 0; + virtual void OnGetSiteStatistics(scoped_ptr<InteractionsStats> stats); + // The base::CancelableTaskTracker can be used for cancelling the // tasks associated with the consumer. base::CancelableTaskTracker* cancelable_task_tracker() { diff --git a/components/password_manager/core/browser/password_store_default.cc b/components/password_manager/core/browser/password_store_default.cc index 4e24ad1..54be8f8 100644 --- a/components/password_manager/core/browser/password_store_default.cc +++ b/components/password_manager/core/browser/password_store_default.cc @@ -148,4 +148,23 @@ bool PasswordStoreDefault::FillBlacklistLogins( return login_db_ && login_db_->GetBlacklistLogins(forms); } +void PasswordStoreDefault::AddSiteStatsImpl(const InteractionsStats& stats) { + DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread()); + if (login_db_) + login_db_->stats_table().AddRow(stats); +} + +void PasswordStoreDefault::RemoveSiteStatsImpl(const GURL& origin_domain) { + DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread()); + if (login_db_) + login_db_->stats_table().RemoveRow(origin_domain); +} + +scoped_ptr<InteractionsStats> PasswordStoreDefault::GetSiteStatsImpl( + const GURL& origin_domain) { + DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread()); + return login_db_ ? login_db_->stats_table().GetRow(origin_domain) + : scoped_ptr<InteractionsStats>(); +} + } // namespace password_manager diff --git a/components/password_manager/core/browser/password_store_default.h b/components/password_manager/core/browser/password_store_default.h index ecfd38f..ab02004 100644 --- a/components/password_manager/core/browser/password_store_default.h +++ b/components/password_manager/core/browser/password_store_default.h @@ -59,8 +59,11 @@ class PasswordStoreDefault : public PasswordStore { ScopedVector<autofill::PasswordForm>* forms) override; bool FillBlacklistLogins( ScopedVector<autofill::PasswordForm>* forms) override; + void AddSiteStatsImpl(const InteractionsStats& stats) override; + void RemoveSiteStatsImpl(const GURL& origin_domain) override; + scoped_ptr<InteractionsStats> GetSiteStatsImpl( + const GURL& origin_domain) override; - protected: inline bool DeleteAndRecreateDatabaseFile() { return login_db_->DeleteAndRecreateDatabaseFile(); } diff --git a/components/password_manager/core/browser/statistics_table.cc b/components/password_manager/core/browser/statistics_table.cc new file mode 100644 index 0000000..1246ee9 --- /dev/null +++ b/components/password_manager/core/browser/statistics_table.cc @@ -0,0 +1,83 @@ +// Copyright 2015 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 "components/password_manager/core/browser/statistics_table.h" + +#include "sql/connection.h" +#include "sql/statement.h" + +namespace password_manager { +namespace { + +// Convenience enum for interacting with SQL queries that use all the columns. +enum LoginTableColumns { + COLUMN_ORIGIN_DOMAIN = 0, + COLUMN_NOPES, + COLUMN_DISMISSALS, + COLUMN_DATE, +}; + +} // namespace + +StatisticsTable::StatisticsTable() : db_(nullptr) { +} + +StatisticsTable::~StatisticsTable() { +} + +bool StatisticsTable::Init(sql::Connection* db) { + db_ = db; + if (!db_->DoesTableExist("stats")) { + const char query[] = + "CREATE TABLE stats (" + "origin_domain VARCHAR NOT NULL PRIMARY KEY, " + "nopes_count INTEGER, " + "dismissal_count INTEGER, " + "start_date INTEGER NOT NULL)"; + if (!db_->Execute(query)) + return false; + } + return true; +} + +bool StatisticsTable::AddRow(const InteractionsStats& stats) { + sql::Statement s(db_->GetCachedStatement( + SQL_FROM_HERE, + "INSERT OR REPLACE INTO stats " + "(origin_domain, nopes_count, dismissal_count, start_date) " + "VALUES (?, ?, ?, ?)")); + s.BindString(COLUMN_ORIGIN_DOMAIN, stats.origin_domain.spec()); + s.BindInt(COLUMN_NOPES, stats.nopes_count); + s.BindInt(COLUMN_DISMISSALS, stats.dismissal_count); + s.BindInt64(COLUMN_DATE, stats.start_date.ToInternalValue()); + return s.Run(); +} + +bool StatisticsTable::RemoveRow(const GURL& domain) { + sql::Statement s(db_->GetCachedStatement(SQL_FROM_HERE, + "DELETE FROM stats WHERE " + "origin_domain = ? ")); + s.BindString(0, domain.spec()); + return s.Run(); +} + +scoped_ptr<InteractionsStats> StatisticsTable::GetRow(const GURL& domain) { + const char query[] = + "SELECT origin_domain, nopes_count, " + "dismissal_count, start_date FROM stats WHERE origin_domain == ?"; + sql::Statement s(db_->GetCachedStatement(SQL_FROM_HERE, query)); + s.BindString(0, domain.spec()); + if (s.Step()) { + scoped_ptr<InteractionsStats> stats(new InteractionsStats); + stats->origin_domain = GURL(s.ColumnString(COLUMN_ORIGIN_DOMAIN)); + stats->nopes_count = s.ColumnInt(COLUMN_NOPES); + stats->dismissal_count = s.ColumnInt(COLUMN_DISMISSALS); + stats->start_date = + base::Time::FromInternalValue(s.ColumnInt64(COLUMN_DATE)); + return stats.Pass(); + } + return scoped_ptr<InteractionsStats>(); +} + +} // namespace password_manager diff --git a/components/password_manager/core/browser/statistics_table.h b/components/password_manager/core/browser/statistics_table.h new file mode 100644 index 0000000..d135309 --- /dev/null +++ b/components/password_manager/core/browser/statistics_table.h @@ -0,0 +1,61 @@ +// Copyright 2015 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. + +#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_STATISTICS_TABLE_H_ +#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_STATISTICS_TABLE_H_ + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "base/time/time.h" +#include "url/gurl.h" + +namespace sql { +class Connection; +} + +namespace password_manager { + +// The statistics containing user interactions with a site. +struct InteractionsStats { + // The domain of the site. + GURL origin_domain; + + // Number of times the user clicked "Don't save the password". + int nopes_count; + + // Number of times the user dismissed the bubble. + int dismissal_count; + + // The beginning date of the measurements. + base::Time start_date; +}; + +// Represents 'stats' table in the Login Database. +class StatisticsTable { + public: + StatisticsTable(); + ~StatisticsTable(); + + // Initializes |db_| and creates the statistics table if it doesn't exist. + bool Init(sql::Connection* db); + + // Adds or replaces the statistics about |stats.origin_domain|. + bool AddRow(const InteractionsStats& stats); + + // Removes the statistics for |domain|. Returns true if the SQL completed + // successfully. + bool RemoveRow(const GURL& domain); + + // Returns the statistics for |domain| if it exists. + scoped_ptr<InteractionsStats> GetRow(const GURL& domain); + + private: + sql::Connection* db_; + + DISALLOW_COPY_AND_ASSIGN(StatisticsTable); +}; + +} // namespace password_manager + +#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_STATISTICS_TABLE_H_ diff --git a/components/password_manager/core/browser/statistics_table_unittest.cc b/components/password_manager/core/browser/statistics_table_unittest.cc new file mode 100644 index 0000000..c3d28ff --- /dev/null +++ b/components/password_manager/core/browser/statistics_table_unittest.cc @@ -0,0 +1,91 @@ +// Copyright 2015 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 "components/password_manager/core/browser/statistics_table.h" + +#include "base/files/scoped_temp_dir.h" +#include "sql/connection.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace password_manager { +namespace { + +const char kTestDomain[] = "http://google.com"; + +void CheckStatsAreEqual(const InteractionsStats& left, + const InteractionsStats& right) { + EXPECT_EQ(left.origin_domain, right.origin_domain); + EXPECT_EQ(left.nopes_count, right.nopes_count); + EXPECT_EQ(left.dismissal_count, right.dismissal_count); + EXPECT_EQ(left.start_date, right.start_date); +} + +class StatisticsTableTest : public testing::Test { + protected: + void SetUp() override { + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + ReloadDatabase(); + + test_data_.origin_domain = GURL(kTestDomain); + test_data_.nopes_count = 5; + test_data_.dismissal_count = 10; + test_data_.start_date = base::Time::FromTimeT(1); + } + + void ReloadDatabase() { + base::FilePath file = temp_dir_.path().AppendASCII("TestDatabase"); + db_.reset(new StatisticsTable); + connection_.reset(new sql::Connection); + connection_->set_exclusive_locking(); + ASSERT_TRUE(connection_->Open(file)); + ASSERT_TRUE(db_->Init(connection_.get())); + } + + InteractionsStats& test_data() { return test_data_; } + StatisticsTable* db() { return db_.get(); } + + private: + base::ScopedTempDir temp_dir_; + scoped_ptr<sql::Connection> connection_; + scoped_ptr<StatisticsTable> db_; + InteractionsStats test_data_; +}; + +TEST_F(StatisticsTableTest, Sanity) { + EXPECT_TRUE(db()->AddRow(test_data())); + scoped_ptr<InteractionsStats> stats = db()->GetRow(test_data().origin_domain); + ASSERT_TRUE(stats); + CheckStatsAreEqual(test_data(), *stats); + EXPECT_TRUE(db()->RemoveRow(test_data().origin_domain)); + EXPECT_FALSE(db()->GetRow(test_data().origin_domain)); +} + +TEST_F(StatisticsTableTest, Reload) { + EXPECT_TRUE(db()->AddRow(test_data())); + EXPECT_TRUE(db()->GetRow(test_data().origin_domain)); + + ReloadDatabase(); + + scoped_ptr<InteractionsStats> stats = db()->GetRow(test_data().origin_domain); + ASSERT_TRUE(stats); + CheckStatsAreEqual(test_data(), *stats); +} + +TEST_F(StatisticsTableTest, DoubleOperation) { + EXPECT_TRUE(db()->AddRow(test_data())); + test_data().nopes_count++; + EXPECT_TRUE(db()->AddRow(test_data())); + + scoped_ptr<InteractionsStats> stats = db()->GetRow(test_data().origin_domain); + ASSERT_TRUE(stats); + CheckStatsAreEqual(test_data(), *stats); + + EXPECT_TRUE(db()->RemoveRow(test_data().origin_domain)); + EXPECT_FALSE(db()->GetRow(test_data().origin_domain)); + EXPECT_TRUE(db()->RemoveRow(test_data().origin_domain)); + EXPECT_FALSE(db()->GetRow(test_data().origin_domain)); +} + +} // namespace +} // namespace password_manager diff --git a/components/password_manager/core/browser/test_password_store.cc b/components/password_manager/core/browser/test_password_store.cc index a420e9e..60f2536 100644 --- a/components/password_manager/core/browser/test_password_store.cc +++ b/components/password_manager/core/browser/test_password_store.cc @@ -139,4 +139,15 @@ bool TestPasswordStore::FillBlacklistLogins( return true; } +void TestPasswordStore::AddSiteStatsImpl(const InteractionsStats& stats) { +} + +void TestPasswordStore::RemoveSiteStatsImpl(const GURL& origin_domain) { +} + +scoped_ptr<InteractionsStats> TestPasswordStore::GetSiteStatsImpl( + const GURL& origin_domain) { + return scoped_ptr<InteractionsStats>(); +} + } // namespace password_manager diff --git a/components/password_manager/core/browser/test_password_store.h b/components/password_manager/core/browser/test_password_store.h index 96f6104..72addcd 100644 --- a/components/password_manager/core/browser/test_password_store.h +++ b/components/password_manager/core/browser/test_password_store.h @@ -66,6 +66,10 @@ class TestPasswordStore : public PasswordStore { ScopedVector<autofill::PasswordForm>* forms) override; bool FillBlacklistLogins( ScopedVector<autofill::PasswordForm>* forms) override; + void AddSiteStatsImpl(const InteractionsStats& stats) override; + void RemoveSiteStatsImpl(const GURL& origin_domain) override; + scoped_ptr<InteractionsStats> GetSiteStatsImpl( + const GURL& origin_domain) override; private: PasswordMap stored_passwords_; diff --git a/components/test/data/password_manager/login_db_v12.sql b/components/test/data/password_manager/login_db_v12.sql new file mode 100644 index 0000000..6f746fe --- /dev/null +++ b/components/test/data/password_manager/login_db_v12.sql @@ -0,0 +1,82 @@ +PRAGMA foreign_keys=OFF; +BEGIN TRANSACTION; +CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR); +INSERT INTO "meta" VALUES('last_compatible_version','1'); +INSERT INTO "meta" VALUES('version','12'); +CREATE TABLE logins ( +origin_url VARCHAR NOT NULL, +action_url VARCHAR, +username_element VARCHAR, +username_value VARCHAR, +password_element VARCHAR, +password_value BLOB, +submit_element VARCHAR, +signon_realm VARCHAR NOT NULL, +ssl_valid INTEGER NOT NULL, +preferred INTEGER NOT NULL, +date_created INTEGER NOT NULL, +blacklisted_by_user INTEGER NOT NULL, +scheme INTEGER NOT NULL, +password_type INTEGER, +possible_usernames BLOB, +times_used INTEGER, +form_data BLOB, +date_synced INTEGER, +display_name VARCHAR, +avatar_url VARCHAR, +federation_url VARCHAR, +skip_zero_click INTEGER, +generation_upload_status INTEGER, +UNIQUE (origin_url, username_element, username_value, password_element, signon_realm)); +INSERT INTO "logins" VALUES( +'https://accounts.google.com/ServiceLogin', /* origin_url */ +'https://accounts.google.com/ServiceLoginAuth', /* action_url */ +'Email', /* username_element */ +'theerikchen', /* username_value */ +'Passwd', /* password_element */ +X'', /* password_value */ +'', /* submit_element */ +'https://accounts.google.com/', /* signon_realm */ +1, /* ssl_valid */ +1, /* preferred */ +13047429345000000, /* date_created */ +0, /* blacklisted_by_user */ +0, /* scheme */ +0, /* password_type */ +X'00000000', /* possible_usernames */ +1, /* times_used */ +X'18000000020000000000000000000000000000000000000000000000', /* form_data */ +0, /* date_synced */ +'', /* display_name */ +'', /* avatar_url */ +'', /* federation_url */ +0, /* skip_zero_click */ +0 /* generation_upload_status */ +); +INSERT INTO "logins" VALUES( +'https://accounts.google.com/ServiceLogin', /* origin_url */ +'https://accounts.google.com/ServiceLoginAuth', /* action_url */ +'Email', /* username_element */ +'theerikchen2', /* username_value */ +'Passwd', /* password_element */ +X'', /* password_value */ +'non-empty', /* submit_element */ +'https://accounts.google.com/', /* signon_realm */ +1, /* ssl_valid */ +1, /* preferred */ +13047423600000000, /* date_created */ +0, /* blacklisted_by_user */ +0, /* scheme */ +0, /* password_type */ +X'00000000', /* possible_usernames */ +1, /* times_used */ +X'18000000020000000000000000000000000000000000000000000000', /* form_data */ +0, /* date_synced */ +'', /* display_name */ +'', /* avatar_url */ +'', /* federation_url */ +0, /* skip_zero_click */ +0 /* generation_upload_status */ +); +CREATE INDEX logins_signon ON logins (signon_realm); +COMMIT; |