Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1620)

Unified Diff: chrome/browser/password_manager/password_store_x_unittest.cc

Issue 2806002: Linux: refactor GNOME Keyring and KWallet integration to allow migration. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 10 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/password_manager/password_store_x.cc ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/password_manager/password_store_x_unittest.cc
===================================================================
--- chrome/browser/password_manager/password_store_x_unittest.cc (revision 49657)
+++ chrome/browser/password_manager/password_store_x_unittest.cc (working copy)
@@ -3,14 +3,14 @@
// found in the LICENSE file.
#include "base/basictypes.h"
+#include "base/scoped_temp_dir.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
-#include "base/scoped_temp_dir.h"
#include "base/time.h"
#include "base/waitable_event.h"
+#include "chrome/browser/password_manager/password_form_data.h"
#include "chrome/browser/password_manager/password_store_change.h"
-#include "chrome/browser/password_manager/password_store_default.h"
-#include "chrome/browser/password_manager/password_form_data.h"
+#include "chrome/browser/password_manager/password_store_x.h"
#include "chrome/browser/webdata/web_data_service.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
@@ -32,7 +32,7 @@
class MockPasswordStoreConsumer : public PasswordStoreConsumer {
public:
MOCK_METHOD2(OnPasswordStoreRequestDone,
- void(int, const std::vector<webkit_glue::PasswordForm*>&));
+ void(int, const std::vector<PasswordForm*>&));
};
class MockWebDataServiceConsumer : public WebDataServiceConsumer {
@@ -61,9 +61,9 @@
// This class will add and remove a mock notification observer from
// the DB thread.
-class DBThreadObserverHelper :
- public base::RefCountedThreadSafe<DBThreadObserverHelper,
- ChromeThread::DeleteOnDBThread> {
+class DBThreadObserverHelper
+ : public base::RefCountedThreadSafe<DBThreadObserverHelper,
+ ChromeThread::DeleteOnDBThread> {
public:
DBThreadObserverHelper() : done_event_(true, false) {}
@@ -101,13 +101,224 @@
MockNotificationObserver observer_;
};
+class FailingBackend : public PasswordStoreX::NativeBackend {
+ public:
+ virtual bool Init() { return true; }
+
+ virtual bool AddLogin(const PasswordForm& form) { return false; }
+ virtual bool UpdateLogin(const PasswordForm& form) { return false; }
+ virtual bool RemoveLogin(const PasswordForm& form) { return false; }
+
+ virtual bool RemoveLoginsCreatedBetween(const base::Time& delete_begin,
+ const base::Time& delete_end) {
+ return false;
+ }
+
+ virtual bool GetLogins(const PasswordForm& form, PasswordFormList* forms) {
+ return false;
+ }
+
+ virtual bool GetLoginsCreatedBetween(const base::Time& get_begin,
+ const base::Time& get_end,
+ PasswordFormList* forms) {
+ return false;
+ }
+
+ virtual bool GetAutofillableLogins(PasswordFormList* forms) { return false; }
+ virtual bool GetBlacklistLogins(PasswordFormList* forms) { return false; }
+};
+
+class MockBackend : public PasswordStoreX::NativeBackend {
+ public:
+ virtual bool Init() { return true; }
+
+ virtual bool AddLogin(const PasswordForm& form) {
+ all_forms_.push_back(form);
+ return true;
+ }
+
+ virtual bool UpdateLogin(const PasswordForm& form) {
+ for (size_t i = 0; i < all_forms_.size(); ++i)
+ if (CompareForms(all_forms_[i], form, true))
+ all_forms_[i] = form;
+ return true;
+ }
+
+ virtual bool RemoveLogin(const PasswordForm& form) {
+ for (size_t i = 0; i < all_forms_.size(); ++i)
+ if (CompareForms(all_forms_[i], form, false))
+ erase(i--);
+ return true;
+ }
+
+ virtual bool RemoveLoginsCreatedBetween(const base::Time& delete_begin,
+ const base::Time& delete_end) {
+ for (size_t i = 0; i < all_forms_.size(); ++i) {
+ if (delete_begin <= all_forms_[i].date_created &&
+ (delete_end.is_null() || all_forms_[i].date_created < delete_end))
+ erase(i--);
+ }
+ return true;
+ }
+
+ virtual bool GetLogins(const PasswordForm& form, PasswordFormList* forms) {
+ for (size_t i = 0; i < all_forms_.size(); ++i)
+ if (all_forms_[i].signon_realm == form.signon_realm)
+ forms->push_back(new PasswordForm(all_forms_[i]));
+ return true;
+ }
+
+ virtual bool GetLoginsCreatedBetween(const base::Time& get_begin,
+ const base::Time& get_end,
+ PasswordFormList* forms) {
+ for (size_t i = 0; i < all_forms_.size(); ++i)
+ if (get_begin <= all_forms_[i].date_created &&
+ (get_end.is_null() || all_forms_[i].date_created < get_end))
+ forms->push_back(new PasswordForm(all_forms_[i]));
+ return true;
+ }
+
+ virtual bool GetAutofillableLogins(PasswordFormList* forms) {
+ for (size_t i = 0; i < all_forms_.size(); ++i)
+ if (!all_forms_[i].blacklisted_by_user)
+ forms->push_back(new PasswordForm(all_forms_[i]));
+ return true;
+ }
+
+ virtual bool GetBlacklistLogins(PasswordFormList* forms) {
+ for (size_t i = 0; i < all_forms_.size(); ++i)
+ if (all_forms_[i].blacklisted_by_user)
+ forms->push_back(new PasswordForm(all_forms_[i]));
+ return true;
+ }
+
+ private:
+ void erase(size_t index) {
+ if (index < all_forms_.size() - 1)
+ all_forms_[index] = all_forms_[all_forms_.size() - 1];
+ all_forms_.pop_back();
+ }
+
+ bool CompareForms(const PasswordForm& a, const PasswordForm& b, bool update) {
+ // An update check doesn't care about the submit element.
+ if (!update && a.submit_element != b.submit_element)
+ return false;
+ return a.origin == b.origin &&
+ a.password_element == b.password_element &&
+ a.signon_realm == b.signon_realm &&
+ a.username_element == b.username_element &&
+ a.username_value == b.username_value;
+ }
+
+ std::vector<PasswordForm> all_forms_;
+};
+
+class MockLoginDatabaseReturn {
+ public:
+ MOCK_METHOD1(OnLoginDatabaseQueryDone,
+ void(const std::vector<PasswordForm*>&));
+};
+
+class LoginDatabaseQueryTask : public Task {
+ public:
+ LoginDatabaseQueryTask(LoginDatabase* login_db,
+ bool autofillable,
+ MockLoginDatabaseReturn* mock_return)
+ : login_db_(login_db), autofillable_(autofillable),
+ mock_return_(mock_return) {
+ }
+
+ virtual void Run() {
+ std::vector<PasswordForm*> forms;
+ if (autofillable_)
+ login_db_->GetAutofillableLogins(&forms);
+ else
+ login_db_->GetBlacklistLogins(&forms);
+ mock_return_->OnLoginDatabaseQueryDone(forms);
+ }
+
+ private:
+ LoginDatabase* login_db_;
+ bool autofillable_;
+ MockLoginDatabaseReturn* mock_return_;
+};
+
+const PasswordFormData g_autofillable_data[] = {
+ { PasswordForm::SCHEME_HTML,
+ "http://foo.example.com",
+ "http://foo.example.com/origin",
+ "http://foo.example.com/action",
+ L"submit_element",
+ L"username_element",
+ L"password_element",
+ L"username_value",
+ L"password_value",
+ true, false, 1 },
+ { PasswordForm::SCHEME_HTML,
+ "http://bar.example.com",
+ "http://bar.example.com/origin",
+ "http://bar.example.com/action",
+ L"submit_element",
+ L"username_element",
+ L"password_element",
+ L"username_value",
+ L"password_value",
+ true, false, 2 },
+ { PasswordForm::SCHEME_HTML,
+ "http://baz.example.com",
+ "http://baz.example.com/origin",
+ "http://baz.example.com/action",
+ L"submit_element",
+ L"username_element",
+ L"password_element",
+ L"username_value",
+ L"password_value",
+ true, false, 3 },
+};
+const PasswordFormData g_blacklisted_data[] = {
+ { PasswordForm::SCHEME_HTML,
+ "http://blacklisted.example.com",
+ "http://blacklisted.example.com/origin",
+ "http://blacklisted.example.com/action",
+ L"submit_element",
+ L"username_element",
+ L"password_element",
+ NULL,
+ NULL,
+ false, false, 1 },
+ { PasswordForm::SCHEME_HTML,
+ "http://blacklisted2.example.com",
+ "http://blacklisted2.example.com/origin",
+ "http://blacklisted2.example.com/action",
+ L"submit_element",
+ L"username_element",
+ L"password_element",
+ NULL,
+ NULL,
+ false, false, 2 },
+};
+
} // anonymous namespace
typedef std::vector<PasswordForm*> VectorOfForms;
-class PasswordStoreDefaultTest : public testing::Test {
+// LoginDatabase isn't reference counted, but in these unit tests that won't be
+// a problem as it always outlives the threads we post tasks to.
+template<>
+struct RunnableMethodTraits<LoginDatabase> {
+ void RetainCallee(LoginDatabase*) {}
+ void ReleaseCallee(LoginDatabase*) {}
+};
+
+enum BackendType {
+ NO_BACKEND,
+ FAILING_BACKEND,
+ WORKING_BACKEND
+};
+
+class PasswordStoreXTest : public testing::TestWithParam<BackendType> {
protected:
- PasswordStoreDefaultTest()
+ PasswordStoreXTest()
: ui_thread_(ChromeThread::UI, &message_loop_),
db_thread_(ChromeThread::DB) {
}
@@ -133,6 +344,17 @@
db_thread_.Stop();
}
+ PasswordStoreX::NativeBackend* GetBackend() {
+ switch (GetParam()) {
+ case FAILING_BACKEND:
+ return new FailingBackend();
+ case WORKING_BACKEND:
+ return new MockBackend();
+ default:
+ return NULL;
+ }
+ }
+
MessageLoopForUI message_loop_;
ChromeThread ui_thread_;
ChromeThread db_thread_; // PasswordStore, WDS schedule work on this thread.
@@ -157,72 +379,17 @@
arg)->GetValue().empty();
}
-TEST_F(PasswordStoreDefaultTest, Migration) {
- PasswordFormData autofillable_data[] = {
- { PasswordForm::SCHEME_HTML,
- "http://foo.example.com",
- "http://foo.example.com/origin",
- "http://foo.example.com/action",
- L"submit_element",
- L"username_element",
- L"password_element",
- L"username_value",
- L"password_value",
- true, false, 1 },
- { PasswordForm::SCHEME_HTML,
- "http://bar.example.com",
- "http://bar.example.com/origin",
- "http://bar.example.com/action",
- L"submit_element",
- L"username_element",
- L"password_element",
- L"username_value",
- L"password_value",
- true, false, 2 },
- { PasswordForm::SCHEME_HTML,
- "http://baz.example.com",
- "http://baz.example.com/origin",
- "http://baz.example.com/action",
- L"submit_element",
- L"username_element",
- L"password_element",
- L"username_value",
- L"password_value",
- true, false, 3 },
- };
- PasswordFormData blacklisted_data[] = {
- { PasswordForm::SCHEME_HTML,
- "http://blacklisted.example.com",
- "http://blacklisted.example.com/origin",
- "http://blacklisted.example.com/action",
- L"submit_element",
- L"username_element",
- L"password_element",
- NULL,
- NULL,
- false, false, 1 },
- { PasswordForm::SCHEME_HTML,
- "http://blacklisted2.example.com",
- "http://blacklisted2.example.com/origin",
- "http://blacklisted2.example.com/action",
- L"submit_element",
- L"username_element",
- L"password_element",
- NULL,
- NULL,
- false, false, 2 },
- };
-
+TEST_P(PasswordStoreXTest, WDSMigration) {
VectorOfForms expected_autofillable;
- for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(autofillable_data); ++i) {
+ for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(g_autofillable_data); ++i) {
expected_autofillable.push_back(
- CreatePasswordFormFromData(autofillable_data[i]));
+ CreatePasswordFormFromData(g_autofillable_data[i]));
}
VectorOfForms expected_blacklisted;
- for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(blacklisted_data); ++i) {
+ for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(g_blacklisted_data); ++i) {
expected_blacklisted.push_back(
- CreatePasswordFormFromData(blacklisted_data[i]));
+ CreatePasswordFormFromData(g_blacklisted_data[i]));
}
// Populate the WDS with logins that should be migrated.
@@ -242,11 +409,14 @@
done.Wait();
// Initializing the PasswordStore should trigger a migration.
- scoped_refptr<PasswordStoreDefault> store(
- new PasswordStoreDefault(login_db_.release(), profile_.get(), wds_.get()));
+ scoped_refptr<PasswordStoreX> store(
+ new PasswordStoreX(login_db_.release(),
+ profile_.get(),
+ wds_.get(),
+ GetBackend()));
store->Init();
- // Check that the migration preference has not been initialized;
+ // Check that the migration preference has not been initialized.
ASSERT_TRUE(NULL == profile_->GetPrefs()->FindPreference(
prefs::kLoginDatabaseMigrated));
@@ -319,7 +489,7 @@
STLDeleteElements(&expected_blacklisted);
}
-TEST_F(PasswordStoreDefaultTest, MigrationAlreadyDone) {
+TEST_P(PasswordStoreXTest, WDSMigrationAlreadyDone) {
PasswordFormData wds_data[] = {
{ PasswordForm::SCHEME_HTML,
"http://bar.example.com",
@@ -356,9 +526,11 @@
true);
// Initializing the PasswordStore shouldn't trigger a migration.
- scoped_refptr<PasswordStoreDefault> store(
- new PasswordStoreDefault(login_db_.release(), profile_.get(),
- wds_.get()));
+ scoped_refptr<PasswordStoreX> store(
+ new PasswordStoreX(login_db_.release(),
+ profile_.get(),
+ wds_.get(),
+ GetBackend()));
store->Init();
MockPasswordStoreConsumer consumer;
@@ -379,15 +551,17 @@
STLDeleteElements(&unexpected_autofillable);
}
-TEST_F(PasswordStoreDefaultTest, Notifications) {
- // Prentend that the migration has already taken place.
+TEST_P(PasswordStoreXTest, Notifications) {
+ // Pretend that the migration has already taken place.
profile_->GetPrefs()->RegisterBooleanPref(prefs::kLoginDatabaseMigrated,
true);
// Initializing the PasswordStore shouldn't trigger a migration.
- scoped_refptr<PasswordStoreDefault> store(
- new PasswordStoreDefault(login_db_.release(), profile_.get(),
- wds_.get()));
+ scoped_refptr<PasswordStoreX> store(
+ new PasswordStoreX(login_db_.release(),
+ profile_.get(),
+ wds_.get(),
+ GetBackend()));
store->Init();
PasswordFormData form_data =
@@ -465,3 +639,133 @@
ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, new SignalingTask(&done));
done.Wait();
}
+
+TEST_P(PasswordStoreXTest, NativeMigration) {
+ VectorOfForms expected_autofillable;
+ for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(g_autofillable_data); ++i) {
+ expected_autofillable.push_back(
+ CreatePasswordFormFromData(g_autofillable_data[i]));
+ }
+
+ VectorOfForms expected_blacklisted;
+ for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(g_blacklisted_data); ++i) {
+ expected_blacklisted.push_back(
+ CreatePasswordFormFromData(g_blacklisted_data[i]));
+ }
+
+ LoginDatabase* login_db = login_db_.get();
+
+ // Populate the login DB with logins that should be migrated.
+ for (VectorOfForms::iterator it = expected_autofillable.begin();
+ it != expected_autofillable.end(); ++it) {
+ ChromeThread::PostTask(ChromeThread::DB,
+ FROM_HERE,
+ NewRunnableMethod(login_db,
+ &LoginDatabase::AddLogin,
+ **it));
+ }
+ for (VectorOfForms::iterator it = expected_blacklisted.begin();
+ it != expected_blacklisted.end(); ++it) {
+ ChromeThread::PostTask(ChromeThread::DB,
+ FROM_HERE,
+ NewRunnableMethod(login_db,
+ &LoginDatabase::AddLogin,
+ **it));
+ }
+
+ // Schedule another task on the DB thread to notify us that it's safe to
+ // carry on with the test.
+ WaitableEvent done(false, false);
+ ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, new SignalingTask(&done));
+ done.Wait();
+
+ // Pretend that the WDS migration has already taken place.
+ profile_->GetPrefs()->RegisterBooleanPref(prefs::kLoginDatabaseMigrated,
+ true);
+
+ // Initializing the PasswordStore shouldn't trigger a native migration (yet).
+ scoped_refptr<PasswordStoreX> store(
+ new PasswordStoreX(login_db_.release(),
+ profile_.get(),
+ wds_.get(),
+ GetBackend()));
+ store->Init();
+
+ MockPasswordStoreConsumer consumer;
+
+ // Make sure we quit the MessageLoop even if the test fails.
+ ON_CALL(consumer, OnPasswordStoreRequestDone(_, _))
+ .WillByDefault(QuitUIMessageLoop());
+
+ // The autofillable forms should have been migrated to the native backend.
+ EXPECT_CALL(consumer,
+ OnPasswordStoreRequestDone(_,
+ ContainsAllPasswordForms(expected_autofillable)))
+ .WillOnce(DoAll(WithArg<1>(STLDeleteElements0()), QuitUIMessageLoop()));
+
+ store->GetAutofillableLogins(&consumer);
+ MessageLoop::current()->Run();
+
+ // The blacklisted forms should have been migrated to the native backend.
+ EXPECT_CALL(consumer,
+ OnPasswordStoreRequestDone(_,
+ ContainsAllPasswordForms(expected_blacklisted)))
+ .WillOnce(DoAll(WithArg<1>(STLDeleteElements0()), QuitUIMessageLoop()));
+
+ store->GetBlacklistLogins(&consumer);
+ MessageLoop::current()->Run();
+
+ VectorOfForms empty;
+ MockLoginDatabaseReturn ld_return;
+
+ if (GetParam() == WORKING_BACKEND) {
+ // No autofillable logins should be left in the login DB.
+ EXPECT_CALL(ld_return,
+ OnLoginDatabaseQueryDone(ContainsAllPasswordForms(empty)));
+ } else {
+ // The autofillable logins should still be in the login DB.
+ EXPECT_CALL(ld_return,
+ OnLoginDatabaseQueryDone(
+ ContainsAllPasswordForms(expected_autofillable)))
+ .WillOnce(WithArg<0>(STLDeleteElements0()));
+ }
+
+ ChromeThread::PostTask(ChromeThread::DB, FROM_HERE,
+ new LoginDatabaseQueryTask(login_db, true, &ld_return));
+
+ // Wait for the login DB methods to execute on the DB thread.
+ ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, new SignalingTask(&done));
+ done.Wait();
+
+ if (GetParam() == WORKING_BACKEND) {
+ // Likewise, no blacklisted logins should be left in the login DB.
+ EXPECT_CALL(ld_return,
+ OnLoginDatabaseQueryDone(ContainsAllPasswordForms(empty)));
+ } else {
+ // The blacklisted logins should still be in the login DB.
+ EXPECT_CALL(ld_return,
+ OnLoginDatabaseQueryDone(
+ ContainsAllPasswordForms(expected_blacklisted)))
+ .WillOnce(WithArg<0>(STLDeleteElements0()));
+ }
+
+ ChromeThread::PostTask(ChromeThread::DB, FROM_HERE,
+ new LoginDatabaseQueryTask(login_db, false, &ld_return));
+
+ // Wait for the login DB methods to execute on the DB thread.
+ ChromeThread::PostTask(ChromeThread::DB, FROM_HERE, new SignalingTask(&done));
+ done.Wait();
+
+ STLDeleteElements(&expected_autofillable);
+ STLDeleteElements(&expected_blacklisted);
+}
+
+INSTANTIATE_TEST_CASE_P(NoBackend,
+ PasswordStoreXTest,
+ testing::Values(NO_BACKEND));
+INSTANTIATE_TEST_CASE_P(FailingBackend,
+ PasswordStoreXTest,
+ testing::Values(FAILING_BACKEND));
+INSTANTIATE_TEST_CASE_P(WorkingBackend,
+ PasswordStoreXTest,
+ testing::Values(WORKING_BACKEND));
« no previous file with comments | « chrome/browser/password_manager/password_store_x.cc ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698