summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build/linux/system.gyp35
-rw-r--r--chrome/browser/password_manager/native_backend_gnome_x.cc94
-rw-r--r--chrome/browser/password_manager/native_backend_gnome_x.h46
-rw-r--r--chrome/browser/password_manager/native_backend_gnome_x_unittest.cc767
-rw-r--r--chrome/browser/password_manager/password_store_default_unittest.cc6
-rw-r--r--chrome/browser/password_manager/password_store_x_unittest.cc74
-rw-r--r--chrome/chrome_browser.gypi2
-rw-r--r--chrome/chrome_tests.gypi44
8 files changed, 958 insertions, 110 deletions
diff --git a/build/linux/system.gyp b/build/linux/system.gyp
index 6e8a8be..8d82eab 100644
--- a/build/linux/system.gyp
+++ b/build/linux/system.gyp
@@ -340,7 +340,7 @@
}]]
},
{
- 'target_name': 'gnome-keyring',
+ 'target_name': 'gnome_keyring',
'type': 'settings',
'conditions': [
['use_gnome_keyring==1', {
@@ -379,6 +379,39 @@
],
},
{
+ # The unit tests use a few convenience functions from the GNOME
+ # Keyring library directly. We ignore linux_link_gnome_keyring and
+ # link directly in this version of the target to allow this.
+ # *** Do not use this target in the main binary! ***
+ 'target_name': 'gnome_keyring_direct',
+ 'type': 'settings',
+ 'conditions': [
+ ['use_gnome_keyring==1', {
+ 'direct_dependent_settings': {
+ 'cflags': [
+ '<!@(<(pkg-config) --cflags gnome-keyring-1)',
+ ],
+ 'defines': [
+ 'USE_GNOME_KEYRING',
+ ],
+ 'conditions': [
+ ['linux_link_gnome_keyring==0', {
+ 'defines': ['DLOPEN_GNOME_KEYRING'],
+ }],
+ ],
+ },
+ 'link_settings': {
+ 'ldflags': [
+ '<!@(<(pkg-config) --libs-only-L --libs-only-other gnome-keyring-1)',
+ ],
+ 'libraries': [
+ '<!@(<(pkg-config) --libs-only-l gnome-keyring-1)',
+ ],
+ },
+ }],
+ ],
+ },
+ {
'target_name': 'dbus-glib',
'type': 'settings',
'direct_dependent_settings': {
diff --git a/chrome/browser/password_manager/native_backend_gnome_x.cc b/chrome/browser/password_manager/native_backend_gnome_x.cc
index 80c9c80..2da9b5a 100644
--- a/chrome/browser/password_manager/native_backend_gnome_x.cc
+++ b/chrome/browser/password_manager/native_backend_gnome_x.cc
@@ -23,66 +23,28 @@
using webkit_glue::PasswordForm;
-namespace {
-
-// Many of the gnome_keyring_* functions use variable arguments, which makes
-// them difficult if not impossible to wrap in C. Therefore, we want the
-// actual uses below to either call the functions directly (if we are linking
-// against libgnome-keyring), or call them via appropriately-typed function
-// pointers (if we are dynamically loading libgnome-keyring).
+#define GNOME_KEYRING_DEFINE_POINTER(name) \
+ typeof(&::gnome_keyring_##name) GnomeKeyringLoader::gnome_keyring_##name;
+GNOME_KEYRING_FOR_EACH_FUNC(GNOME_KEYRING_DEFINE_POINTER)
+#undef GNOME_KEYRING_DEFINE_POINTER
-// Thus, instead of making a wrapper class with two implementations, we use
-// the preprocessor to rename the calls below in the dynamic load case, and
-// provide a function to initialize a set of function pointers that have the
-// alternate names. We also make sure the types are correct, since otherwise
-// dynamic loading like this would leave us vulnerable to signature changes.
+bool GnomeKeyringLoader::keyring_loaded = false;
#if defined(DLOPEN_GNOME_KEYRING)
-// Call a given parameter with the name of each function we use from GNOME
-// Keyring.
-#define GNOME_KEYRING_FOR_EACH_FUNC(F) \
- F(is_available) \
- F(store_password) \
- F(delete_password) \
- F(find_itemsv) \
- F(result_to_message)
-
-// Define the actual function pointers that we'll use in application code.
-#define GNOME_KEYRING_DEFINE_WRAPPER(name) \
- typeof(&gnome_keyring_##name) wrap_gnome_keyring_##name;
-GNOME_KEYRING_FOR_EACH_FUNC(GNOME_KEYRING_DEFINE_WRAPPER)
-#undef GNOME_KEYRING_DEFINE_WRAPPER
-
-// Make it easy to initialize the function pointers above with a loop below.
-#define GNOME_KEYRING_FUNCTION(name) \
- {"gnome_keyring_"#name, reinterpret_cast<void**>(&wrap_gnome_keyring_##name)},
-const struct {
- const char* name;
- void** pointer;
-} gnome_keyring_functions[] = {
- GNOME_KEYRING_FOR_EACH_FUNC(GNOME_KEYRING_FUNCTION)
+#define GNOME_KEYRING_FUNCTION_INFO(name) \
+ {"gnome_keyring_"#name, reinterpret_cast<void**>(&gnome_keyring_##name)},
+const GnomeKeyringLoader::FunctionInfo GnomeKeyringLoader::functions[] = {
+ GNOME_KEYRING_FOR_EACH_FUNC(GNOME_KEYRING_FUNCTION_INFO)
{NULL, NULL}
};
-#undef GNOME_KEYRING_FUNCTION
-
-#undef GNOME_KEYRING_FOR_EACH_FUNC
-
-// Allow application code below to use the normal function names, but actually
-// end up using the function pointers above instead.
-#define gnome_keyring_is_available \
- wrap_gnome_keyring_is_available
-#define gnome_keyring_store_password \
- wrap_gnome_keyring_store_password
-#define gnome_keyring_delete_password \
- wrap_gnome_keyring_delete_password
-#define gnome_keyring_find_itemsv \
- wrap_gnome_keyring_find_itemsv
-#define gnome_keyring_result_to_message \
- wrap_gnome_keyring_result_to_message
+#undef GNOME_KEYRING_FUNCTION_INFO
/* Load the library and initialize the function pointers. */
-bool LoadGnomeKeyring() {
+bool GnomeKeyringLoader::LoadGnomeKeyring() {
+ if (keyring_loaded)
+ return true;
+
void* handle = dlopen("libgnome-keyring.so.0", RTLD_NOW | RTLD_GLOBAL);
if (!handle) {
// We wanted to use GNOME Keyring, but we couldn't load it. Warn, because
@@ -91,30 +53,40 @@ bool LoadGnomeKeyring() {
LOG(WARNING) << "Could not load libgnome-keyring.so.0: " << dlerror();
return false;
}
- for (size_t i = 0; gnome_keyring_functions[i].name; ++i) {
+
+ for (size_t i = 0; functions[i].name; ++i) {
dlerror();
- *gnome_keyring_functions[i].pointer =
- dlsym(handle, gnome_keyring_functions[i].name);
+ *functions[i].pointer = dlsym(handle, functions[i].name);
const char* error = dlerror();
if (error) {
LOG(ERROR) << "Unable to load symbol "
- << gnome_keyring_functions[i].name << ": " << error;
+ << functions[i].name << ": " << error;
dlclose(handle);
return false;
}
}
+
+ keyring_loaded = true;
// We leak the library handle. That's OK: this function is called only once.
return true;
}
-#else // !defined(DLOPEN_GNOME_KEYRING)
+#else // defined(DLOPEN_GNOME_KEYRING)
-bool LoadGnomeKeyring() {
- // We don't need to do anything here.
+bool GnomeKeyringLoader::LoadGnomeKeyring() {
+ if (keyring_loaded)
+ return true;
+#define GNOME_KEYRING_ASSIGN_POINTER(name) \
+ gnome_keyring_##name = &::gnome_keyring_##name;
+ GNOME_KEYRING_FOR_EACH_FUNC(GNOME_KEYRING_ASSIGN_POINTER)
+#undef GNOME_KEYRING_ASSIGN_POINTER
+ keyring_loaded = true;
return true;
}
-#endif // !defined(DLOPEN_GNOME_KEYRING)
+#endif // defined(DLOPEN_GNOME_KEYRING)
+
+namespace {
const char kGnomeKeyringAppString[] = "chrome";
@@ -221,7 +193,7 @@ const GnomeKeyringPasswordSchema kGnomeSchema = {
// a WaitResult() method should be called to wait for the result. Each instance
// supports only one outstanding method at a time, though multiple instances may
// be used in parallel.
-class GKRMethod {
+class GKRMethod : public GnomeKeyringLoader {
public:
typedef NativeBackendGnome::PasswordFormList PasswordFormList;
diff --git a/chrome/browser/password_manager/native_backend_gnome_x.h b/chrome/browser/password_manager/native_backend_gnome_x.h
index 1740c42..88f4250 100644
--- a/chrome/browser/password_manager/native_backend_gnome_x.h
+++ b/chrome/browser/password_manager/native_backend_gnome_x.h
@@ -6,6 +6,8 @@
#define CHROME_BROWSER_PASSWORD_MANAGER_NATIVE_BACKEND_GNOME_X_H_
#pragma once
+#include <gnome-keyring.h>
+
#include <string>
#include "base/basictypes.h"
@@ -19,8 +21,50 @@ namespace webkit_glue {
struct PasswordForm;
}
+// Many of the gnome_keyring_* functions use variable arguments, which makes
+// them difficult if not impossible to truly wrap in C. Therefore, we use
+// appropriately-typed function pointers and scoping to make the fact that we
+// might be dynamically loading the library almost invisible. As a bonus, we
+// also get a simple way to mock the library for testing. Classes that inherit
+// from GnomeKeyringLoader will use its versions of the gnome_keyring_*
+// functions. Note that it has only static fields.
+class GnomeKeyringLoader {
+ protected:
+ static bool LoadGnomeKeyring();
+
+// Call a given parameter with the name of each function we use from GNOME
+// Keyring. Make sure to adjust the unit test if you change these.
+#define GNOME_KEYRING_FOR_EACH_FUNC(F) \
+ F(is_available) \
+ F(store_password) \
+ F(delete_password) \
+ F(find_itemsv) \
+ F(result_to_message)
+
+// Declare the actual function pointers that we'll use in client code.
+#define GNOME_KEYRING_DECLARE_POINTER(name) \
+ static typeof(&::gnome_keyring_##name) gnome_keyring_##name;
+ GNOME_KEYRING_FOR_EACH_FUNC(GNOME_KEYRING_DECLARE_POINTER)
+#undef GNOME_KEYRING_DECLARE_POINTER
+
+ // Set to true if LoadGnomeKeyring() has already succeeded.
+ static bool keyring_loaded;
+
+ private:
+#if defined(DLOPEN_GNOME_KEYRING)
+ struct FunctionInfo {
+ const char* name;
+ void** pointer;
+ };
+
+ // Make it easy to initialize the function pointers in LoadGnomeKeyring().
+ static const FunctionInfo functions[];
+#endif // defined(DLOPEN_GNOME_KEYRING)
+};
+
// NativeBackend implementation using GNOME Keyring.
-class NativeBackendGnome : public PasswordStoreX::NativeBackend {
+class NativeBackendGnome : public PasswordStoreX::NativeBackend,
+ public GnomeKeyringLoader {
public:
NativeBackendGnome(LocalProfileId id, PrefService* prefs);
diff --git a/chrome/browser/password_manager/native_backend_gnome_x_unittest.cc b/chrome/browser/password_manager/native_backend_gnome_x_unittest.cc
new file mode 100644
index 0000000..232278b
--- /dev/null
+++ b/chrome/browser/password_manager/native_backend_gnome_x_unittest.cc
@@ -0,0 +1,767 @@
+// Copyright (c) 2011 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 <stdarg.h>
+
+#include "base/basictypes.h"
+#include "base/stl_util-inl.h"
+#include "base/string_util.h"
+#include "base/time.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/password_manager/native_backend_gnome_x.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/testing_profile.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using webkit_glue::PasswordForm;
+
+namespace {
+
+// What follows is a very simple implementation of the subset of the GNOME
+// Keyring API that we actually use. It gets substituted for the real one by
+// MockGnomeKeyringLoader, which hooks into the facility normally used to load
+// the GNOME Keyring library at runtime to avoid a static dependency on it.
+
+struct MockKeyringItem {
+ MockKeyringItem() {}
+ MockKeyringItem(const char* keyring,
+ const std::string& display_name,
+ const std::string& password)
+ : keyring(keyring ? keyring : "login"),
+ display_name(display_name),
+ password(password) {}
+
+ struct ItemAttribute {
+ ItemAttribute() : type(UINT32), value_uint32(0) {}
+ explicit ItemAttribute(uint32_t value)
+ : type(UINT32), value_uint32(value) {}
+ explicit ItemAttribute(const std::string& value)
+ : type(STRING), value_string(value) {}
+
+ bool Equals(const ItemAttribute& x) const {
+ if (type != x.type) return false;
+ return (type == STRING) ? value_string == x.value_string
+ : value_uint32 == x.value_uint32;
+ }
+
+ enum { UINT32, STRING } type;
+ uint32_t value_uint32;
+ std::string value_string;
+ };
+
+ typedef std::map<std::string, ItemAttribute> attribute_map;
+ typedef std::vector<std::pair<std::string, ItemAttribute> > attribute_query;
+
+ bool Matches(const attribute_query& query) const {
+ // The real GNOME Keyring doesn't match empty queries.
+ if (query.empty()) return false;
+ for (size_t i = 0; i < query.size(); ++i) {
+ attribute_map::const_iterator match = attributes.find(query[i].first);
+ if (match == attributes.end()) return false;
+ if (!match->second.Equals(query[i].second)) return false;
+ }
+ return true;
+ }
+
+ std::string keyring;
+ std::string display_name;
+ std::string password;
+
+ attribute_map attributes;
+};
+
+// The list of all keyring items we have stored.
+std::vector<MockKeyringItem> mock_keyring_items;
+bool mock_keyring_reject_local_ids = false;
+
+bool IsStringAttribute(const GnomeKeyringPasswordSchema* schema,
+ const std::string& name) {
+ for (size_t i = 0; schema->attributes[i].name; ++i)
+ if (name == schema->attributes[i].name)
+ return schema->attributes[i].type == GNOME_KEYRING_ATTRIBUTE_TYPE_STRING;
+ NOTREACHED() << "Requested type of nonexistent attribute";
+ return false;
+}
+
+gboolean mock_gnome_keyring_is_available() {
+ return true;
+}
+
+gpointer mock_gnome_keyring_store_password(
+ const GnomeKeyringPasswordSchema* schema,
+ const gchar* keyring,
+ const gchar* display_name,
+ const gchar* password,
+ GnomeKeyringOperationDoneCallback callback,
+ gpointer data,
+ GDestroyNotify destroy_data,
+ ...) {
+ mock_keyring_items.push_back(
+ MockKeyringItem(keyring, display_name, password));
+ MockKeyringItem* item = &mock_keyring_items.back();
+ const std::string keyring_desc = keyring ? StringPrintf("keyring %s", keyring)
+ : std::string("default keyring");
+ VLOG(1) << "Adding item with origin " << display_name
+ << " to " << keyring_desc;
+ va_list ap;
+ va_start(ap, destroy_data);
+ char* name;
+ while ((name = va_arg(ap, gchar*))) {
+ if (IsStringAttribute(schema, name)) {
+ item->attributes[name] =
+ MockKeyringItem::ItemAttribute(va_arg(ap, gchar*));
+ VLOG(1) << "Adding item attribute " << name
+ << ", value '" << item->attributes[name].value_string << "'";
+ } else {
+ item->attributes[name] =
+ MockKeyringItem::ItemAttribute(va_arg(ap, uint32_t));
+ VLOG(1) << "Adding item attribute " << name
+ << ", value " << item->attributes[name].value_uint32;
+ }
+ }
+ va_end(ap);
+ // As a hack to ease testing migration, make it possible to reject the new
+ // format for the app string. This way we can add them easily to migrate.
+ if (mock_keyring_reject_local_ids) {
+ MockKeyringItem::attribute_map::iterator it =
+ item->attributes.find("application");
+ if (it != item->attributes.end() &&
+ it->second.type == MockKeyringItem::ItemAttribute::STRING &&
+ base::StringPiece(it->second.value_string).starts_with("chrome-")) {
+ mock_keyring_items.pop_back();
+ // GnomeKeyringResult, data
+ callback(GNOME_KEYRING_RESULT_IO_ERROR, data);
+ return NULL;
+ }
+ }
+ // GnomeKeyringResult, data
+ callback(GNOME_KEYRING_RESULT_OK, data);
+ return NULL;
+}
+
+gpointer mock_gnome_keyring_delete_password(
+ const GnomeKeyringPasswordSchema* schema,
+ GnomeKeyringOperationDoneCallback callback,
+ gpointer data,
+ GDestroyNotify destroy_data,
+ ...) {
+ MockKeyringItem::attribute_query query;
+ va_list ap;
+ va_start(ap, destroy_data);
+ char* name;
+ while ((name = va_arg(ap, gchar*))) {
+ if (IsStringAttribute(schema, name)) {
+ query.push_back(make_pair(std::string(name),
+ MockKeyringItem::ItemAttribute(va_arg(ap, gchar*))));
+ VLOG(1) << "Querying with item attribute " << name
+ << ", value '" << query.back().second.value_string << "'";
+ } else {
+ query.push_back(make_pair(std::string(name),
+ MockKeyringItem::ItemAttribute(va_arg(ap, uint32_t))));
+ VLOG(1) << "Querying with item attribute " << name
+ << ", value " << query.back().second.value_uint32;
+ }
+ }
+ va_end(ap);
+ bool deleted = false;
+ for (size_t i = mock_keyring_items.size(); i > 0; --i) {
+ const MockKeyringItem* item = &mock_keyring_items[i - 1];
+ if (item->Matches(query)) {
+ VLOG(1) << "Deleting item with origin " << item->display_name;
+ mock_keyring_items.erase(mock_keyring_items.begin() + (i - 1));
+ deleted = true;
+ }
+ }
+ // GnomeKeyringResult, data
+ callback(deleted ? GNOME_KEYRING_RESULT_OK
+ : GNOME_KEYRING_RESULT_NO_MATCH, data);
+ return NULL;
+}
+
+gpointer mock_gnome_keyring_find_itemsv(
+ GnomeKeyringItemType type,
+ GnomeKeyringOperationGetListCallback callback,
+ gpointer data,
+ GDestroyNotify destroy_data,
+ ...) {
+ MockKeyringItem::attribute_query query;
+ va_list ap;
+ va_start(ap, destroy_data);
+ char* name;
+ while ((name = va_arg(ap, gchar*))) {
+ // Really a GnomeKeyringAttributeType, but promoted to int through ...
+ if (va_arg(ap, int) == GNOME_KEYRING_ATTRIBUTE_TYPE_STRING) {
+ query.push_back(make_pair(std::string(name),
+ MockKeyringItem::ItemAttribute(va_arg(ap, gchar*))));
+ VLOG(1) << "Querying with item attribute " << name
+ << ", value '" << query.back().second.value_string << "'";
+ } else {
+ query.push_back(make_pair(std::string(name),
+ MockKeyringItem::ItemAttribute(va_arg(ap, uint32_t))));
+ VLOG(1) << "Querying with item attribute " << name
+ << ", value " << query.back().second.value_uint32;
+ }
+ }
+ va_end(ap);
+ // Find matches and add them to a list of results.
+ GList* results = NULL;
+ for (size_t i = 0; i < mock_keyring_items.size(); ++i) {
+ const MockKeyringItem* item = &mock_keyring_items[i];
+ if (item->Matches(query)) {
+ GnomeKeyringFound* found = new GnomeKeyringFound;
+ found->keyring = strdup(item->keyring.c_str());
+ found->item_id = i;
+ found->attributes = gnome_keyring_attribute_list_new();
+ for (MockKeyringItem::attribute_map::const_iterator it =
+ item->attributes.begin();
+ it != item->attributes.end();
+ ++it) {
+ if (it->second.type == MockKeyringItem::ItemAttribute::STRING) {
+ gnome_keyring_attribute_list_append_string(
+ found->attributes, it->first.c_str(),
+ it->second.value_string.c_str());
+ } else {
+ gnome_keyring_attribute_list_append_uint32(
+ found->attributes, it->first.c_str(),
+ it->second.value_uint32);
+ }
+ }
+ found->secret = strdup(item->password.c_str());
+ results = g_list_prepend(results, found);
+ }
+ }
+ // GnomeKeyringResult, GList*, data
+ callback(results ? GNOME_KEYRING_RESULT_OK
+ : GNOME_KEYRING_RESULT_NO_MATCH, results, data);
+ // Now free the list of results.
+ GList* element = g_list_first(results);
+ while (element) {
+ GnomeKeyringFound* found = static_cast<GnomeKeyringFound*>(element->data);
+ free(found->keyring);
+ gnome_keyring_attribute_list_free(found->attributes);
+ free(found->secret);
+ element = g_list_next(element);
+ }
+ g_list_free(results);
+ return NULL;
+}
+
+const gchar* mock_gnome_keyring_result_to_message(GnomeKeyringResult res) {
+ return "mock keyring simulating failure";
+}
+
+// Inherit to get access to protected fields.
+class MockGnomeKeyringLoader : public GnomeKeyringLoader {
+ public:
+ static bool LoadMockGnomeKeyring() {
+#define GNOME_KEYRING_ASSIGN_POINTER(name) \
+ gnome_keyring_##name = &mock_gnome_keyring_##name;
+ GNOME_KEYRING_FOR_EACH_FUNC(GNOME_KEYRING_ASSIGN_POINTER)
+#undef GNOME_KEYRING_ASSIGN_POINTER
+ keyring_loaded = true;
+ // Reset the state of the mock library.
+ mock_keyring_items.clear();
+ mock_keyring_reject_local_ids = false;
+ return true;
+ }
+};
+
+} // anonymous namespace
+
+// NativeBackendGnome 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<NativeBackendGnome> {
+ void RetainCallee(NativeBackendGnome*) {}
+ void ReleaseCallee(NativeBackendGnome*) {}
+};
+
+class NativeBackendGnomeTest : public testing::Test {
+ protected:
+ NativeBackendGnomeTest()
+ : ui_thread_(BrowserThread::UI, &message_loop_),
+ db_thread_(BrowserThread::DB) {
+ }
+
+ virtual void SetUp() {
+ ASSERT_TRUE(db_thread_.Start());
+
+ MockGnomeKeyringLoader::LoadMockGnomeKeyring();
+ profile_.reset(new TestingProfile());
+
+ form_google_.origin = GURL("http://www.google.com/");
+ form_google_.action = GURL("http://www.google.com/login");
+ form_google_.username_element = UTF8ToUTF16("user");
+ form_google_.username_value = UTF8ToUTF16("joeschmoe");
+ form_google_.password_element = UTF8ToUTF16("pass");
+ form_google_.password_value = UTF8ToUTF16("seekrit");
+ form_google_.submit_element = UTF8ToUTF16("submit");
+ form_google_.signon_realm = "Google";
+
+ form_isc_.origin = GURL("http://www.isc.org/");
+ form_isc_.action = GURL("http://www.isc.org/auth");
+ form_isc_.username_element = UTF8ToUTF16("id");
+ form_isc_.username_value = UTF8ToUTF16("janedoe");
+ form_isc_.password_element = UTF8ToUTF16("passwd");
+ form_isc_.password_value = UTF8ToUTF16("ihazabukkit");
+ form_isc_.submit_element = UTF8ToUTF16("login");
+ form_isc_.signon_realm = "ISC";
+ }
+
+ virtual void TearDown() {
+ MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask);
+ MessageLoop::current()->Run();
+ db_thread_.Stop();
+ }
+
+ void RunBothThreads() {
+ // First we post a message to the DB thread that will run after all other
+ // messages that have been posted to the DB thread (we don't expect more
+ // to be posted), which posts a message to the UI thread to quit the loop.
+ // That way we can run both loops and be sure that the UI thread loop will
+ // quit so we can get on with the rest of the test.
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+ NewRunnableFunction(&PostQuitTask, &message_loop_));
+ MessageLoop::current()->Run();
+ }
+
+ static void PostQuitTask(MessageLoop* loop) {
+ loop->PostTask(FROM_HERE, new MessageLoop::QuitTask);
+ }
+
+ void CheckUint32Attribute(const MockKeyringItem* item,
+ const std::string& attribute,
+ uint32_t value) {
+ MockKeyringItem::attribute_map::const_iterator it =
+ item->attributes.find(attribute);
+ EXPECT_NE(item->attributes.end(), it);
+ if (it != item->attributes.end()) {
+ EXPECT_EQ(MockKeyringItem::ItemAttribute::UINT32, it->second.type);
+ EXPECT_EQ(value, it->second.value_uint32);
+ }
+ }
+
+ void CheckStringAttribute(const MockKeyringItem* item,
+ const std::string& attribute,
+ const std::string& value) {
+ MockKeyringItem::attribute_map::const_iterator it =
+ item->attributes.find(attribute);
+ EXPECT_NE(item->attributes.end(), it);
+ if (it != item->attributes.end()) {
+ EXPECT_EQ(MockKeyringItem::ItemAttribute::STRING, it->second.type);
+ EXPECT_EQ(value, it->second.value_string);
+ }
+ }
+
+ void CheckMockKeyringItem(const MockKeyringItem* item,
+ const PasswordForm& form,
+ const std::string& app_string) {
+ // We always add items to the login keyring.
+ EXPECT_EQ("login", item->keyring);
+ EXPECT_EQ(form.origin.spec(), item->display_name);
+ EXPECT_EQ(UTF16ToUTF8(form.password_value), item->password);
+ EXPECT_EQ(13u, item->attributes.size());
+ CheckStringAttribute(item, "origin_url", form.origin.spec());
+ CheckStringAttribute(item, "action_url", form.action.spec());
+ CheckStringAttribute(item, "username_element",
+ UTF16ToUTF8(form.username_element));
+ CheckStringAttribute(item, "username_value",
+ UTF16ToUTF8(form.username_value));
+ CheckStringAttribute(item, "password_element",
+ UTF16ToUTF8(form.password_element));
+ CheckStringAttribute(item, "submit_element",
+ UTF16ToUTF8(form.submit_element));
+ CheckStringAttribute(item, "signon_realm", form.signon_realm);
+ CheckUint32Attribute(item, "ssl_valid", form.ssl_valid);
+ CheckUint32Attribute(item, "preferred", form.preferred);
+ // We don't check the date created. It varies.
+ CheckUint32Attribute(item, "blacklisted_by_user", form.blacklisted_by_user);
+ CheckUint32Attribute(item, "scheme", form.scheme);
+ CheckStringAttribute(item, "application", app_string);
+ }
+
+ MessageLoopForUI message_loop_;
+ BrowserThread ui_thread_;
+ BrowserThread db_thread_;
+
+ scoped_ptr<TestingProfile> profile_;
+
+ // Provide some test forms to avoid having to set them up in each test.
+ PasswordForm form_google_;
+ PasswordForm form_isc_;
+};
+
+TEST_F(NativeBackendGnomeTest, BasicAddLogin) {
+ // Pretend that the migration has already taken place.
+ profile_->GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
+
+ NativeBackendGnome backend(42, profile_->GetPrefs());
+ backend.Init();
+
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+ NewRunnableMethod(&backend,
+ &NativeBackendGnome::AddLogin,
+ form_google_));
+
+ RunBothThreads();
+
+ EXPECT_EQ(1u, mock_keyring_items.size());
+ if (mock_keyring_items.size() > 0)
+ CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42");
+}
+
+TEST_F(NativeBackendGnomeTest, BasicListLogins) {
+ // Pretend that the migration has already taken place.
+ profile_->GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
+
+ NativeBackendGnome backend(42, profile_->GetPrefs());
+ backend.Init();
+
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+ NewRunnableMethod(&backend,
+ &NativeBackendGnome::AddLogin,
+ form_google_));
+
+ std::vector<PasswordForm*> form_list;
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+ NewRunnableMethod(&backend,
+ &NativeBackendGnome::GetAutofillableLogins,
+ &form_list));
+
+ RunBothThreads();
+
+ // Quick check that we got something back.
+ EXPECT_EQ(1u, form_list.size());
+ STLDeleteElements(&form_list);
+
+ EXPECT_EQ(1u, mock_keyring_items.size());
+ if (mock_keyring_items.size() > 0)
+ CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42");
+}
+
+TEST_F(NativeBackendGnomeTest, BasicRemoveLogin) {
+ // Pretend that the migration has already taken place.
+ profile_->GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
+
+ NativeBackendGnome backend(42, profile_->GetPrefs());
+ backend.Init();
+
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+ NewRunnableMethod(&backend,
+ &NativeBackendGnome::AddLogin,
+ form_google_));
+
+ RunBothThreads();
+
+ EXPECT_EQ(1u, mock_keyring_items.size());
+ if (mock_keyring_items.size() > 0)
+ CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42");
+
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+ NewRunnableMethod(&backend,
+ &NativeBackendGnome::RemoveLogin,
+ form_google_));
+
+ RunBothThreads();
+
+ EXPECT_EQ(0u, mock_keyring_items.size());
+}
+
+TEST_F(NativeBackendGnomeTest, RemoveNonexistentLogin) {
+ // Pretend that the migration has already taken place.
+ profile_->GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
+
+ NativeBackendGnome backend(42, profile_->GetPrefs());
+ backend.Init();
+
+ // First add an unrelated login.
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+ NewRunnableMethod(&backend,
+ &NativeBackendGnome::AddLogin,
+ form_google_));
+
+ RunBothThreads();
+
+ EXPECT_EQ(1u, mock_keyring_items.size());
+ if (mock_keyring_items.size() > 0)
+ CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42");
+
+ // Attempt to remove a login that doesn't exist.
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+ NewRunnableMethod(&backend,
+ &NativeBackendGnome::RemoveLogin,
+ form_isc_));
+
+ // Make sure we can still get the first form back.
+ std::vector<PasswordForm*> form_list;
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+ NewRunnableMethod(&backend,
+ &NativeBackendGnome::GetAutofillableLogins,
+ &form_list));
+
+ RunBothThreads();
+
+ // Quick check that we got something back.
+ EXPECT_EQ(1u, form_list.size());
+ STLDeleteElements(&form_list);
+
+ EXPECT_EQ(1u, mock_keyring_items.size());
+ if (mock_keyring_items.size() > 0)
+ CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42");
+}
+
+TEST_F(NativeBackendGnomeTest, AddDuplicateLogin) {
+ // Pretend that the migration has already taken place.
+ profile_->GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
+
+ NativeBackendGnome backend(42, profile_->GetPrefs());
+ backend.Init();
+
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+ NewRunnableMethod(&backend,
+ &NativeBackendGnome::AddLogin,
+ form_google_));
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+ NewRunnableMethod(&backend,
+ &NativeBackendGnome::AddLogin,
+ form_google_));
+
+ RunBothThreads();
+
+ EXPECT_EQ(1u, mock_keyring_items.size());
+ if (mock_keyring_items.size() > 0)
+ CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42");
+}
+
+// TODO(mdm): add more basic (i.e. non-migration) tests here at some point.
+
+TEST_F(NativeBackendGnomeTest, MigrateOneLogin) {
+ // Reject attempts to migrate so we can populate the store.
+ mock_keyring_reject_local_ids = true;
+
+ {
+ NativeBackendGnome backend(42, profile_->GetPrefs());
+ backend.Init();
+
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+ NewRunnableMethod(&backend,
+ &NativeBackendGnome::AddLogin,
+ form_google_));
+
+ // Make sure we can get the form back even when migration is failing.
+ std::vector<PasswordForm*> form_list;
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+ NewRunnableMethod(&backend,
+ &NativeBackendGnome::GetAutofillableLogins,
+ &form_list));
+
+ RunBothThreads();
+
+ // Quick check that we got something back.
+ EXPECT_EQ(1u, form_list.size());
+ STLDeleteElements(&form_list);
+ }
+
+ EXPECT_EQ(1u, mock_keyring_items.size());
+ if (mock_keyring_items.size() > 0)
+ CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
+
+ // Now allow the migration.
+ mock_keyring_reject_local_ids = false;
+
+ {
+ NativeBackendGnome backend(42, profile_->GetPrefs());
+ backend.Init();
+
+ // This should not trigger migration because there will be no results.
+ std::vector<PasswordForm*> form_list;
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+ NewRunnableMethod(&backend,
+ &NativeBackendGnome::GetBlacklistLogins,
+ &form_list));
+
+ RunBothThreads();
+
+ // Check that we got nothing back.
+ EXPECT_EQ(0u, form_list.size());
+ STLDeleteElements(&form_list);
+ }
+
+ // Check that the keyring is unmodified.
+ EXPECT_EQ(1u, mock_keyring_items.size());
+ if (mock_keyring_items.size() > 0)
+ CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
+
+ // Check that we haven't set the persistent preference.
+ EXPECT_FALSE(
+ profile_->GetPrefs()->GetBoolean(prefs::kPasswordsUseLocalProfileId));
+
+ {
+ NativeBackendGnome backend(42, profile_->GetPrefs());
+ backend.Init();
+
+ // Trigger the migration by looking something up.
+ std::vector<PasswordForm*> form_list;
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+ NewRunnableMethod(&backend,
+ &NativeBackendGnome::GetAutofillableLogins,
+ &form_list));
+
+ RunBothThreads();
+
+ // Quick check that we got something back.
+ EXPECT_EQ(1u, form_list.size());
+ STLDeleteElements(&form_list);
+ }
+
+ EXPECT_EQ(2u, mock_keyring_items.size());
+ if (mock_keyring_items.size() > 0)
+ CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
+ if (mock_keyring_items.size() > 1)
+ CheckMockKeyringItem(&mock_keyring_items[1], form_google_, "chrome-42");
+
+ // Check that we have set the persistent preference.
+ EXPECT_TRUE(
+ profile_->GetPrefs()->GetBoolean(prefs::kPasswordsUseLocalProfileId));
+}
+
+TEST_F(NativeBackendGnomeTest, MigrateToMultipleProfiles) {
+ // Reject attempts to migrate so we can populate the store.
+ mock_keyring_reject_local_ids = true;
+
+ {
+ NativeBackendGnome backend(42, profile_->GetPrefs());
+ backend.Init();
+
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+ NewRunnableMethod(&backend,
+ &NativeBackendGnome::AddLogin,
+ form_google_));
+
+ RunBothThreads();
+ }
+
+ EXPECT_EQ(1u, mock_keyring_items.size());
+ if (mock_keyring_items.size() > 0)
+ CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
+
+ // Now allow the migration.
+ mock_keyring_reject_local_ids = false;
+
+ {
+ NativeBackendGnome backend(42, profile_->GetPrefs());
+ backend.Init();
+
+ // Trigger the migration by looking something up.
+ std::vector<PasswordForm*> form_list;
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+ NewRunnableMethod(&backend,
+ &NativeBackendGnome::GetAutofillableLogins,
+ &form_list));
+
+ RunBothThreads();
+
+ // Quick check that we got something back.
+ EXPECT_EQ(1u, form_list.size());
+ STLDeleteElements(&form_list);
+ }
+
+ EXPECT_EQ(2u, mock_keyring_items.size());
+ if (mock_keyring_items.size() > 0)
+ CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
+ if (mock_keyring_items.size() > 1)
+ CheckMockKeyringItem(&mock_keyring_items[1], form_google_, "chrome-42");
+
+ // Check that we have set the persistent preference.
+ EXPECT_TRUE(
+ profile_->GetPrefs()->GetBoolean(prefs::kPasswordsUseLocalProfileId));
+
+ // Normally we'd actually have a different profile. But in the test just reset
+ // the profile's persistent pref; we pass in the local profile id anyway.
+ profile_->GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, false);
+
+ {
+ NativeBackendGnome backend(24, profile_->GetPrefs());
+ backend.Init();
+
+ // Trigger the migration by looking something up.
+ std::vector<PasswordForm*> form_list;
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+ NewRunnableMethod(&backend,
+ &NativeBackendGnome::GetAutofillableLogins,
+ &form_list));
+
+ RunBothThreads();
+
+ // Quick check that we got something back.
+ EXPECT_EQ(1u, form_list.size());
+ STLDeleteElements(&form_list);
+ }
+
+ EXPECT_EQ(3u, mock_keyring_items.size());
+ if (mock_keyring_items.size() > 0)
+ CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
+ if (mock_keyring_items.size() > 1)
+ CheckMockKeyringItem(&mock_keyring_items[1], form_google_, "chrome-42");
+ if (mock_keyring_items.size() > 2)
+ CheckMockKeyringItem(&mock_keyring_items[2], form_google_, "chrome-24");
+}
+
+TEST_F(NativeBackendGnomeTest, NoMigrationWithPrefSet) {
+ // Reject attempts to migrate so we can populate the store.
+ mock_keyring_reject_local_ids = true;
+
+ {
+ NativeBackendGnome backend(42, profile_->GetPrefs());
+ backend.Init();
+
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+ NewRunnableMethod(&backend,
+ &NativeBackendGnome::AddLogin,
+ form_google_));
+
+ RunBothThreads();
+ }
+
+ EXPECT_EQ(1u, mock_keyring_items.size());
+ if (mock_keyring_items.size() > 0)
+ CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
+
+ // Now allow migration, but also pretend that the it has already taken place.
+ mock_keyring_reject_local_ids = false;
+ profile_->GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
+
+ {
+ NativeBackendGnome backend(42, profile_->GetPrefs());
+ backend.Init();
+
+ // Trigger the migration by adding a new login.
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+ NewRunnableMethod(&backend,
+ &NativeBackendGnome::AddLogin,
+ form_isc_));
+
+ // Look up all logins; we expect only the one we added.
+ std::vector<PasswordForm*> form_list;
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+ NewRunnableMethod(&backend,
+ &NativeBackendGnome::GetAutofillableLogins,
+ &form_list));
+
+ RunBothThreads();
+
+ // Quick check that we got the right thing back.
+ EXPECT_EQ(1u, form_list.size());
+ if (form_list.size() > 0)
+ EXPECT_EQ(form_isc_.signon_realm, form_list[0]->signon_realm);
+ STLDeleteElements(&form_list);
+ }
+
+ EXPECT_EQ(2u, mock_keyring_items.size());
+ if (mock_keyring_items.size() > 0)
+ CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
+ if (mock_keyring_items.size() > 1)
+ CheckMockKeyringItem(&mock_keyring_items[1], form_isc_, "chrome-42");
+}
diff --git a/chrome/browser/password_manager/password_store_default_unittest.cc b/chrome/browser/password_manager/password_store_default_unittest.cc
index 06ec903..57651c4 100644
--- a/chrome/browser/password_manager/password_store_default_unittest.cc
+++ b/chrome/browser/password_manager/password_store_default_unittest.cc
@@ -151,7 +151,7 @@ MATCHER(EmptyWDResult, "") {
}
TEST_F(PasswordStoreDefaultTest, NonASCIIData) {
- // Prentend that the migration has already taken place.
+ // Pretend that the migration has already taken place.
profile_->GetPrefs()->RegisterBooleanPref(prefs::kLoginDatabaseMigrated,
true,
PrefService::UNSYNCABLE_PREF);
@@ -399,7 +399,7 @@ TEST_F(PasswordStoreDefaultTest, MigrationAlreadyDone) {
new SignalingTask(&done));
done.Wait();
- // Prentend that the migration has already taken place.
+ // Pretend that the migration has already taken place.
profile_->GetPrefs()->RegisterBooleanPref(prefs::kLoginDatabaseMigrated,
true,
PrefService::UNSYNCABLE_PREF);
@@ -431,7 +431,7 @@ TEST_F(PasswordStoreDefaultTest, MigrationAlreadyDone) {
}
TEST_F(PasswordStoreDefaultTest, Notifications) {
- // Prentend that the migration has already taken place.
+ // Pretend that the migration has already taken place.
profile_->GetPrefs()->RegisterBooleanPref(prefs::kLoginDatabaseMigrated,
true,
PrefService::UNSYNCABLE_PREF);
diff --git a/chrome/browser/password_manager/password_store_x_unittest.cc b/chrome/browser/password_manager/password_store_x_unittest.cc
index 1a6b9bd..efcec40 100644
--- a/chrome/browser/password_manager/password_store_x_unittest.cc
+++ b/chrome/browser/password_manager/password_store_x_unittest.cc
@@ -3,20 +3,28 @@
// found in the LICENSE file.
#include "base/basictypes.h"
+#include "base/file_util.h"
+#include "base/platform_file.h"
#include "base/scoped_temp_dir.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "base/synchronization/waitable_event.h"
#include "base/time.h"
+#include "base/utf_string_conversions.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_consumer.h"
#include "chrome/browser/password_manager/password_store_x.h"
+#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/webdata/web_data_service.h"
+#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/signaling_task.h"
#include "chrome/test/testing_profile.h"
+#include "content/common/notification_details.h"
#include "content/common/notification_observer_mock.h"
-#include "content/common/notification_service.h"
+#include "content/common/notification_registrar.h"
+#include "content/common/notification_source.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -54,12 +62,14 @@ class DBThreadObserverHelper
public:
DBThreadObserverHelper() : done_event_(true, false) {}
- void Init() {
+ void Init(PasswordStore* password_store) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
BrowserThread::PostTask(
BrowserThread::DB,
FROM_HERE,
- NewRunnableMethod(this, &DBThreadObserverHelper::AddObserverTask));
+ NewRunnableMethod(this,
+ &DBThreadObserverHelper::AddObserverTask,
+ make_scoped_refptr(password_store)));
done_event_.Wait();
}
@@ -75,11 +85,11 @@ class DBThreadObserverHelper
protected:
friend class base::RefCountedThreadSafe<DBThreadObserverHelper>;
- void AddObserverTask() {
+ void AddObserverTask(PasswordStore* password_store) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
registrar_.Add(&observer_,
- chrome::LOGINS_CHANGED,
- NotificationService::AllSources());
+ chrome::NOTIFICATION_LOGINS_CHANGED,
+ Source<PasswordStore>(password_store));
done_event_.Signal();
}
@@ -357,9 +367,9 @@ TEST_P(PasswordStoreXTest, WDSMigration) {
// Initializing the PasswordStore should trigger a migration.
scoped_refptr<PasswordStoreX> store(
new PasswordStoreX(login_db_.release(),
- profile_.get(),
- wds_.get(),
- GetBackend()));
+ profile_.get(),
+ wds_.get(),
+ GetBackend()));
store->Init();
// Check that the migration preference has not been initialized.
@@ -437,7 +447,8 @@ TEST_P(PasswordStoreXTest, WDSMigration) {
STLDeleteElements(&expected_autofillable);
STLDeleteElements(&expected_blacklisted);
- store->Shutdown();
+ // Public in PasswordStore, protected in PasswordStoreX.
+ static_cast<PasswordStore*>(store)->Shutdown();
}
TEST_P(PasswordStoreXTest, WDSMigrationAlreadyDone) {
@@ -473,7 +484,7 @@ TEST_P(PasswordStoreXTest, WDSMigrationAlreadyDone) {
new SignalingTask(&done));
done.Wait();
- // Prentend that the migration has already taken place.
+ // Pretend that the migration has already taken place.
profile_->GetPrefs()->RegisterBooleanPref(prefs::kLoginDatabaseMigrated,
true,
PrefService::UNSYNCABLE_PREF);
@@ -481,9 +492,9 @@ TEST_P(PasswordStoreXTest, WDSMigrationAlreadyDone) {
// Initializing the PasswordStore shouldn't trigger a migration.
scoped_refptr<PasswordStoreX> store(
new PasswordStoreX(login_db_.release(),
- profile_.get(),
- wds_.get(),
- GetBackend()));
+ profile_.get(),
+ wds_.get(),
+ GetBackend()));
store->Init();
MockPasswordStoreConsumer consumer;
@@ -503,7 +514,8 @@ TEST_P(PasswordStoreXTest, WDSMigrationAlreadyDone) {
STLDeleteElements(&unexpected_autofillable);
- store->Shutdown();
+ // Public in PasswordStore, protected in PasswordStoreX.
+ static_cast<PasswordStore*>(store)->Shutdown();
}
TEST_P(PasswordStoreXTest, Notifications) {
@@ -515,9 +527,9 @@ TEST_P(PasswordStoreXTest, Notifications) {
// Initializing the PasswordStore shouldn't trigger a migration.
scoped_refptr<PasswordStoreX> store(
new PasswordStoreX(login_db_.release(),
- profile_.get(),
- wds_.get(),
- GetBackend()));
+ profile_.get(),
+ wds_.get(),
+ GetBackend()));
store->Init();
PasswordFormData form_data =
@@ -534,15 +546,15 @@ TEST_P(PasswordStoreXTest, Notifications) {
scoped_ptr<PasswordForm> form(CreatePasswordFormFromData(form_data));
scoped_refptr<DBThreadObserverHelper> helper = new DBThreadObserverHelper;
- helper->Init();
+ helper->Init(store);
const PasswordStoreChange expected_add_changes[] = {
PasswordStoreChange(PasswordStoreChange::ADD, *form),
};
EXPECT_CALL(helper->observer(),
- Observe(int(chrome::LOGINS_CHANGED),
- NotificationService::AllSources(),
+ Observe(int(chrome::NOTIFICATION_LOGINS_CHANGED),
+ Source<PasswordStore>(store),
Property(&Details<const PasswordStoreChangeList>::ptr,
Pointee(ElementsAreArray(
expected_add_changes)))));
@@ -565,8 +577,8 @@ TEST_P(PasswordStoreXTest, Notifications) {
};
EXPECT_CALL(helper->observer(),
- Observe(int(chrome::LOGINS_CHANGED),
- NotificationService::AllSources(),
+ Observe(int(chrome::NOTIFICATION_LOGINS_CHANGED),
+ Source<PasswordStore>(store),
Property(&Details<const PasswordStoreChangeList>::ptr,
Pointee(ElementsAreArray(
expected_update_changes)))));
@@ -584,8 +596,8 @@ TEST_P(PasswordStoreXTest, Notifications) {
};
EXPECT_CALL(helper->observer(),
- Observe(int(chrome::LOGINS_CHANGED),
- NotificationService::AllSources(),
+ Observe(int(chrome::NOTIFICATION_LOGINS_CHANGED),
+ Source<PasswordStore>(store),
Property(&Details<const PasswordStoreChangeList>::ptr,
Pointee(ElementsAreArray(
expected_delete_changes)))));
@@ -598,7 +610,8 @@ TEST_P(PasswordStoreXTest, Notifications) {
new SignalingTask(&done));
done.Wait();
- store->Shutdown();
+ // Public in PasswordStore, protected in PasswordStoreX.
+ static_cast<PasswordStore*>(store)->Shutdown();
}
TEST_P(PasswordStoreXTest, NativeMigration) {
@@ -654,9 +667,9 @@ TEST_P(PasswordStoreXTest, NativeMigration) {
// Initializing the PasswordStore shouldn't trigger a native migration (yet).
scoped_refptr<PasswordStoreX> store(
new PasswordStoreX(login_db_.release(),
- profile_.get(),
- wds_.get(),
- GetBackend()));
+ profile_.get(),
+ wds_.get(),
+ GetBackend()));
store->Init();
MockPasswordStoreConsumer consumer;
@@ -740,7 +753,8 @@ TEST_P(PasswordStoreXTest, NativeMigration) {
STLDeleteElements(&expected_autofillable);
STLDeleteElements(&expected_blacklisted);
- store->Shutdown();
+ // Public in PasswordStore, protected in PasswordStoreX.
+ static_cast<PasswordStore*>(store)->Shutdown();
}
INSTANTIATE_TEST_CASE_P(NoBackend,
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 7a45515..c2981fd 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -3857,7 +3857,7 @@
'conditions': [
['use_gnome_keyring==1', {
'dependencies': [
- '../build/linux/system.gyp:gnome-keyring',
+ '../build/linux/system.gyp:gnome_keyring',
],
}],
['linux_breakpad==1', {
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index dbf61c0..a8ab510 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1490,12 +1490,14 @@
'browser/password_manager/encryptor_password_mac_unittest.cc',
'browser/password_manager/encryptor_unittest.cc',
'browser/password_manager/login_database_unittest.cc',
+ 'browser/password_manager/native_backend_gnome_x_unittest.cc',
'browser/password_manager/password_form_data.cc',
'browser/password_manager/password_form_manager_unittest.cc',
'browser/password_manager/password_manager_unittest.cc',
'browser/password_manager/password_store_default_unittest.cc',
'browser/password_manager/password_store_mac_unittest.cc',
'browser/password_manager/password_store_win_unittest.cc',
+ 'browser/password_manager/password_store_x_unittest.cc',
'browser/plugin_exceptions_table_model_unittest.cc',
'browser/policy/asynchronous_policy_loader_unittest.cc',
'browser/policy/asynchronous_policy_provider_unittest.cc',
@@ -1827,7 +1829,7 @@
'browser/ui/content_settings/content_setting_bubble_model_unittest.cc',
'browser/ui/content_settings/content_setting_image_model_unittest.cc',
'browser/ui/find_bar/find_backend_unittest.cc',
- 'browser/ui/gtk/accelerators_gtk_unittest.cc',
+ 'browser/ui/gtk/accelerators_gtk_unittest.cc',
'browser/ui/gtk/bookmarks/bookmark_bar_gtk_unittest.cc',
'browser/ui/gtk/bookmarks/bookmark_editor_gtk_unittest.cc',
'browser/ui/gtk/bookmarks/bookmark_utils_gtk_unittest.cc',
@@ -2087,11 +2089,12 @@
}],
['chromeos==1', {
'sources/': [
+ ['exclude', '^browser/notifications/desktop_notifications_unittest.cc'],
+ ['exclude', '^browser/password_manager/native_backend_gnome_x_unittest.cc'],
+ ['exclude', '^browser/renderer_host/gtk_key_bindings_handler_unittest.cc'],
# TODO(thestig) Enable PrintPreviewUI tests on CrOS when
# print preview is enabled on CrOS.
- ['exclude', 'browser/notifications/desktop_notifications_unittest.cc'],
- ['exclude', 'browser/renderer_host/gtk_key_bindings_handler_unittest.cc'],
- ['exclude', 'browser/ui/webui/print_preview_ui_unittest.cc'],
+ ['exclude', '^browser/ui/webui/print_preview_ui_unittest.cc'],
],
}, { # else: chromeos == 0
'sources/': [
@@ -2111,15 +2114,30 @@
}],
['toolkit_views==1', {
'sources!': [
- 'browser/ui/gtk/accelerators_gtk_unittest.cc',
- 'browser/ui/gtk/bookmarks/bookmark_bar_gtk_unittest.cc',
- 'browser/ui/gtk/bookmarks/bookmark_editor_gtk_unittest.cc',
- 'browser/ui/gtk/gtk_chrome_shrinkable_hbox_unittest.cc',
- 'browser/ui/gtk/gtk_expanded_container_unittest.cc',
- 'browser/ui/gtk/gtk_theme_service_unittest.cc',
- 'browser/ui/gtk/omnibox/omnibox_popup_view_gtk_unittest.cc',
- 'browser/ui/gtk/reload_button_gtk_unittest.cc',
- 'browser/ui/gtk/status_icons/status_tray_gtk_unittest.cc',
+ 'browser/ui/gtk/accelerators_gtk_unittest.cc',
+ 'browser/ui/gtk/bookmarks/bookmark_bar_gtk_unittest.cc',
+ 'browser/ui/gtk/bookmarks/bookmark_editor_gtk_unittest.cc',
+ 'browser/ui/gtk/gtk_chrome_shrinkable_hbox_unittest.cc',
+ 'browser/ui/gtk/gtk_expanded_container_unittest.cc',
+ 'browser/ui/gtk/gtk_theme_service_unittest.cc',
+ 'browser/ui/gtk/omnibox/omnibox_popup_view_gtk_unittest.cc',
+ 'browser/ui/gtk/reload_button_gtk_unittest.cc',
+ 'browser/ui/gtk/status_icons/status_tray_gtk_unittest.cc',
+ ],
+ }],
+ ['chromeos==0', {
+ 'conditions': [
+ ['use_gnome_keyring==1', {
+ # We use a few library functions directly, so link directly.
+ 'dependencies': [
+ '../build/linux/system.gyp:gnome_keyring_direct',
+ ],
+ }, {
+ # Disable the GNOME Keyring tests if we are not using it.
+ 'sources!': [
+ 'browser/password_manager/native_backend_gnome_x_unittest.cc',
+ ],
+ }],
],
}],
],